Проблема с совмещением ребер при выводе наклонных линий, сглаживание в Canvas JS

219
13 апреля 2022, 12:20

Вывожу на <canvas> линии, соединенные в треугольники, полученные в результате триангуляции Делоне. При этом возникают артефакты на стыках ребер, причем они "просвечиваются" - при выводе нового рисунка поверх в ребрах между треугольниками виден предыдущий рисунок:

Если же выводить одну и ту же картинку несколько раз, например, 5, то эти артефакты "размываются" и получается ожидаемый результат:

Есть ли способ выводить это сразу со сглаживанием?

Реализовано в классе Canvas

export class Canvas {
  constructor(id) {
    this.canvas = document.getElementById(id);
    this.ctx = this.canvas.getContext('2d');
    this.triangles = [];
    this.color = '';
    const dpr = window.devicePixelRatio || 1;
    const rect = document.body.getBoundingClientRect();
    this.canvas.width  = rect.width * dpr;
    this.canvas.height = rect.height * dpr;
    this.ctx.scale(dpr, dpr);
    this.redraw();
  }
  redraw() {
    this.#update();
    // вот здесь я повторяю отрисовку
    for (let i = 0; i < 5; i++) {
      this.#draw();
    }
  }
  #draw() {
    function drawTriangle(triangle, light, color) {
      this.ctx.fillStyle = `hsl(${color}, 100%, ${30 - light * 150}%)`;
      this.ctx.beginPath();
      this.ctx.moveTo(triangle[0][0], triangle[0][1]);
      this.ctx.lineTo(triangle[1][0], triangle[1][1]);
      this.ctx.lineTo(triangle[2][0], triangle[2][1]);
      this.ctx.fill();
      this.ctx.closePath();
    }
    this.triangles.forEach((triangle, i) => 
      drawTriangle.call(this, triangle, i / this.triangles.length, this.color)
    );
  }
  #update(cols = 40, rows = 40, dps = 1) {
    function getDots(dps) { // dots per square
      const columnWidth = this.canvas.width / cols;
      const columnHeight = this.canvas.height / rows;
      const dots = [];
      for (let i = 0; i < rows; i++ ){
        const line = [];
        for (let j = 0; j < cols; j++ ){
          for (let k = 0; k < dps; k++) {
            line.push([
              rand(i * columnWidth, (i + 1) * columnWidth),
              rand(j * columnHeight, (j + 1) * columnHeight)
            ])
          }
        }
        dots.push(line);
      }
      return dots;
    }
    function getTriangles(dots) {
      const converted = [];
      dots.forEach(column => converted.push(...column));
      const delaunay = Delaunator.from(converted).triangles;
      const triangles = [];
      for (let i = 0; i < delaunay.length; i += 3) {
        triangles.push([
          converted[delaunay[i]],
          converted[delaunay[i + 1]],
          converted[delaunay[i + 2]]
        ]);
      }
      return triangles;
    }
    if (cols <= 0 || rows <= 0 || dps <= 0) return;
    const dots = getDots.call(this, dps);
    this.triangles = getTriangles(dots);
    this.color = rand(50, 330);
  }
}
READ ALSO
Как анимировать border input&#39;а?

Как анимировать border input'а?

Есть вот такая форма:

237
Как убрать фото у категорий в woocommerce?

Как убрать фото у категорий в woocommerce?

Нужно сделать так, чтобы у категорий были только названия + стилизовать под свою темуУ стандартных категорий есть фото

160