Reynau
Reynau

Reputation: 304

Diagonal lines on canvas are drawing with different color/opacity

I'm drawing diagonal lines on an HTML canvas with a specific size, but some of them appear to have different color/opacity than the others. I would like them to have the same color/opacity.

Diagonal lines picture

The code I'm using to generate this output is the following:

let artist = {
    step: 50,
    distanceBetweenLines: 10,
    verticalDifferenceInLines: 150,
}

window.onload = function () {
    canv = document.getElementById("gc");
    ctx = canv.getContext("2d");
    ctx.translate(0.5, 0.5);
    ctx.lineWidth = "1";
    ctx.strokeStyle = "black";

    draw();
}

function draw () {
    let step = artist.step;
    let d = artist.distanceBetweenLines;
    let v = artist.verticalDifferenceInLines;

    for (let x = 0; x < 500; x += step) {
        for (let y = 0; y < 500; y += step) {
            let increment = 30;
            line({x:x, y: y}, {x:x+increment, y: y+increment});
        }
    }
}

function line(init, end) {
    ctx.beginPath();
    ctx.moveTo(init.x, init.y);
    ctx.lineTo(end.x, end.y);
    ctx.stroke();
}

Why I'm getting this effect on some of the lines?

Upvotes: 2

Views: 524

Answers (1)

Kaiido
Kaiido

Reputation: 137016

This is a chrome bug. I opened an issue here.

That's basically a problem with Hardware Acceleration, if you disable it, it will render nicely even in Chrome.

To workaround the issue, you can compose a single bigger path which will contain all your lines and call stroke() only once:

let artist = {
  step: 50,
  distanceBetweenLines: 10,
  verticalDifferenceInLines: 150,
}

window.onload = function() {
  canv = document.getElementById("gc");
  ctx = canv.getContext("2d");
  ctx.translate(0.5, 0.5);
  ctx.lineWidth = "1";
  ctx.strokeStyle = "black";

  draw();
}

function draw() {
  let step = artist.step;
  let d = artist.distanceBetweenLines;
  let v = artist.verticalDifferenceInLines;
  
  // a single big path
  ctx.beginPath();
  for (let x = 0; x < 500; x += step) {
    for (let y = 0; y < 500; y += step) {
      let increment = 30;
      line({
        x: x,
        y: y
      }, {
        x: x + increment,
        y: y + increment
      });
    }
  }
  // stroke only once
  ctx.stroke();
}

function line(init, end) {
  ctx.moveTo(init.x, init.y);
  ctx.lineTo(end.x, end.y);
}
<canvas id="gc" width="500" height="500"></canvas>

But for this exact drawing, it would even be better to use a CanvasPattern:

// An helper function to create CanvasPatterns
// returns a 2DContext on which a simple `finalize` method is attached
// method which does return a CanvasPattern from the underlying canvas
function patternMaker( width, height ) {
  const canvas = document.createElement( 'canvas' );
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext( '2d' );
  ctx.finalize = (repetition = "repeat") => ctx.createPattern( canvas, repetition );
  return ctx;
}

const canvas = document.getElementById("gc");
const ctx = canvas.getContext("2d");

const step = 50;
const offset = 30;

const patt_maker = patternMaker( step, step );
patt_maker.translate( 0.5, 0.5 );
patt_maker.moveTo( 0, 0 );
patt_maker.lineTo( offset, offset );
patt_maker.stroke();
const patt = patt_maker.finalize();

ctx.fillStyle = patt;
ctx.fillRect( 0, 0, canvas.width, canvas.height );
<canvas id="gc" width="500" height="500"></canvas>

Upvotes: 2

Related Questions