Performance issue with tweenjs when animating line draw

606 views Asked by At

I am using eaeljs and tweenjs to animate multiple lines getting drawn from a position to a position through a point, making it a curved line with an img attached to the front of the line. I am using the tween plugin MotionGuidePlugin for this. This is supposed to happen inside a init()-function. No mouse-event or user-based event triggers this.

My problem is that my canvas gets really slow after some time. The lines get more "pixel-ly", and the animation skips a lot of the frames - creating a straight line instead of a curve. I have researched this problem on Stack Overflow, and have found out that this is because a new Graphics are drawn for every frame. The solution seems to be to clear the Graphics or cache it, but I do not know how to implement this with my current code:

createjs.MotionGuidePlugin.install();

var shape = new createjs.Shape();
var bar = { x: arrowStartPosX, y: arrowStartPosY, oldx: arrowStartPosX, oldy: arrowStartPosY };
stage.addChild(shape);

var image = new createjs.Bitmap("arrow.png");
image.alpha = 0;
stage.addChild(image);

createjs.Ticker.addEventListener("tick", tick);

run();

function getMotionPathFromPoints (points) {
    console.log(points);
    var i, motionPath;
    console.log(points.length);
    for (i = 0, motionPath = []; i < points.length - 1; ++i) {
        if (i === 0) {
            motionPath.push(points[i].x, points[i].y);
        }
        else if(i === 1){
            motionPath.push(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y);
        } else {
            i++;
            motionPath.push(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y);
        }
    }
    return motionPath;
}

function run() {
    var posXStart = arrowStartPosX + 200;
    var points = [
        new createjs.Point(arrowStartPosX, arrowStartPosY),
        new createjs.Point(posXStart, middlePosY),
        new createjs.Point(arrowStartPosX, arrowEndPosY)
    ];

    createjs.Tween.get(bar).wait(timeCount-400).to({
        guide: {path: getMotionPathFromPoints(points)}
    }, 1900);

    createjs.Tween.get(image).to({rotation: -70}, 0)
    .wait(timeCount-400).to({alpha: 1}, 0)
    .to({rotation: -290, 
    guide:{ path:[startImgPosX, startImgPosY, middleImgPosX, middleImgPosY, endImgPosX, endImgPosY], 
    orient: "auto"}},1900);
}

function tick() {
    shape.graphics
    .setStrokeStyle(2, 'round', 'round')
    .beginStroke("#000000")
    .curveTo(bar.oldx, bar.oldy, bar.x, bar.y)
    .endStroke();

    bar.oldx = bar.x;
    bar.oldy = bar.y;
}

The lines should be drawn, and when finished, they should stay in place. Can anyone explain to me how to fix my code, and make the Canvas perform normally again?

Update:

I have now created a FIDDLE for my problem. If you do nothing in the fiddle for some time, you'll see that the JSFiddle webpage gets slower, as my own webpage does.

1

There are 1 answers

4
Lanny On

Vectors can be very expensive, and your demo shows that you are adding a ton of small lines. Every time you update the stage, the graphics have to be redrawn. You won't be able to do this effect for long without caching, especially on a low-powered device.

Depending on your end goal, you can cache the shape, then draw in the new content as it gets created.

// Cache up front
var shape = new createjs.Shape();
shape.cache(0,0,100,1000);

// Clear the graphics before drawing new content
shape.graphics.clear()
    .setStrokeStyle(3, 'round', 'round')
    .beginStroke("#aaa")
    .curveTo(bar.oldx, bar.oldy, bar.x, bar.y)
    .endStroke();

// Update the cache with "source-over" to just add the new content.
    shape.updateCache("source-over");
    stage.update();

Here is a fiddle update: http://jsfiddle.net/lannymcnie/km89jbn2/2/

This approach will never slow down.

Cheers.