如何提高绘制动画路径的性能?

时间:2014-02-02 11:08:18

标签: javascript animation kineticjs

我画了一个带有kinetic.js的矩形并在圆形路径中制作动画。在每个动画帧中,我减少它的半径,然后我通过kineticJS Line绘制该对象的动画路径。但是这个动力学动画循环产生了一种不受欢迎的暂停"错开"。 Chrome中的这种错位很小,在IE中很明显,在FireFox中也很糟糕。这似乎是由于Kinetic.Line无法顺利添加+绘制数千个数据变化点。怎么能让这个动画完美无瑕,流畅。如果你给我一个jsfiddle的链接会很有帮助。提前感谢一揽子。

CODES

var R= 80;

$(document).ready(function(){
var stage= new Kinetic.Stage({
    container: 'container',
    width:500,
    height:500
});

var layer = new Kinetic.Layer();
var line = new Kinetic.Line({
    points:[0,0,0,0],
    stroke:'blue',
    strokeWidth:2
});
var rect = new Kinetic.Rect({
    x:10,
    y:10,
    width:10,
    height: 10,
    fill:'black',
    stroke:'red'
});
layer.add(rect);
layer.add(line);
stage.add(layer);

var centerX = stage.width()/2;
var points=[];
var anim = new Kinetic.Animation(
        function(f){
            var cX= stage.width()/2;
            var cY= stage.height()/2;
            R=R-1/100;
            var X = cX + R*Math.cos(f.time/1000);
            var Y = cY+ R*Math.sin(f.time/1000);
            points.push(X,Y);
            line.setPoints(points);
            rect.setX(X);
            rect.setY(Y);
        }
,layer);
anim.start();
});

JSFIDDLE: http://jsfiddle.net/tanvirgeek/n8z8N/7/

提前致谢。

1 个答案:

答案 0 :(得分:1)

正如您所发现的,更新和绘制包含数千个线段的Kinetic.Line会导致明显的延迟。

我很少看到的一个动力学技巧对于创建数千个线段的无滞后动画非常有用。

首先,在屏幕外的html5画布上绘制线段。当需要新的细分市场时,只需将该细分市场添加到所有预先存在的细分市场。这非常有效,因为只需要绘制最后一个线段。

您可以使用Kinetic.Image在屏幕上显示屏幕外的html5画布。

诀窍是将Kinetic.Image图像源设置为html画布:myKineticImage.setImage(myOffscreenCanvas)。这是因为“幕后”Kinetic.Image正在使用context.drawImage来显示其图像。由于context.drawImage也可以接受另一个画布作为其图像源,因此您可以有效地显示当前的屏幕外画布图。

演示:http://jsfiddle.net/m1erickson/rYC96/

enter image description here

示例代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Prototype</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>

<style>
body{padding:20px;}
#container{
  border:solid 1px #ccc;
  margin-top: 10px;
  width:350px;
  height:350px;
}
</style>        
<script>
$(function(){

    var stage = new Kinetic.Stage({
        container: 'container',
        width: 350,
        height: 350
    });
    var layer = new Kinetic.Layer();
    stage.add(layer);

    // variables used to set the stage and animate
    var rectSize=15;
    var cx=stage.getWidth()/2;
    var cy=stage.getHeight()/2;
    var R=100;
    var A=0;
    var deltaA=Math.PI/180;
    var lastX=cx+R*Math.cos(A);
    var lastY=cy+R*Math.sin(A);

    // the html canvas incrementally draws the line segments
    // which are in turn displayed as a Kinetic.Image (called line)
    var canvas=document.createElement("canvas");
    var ctx=canvas.getContext("2d");
    canvas.width=stage.getWidth();
    canvas.height=stage.getHeight();
    ctx.strokeStyle="blue";
    ctx.lineWidth=2;


    // this Kinetic.Image exactly displays the current html canvas drawings
    // (this trick cures the lags)
    var line=new Kinetic.Image({
        x:0,
        y:0,
        width:canvas.width,
        height:canvas.height,
        image:canvas
    });
    layer.add(line);


    // the rotating Kinetic.Rectangle
    var rect = new Kinetic.Rect({
        x:lastX,
        y:lastY,
        width:rectSize,
        height:rectSize,
        fill:'black',
        stroke:'red'
    });
    layer.add(rect);


    // use requestAnimationFrame (RAF) to drive the animation
    // RAF efficiently schedules animation frames with display 
    function animate(){

        // stop animating when rect reaches center
        if(R<=rectSize/2){return;}

        // schedule another animation frame even before this one is done
        requestAnimationFrame(animate);

        // calc the new XY position
        R=R-.01;
        A+=deltaA;
        var X=cx+R*Math.cos(A);
        var Y=cy+R*Math.sin(A);

        // animate the rect and line to their next position

        // draw just the latest line segment to the canvas
        // (all the previous line segments are still there--no need to redraw them)
        ctx.beginPath();
        ctx.moveTo(lastX,lastY);
        ctx.lineTo(X,Y);
        ctx.stroke();
        // set lastXY for next frame
        lastX=X;
        lastY=Y;

        // update the rect position
        rect.setX(X);
        rect.setY(Y);

        // draw the changed line-image and rect to the kinetic layer
        layer.draw();
    }

    // start animating!
    animate();

}); // end $(function(){});
</script>       
</head>
<body>
    <div id="container"></div>
</body>
</html>