0

The following snippet draws vertical lines on a canvas (1px width). However, some lines appear to be wider than others, some are blurry, others are ok. In different posts i've read that one needs to substract 0.5 px or translate coordinates. It doesn't work in my case.

I've tried using translate by a factor odf 0.5, rounding coordinates and manually adding 0.5 (see the variations of the drawLine method). Nothing works

How can i get the vertical lines to be crisp and clean?

thank you

function doStuff() {
  var cnv = document.getElementById("cnvs");
  var ctx = cnv.getContext("2d");
  var lw = 1;
  ctx.lineWidth = lw;
  var xMax = cnv.width;
  var ygMax = cnv.height;

  var iTranslate = 0.5; // (lw % 2) / 2;
  ctx.translate(iTranslate, iTranslate);

  deltaX = 12;

  for (var x = deltaX; x < xMax; x += deltaX) {
    drawLine(ctx, x, ygMax, x, 0);
  }
}

function drawLine(ctx, x0, y0, xf, yf) {
  ctx.beginPath();
  ctx.moveTo(x0, y0);
  ctx.lineTo(xf, yf);
  ctx.stroke();
  ctx.closePath();
}

function drawLine2(ctx, x0, y0, xf, yf) {
    ctx.beginPath();
    ctx.moveTo(Math.round(x0), y0);
    ctx.lineTo(Math.round(xf), yf);
    ctx.stroke();
    ctx.closePath();
}

function drawLine3(ctx, x0, y0, xf, yf) {
    ctx.beginPath();
    ctx.moveTo(x0 + 0.5, y0);
    ctx.lineTo(xf + 0.5, yf);
    ctx.stroke();
    ctx.closePath();
}

doStuff();
<canvas id="cnvs" width="200" height="100"></canvas>
  • Possible duplicate of [Can I turn off antialiasing on an HTML element?](http://stackoverflow.com/questions/195262/can-i-turn-off-antialiasing-on-an-html-canvas-element) – Mike Cluck May 20 '16 at 19:45
  • @MikeC hi mike i tried playing with ctx.imageSmoothingEnabled = false / true; to see if it makes any difference but lines are blurry either way. – Prefijo Sustantivo May 20 '16 at 19:52
  • Read the rest of the answer. That only works for images. There isn't a simple solution for fixing this with normal lines. – Mike Cluck May 20 '16 at 19:53
  • @MikeC well, i think i've already tried all the solutions there (except the Bresenham algorithm) and nothing works... – Prefijo Sustantivo May 20 '16 at 20:05

2 Answers2

1

The lines shown in the code are as crisp as they can get. Lines cannot be thinner than one pixel (this is what I get from your code in Firefox and Opera):

https://i.stack.imgur.com/SXoWX.png

You can from this point only give the illusion of them being thinner by reducing the blackness. For example, if you stroke with mid-gray (#777) color they will appear like this:

https://i.stack.imgur.com/xmF9z.png

But they are the exact same size.

This illusion is the same that you would get if you used a line width of 0.5 or used a double sized canvas and reduced it to half using CSS (in those cases due to resampling / interpolation).

Addendum: If the lines in the images above still look uneven there is the possibility that your monitor settings aren't optimal, ie. the resolution in use does not match the physical pixels of the screen. Check that the system settings are using the recommended resolution as any other will force interpolation/resampling at system/hardware level and no matter what you do in canvas won't help.

function doStuff() {
  var cnv = document.getElementById("cnvs");
  var ctx = cnv.getContext("2d");
  var lw = 1;
  ctx.lineWidth = lw;
  var xMax = cnv.width;
  var ygMax = cnv.height;

  var iTranslate = 0.5; // (lw % 2) / 2;
  ctx.translate(iTranslate, iTranslate);

  deltaX = 12;

  ctx.strokeStyle = "#777";
  
  for (var x = deltaX; x < xMax; x += deltaX) {
    drawLine(ctx, x, ygMax, x, 0);
  }
}

function drawLine(ctx, x0, y0, xf, yf) {
  ctx.beginPath();
  ctx.moveTo(x0, y0);
  ctx.lineTo(xf, yf);
  ctx.stroke();
}

doStuff();
<canvas id="cnvs" width="200" height="100"></canvas>
  • hi. i dont want lines to be thinner than 1 px. i want all lines to be the same width. In the first image, lines 7 and 8 (counting ltr) are thinner than line 1. thanks. – Prefijo Sustantivo May 20 '16 at 20:34
  • @PrefijoSustantivo they are all at the same width. The image should show this. Does the lines in the image in the answer appear uneven too? If so it could be that your monitor size settings aren't optimal (the resolution does not match the actual physical pixels) –  May 20 '16 at 20:36
  • well, here at the office, various monitors show both images as uneven. for instance, in the first image, lines in the middle appear to be thinner than lines at the sides, and in the second image (the one depicting the color shade trick), lines in the middle appear to be lighter and wider than lines at the sides. this is crazy! – Prefijo Sustantivo May 20 '16 at 20:56
  • 1
    computers in another office display images properly. it seems its a screen configuration problem as you pointed out. thank you. – Prefijo Sustantivo May 20 '16 at 21:12
0

It'd be better to round your coordinates to an integer rather than changing the values by 0.5 every time - for example, x = Math.floor(x) (to round down automatically) or x = Math.round(x) (for more traditional rounding). Coordinates can be off by intervals other than 0.5, which would make them render fuzzily as you're experiencing.

Sander Moolin
  • 450
  • 4
  • 11
  • While this is right 99% of the time, it won't help them if they're translating the entire canvas by fractions of a pixel. – Mike Cluck May 20 '16 at 19:41
  • @sander hi sander. thanks for your answer. i tried the method you described (via the drawLine2 method) but still get blurry lines – Prefijo Sustantivo May 20 '16 at 19:49