Why does a tiny dot appears out of nowhere on the top left corner of ctx.roundRect when using ctx.lineCap = "round"
Is this a bug in Chromium browser because it does not appear in Firefox?
Below is the code to reproduce the issue:
const ctx = canvas.getContext('2d')
let width = window.innerWidth
let height = window.innerHeight
canvas.width = width
canvas.height = height
ctx.clearRect(0,0,canvas.width, canvas.height)
ctx.lineWidth = 5
ctx.strokeStyle = "black"
ctx.lineCap = "round"
ctx.beginPath()
ctx.roundRect(100,100,100,100,12)
ctx.closePath()
ctx.stroke()
here is an image https://imgur.com/tFcbClp
This is caused by the same Chrome bug as the one that lead to this Q.A. I'll thus invite you to read my answer there for the long explanation.
The TL;DR; is that the specs are relatively confusing on how zero-length sub-paths are to be stroked, moreover with line-caps, and the 3 major implementations do differ on that.
ctx.roundRect()
is specced to
- Mark the subpath as closed.
- Create a new subpath with the point (x, y) as the only point in the subpath.
after it traced the rounded rectangle.
This is equivalent to calling ctx.closePath(); ctx.moveTo(x, y)
;
So when your script gains control again after it called ctx.roundRect()
, you indeed have a lone zero-length subpath on the context. And Chrome will render that.
They are the only ones doing this, and even did an update currently available on Canary that does remove such zero-length subpaths, but that "fix" fails to handle subpaths that are not alone (i.e when there is something more in the current path to be drawn).
But anyway, the discussions for standardizing the correct behavior™ are still going on and for the time being we just have to live with these discrepancies (there are a lot more if you start playing with setLineDash()
).
closePath()
here.As seen in the previous citation, the rounded rectangle subpath is already "marked as closed", so you don't need to call it again.