Reputation: 153
I have a semi-transparent shape:
this.cx.beginPath();
this.cx.globalAlpha = .1;
this.cx.fillStyle = gradientFill;
this.cx.strokeStyle = gradientStroke;
this.cx.arc(150, 150, 139, 0, Math.PI * 2, true);
this.cx.lineWidth = 1;
this.cx.stroke();
this.cx.fill();
I want to add a bit of shadow, but I want it to only appear outside of the shape, I guess more of a glow than a shadow. Is there a way to do this in canvas as my attempts with:
this.cx.shadowColor = 'rgba(0, 0, 0, .75)';
this.cx.shadowBlur = 5;
this.cx.shadowOffsetX = 5;
this.cx.shadowOffsetY = -5;
Look fairy ordinary as the dark shadow is visible through the semi-transparent shape.
Thanks!
Upvotes: 0
Views: 564
Reputation: 137044
One way is to use globalCompositeOperations in order to keep only your outer shadow first, and then redraw your semi-transparent parts over it.
But note that you'll have a lot of artifact noise...
(async function() {
var ctx = c.getContext('2d');
// commons
var gradientFill = ctx.createLinearGradient(0, 0, 200, 0);
gradientFill.addColorStop(0, 'rgba(0,0,0,0)')
gradientFill.addColorStop(1, 'rgba(255,0,0,1)')
var gradientStroke = ctx.createLinearGradient(0, 0, 200, 0);
gradientStroke.addColorStop(0, 'rgba(0,0,0,0)')
gradientStroke.addColorStop(1, 'rgba(0,255,0,1)')
ctx.lineWidth = 5;
// needed only once
ctx.beginPath();
ctx.arc(150, 150, 139, 0, Math.PI * 2, true);
await wait(1000); // simply to show each step
// firt we draw only the shadow with black fill and stroke
ctx.shadowColor = 'rgba(0, 0, 0, .75)';
ctx.shadowBlur = 5;
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = -5;
ctx.stroke();
ctx.fill();
await wait(1000);
// then keep only the shadow
ctx.globalCompositeOperation = 'destination-out'; // will erase existing content at drawn position
ctx.shadowColor = 'transparent'; // remove the shadow
ctx.stroke();
ctx.fill();
await wait(1000);
// finally draw the semi-transparent version
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = .1;
ctx.fillStyle = gradientFill;
ctx.strokeStyle = gradientStroke;
ctx.stroke();
ctx.fill();
})();
function wait(t) {
return new Promise(r => setTimeout(r, t))
}
<canvas id="c" height="300"></canvas>
Upvotes: 1