I have been having quite a time trying to get pixel perfect straight lines on a canvas element. I have tried a number of solutions that have been proposed on other stackoverflow issues and on an issue opened on the WebGL github repo. I'm still not sure what I'm missing. I'm trying to draw a ruler (like a word processor ruler) with a triangle that represents current indentation. A paragraph of text below this ruler should have the left indent of the paragraph match the position of the triangle on the ruler. I have succeeded in doing so, but not all of the vertical lines on the ruler are perfectly sharp, some are slightly thicker than others. Here is my test sandbox for this case. The only solution that worked very nicely (as regards sharpness) on my screen (which has 1.25 devicePixelRatio) does not however work (as regards ruler size and paragraph alignment with the ruler) on screens of different dPR. The solution that works (as regards ruler size and paragraph alignment with the ruler) for all screens I have tested on does not work (as regards line sharpness) on any of the screens I have tested on. Any ideas how I can get the vertical lines to be perfectly sharp? I could certainly live with them not being perfect, but I believe in the end it makes for a better user experience when generated graphic ui interfaces are pixel perfect.
I don't think it's useful to post all of the code from the jsbin example here but I'm fundamentally doing what is recommened on the mozilla website:
//options.rulerLength == 6.25, options.initialPadding == 35
options.canvasWidth = (options.rulerLength * 96 * window.devicePixelRatio) + (options.initialPadding*2);
canvas.style.width = options.canvasWidth + 'px';
canvas.style.height = options.canvasHeight + 'px';
canvas.width = options.canvasWidth * window.devicePixelRatio;
canvas.height = options.canvasHeight * window.devicePixelRatio;
context.scale(window.devicePixelRatio,window.devicePixelRatio);
In my initial quest I had naively set out to make a ruler with exact real life unit size, until researching I found that this is currently impossible (and considered not important for web standards) so I gave up on trying to get the ruler to match real life unit inches or centimeters (since this UI is going to be part of an add-on for Google Docs, I even tried measuring the ruler at the top of a Google Docs document and in fact it does not correpond to real unit inches). And so I gave the title "the CSS inch ruler", I have abandoned attempting a real unit inch ruler and have accepted to create a "CSS unit inch" ruler. But my main priority now, other than keeping the paragraph and the ruler in sync, is that of getting pixel sharp lines...
Choosing "INCHES" and "Greater Draw Precision (on my 1.25 dPR monitor)" from the above mentioned test gives me this result:
But the soluton only works on my 1.25 dPR monitor, and only when drawing "INCHES".
Choosing the "Recommended Draw" (solution from the Mozilla website) makes the paragraph line up nicely with the ruler on all displays but gives me this kind of vertical lines:
I have tried translating the context by 0.5, I've tried translating by dPR, I've tried rounding the x position of the line that I need to draw, nothing seems to work. Some lines are sharp, others aren't. (I've only been testing on Chrome btw.) I have tried the 3 step process mentioned towards the end of this comment, still didn't work with and without rounding, with and without translating...
I haven't tried getBoundingClientRect as mentioned in this comment, I'm not sure how I would implement it, if that could be a solution and anyone can help I would be grateful. Feel free to touch up the code on the jsbin sandbox test.
I firmly believe you cannot get sharp lines because you are drawing them using the path API. I have only gotten pixel perfection by using the pixel manipulation API.