显示带阴影效果的底部画布 - 剪裁区域内的阴影

时间:2015-05-22 08:47:55

标签: javascript canvas html5-canvas

我是画布的新手,所以感谢您的耐心等待。

我写了一个引擎,它在2个画布元素中创建了2个不同的图层,这些图层是一个在另一个上面。它们包含一些生成的图片,这些图片并不重要 They are on over another

我正在尝试创建一种效果,当我将鼠标移到顶层并点击时,它会显示底层。

这样的事情:
enter image description here

这是我到目前为止所尝试的:

  1. 在canvas元素上使用透明度并显示底部画布(快速但不可用)
  2. 重新创建裁剪区域 每当我按下鼠标时,我都会存储当前坐标并使用更新的剪辑区域重新渲染画布

  3. 如果我使用笔划创建阴影,那么更新剪裁区域会很慢+我不知道如何从中删除线条(见图片)。
    Lines show up

    如果我删除阴影效果,它的效果非常快,但我需要它。

    我唯一想到的是如何加快速度,保存每次点击的坐标,然后将其重新计算成1个形状并在其上留下阴影 - 我仍然会有线条,但它会更快,因为不会有数千个圈子来画...

    非常感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

您可以利用浏览器的内置插值将其用作伪低通滤镜,但首先将其涂成黑色:

  • 将顶层复制到底层
  • 设置source-in comp。模式
  • 画全黑
  • 设置source-in comp。模式
  • 将图片缩小至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>