显示带有阴影效果的底部 canvas - 裁剪区域内的阴影
Display bottom canvas with a shadow effect - shadow within clipped area
我是 canvas 的新手,感谢您的耐心等待。
我编写了一个引擎,它在 2 个 canvas 元素中创建了 2 个不同的层,这些元素层层叠叠。它们包含一些生成的图片,这里不重要。
我正在尝试创建一种效果,当我将鼠标移到顶层上并单击时将显示底层。
像这样:
这是我目前尝试过的方法:
- 在 canvas 元素上使用透明度并显示底部 canvas(快速但不可用)
- 重新创建剪辑区域。
每当我按下鼠标时,我都会存储当前坐标并使用更新的剪辑区域 重新渲染 canvas
如果我使用描边创建阴影,更新剪辑区域会很慢 + 我不确定如何从中删除线条(见图)。
如果我去掉阴影效果,效果会非常快,但我需要它。
我唯一想到的是如何加快速度,就是保存每次点击的坐标,然后将其重新计算为 1 个形状并在其上投下阴影 - 我仍然会有线条,但它会更快,因为不会画上千个圆...
任何帮助将不胜感激!
您可以利用浏览器的内置插值,将其用作伪低通滤波器,但首先将其涂成黑色:
- 将顶层复制到底层
- 设置源输入补偿。模式
- 全黑
- 设置源输入补偿。模式
- 将图像缩小到 25%
- 将 25% 的区域缩放回原来的 50%(或当前的两倍)
- 将现在 50% 的区域缩放回原来的 100%。会模糊。
根据您想要的模糊程度,您可以添加额外的步骤。话虽这么说:模糊阴影无论如何扭曲都是一个密集的操作。可以做出妥协,例如仅渲染鼠标上的阴影(如下面的演示所示)。
例子
使用两层的示例。顶层让你画任何东西,底层会在稍后绘制时在底部显示阴影版本。
var ctx = document.getElementById("top").getContext("2d"),
bctx = document.getElementById("bottom").getContext("2d"),
bg = new Image(),
isDown = false;
bg.src = "http://i.imgur.com/R2naCpK.png";
ctx.fillStyle = "#27f";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.globalCompositeOperation = "destination-out"; // "eraser"
ctx.canvas.onmousedown = function(e) {isDown = true};
window.onmousemove = function(e) {
if (!isDown) return;
var pos = getPos(ctx.canvas, e);
ctx.beginPath();
ctx.moveTo(pos.x + 10, pos.y);
ctx.arc(pos.x, pos.y, 10, 0, 2*Math.PI); // erase while drawing
ctx.fill();
};
window.onmouseup = function(e) {
if (isDown) {
isDown = false;
makeShadow();
}
};
function makeShadow(){
var w = bctx.canvas.width,
h = bctx.canvas.height,
offset = 7,
alpha = 0.75;
// reset alpha
bctx.globalAlpha = 1;
// normal comp mode to clear as it is faster than using "copy"
bctx.globalCompositeOperation = "source-over";
bctx.clearRect(0, 0, w, h);
// copy top-layer to bottom-layer
bctx.drawImage(ctx.canvas, 0, 0);
// comp. mode will only draw in to non-alpha pixels next
bctx.globalCompositeOperation = "source-in";
// black overlay
bctx.fillRect(0, 0, w, h);
// copy mode so we don't need an extra canvas
bctx.globalCompositeOperation = "copy";
// step 1: reduce to 50% (quality related - create more steps to increase blur/quality)
bctx.drawImage(bctx.canvas, 0, 0, w, h, 0, 0, w * 0.5, h * 0.5);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, 0, 0, w * 0.25, h * 0.25);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.25, h * 0.25, 0, 0, w * 0.5, h * 0.5);
// shadow transparency
bctx.globalAlpha = alpha;
// step 2: draw back up to 100%, draw offset
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, offset, offset, w, h);
// comp in background image
bctx.globalCompositeOperation = "destination-over";
bctx.drawImage(bg, 0, 0, w, h);
}
function getPos(canvas, e) {
var r = canvas.getBoundingClientRect();
return {x: e.clientX - r.left, y: e.clientY - r.top};
}
div {position:relative;border:1px solid #000;width:500px;height:500px}
canvas {position:absolute;left:0;top:0}
#bottom {background:#eee}
<div>
<canvas id="bottom" width=500 height=500></canvas>
<canvas id="top" width=500 height=500></canvas>
</div>
我是 canvas 的新手,感谢您的耐心等待。
我编写了一个引擎,它在 2 个 canvas 元素中创建了 2 个不同的层,这些元素层层叠叠。它们包含一些生成的图片,这里不重要。
我正在尝试创建一种效果,当我将鼠标移到顶层上并单击时将显示底层。
像这样:
这是我目前尝试过的方法:
- 在 canvas 元素上使用透明度并显示底部 canvas(快速但不可用)
- 重新创建剪辑区域。
每当我按下鼠标时,我都会存储当前坐标并使用更新的剪辑区域 重新渲染 canvas
如果我使用描边创建阴影,更新剪辑区域会很慢 + 我不确定如何从中删除线条(见图)。
如果我去掉阴影效果,效果会非常快,但我需要它。
我唯一想到的是如何加快速度,就是保存每次点击的坐标,然后将其重新计算为 1 个形状并在其上投下阴影 - 我仍然会有线条,但它会更快,因为不会画上千个圆...
任何帮助将不胜感激!
您可以利用浏览器的内置插值,将其用作伪低通滤波器,但首先将其涂成黑色:
- 将顶层复制到底层
- 设置源输入补偿。模式
- 全黑
- 设置源输入补偿。模式
- 将图像缩小到 25%
- 将 25% 的区域缩放回原来的 50%(或当前的两倍)
- 将现在 50% 的区域缩放回原来的 100%。会模糊。
根据您想要的模糊程度,您可以添加额外的步骤。话虽这么说:模糊阴影无论如何扭曲都是一个密集的操作。可以做出妥协,例如仅渲染鼠标上的阴影(如下面的演示所示)。
例子
使用两层的示例。顶层让你画任何东西,底层会在稍后绘制时在底部显示阴影版本。
var ctx = document.getElementById("top").getContext("2d"),
bctx = document.getElementById("bottom").getContext("2d"),
bg = new Image(),
isDown = false;
bg.src = "http://i.imgur.com/R2naCpK.png";
ctx.fillStyle = "#27f";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.globalCompositeOperation = "destination-out"; // "eraser"
ctx.canvas.onmousedown = function(e) {isDown = true};
window.onmousemove = function(e) {
if (!isDown) return;
var pos = getPos(ctx.canvas, e);
ctx.beginPath();
ctx.moveTo(pos.x + 10, pos.y);
ctx.arc(pos.x, pos.y, 10, 0, 2*Math.PI); // erase while drawing
ctx.fill();
};
window.onmouseup = function(e) {
if (isDown) {
isDown = false;
makeShadow();
}
};
function makeShadow(){
var w = bctx.canvas.width,
h = bctx.canvas.height,
offset = 7,
alpha = 0.75;
// reset alpha
bctx.globalAlpha = 1;
// normal comp mode to clear as it is faster than using "copy"
bctx.globalCompositeOperation = "source-over";
bctx.clearRect(0, 0, w, h);
// copy top-layer to bottom-layer
bctx.drawImage(ctx.canvas, 0, 0);
// comp. mode will only draw in to non-alpha pixels next
bctx.globalCompositeOperation = "source-in";
// black overlay
bctx.fillRect(0, 0, w, h);
// copy mode so we don't need an extra canvas
bctx.globalCompositeOperation = "copy";
// step 1: reduce to 50% (quality related - create more steps to increase blur/quality)
bctx.drawImage(bctx.canvas, 0, 0, w, h, 0, 0, w * 0.5, h * 0.5);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, 0, 0, w * 0.25, h * 0.25);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.25, h * 0.25, 0, 0, w * 0.5, h * 0.5);
// shadow transparency
bctx.globalAlpha = alpha;
// step 2: draw back up to 100%, draw offset
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, offset, offset, w, h);
// comp in background image
bctx.globalCompositeOperation = "destination-over";
bctx.drawImage(bg, 0, 0, w, h);
}
function getPos(canvas, e) {
var r = canvas.getBoundingClientRect();
return {x: e.clientX - r.left, y: e.clientY - r.top};
}
div {position:relative;border:1px solid #000;width:500px;height:500px}
canvas {position:absolute;left:0;top:0}
#bottom {background:#eee}
<div>
<canvas id="bottom" width=500 height=500></canvas>
<canvas id="top" width=500 height=500></canvas>
</div>