Opacity is how a canvas creates the appearance of lines narrower than a pixel, because a pixel is (by definition) the smallest unit a canvas works with.
That doesn't mean all hope is lost, however, because this is only a problem depending on what you mean by "pixel".
There's the CSS unit px
, which corresponds to what used to be the smallest actual pixels available on video display devices, typically in the range of 72-96 per inch (28-38 per cm).
And then there are actual device pixels, which are now often half as small or smaller.
The trick to getting sharper lines with a canvas when you've got high-res device pixels is scaling. Use this to figure how much you can effectively scale:
const scaling = window.devicePixelRatio || 1;
Suppose the value here is 2 (as it is on my current laptop). If you want to create a canvas that occupies, say, 400px by 300px, create an 800x600 canvas. Then use CSS styling width: 400px; height: 300px
on your canvas.
Now you'll be able to create sharp half-width lines so long as the device you're drawing to supports the higher resolution.
I use this trick many places in the Angular app at https://skyviewcafe.com/. There's a link there to the source code if you want to dig through it to find examples of high-res canvas drawing.
Please note!
You're either have to specify a lineWidth
of 1 when you mean half-width, or use canvas scaling like this:
const context = this.canvas.getContext('2d');
context.scale(scaling, scaling);
Be careful with context.scale()
— its effects are cumulative. If you execute context.scale(2, 2)
twice in a row with the same context, your scaling factor will be 4, not 2.
context.setTransform(1, 0, 0, 1, 0, 0);
...resets the scaling factor if you want to call context.scale()
more than once, without the effect being cumulative.