Android is significantly slower at resizing and moving multiple canvas elements

I need to create a map view in canvas that needs to be able to hold more than 10,000 elements and thus is small in some cases ( 8000 px width,> 4000 px height ). Also I need to pan and scale the map . After some problems with existing libraries (Paper.js) and possible other solutions (sheetmap), I ended up writing my own library from scratch, because the main requirement is really very fast (load, mouse, ...), and neither one of the libraries i tried couldn't offer everything .

The structure looks like this:

  • I have one map object with an associated Control object that logs events and has resizing methods, etc.
  • The map is split into several alternating sizes (1024px x 1024px - configurable) as using the map with only one canvas over 8000px wide makes it incredibly slow.
  • Each piece is linked to a canvas
  • Elements (circles only) are added to one or more tiles (if it's around the edge) - more specifically to the tile canvas.
  • The tiles are placed inside a container div that is sized to the map area (if not scaled up)
  • The container container is placed inside the viewport div to display the map as a "widget"
  • Scaling the scale of each tile / canvas and container. For efficiency, I sacrificed smooth scaling and implemented a configurable number of scaling steps, which is still good.
  • Panning sets the style top

    and left

    container.
  • Use events: window.resize

    , mousewheel

    , DOMMouseScrol

    , mousedown

    , mouseup

    , mousemove

    , touchstart

    , touchend

    , touchmove

    and Hammertime pinch

This alltogether works satisfactorily on Desktop Browsers and iPhone (tested with SE, 6S), but on every android device I tested it (Samsung S4, One Plus One and another summer device and android studio emulator), it is very slow. Card Drawing excellent speed, but the zoom and pan close to impossible .

The code is too verbose to post here, so I'm asking you if there are any known issues with canvas on android that could explain this issue, or maybe some issues with how I built the framework that could would create problems with Android. I'm really clueless here as it works on desktop and iPhone.

+1


source to share


1 answer


The real problem you are facing is GPU overload. Loading this large amount of data and then navigating through it will crash the GPU and will likely force the browser to run in software rendering mode, which is a big performance hit.

Instead, I suggest changing the approach. Instead of having different large canvases, you should have one canvas, which is, at best, the user's screen size. Then use canvas API methods like scale

and translate

to do what you need. For an added bonus, don't try to display objects that are not visible on screen.

It might seem like needing to redraw the scene every time you move will be slow, but it is not. The reality is that either you determine exactly what needs to be done, or the browser should try to draw the whole thing again when you move it. Here's a quick example of how you can display and move large images.



var ctx = document.querySelector('canvas').getContext('2d');
var img = new Image();
img.src = 'https://placeimg.com/1000/1000/nature';
img.onload = start;


function start() {
  var xDirection = -1;
  var yDirection = -1;
  var xPosition = 0;
  var yPosition = 0;
  
  var prev = Date.now();
  (function render() {
    var now = Date.now();
    var delta = (now - prev) / 1000;
    
    xPosition += xDirection * delta * 20;
    yPosition += yDirection * delta * 40;
    if (xPosition > 0) {
      xPosition = 0;
      xDirection *= -1;
    } else if (xPosition < -320) {
      xPosition = -320;
      xDirection *= -1;
    }
    if (yPosition > 0) {
      yPosition = 0;
      yDirection *= -1;
    } else if (yPosition < -240) {
      yPosition = -240;
      yDirection *= -1;
    }
    
    prev = now;
    ctx.save();
    ctx.translate(xPosition, yPosition);
    ctx.drawImage(img, 0, 0);
    ctx.restore();
    requestAnimationFrame(render);
  })();
}
      

body {
  background: #111;
}
canvas {
  background: #FFF;
}
      

<canvas width="320" height="240"></canvas>
      

Run code


+1


source







All Articles