Konva.js 在移动设备上非常滞后

Konva.js is very laggy on mobile devices

我想开始使用 Konva.js 库。它在我的电脑上的浏览器 (chrome) 中看起来非常棒,并且具有很棒的功能。我创建了代码来制作一些非常简单的动画(移动和旋转)。但是,当我尝试 运行 在移动设备上什至在 Safari 浏览器中访问我的网页时,它开始变得非常缓慢。而且,当我将四个对象(图像)设置为一个运动时,浏览器崩溃了。

我做了一些测试,发现即使是可拖动的对象在移动设备上也有延迟。 (当我试图移动它们时,它们的移动非常缓慢且不稳定)。

有没有办法优化一下。 (我已经尝试了推荐的batchDraw()功能,但没有帮助)?怎样才能让动作流畅?如果目前做不到,以后会不会有一些优化的可能?

这是我的代码...但显然您必须 运行 在手机上 phone 才能看到效果。要激活效果,请单击(触摸)图像。

http://bannerteam.tode.cz/konvaAnim/

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
    <title>Konva animace</title>
    <style>
        body {
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: #F0F0F0;
    }
  </style>
  <script src="https://cdn.rawgit.com/konvajs/konva/2.0.3/konva.min.js"></script>
</head>
<body>
<div id="container"></div>
<script>
    var width = window.innerWidth;
    var height = window.innerHeight;
    var lengthOfAnim = 60;
    var pos = [{x: 50, y: 50, p: 'A'}, {x: 250, y: 50, p: 'B'}, {x: 450, y: 50, p: 'C'},
                {x: 50, y: 250, p: 'D'}, {x: 250, y: 250, p: 'E'}, {x: 450, y: 250, p: 'F'},
                {x: 50, y: 450, p: 'G'}, {x: 250, y: 450, p: 'I'}, {x: 450, y: 450, p: 'J'},
                {x: 50, y: 650, p: 'K'}, {x: 250, y: 650, p: 'F'}];

    var stage = new Konva.Stage({
      container: 'container',
      width: width,
      height: height
    });

    var imageObj = [];
    var img = new Image();

    var doAnimations = function(i){
        switch(i){
            case 0:
                imageObj[i].img.opacity(1 - imageObj[i].time/lengthOfAnim);
                break;
            case 1:
                if(imageObj[i].time === lengthOfAnim -1)
                    imageObj[i].img.y(imageObj[i].img.y() + (lengthOfAnim-1)*2);
                else
                    imageObj[i].img.y(imageObj[i].img.y() - 2);
                break;
            case 2:
                imageObj[i].img.opacity(1 - imageObj[i].time/lengthOfAnim);
                if(imageObj[i].time === lengthOfAnim -1)
                    imageObj[i].img.y(imageObj[i].img.y() + (lengthOfAnim-1)*2);
                else
                    imageObj[i].img.y(imageObj[i].img.y() - 2);
                break;
            case 3:
                var parent = imageObj[i].img.getParent();
                parent.clipFunc(function(ctx) {
                    ctx.rect(imageObj[i].img.x() - 75, imageObj[i].img.y() - 75, 75*(1 - imageObj[i].time/lengthOfAnim), 150);
                    ctx.rect(imageObj[i].img.x() + 75 - 75*(1 - imageObj[i].time/lengthOfAnim) , imageObj[i].img.y() - 75, 75*(1 - imageObj[i].time/lengthOfAnim), 150);
                });
                break;
            case 4:
                var parent = imageObj[i].img.getParent();
                parent.clipHeight(150*(1 - imageObj[i].time/lengthOfAnim));
                break;
            case 5:
                imageObj[i].img.opacity(1 - imageObj[i].time/lengthOfAnim);
                imageObj[i].img.rotation(90*(imageObj[i].time/lengthOfAnim));
                break;
            case 6:
                imageObj[i].img.opacity(1 - imageObj[i].time/lengthOfAnim);
                var pom = (1 - imageObj[i].time/lengthOfAnim);
                imageObj[i].img.scale({x: pom, y: pom});
                break;
            case 7:
                if(imageObj[i].time === lengthOfAnim -1)
                    imageObj[i].img.x(imageObj[i].img.x() - (lengthOfAnim-1)*2);
                else
                    imageObj[i].img.x(imageObj[i].img.x() + 2);
                imageObj[i].img.move({x: 0, y: 10*(Math.sin(6*Math.PI*(imageObj[i].time/lengthOfAnim)))});
                break;
            case 8:
                imageObj[i].img.rotation(20*Math.sin(6*Math.PI*(imageObj[i].time/lengthOfAnim)));
                break;
            case 9:
                imageObj[i].img.opacity(0.5 + Math.abs((imageObj[i].time/lengthOfAnim-0.5)));
                break;
            case 10:
                imageObj[i].img.draggable(true);
                break;
        }

    }

    img.onload = function() {
        for(let i = 0; i < pos.length; i++){
            var layer = new Konva.Layer();

            var yoda = new Konva.Image({
                x: pos[i].x + 75,
                y: pos[i].y + 75,
                image: img,
                width: 150,
                height: 150,
                offset: {
                    x: 75,
                    y: 75
                }
                });

            imageObj.push({img: yoda, layer: layer, time: 0});

            var charac = new Konva.Text({
                x: pos[i].x + 50,
                y: pos[i].y + 160,
                text: pos[i].p,
                fontSize: 30,
                fontFamily: 'Calibri',
                fill: 'black'
            });

            if(i === 3){
                var group = new Konva.Group({clipFunc:function(ctx) {
                        ctx.rect(pos[i].x, pos[i].y, 150, 150)
                    },});
                group.add(yoda);
                layer.add(group);
            }else if(i === 4){
                var group = new Konva.Group({clip: {
                    x : pos[i].x,
                    y : pos[i].y,
                    width : 150,
                    height : 150
                    },});
                group.add(yoda);
                layer.add(group);
            }else
                layer.add(yoda);
            layer.add(charac);

            stage.add(layer);

            yoda.on('click tap', function() {
                if(imageObj[i].time === 0)
                    imageObj[i].time = lengthOfAnim;
            });
        }
        setInterval(function(){
            for(var i = 0; i < pos.length; i++){
                if(imageObj[i].time > 0){
                    imageObj[i].time--;
                    doAnimations(i);
                    imageObj[i].layer.draw();
                }
            }
        }, 40);
    }

    img.src = './castle.png';

</script>
<body>
</html>

有很多方法可以提高性能。

您可以在这里阅读很多提示:https://konvajs.github.io/docs/performance/All_Performance_Tips.html

你的舞台看起来很简单,所以在移动设备上表现应该很好。

一些提示:

  1. 不要使用 setInterval。使用 requestAnimationFrame。动画会更流畅
  2. 使用layer.batchDraw()
  3. 如果可能,尝试将动画对象移动到另一层,这样您就不需要重绘所有节点