问题
I'm working on a doodling app in HTML5 and I would like to do a sort of bucket feature. The idea is to draw a path and it will be closed and filled with the selected colour (colour of the stroke). It works quite well with solid colours, but if I want to have a transparent stroke and fill, I run into this problem: http://imgur.com/0N3MW
What happens is the fill is done until the middle of the stroke (the actual sampling point of the path) so there's a line of half the size of the stroke inside the shape which is darker because it's the intersection of the fill and the stroke.
Do you see any workaround for this?
Unfortunately, I can't post to JSFiddle right now because it's on READ ONLY mode. But you should be able to see what I'm talking about live in this sandbox: http://bit.ly/AbaMLl (The website and library is unrelated to what I'm using, it's just a canvas sanbox I found)
Any ideas/leads welcome :)
回答1:
Sure, use ctx.globalCompositeOperation = 'destination-atop';
and it ought to look the way you're expecting.
Like so: http://jsfiddle.net/UcyX4/
(Take out that line in order to see the problem you're having)
Assuming its not the only thing drawn on canvas, you're probably going to have to draw this to a temporary canvas and then draw that canvas onto your normal one, otherwise it may ruin all the previously drawn shapes. So you'd need a system like so: http://jsfiddle.net/dATfj/
edit: code pasted in case of jsfiddle failure:
html:
<canvas id="canvas1" width="500" height="500"></canvas>
script:
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
var can2 = document.createElement('canvas');
can2.width = can.width;
can2.height = can.height;
ctx2 = can2.getContext('2d');
ctx.strokeStyle = 'rgba(0,0,0,0.7)';
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.lineWidth = 10;
// Stuff drawn normally before
// Here I draw one rect in the old way just to show the old way
// and show something on the canvas before:
ctx.beginPath();
ctx.rect(50,50,100,100);
ctx.fill();
ctx.stroke();
// Draw on can2 then draw can2 to can
ctx2.strokeStyle = 'rgba(0,0,0,0.7)';
ctx2.fillStyle = 'rgba(0,0,0,0.7)';
ctx2.lineWidth = 10;
ctx2.beginPath();
ctx2.rect(50,250,100,100);
ctx2.globalCompositeOperation = 'destination-atop';
ctx2.fill();
ctx2.stroke();
ctx.drawImage(can2, 0, 0);
回答2:
Simon's answer was correct at the time but it now seems that Chrome 36 has corrected a bug which affects his solution and it no longer works. It already didn't work on Firefox and it seems to be the expected behaviour: https://bugzilla.mozilla.org/show_bug.cgi?id=898375
So, how do you get this done?
You first need another canvas.
Draw your filled and stroked shape on this canvas without opacity (not in the colour and no globalAlpha).
Now, draw set the globalAlpha to whatever you want on your main canvas.
Draw the first canvas on your main one.
Set the globalAlpha to whatever you had on your main canvas.
Done.
回答3:
2018 answer : use context.globalAlpha
ex : context.globalAlpha = 0.2;
来源:https://stackoverflow.com/questions/9231531/transparency-of-a-filled-stroke-in-html5