Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does HTML Canvas rounded lineCap fail for last segment?

Tags:

html

canvas

With the HTML Canvas if you draw a dotted line like this:

ctx.lineWidth   = 40;
ctx.lineCap     = 'round';
ctx.strokeStyle = 'red';

ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(150,200);
ctx.moveTo(200,300);
ctx.lineTo(250,400);
ctx.moveTo(300,500);
ctx.lineTo(350,600);
ctx.closePath();
ctx.stroke();

then the result is this:

Dashed line with first two dashes using rounded line caps and last dash using butt caps
(source: phrogz.net)

As you can see on this test page, adding a "superfluous" moveTo call after the last lineTo fixes the last line segment to use rounded caps.

I was prepared to file this as a bug, but then I found that the behavior is identical on Safari v5, Chrome v8, and FireFox v3.6 and v4.0b. This leads me to believe that it is intentional.

Where in the standard is this behavior specified, and (if you can discern it) why was it specced as such?

like image 640
Phrogz Avatar asked Jan 02 '11 06:01

Phrogz


People also ask

What is lineCap?

Definition and Usage The lineCap property sets or returns the style of the end caps for a line. Note: The value "round" and "square" make the lines slightly longer. Default value: butt.

What is lineJoin?

Definition and Usage. The lineJoin property sets or returns the type of corner created, when two lines meet. Note: The "miter" value is affected by the miterLimit property.


1 Answers

Here are the relevant definitions from the canvas spec (section 9, paths):

The moveTo(x, y) method must create a new subpath with the specified point as its first (and only) point.

The lineTo(x, y) method ... must connect the last point in the subpath to the given point (x, y) using a straight line, and must then add the given point (x, y) to the subpath.

The closePath() method ... must mark the last subpath as closed ... this is equivalent to adding a straight line connecting the last point back to the first point, thus "closing" the shape ...

Each moveTo call creates a new subpath, thus ending the previous subpath. In your case, the first two segments are ended this way. For the final segment, calling closePath "closes" the segment by drawing another segment in the reverse direction, hence the result you are seeing -- there is not one segment but rather two overlapping segments. Adding another moveTo ends this segment just like the others, so you see the rounded line cap as expected.

like image 103
casablanca Avatar answered Oct 10 '22 03:10

casablanca