Tiago Marinho
Tiago Marinho

Reputation: 2216

Drawing multiple arbitrary lines is over-expensive EaselJS

I'm programming a HTML5 2D "game" using EaselJS, which looks like a planet/gravity simulator, and I've decided to trace the planet's movement/orbit with a line that follows each planet as it moves. Here's a quick gif demonstration:

Demonstration of what I want

The problem is: If I create a line at every tick the canvas goes completely slow (because it's drawing lots of lines at every tick, which is expensive), so I moved the expensive code to a setInterval with 250ms intervals between loops, and the problem persists because when there are lots of shapes, it'll create lots of lines per loop. Also, if I just add more time between each loop, the result will start to look... Minecraft-ish.

Demonstration of 750ms intervals between each loop

I don't have any idea on how to solve this problem since everything I can think of will include creating lots of lines at every loop. I've tried using cache but caching this tiny-detailed lines just caused them to disappear in the final cached images, and since the problem is not with updating the lines, but creating new ones, I think caching will do nothing for me.

Here's the relevant code:

setInterval(function() {
    allObjs.forEach(function(obj1) {
        if (typeof obj1.xpast !== "undefined" || typeof obj1.ypast !== "undefined") {
            var trail = new createjs.Shape();
            trail.graphics.s("#fff").ss(1, "round").moveTo(obj1.xpast + .5, obj1.ypast + .5).lineTo(obj1.x + .5, obj1.y + .5);
            trail.alpha = 0.25;
            stage.addChild(trail);
            setTimeout(function() {
                createjs.Tween.get(trail).to({
                    alpha: 0
                }, 1000).call(function() {
                    stage.removeChild(trail);
                });
            }, 10000);
        }
        obj1.xpast = obj1.x;
        obj1.ypast = obj1.y;
    });
}, 750);

Unfortunately, I can't put my code in JSFiddle at the moment.

Upvotes: 1

Views: 831

Answers (1)

Lanny
Lanny

Reputation: 11294

When redrawing the canvas each frame (and clearing it reflect changing content), vector lines add up very quickly. This is because the Graphics instructions are redrawn each frame. Vectors on Canvas are not hardware accelerated, so using this approach will be super slow as you approach a lot of lines.

The best approach is to cache the vector, and then only draw what is new. When you cache it, a new canvas element is created behind the scenes, and used in place of the actual graphics. This means you can make it as complex as you want, without any change in performance.

  • Cache the shape at the size you will need (maybe the canvas size?)
  • Draw the new graphics for that frame
  • Update the cache (draws the contents of the Graphics onto the existing Cache)
  • Clear the graphics for next time

There is an example of this on GitHub:

Hope this helps!

Upvotes: 3

Related Questions