我需要在 Canvas 中构建一种显示超过 10.000 个元素(圆圈)并且需要缩放和平移的 map 。我在这里描述了我的方法 Android significantly slower in resizing and moving multiple canvas elements并改变了我对评论中提出的建议的实现。
要平移 map setTransform
现在用于 Canvas 上下文,然后在删除 Canvas 后重新绘制视口(viewport)中的所有元素。 (我从 R 树中取出它们)。这发生在每个 mousemove
事件上。
虽然当我有一张要绘制约 200 个对象的缩放 map 时这确实很快,但是当缩小并且需要绘制超过 10k 个对象时平移速度非常慢。我显然也需要它快。
满足此要求的最佳做法是什么? 我的方法如下:
- 在 Canvas 上设置一个视口(viewport) div 并使 Canvas 变大(比如每边 50%)
- 在带有
top
和left
样式的div中移动 Canvas 并减少重绘的频率(当 Canvas 靠近视口(viewport)边界时)
最佳答案
我的方法可能是:
创建“视口(viewport)”大小(例如浏览器窗口的大小)的屏幕 Canvas
将要绘制的对象存储在一个数据结构中,让您可以快速确定哪些对象在任何给定时间(给定当前视口(viewport)位置和缩放)可见。
- 确保要绘制的对象(圆圈)可用作位图(如果您使用 Canvas 绘制它们,则可以从图像文件加载或预渲染到 Canvas )。
- 在给定缩放级别的情况下,圆圈的位图应具有正确的大小,因此当缩放级别发生变化时,将图像预渲染到具有正确大小的屏幕外 Canvas 。我假设并非所有 10000 个点都具有独特的图像,它们看起来都一样或者只有少数变化。
然后在每个渲染上:
- 清除 Canvas
- 为视口(viewport)中可见的每个圆调用 drawImage(),但仅指定位置,不指定宽度/高度或使用任何变换。关键是图像应该只“复制”到视口(viewport) Canvas 1-1。这真的很快。
- 我建议不要在每次鼠标移动事件(或窗口调整大小等)时重绘。相反,使用 window.requestAnimationFrame() 来安排重绘。这样你就不会重绘超过浏览器的“刷新”率,通常是 60fps。
- 在视口(viewport)中平移应该非常快,因为您只是调用 drawImage() 而不对每个可见圆圈进行任何转换。当您渲染并且缩放级别发生变化时,将产生重新绘制用作 drawImage 源的预渲染图像的成本。
关于javascript - 缩放和平移具有 > 10k 对象的 HTML5 Canvas 的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43543679/