Android在调整大小和移动多个画布元素方面明显变慢 [英] Android significantly slower in resizing and moving multiple canvas elements

查看:170
本文介绍了Android在调整大小和移动多个画布元素方面明显变慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在画布中构建一种地图,它必须能够容纳超过10.000个元素,因此在某些情况下具有安静的大尺寸(> 8000px宽度,> 4000 px身高)。此外,我需要平移和缩放地图。
在对现有库(Paper.js)和其他可能的解决方案(Leaflet Map)进行一些调整后,我最终从头开始编写了一个自己的库,因为主要要求是,真的非常快(加载,鼠标悬停,...)并且我尝试过的库都没有提供所有方面。



结构如下:




  • 我有一个带有关联Control对象的地图对象,它注册事件并调整方法等。

  • 地图被划分为多个均匀尺寸的瓷砖(1024px x 1024px - 可自定义),因为使用仅有一个尺寸超过8000px宽度的画布使得它非常慢

  • 每个图块都与画布相关联

  • 元素(只是圆圈)被添加到一个或多个图块(如果它在边缘上) - 更具体地说是图块的画布。 / li>
  • 将瓷砖放在具有di的容器div中地图区域的大小(未缩小时)

  • 容器div放置在视口div中,以使地图显示为小部件

  • 缩放每个图块/画布和容器。为了提高性能,我牺牲了平滑变焦并实现了可定制的缩放步数,这仍然感觉还不错。

  • 平移设置为顶部容器的样式。

  • 使用的事件是 window.resize mousewheel DOMMouseScrol mousedown mouseup mousemove touchstart touchend touchmove Hammertime pinch



这对桌面浏览器和iPhone(使用SE,6S测试)完全满意,但每个 Android 设备我测试了它(三星S4,One Plus One和另一个1岁的设备,以及android工作室模拟器),它运行速度非常慢。绘制地图的速度很快,但缩放和平移接近不可能



代码是太全面,不能在这里发布,所以我问你是否在android上有任何已知的问题,这可以解释这个问题,或者可能是我构建可能产生android问题的结构的一些问题。我真的很无能为力,因为它适用于桌面和iPhone。

解决方案

你遇到的真正问题是你'重新加载GPU。加载大量数据然后再移动它会对GPU产生影响,并可能迫使浏览器进入软件渲染模式,这是一个很大的性能损失。



<相反,我建议改变你的方法。您应该拥有一个最多只是用户屏幕大小的画布,而不是拥有各种大型画布。然后,使用canvas API的方法,例如 scale 翻译 以呈现您所需的内容。为了获得额外的奖励,请避免尝试渲染不在屏幕上的内容。



每次移动时看起来不得不重绘场景会很慢但不是。实际情况是,您指定完全需要绘制的内容,或者当您移动它时浏览器必须再次尝试绘制所有。这是一个如何渲染和移动大图像的简短示例。



  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 =320height =240>< / canvas>  


I need to build a kind of map in canvas, which must be able to hold more than 10.000 elements and thus has quiet big dimensions in some cases (> 8000px width, >4000 px height). Also I need to pan and zoom the map. After some fiddeling around with existing libraries (Paper.js) and possible other solutions (Leaflet Map) I eventually wrote an own library from scratch, because the main requirement is, that is should be really really fast (loading, mouseovers, ...) and none of the libraries I tried could offer all of the aspects.

The structure is as follows:

  • I have one map object with an associated Control object, which registers events and has resize methods etc.
  • A map is divided in mutliple even sized tiles (1024px x 1024px - customizable) because using the map with only one canvas at a size over 8000px width made it incredibly slow
  • Each tile is associated with a canvas
  • The elements (just circles) are added to one or multiple tiles (If it's on the edge) - more specifically to the tiles' canvas.
  • The tiles are placed within an container div which has the dimensions of the map area (when not zoomed out)
  • The container div is placed within a viewport div to enable the map being displayed as a "widget"
  • Zooming scales every tile/canvas and the container. For sake of performance I sacrificed smooth zoom and implemented a customizable amount of zoom steps, which still feels okay.
  • Panning set's the topand left style of the container.
  • Events used are window.resize, mousewheel, DOMMouseScrol, mousedown, mouseup, mousemove, touchstart,touchend,touchmove and Hammertime pinch

This alltogether runs satisfying on Desktop Browsers, and iPhones (tested with SE, 6S) but on every Android device I tested it (Samsung S4, One Plus One and another 1 year old device, and android studio emulator) it runs extremly slow. Drawing of the Map is fine in speed, but zooming and panning is near to impossible.

The code is too comprehensive to post it here, so I'm asking you if there are any known problems with canvas on android, that could explain this problem, or maybe some issues with the way I built the structure that could produce issues with android. I'm really clueless here, since it works on desktop and iPhone.

解决方案

The real problem you're hitting is you're overloading the GPU. Loading that much data all and once then moving it around is going to put a toll on the GPU and likely force the browser into software rendering mode, which is a big performance hit.

Instead, I'd suggest changing your approach. Rather than having various large canvases, you should have one canvas that is, at most, the size of the users screen. Then, utilize methods of the canvas API such as scale and translate to render what you need. For an added bonus, avoid trying to render things which are off screen.

It may seem like having to redraw the scene every time you move around would be slow but it's not. The reality is that either you specify exactly what needs to be drawn or the browser has to attempt to draw all of it again when you shift it around. Here's a brief example of how you can render 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>

这篇关于Android在调整大小和移动多个画布元素方面明显变慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆