Kineticjs性能滞后

kineticjs performance lag

本文关键字:滞后 性能 Kineticjs      更新时间:2023-09-26

我正在做一个类似HTML5幸运轮的径向控制。我在这里用我需要的一些额外功能的例子修改了原始内容:http://jsfiddle.net/fEm9P/当你点击内部动态楔子时,它们会在更大的楔子内收缩和膨胀。不幸的是,当我转动轮子时,它落后于指针。这在这里还不算太糟,但在手机上就很明显了。

我知道这是由于我没有缓存车轮的事实。当我缓存轮子(取消注释行239-249),内部楔形不再响应鼠标/触摸,但对旋转的响应是完美的。我也试过将内楔添加到一个单独的图层中,只缓存主车轮。然后我用外轮转动内轮。这样做会更好一些,但在手机平台上仍然不可行。

如有任何建议,不胜感激。

斯蒂芬

  //constants
  var MAX_ANGULAR_VELOCITY = 360 * 5;
  var NUM_WEDGES = 25;
  var WHEEL_RADIUS = 410;
  var ANGULAR_FRICTION = 0.2;
  // globals
  var angularVelocity = 360;
  var lastRotation = 0;
  var controlled = false;
  var target, activeWedge, stage, layer, wheel, 
      pointer, pointerTween, startRotation, startX, startY;
  var currentVolume, action;
  function purifyColor(color) {
    var randIndex = Math.round(Math.random() * 3);
    color[randIndex] = 0;
    return color;
  }
  function getRandomColor() {
    var r = 100 + Math.round(Math.random() * 55);
    var g = 100 + Math.round(Math.random() * 55);
    var b = 100 + Math.round(Math.random() * 55);
    var color = [r, g, b];
    color = purifyColor(color);
    color = purifyColor(color);
    return color;
  }
  function bind() {
    wheel.on('mousedown', function(evt) {
      var mousePos = stage.getPointerPosition();
      angularVelocity = 0;
      controlled = true;
      target = evt.targetNode;
      startRotation = this.rotation();
      startX = mousePos.x;
      startY = mousePos.y;
    });
    // add listeners to container
    document.body.addEventListener('mouseup', function() {
      controlled = false;
        action = null;
      if(angularVelocity > MAX_ANGULAR_VELOCITY) {
        angularVelocity = MAX_ANGULAR_VELOCITY;
      }
      else if(angularVelocity < -1 * MAX_ANGULAR_VELOCITY) {
        angularVelocity = -1 * MAX_ANGULAR_VELOCITY;
      }
      angularVelocities = [];
    }, false);
    document.body.addEventListener('mousemove', function(evt) {
      var mousePos = stage.getPointerPosition();
      var x1, y1;
      if(action == 'increase') {
            x1 = (mousePos.x-(stage.getWidth() / 2));
            y1 = (mousePos.y-WHEEL_RADIUS+20);
            var r = Math.sqrt(x1 * x1 + y1 * y1);
            if (r>500){
                r=500;
            } else if (r<100){
                r=100;
            };          
            currentVolume.setRadius(r);
            layer.draw();            
      } else {  
          if(controlled && mousePos && target) {
            x1 = mousePos.x - wheel.x();
            y1 = mousePos.y - wheel.y();
            var x2 = startX - wheel.x();
            var y2 = startY - wheel.y();
            var angle1 = Math.atan(y1 / x1) * 180 / Math.PI;
            var angle2 = Math.atan(y2 / x2) * 180 / Math.PI;
            var angleDiff = angle2 - angle1;
            if ((x1 < 0 && x2 >=0) || (x2 < 0 && x1 >=0)) {
              angleDiff += 180;
            }
            wheel.setRotation(startRotation - angleDiff);
          }
      };
    }, false);
  }
  function getRandomReward() {
    var mainDigit = Math.round(Math.random() * 9);
    return mainDigit + ''n0'n0';
  }
  function addWedge(n) {
    var s = getRandomColor();
    var reward = getRandomReward();
    var r = s[0];
    var g = s[1];
    var b = s[2];
    var angle = 360 / NUM_WEDGES;
    var endColor = 'rgb(' + r + ',' + g + ',' + b + ')';
    r += 100;
    g += 100;
    b += 100;
    var startColor = 'rgb(' + r + ',' + g + ',' + b + ')';
    var wedge = new Kinetic.Group({
      rotation: n * 360 / NUM_WEDGES,
    });
    var wedgeBackground = new Kinetic.Wedge({
      radius: WHEEL_RADIUS,
      angle: angle,
      fillRadialGradientStartRadius: 0,
      fillRadialGradientEndRadius: WHEEL_RADIUS,
      fillRadialGradientColorStops: [0, startColor, 1, endColor],
      fill: '#64e9f8',
      fillPriority: 'radial-gradient',
      stroke: '#ccc',
      strokeWidth: 2,
      rotation: (90 + angle/2) * -1
    });
    wedge.add(wedgeBackground);
    var text = new Kinetic.Text({
      text: reward,
      fontFamily: 'Calibri',
      fontSize: 50,
      fill: 'white',
      align: 'center',
      stroke: 'yellow',
      strokeWidth: 1,
      listening: false
    });
    text.offsetX(text.width()/2);
    text.offsetY(WHEEL_RADIUS - 15);
    wedge.add(text);
    volume = createVolumeControl(angle, endColor);
    wedge.add(volume);
    wheel.add(wedge);
  }
  var activeWedge;
function createVolumeControl(angle, colour){
    var volume = new Kinetic.Wedge({
        radius: 100,
        angle: angle,
        fill: colour,
        stroke: '#000000',
        rotation: (90 + angle/2) * -1
    });
    volume.on("mousedown touchstart", function() {
        currentVolume = this;
        action='increase';
    });
    return volume;
}

  function animate(frame) {
    // wheel
    var angularVelocityChange = angularVelocity * frame.timeDiff * (1 - ANGULAR_FRICTION) / 1000;
    angularVelocity -= angularVelocityChange;
    if(controlled) {
      angularVelocity = ((wheel.getRotation() - lastRotation) * 1000 / frame.timeDiff);
    }
    else {
      wheel.rotate(frame.timeDiff * angularVelocity / 1000);
    }
    lastRotation = wheel.getRotation();
    // pointer
    var intersectedWedge = layer.getIntersection({x: stage.width()/2, y: 50});
    if (intersectedWedge && (!activeWedge || activeWedge._id !== intersectedWedge._id)) {
      pointerTween.reset();
      pointerTween.play();
      activeWedge = intersectedWedge; 
    }
  }
  function init() {
    stage = new Kinetic.Stage({
      container: 'container',
      width: 578,
      height: 500
    });
    layer = new Kinetic.Layer();
    wheel = new Kinetic.Group({
      x: stage.getWidth() / 2,
      y: WHEEL_RADIUS + 20
    });
    for(var n = 0; n < NUM_WEDGES; n++) {
      addWedge(n);
    }
    pointer = new Kinetic.Wedge({
      fillRadialGradientStartPoint: 0,
      fillRadialGradientStartRadius: 0,
      fillRadialGradientEndPoint: 0,
      fillRadialGradientEndRadius: 30,
      fillRadialGradientColorStops: [0, 'white', 1, 'red'],
      stroke: 'white',
      strokeWidth: 2,
      lineJoin: 'round',
      angle: 30,
      radius: 30,
      x: stage.getWidth() / 2,
      y: 20,
      rotation: -105,
      shadowColor: 'black',
      shadowOffset: {x:3,y:3},
      shadowBlur: 2,
      shadowOpacity: 0.5
    });
    // add components to the stage
    layer.add(wheel);
    layer.add(pointer);
    stage.add(layer);
    pointerTween = new Kinetic.Tween({
      node: pointer,
      duration: 0.1,
      easing: Kinetic.Easings.EaseInOut,
      y: 30
    });
    pointerTween.finish();
    var radiusPlus2 = WHEEL_RADIUS + 2;
    wheel.cache({
      x: -1* radiusPlus2,
      y: -1* radiusPlus2,
      width: radiusPlus2 * 2,
      height: radiusPlus2 * 2
    }).offset({
      x: radiusPlus2,
      y: radiusPlus2
    });
    layer.draw();
    // bind events
    bind();
    var anim = new Kinetic.Animation(animate, layer);
    //document.getElementById('debug').appendChild(layer.hitCanvas._canvas);
    // wait one second and then spin the wheel
    setTimeout(function() {
      anim.start();
    }, 1000);
  }
  init();

我对脚本做了一些修改,极大地提高了响应时间。第一个是用layer.batchDraw()替换layer.draw()。当绘制函数在每次触碰事件中被调用时,交互变得很笨拙。另一方面,BatchDraw会在内部堆叠绘制请求"根据每秒最大帧数限制每秒重画的次数"(http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-batch-draw)。

当我缓存/清除轮子时,我最初看到的画布的跳跃是由于我在清除缓存时没有重置轮子上的偏移量。http://jsfiddle.net/leydar/a7tkA/5

wheel.clearCache().offset({
  x: 0,
  y: 0
});

我希望这对其他人有好处。它仍然不是完美的响应,但至少是在正确的方向。

斯蒂芬