konvajs / konva

Konva.js is an HTML5 Canvas JavaScript framework that extends the 2d context by enabling canvas interactivity for desktop and mobile applications.
http://konvajs.org/
Other
11.07k stars 896 forks source link

Smooth Scrolling of Bitmap Render on LED Display #1736

Closed djrobby closed 3 months ago

djrobby commented 3 months ago

Hello, I am working on an app that renders bitmap characters onto and LED display using the Konva library. I have everything working except smooth scrolling behavior of the rendered bitmaps.

Issue: Whenever the rendered characters are set to scroll, the scrolling seems really choppy. Each time the pixels are rendered at the new X position, it appears that some pixels are not filled. See scrolling video below. Here is the code I am using to scroll the bitmap nodes and update their X position:

const handleScrollEvents = frame => {
  scrollNodes() &&
    scrollNodes().map((n, nIdx) => {
      // default scrollSpeed = 40
     // default canvasViewScale = 1
      var newX = (frame.timeDiff * cfg.scrollSpeed * cfg.canvasViewScale) / 1000;
      if (n.x() < -n.getAttr("bitmapWidth")) {
        // default canvasWidth = 480
        // default canvasViewScale = 1
        n.x(cfg.canvasWidth * cfg.canvasViewScale);
      } else {
        n.x(n.x() - newX);
      }
    });
};

Static Video - Here's a video of what the rendered bitmap characters look like with color changing animation but not scrolling:

IMAGE ALT TEXT HERE

Scrolling Video - Here's a video of what the rendered bitmap characters look like with scrolling:

IMAGE ALT TEXT HERE

The scrolling itself is great, but what can I do to ensure that on each update of the new X position, the pixels are fully filled with their color? This will prevent it from appearing like some pixels are dead, which can make the scroll behavior on an LED display look choppy.

lavrton commented 3 months ago

I am not sure how can I help here from konva side.

Probably you need to do a bit of different position calculation. You may need to be strict with LED positions. So text doesn't go between them.

djrobby commented 3 months ago

Actually, the LED display is just another monitor (setup as a secondary display) and we simply mirror what is on the PC's main display onto this secondary LED display. I am able to see the exact same behavior (at a pixel level) on a regular monitor as well but you really need to squint your eyes as pixels on a 1920x1080 display are very tiny.

djrobby commented 3 months ago

Problem fixed! newX was being calculated as a float value, resulting in fractional pixels that do not exist in real pixel-to-pixel mapped space. I simply updated the function to interpolate the node's new X position as the nearest whole number as follows, and now everything works as expected.

const handleScrollEvents = frame => {
  scrollNodes() &&
    scrollNodes().map((n, nIdx) => {
      // default scrollSpeed = 40
     // default canvasViewScale = 1
      var newX = (frame.timeDiff * cfg.scrollSpeed * cfg.canvasViewScale) / 1000;
      if (n.x() < -n.getAttr("bitmapWidth")) {
        // default canvasWidth = 480
        // default canvasViewScale = 1
        n.x(cfg.canvasWidth * cfg.canvasViewScale);
      } else {
        n.x(Math.round(n.x() - newX));
      }
    });
};