Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transparency of a filled stroke in HTML5

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:

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.

You should be able to see what I'm talking about live in this sandbox.

like image 388
Mathieu Avatar asked Feb 10 '12 16:02

Mathieu


People also ask

What is stroke opacity?

The stroke-opacity attribute is a presentation attribute defining the opacity of the paint server (color, gradient, pattern, etc.) applied to the stroke of a shape. Note: As a presentation attribute stroke-opacity can be used as a CSS property.

What is stroke in HTML?

The stroke() method of the HTML canvas is used to draw the path. This path is drawn with moveTo() and lineTo() method. The <canvas> element allows you to draw graphics on a web page using JavaScript. Every canvas has two elements that describes the height and width of the canvas i.e. height and width respectively.

How do you fill a rectangle with color in HTML?

The fillRect() method draws a "filled" rectangle. The default color of the fill is black. Tip: Use the fillStyle property to set a color, gradient, or pattern used to fill the drawing.


2 Answers

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);
like image 149
Simon Sarris Avatar answered Sep 26 '22 07:09

Simon Sarris


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.

like image 25
Mathieu Avatar answered Sep 24 '22 07:09

Mathieu