There is no way to get a real world dimension of details for the canvas such as millimeters or inches so you will have to do it in pixels.
As the canvas resolution decreases the pixel width of a line needs to decrease as well. The limiting property of line width is a pixel. Rendering a line narrower than a pixel will only approximate the appearance of a narrower line by reducing the opacity (this is done automatically)
You need to define the line width in terms of the lowest resolution you will expect, within reason of course and adjust that width as the canvas resolution changes in relation to this selected ideal resolution.
If you are scaling the chart by different amounts in the x and y directions you will have to use the ctx.scale
or ctx.setTransform
methods. As you say you do not want to do this I will assume that your scaling is always with a square aspect.
So we can pick the lowest acceptable resolution. Say 512 pixels for either width or height of the canvas and select the lineWidth
in pixels for that resolution.
Thus we can create two constants
const NATIVE_RES = 512; // the minimum resolution we reasonably expect
const LINE_WIDTH = 1; // pixel width of the line at that resolution
// Note I Capitalize constants, This is non standard in Javascript
Then to calculate the actual line width is simply the actual canvas.width
divided by the NATIVE_RES
then multiply that result by the LINE_WIDTH
.
var actualLineWidth = LINE_WIDTH * (canvas.width / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
You may want to limit that size to the smallest canvas dimension. You can do that with Math.min
or you can limit it in the largest dimension with Math.max
For min dimention.
var actualLineWidth = LINE_WIDTH * (Math.min(canvas.width, canvas.height) / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
For max dimension
var actualLineWidth = LINE_WIDTH * (Math.max(canvas.width, canvas.height) / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
You could also consider the diagonal as the adjusting factor that would incorporate the best of both x and y dimensions.
// get the diagonal resolution
var diagonalRes = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height)
var actualLineWidth = LINE_WIDTH * (diagonalRes / NATIVE_RES);
ctx.lineWidth = actualLineWidth;
And finally you may wish to limit the lower range of the line to stop strange artifacts when the line gets smaller than 1 pixel.
Set lower limit using the diagonal
var diagonalRes = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height)
var actualLineWidth = Math.max(1, LINE_WIDTH * (diagonalRes / NATIVE_RES));
ctx.lineWidth = actualLineWidth;
This will create a responsive line width that will not go under 1 pixel if the canvas diagonal resolution goes under 512.
The method you use is up to you. Try them out a see what you like best. The NATIVE_RES
I picked "512" is also arbitrary and can be what ever you wish. You will just have to experiment with the values and method to see which you like best.
If your scaling aspect is changing then there is a completely different technique to solve that problem which I will leave for another question.
Hope this has helped.