I'm trying to draw multiple strokes on a canvas and I'd like them to have a common shadow. Currently the cast shadows on one another which is not what I want.
If you need each stroke to be independent (i.e so that they have each their own strokeStyle or lineWidth), you will need to use a second detached canvas:
drawImage
that detached canvas on the visible one with the shadow: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>
But to produce the image you have all you need is to call stroke()
only once after you did compose your full path:
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>
You can use Path2D
and add all your segments to one path, then do the stroke to that path.
Here is your jsfiddle using ctx.filter with my recommendation.
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"/>
You can read more about Path2D
here:
https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D