如何在单个 canvas 中为多个笔划创建公共阴影?

How to create a common shadow for multiple strokes in a single canvas?

我正在尝试在 canvas 上绘制多个笔触,我希望它们有一个共同的阴影。目前相互投射的阴影不是我想要的。

理想结果

我试过的

如果您需要每个笔划都是独立的(即它们都有自己的 strokeStyle 或 lineWidth),您将需要使用第二个分离的 canvas:

  • 在这个分离的 canvas 上,你画的所有笔触都没有阴影
  • drawImage 分离 canvas 在可见的阴影上:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const detached = canvas.cloneNode();
const detachedCtx = detached.getContext("2d");
const colors = ["green", "blue", "yellow", "orange", "aqua"];  

detachedCtx.lineWidth = 5;
for (let color of colors) {
  // draw on the detached canvas
  detachedCtx.beginPath();
  for (let i = 0; i<5; i++) {
    detachedCtx.lineTo(Math.random() * canvas.width, Math.random() * canvas.height);
  }
  detachedCtx.strokeStyle = color;
  detachedCtx.lineWidth = Math.random() * 8 + 2;
  detachedCtx.stroke();
}

// now draw all this with shadows on the visible canvas
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
ctx.shadowBlur    = 3;
ctx.shadowColor   = "red";
ctx.drawImage(detached, 0, 0);
<canvas></canvas>

但是要生成图像,您只需要在完成完整路径后调用 stroke() 一次:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

ctx.fillStyle = "#0F0";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.lineWidth = 5;
ctx.shadowOffsetX = -3;
ctx.shadowOffsetY = -3;
ctx.shadowBlur    = 3;
ctx.shadowColor   = "red";
ctx.moveTo(10, 50);
ctx.lineTo(90, 50);
ctx.moveTo(50, 10);
ctx.lineTo(50, 90);
ctx.stroke(); // stroke only once, with the full path being traced
<canvas width=100 height=100></canvas>

您可以使用 Path2D 并将所有线段添加到一条路径,然后对该路径进行描边。

这是我推荐的使用 ctx.filter 的 jsfiddle。

const segments = [
 [{x: 10, y: 50}, {x: 50, y: 50}],
 [{x: 50, y: 10}, {x: 50, y: 50}],
 [{x: 90, y: 50}, {x: 50, y: 50}],
 [{x: 50, y: 90}, {x: 50, y: 50}],
]

let path = new Path2D()
segments.forEach(segment => {  
  path.moveTo(segment[0].x, segment[0].y)
  path.lineTo(segment[1].x, segment[1].y)  
})

const ctx = document.getElementById('my-canvas').getContext('2d')
ctx.lineWidth = 5
ctx.filter = 'drop-shadow(-3px -3px 3px #f00)';
ctx.strokeStyle = 'black'
ctx.stroke(path)
<canvas width="100" height="100" id="my-canvas" style="background: #00ff00"/>

您可以在此处阅读有关 Path2D 的更多信息:
https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D