Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Artifacts when drawing lines with Firefox #1807

Open
psychedelicious opened this issue Aug 19, 2024 · 1 comment
Open

Artifacts when drawing lines with Firefox #1807

psychedelicious opened this issue Aug 19, 2024 · 1 comment

Comments

@psychedelicious
Copy link

Occasionally on Firefox, when drawing lines, there are artifacts. Single pixels or a line of pixels are unexpectedly fully transparent. The issue is reproducible - if you destroy/recreate layer, change vsibility, or restart the browser, so long as the window and zoom and points/attrs don't change, the artifacts are identical.

If you cache the node, there are often similar artifacts except up in different places. Unfortunately these artifacts are "real" and appear in blobs or images created from the node.

The issue appears to be that the lineCap isn't drawn correctly. Issue only appears with specific combinations of:

  • lineCap
  • points
  • window size/zoom
  • ?

Strangely, the problem seems to occur more when drawing towards the bottom-right corner of the page, but maybe this is placebo.

When using native canvas to draw, there is no such problem. I cannot reproduce the issue on Chromium browsers.

To reproduce the issue:

  • Use this demo https://konvajs.org/docs/sandbox/Free_Drawing.html
  • Change strokeWidth to 100
  • Remove lineCap or set to default butt - this makes it much more common
  • Draw a lot
  • Log lastPoint.points() in the mouseup handler to get a reproducible set of points for the given config

Below is a repro that works on my system, when the window is at the just the right size. A button changes rendering w/ Konva.Line to native context.

Here's a video, bc this probably won't reproduce the specific instance of the problem on your system. Red = draw with Konva.Line, green = draw with native context.

Screen.Recording.2024-08-19.at.6.32.34.pm.mov

This can occur with any pixelRatio. In the video/repro, my pixelRatio is 1, matching window.devicePixelRatio.

<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/konva@8/konva.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
    <meta charset="utf-8" />
    <title>Konva Free Drawing Demo</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        background-color: #f0f0f0;
      }
    </style>
  </head>

  <body>
    <button id="draw-with-konva">Draw with Konva.Line</button>
    <button id="draw-with-native">Draw with Native</button>
    <div id="container"></div>
    <script>
      // These points reproduce the issue for my browser when window is at the right size etc
      const points = [
        1105, 863, 1105, 863, 1105, 863, 1104, 864, 1110, 870, 1126, 880, 1153, 891, 1208, 910,
        1313, 932, 1417, 946, 1473, 951, 1507, 952, 1524, 952, 1525, 952,
      ];

      console.log('window.devicePixelRatio', window.devicePixelRatio);
      console.log('Konva.pixelRatio', Konva.pixelRatio);

      let width = window.innerWidth;
      let height = window.innerHeight - 25;

      const stage = new Konva.Stage({
        container: 'container',
        width: width,
        height: height,
      });

      function drawWithKonvaLine(points) {
        // Draw the line w/ Konva.Line
        stage.destroyChildren();

        const layer = new Konva.Layer();

        stage.add(layer);

        layer.add(
          new Konva.Line({
            stroke: 'red',
            strokeWidth: 100,
            lineCap: 'round',
            lineJoin: 'round',
            points: [...points],
          })
        );
      }

      function drawWithNativeContext(points) {
        // Draw the line w/ native 2d context
        stage.destroyChildren();

        const layer = new Konva.Layer();
        stage.add(layer);

        // then we are going to draw into special canvas element
        const canvas = document.createElement('canvas');
        canvas.width = stage.width();
        canvas.height = stage.height();

        const image = new Konva.Image({
          image: canvas,
          x: 0,
          y: 0,
        });
        layer.add(image);

        // Chunk points for ease of drawing
        const chunkedPoints = _.chunk(points, 2);

        // Good. Now we need to get access to context element
        const context = canvas.getContext('2d');
        context.strokeStyle = 'green';
        context.lineJoin = 'round';
        context.lineCap = 'round';
        context.lineWidth = 100;

        context.beginPath();

        let lastPoint = chunkedPoints[0];
        for (const point of chunkedPoints.slice(1)) {
          context.moveTo(lastPoint[0], lastPoint[1]);
          context.lineTo(point[0], point[1]);
          context.stroke();
          lastPoint = point;
        }
        context.closePath();
        layer.batchDraw();
      }

      document.querySelector('#draw-with-konva').addEventListener('click', () => {
        drawWithKonvaLine(points);
      });

      document.querySelector('#draw-with-native').addEventListener('click', () => {
        drawWithNativeContext(points);
      });

      drawWithKonvaLine(points);
    </script>
  </body>
</html>
@lavrton
Copy link
Member

lavrton commented Sep 13, 2024

I see the issue on my Mac with Firefox. But I don't think there is much we can do from Konva side. That looks like a Firefox bug. The only solution I can think of is drawing such a large stroke manually as a large blob (like a closed path that goes around stroke border).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants