vrijdag 24 april 2015

Canvas LineWidth 0



For a client I have to create a graph with a linewidth of 1 pixel, regardless of the
scaling of the matrix the canvas is currently operating under.

So for instance:
var c = document.getElementById("theCanvas");
var ctx = c.getContext("2d");
ctx.scale(5,5);
ctx.lineWidth = 1;
ctx.strokeRect(20, 20, 80, 100);

This will ofcourse render a line thickness of 5.
Now I tried the following:

var c = document.getElementById("theCanvas");
var ctx = c.getContext("2d");
ctx.scale(5,5);
ctx.lineWidth = 0.001;
ctx.strokeRect(20, 20, 80, 100);

This will give you a line thickness of 0.005 and the line will hardly be visible (antialiased to a nice alpha version of your color.)
However lineWidth has an exception for lineWidth = 0!
It will default to 1 instead.
I thought: "Haleluja, some developer has foreseen my plight."
But alas no..

var c = document.getElementById("theCanvas");
var ctx = c.getContext("2d");
ctx.scale(5,5);
ctx.lineWidth = 0;
ctx.strokeRect(20, 20, 80, 100);

Yields a line of 5 pixels thickness. How can this be? Well, the function linewidth has a very simple error catch: if 0 -> 1 (Because linewidth 0 doesn't make sense)
After it's been set to 1 the scale is adapted and the line becomes 5pixels thick.

I only tested it in Chrome, maybe other browsers behave differently, but that's enough for me. It's a bust. The way to fix it is to keep track of your transforms.

var c = document.getElementById("theCanvas");
var s=1;
var ctx = c.getContext("2d");
ctx.scale(5,5);
s=s*5;
ctx.scale(0.5,0.5);
s=s*0.5;
ctx.lineWidth = 1/s; // for a single pixel line..
ctx.strokeRect(20, 20, 80, 100);

This will yield a scaled rectangle with a single pixel line.
It works pretty good, but there is no guarantee it will behave exactly the same way as expected with a hairline.

I hope someday ..... lineWidth 0 will yeald the expected result.

In line with this issue:
http://stackoverflow.com/questions/195262/can-i-turn-off-antialiasing-on-an-html-canvas-element