针对多张图片优化Konva.js

时间:2017-03-11 00:23:44

标签: javascript html5-canvas png electron konvajs

我目前正在使用Konva.js在几个堆叠的FastLayers上拼贴许多PNG图像。 PNG包含不透明度,它们不需要拖动或命中框。瓷砖经常更换,这似乎适用于尺寸约为30x30的中型网格。一旦瓷砖开始增长到100x100左右,甚至60x60左右,更换单个瓷砖时性能开始变慢。

我已经开始研究“分块”磁贴,即将磁贴添加到较小的FastLayer组中。例如,单个100x100 FastLayer将分为几个10x10 FastLayer。当单个磁贴发生变化时,我们的想法是只应该重新渲染该块,理想情况下整个渲染时间会加快。

这是一个很好的尝试设计,还是我应该尝试不同的方法?我查看了Konva.js文档中的性能提示,但我没有看到与此案例直接相关的任何内容。

2 个答案:

答案 0 :(得分:3)

因此,经过一些研究和修补,我发现了渲染~4000张图像的最快方法。

  • 不要为Konva.js使用React组件。我使用React来构建我的应用程序,但是我已经跳过了使用Konva.js渲染的中间库。对画布使用React Components会使性能降低一半。
  • 缓存常见图片。我使用一个简单的LRU缓存来重用HTMLImageElement对象。
  • 尽可能重用Konva.js节点(Konva.Image)。我的实现是渲染图像网格。位置不会改变,但图像可能会改变。之前,我会破坏()一个节点,然后添加另一个节点。 destroy()会导致额外的渲染,为您的用户创建jank。相反,我只是将image()方法与id()和name()结合使用来查找和替换网格坐标处的图像。
  • 我的应用程序允许用户在网格上绘制长笔画。当仅使用文字鼠标事件时,这可以在小笔画中正常工作。对于长冲程,这不起作用有两个原因。首先,操作系统和浏览器限制鼠标事件,为您提供间歇性的鼠标事件。其次,处于渲染的中间会产生相同的副作用。相反,该软件现在检测到长笔画,并且"填充"用户打算在间歇性鼠标事件之间绘制的缺失坐标。
  • 每隔一段时间渲染一次。由于我的网格经常变化,我决定每秒24次对网格信息进行采样,而不是允许每个tile更改为batchDraw()排队。底层实现是使用RxJS每42ms轮询一次Redux存储,并且只有在某些内容发生变化时才将batchDraw()排队。

答案 1 :(得分:1)

缓存肯定有助于提高性能,但隐藏也是如此。 Konva没有(或者我没有研究过这个)做任何视图剔除。下面是我在Konva策略游戏中隐藏岛屿形状的代码。

stage.on('dragmove', function() {
    cullView();
});


function cullView() {

var boundingX = ((-1 * (stage.x() * (1/zoomLevel)))-(window.innerWidth/2))-degreePixels;
var boundingY = ((-1 * (stage.y() * (1/zoomLevel)))-(window.innerHeight/2))-degreePixels;
var boundingWidth = (2 * window.innerWidth * (1/zoomLevel)) + (2*degreePixels);
var boundingHeight = (2 * window.innerHeight * (1/zoomLevel)) + (2*degreePixels);
var x = 0;
var y = 0;
for (var i = 0; i < oceanIslands.length; i++) {
    x = oceanIslands[i].getX();
    y = oceanIslands[i].getY();
    if (((x > boundingX) && (x < (boundingX + boundingWidth))) && ((y > boundingY) && (y < (boundingY + boundingHeight)))) {
        if (!oceanIslands[i].visible()) {
            oceanIslands[i].show();
            oceanIslands[i].clearCache();
            if (zoomLevel <= cacheMaxZoom) {
                oceanIslands[i].cache();
            }
        }
    } else {
        oceanIslands[i].hide();
    }
}