HTML5 Canvas diagonal lines get thicker or bolder after drawing another line somewhere else on the canvas (not on top)

Viewed 34

For horizontal and vertical lines, using translation of 0.5 for odd stroke widths produces crisper/sharper lines. How about the diagonal lines?

Link to jsfiddle

<!DOCTYPE html>
<html lang="en">

<body style="background: black">
    <button id="btn">Draw Next Line</button>
    <br> 
    <canvas style="border: 2px solid red" id="cnv"></canvas>
    <script>
        const ctx = document.getElementById("cnv").getContext("2d");

        debugger;

        const delta = 25;
        const color = 'white';

        const W = window.innerWidth - 80;
        const H = window.innerHeight - 100;
        ctx.canvas.width = W;
        ctx.canvas.height = H;

        ctx.lineWidth = 1;
        ctx.strokeStyle = color;

        // diagonal line.
        ctx.moveTo(0.5, 0);
        ctx.lineTo(W, H);


        ctx.stroke();
        
        // vertical lines
        let i = 0.5;
        document.getElementById("btn").onclick = () => {
            ctx.moveTo(i * delta, 0);
            ctx.lineTo(i * delta, H);
            ctx.stroke();
            i++;
        }


    </script>
</body>

</html>

As can be seen on the demo, after adding another line previously drawn diagonal lines get bolder or thicker. How to get consistent thickness/sharpness irrespective of whether the diagonal line is drawn first or last?

2 Answers

I would research a bit and draw a line manually using pixels and some online algorithm. This also involves special pixel function because we don't want the same effect over each pixel. Found this function draw_line taken from here .

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext('2d');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);

var r = 255
var g = 255
var b = 255

function pixel(x, y) {
  var id = ctx.createImageData(1, 1); // only do this once per page
  var d = id.data; // only do this once per page
  d[0] = r;
  d[1] = g;
  d[2] = b;
  d[3] = 255;
  ctx.putImageData(id, x, y);
}

let draw_line = (x1, y1, x2, y2) => {
  // Iterators, counters required by algorithm
  let x, y, dx, dy, dx1, dy1, px, py, xe, ye, i;
  // Calculate line deltas
  dx = x2 - x1;
  dy = y2 - y1;
  // Create a positive copy of deltas (makes iterating easier)
  dx1 = Math.abs(dx);
  dy1 = Math.abs(dy);
  // Calculate error intervals for both axis
  px = 2 * dy1 - dx1;
  py = 2 * dx1 - dy1;
  // The line is X-axis dominant
  if (dy1 <= dx1) {
    // Line is drawn left to right
    if (dx >= 0) {
      x = x1;
      y = y1;
      xe = x2;
    } else { // Line is drawn right to left (swap ends)
      x = x2;
      y = y2;
      xe = x1;
    }
    pixel(x, y); // Draw first pixel
    // Rasterize the line
    for (i = 0; x < xe; i++) {
      x = x + 1;
      // Deal with octants...
      if (px < 0) {
        px = px + 2 * dy1;
      } else {
        if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) {
          y = y + 1;
        } else {
          y = y - 1;
        }
        px = px + 2 * (dy1 - dx1);
      }
      // Draw pixel from line span at
      // currently rasterized position
      pixel(x, y);
    }
  } else { // The line is Y-axis dominant
    // Line is drawn bottom to top
    if (dy >= 0) {
      x = x1;
      y = y1;
      ye = y2;
    } else { // Line is drawn top to bottom
      x = x2;
      y = y2;
      ye = y1;
    }
    pixel(x, y); // Draw first pixel
    // Rasterize the line
    for (i = 0; y < ye; i++) {
      y = y + 1;
      // Deal with octants...
      if (py <= 0) {
        py = py + 2 * dx1;
      } else {
        if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) {
          x = x + 1;
        } else {
          x = x - 1;
        }
        py = py + 2 * (dx1 - dy1);
      }
      // Draw pixel from line span at
      // currently rasterized position
      pixel(x, y);
    }
  }
}


for (var i = 0; i < 50; i++) {
  draw_line(0, 0, 50, 100)
}
<canvas></canvas>

You're missing a ctx.beginPath(); call before each new line:

<!DOCTYPE html>
<html lang="en">

<body style="background: black">
    <button id="btn">Draw Next Line</button>
    <br> 
    <canvas style="border: 2px solid red" id="cnv"></canvas>
    <script>
        const ctx = document.getElementById("cnv").getContext("2d");

        debugger;

        const delta = 25;
        const color = 'white';

        const W = window.innerWidth - 80;
        const H = window.innerHeight - 100;
        ctx.canvas.width = W;
        ctx.canvas.height = H;

        ctx.lineWidth = 1;
        ctx.strokeStyle = color;

        // diagonal line.
        ctx.moveTo(0.5, 0);
        ctx.lineTo(W, H);


        ctx.stroke();
        
        // vertical lines
        let i = 0.5;
        document.getElementById("btn").onclick = () => {
            ctx.beginPath(); // <------------------------ Here
            ctx.moveTo(i * delta, 0);
            ctx.lineTo(i * delta, H);
            ctx.stroke();
            i++;
        }


    </script>
</body>

</html>

Related