sirjay
sirjay

Reputation: 1766

D3/Raphael js draws 1000+ animated circle with slow fps

I wrote script on Raphael JS v2.1 that draws 1000+ circles and many paths. Circles are animated along that paths and then removed. At ~100 circles fps is 40. At 1000+ fps is 1-10. Code example:

var r = Raphael("diagram", "100%", "100%");
setInterval(function () {
    r.moveCircle(lines[Math.floor(Math.random() * 20)]);
}, 100);

Raphael.fn.moveCircle = function (path) {
    var circle = this.circle(0, 0, 4).attr({fill: '#000'});
    circle.animateAlong({
        path: path,
        duration: 1000
    },
    function() {
        circle.remove();
    });
};

Raphael.el.animateAlong = function (params, props, callback) {
    var element = this,
        paper = element.paper,
        path = params.path,
        rotate = params.rotate,
        duration = params.duration,
        easing = params.easing,
        debug = params.debug,
        isElem = typeof path !== 'string';

    element.path = 
        isElem
            ? path
            : paper.path(path);
    element.pathLen = element.path.getTotalLength();
    element.rotateWith = rotate;

    element.path.attr({
        stroke: debug ? 'red' : isElem ? path.attr('stroke') : 'rgba(0,0,0,0)',
        'stroke-width': debug ? 2 : isElem ? path.attr('stroke-width') : 0
    });

    paper.customAttributes.along = function(v) {
        var point = this.path.getPointAtLength(v * this.pathLen),
            attrs = {
                cx: point.x,
                cy: point.y 
            };
        this.rotateWith && (attrs.transform = 'r'+point.alpha);

        return attrs;
    };

    if(props instanceof Function) {
        callback = props;
        props = null;
    }
    if(!props) {
        props = {
            along: 1
        };
    } else {
        props.along = 1;    
    }

    var startAlong = element.attr('along') || 0;

    element.attr({along: startAlong}).animate(props, duration, easing, function() {
        !isElem && element.path.remove();

        callback && callback.call(element);
    });
};

QUESTIONS:

1) is it possible to improve performance/speed/fps on Raphael JS?

2) on d3.js will fps be beter? what about 10,000+ animated circles?

3) is there any solutions to visualise 10,000+ animated circles along paths with good fps?

Upvotes: 0

Views: 468

Answers (2)

Erik Dahlström
Erik Dahlström

Reputation: 60986

Another way to animate circles along a path is to use stroke-dasharray, stroke-dashoffset and stroke-linecap:round. Any zero-length dash will render as a circle. You can then use stroke-dashoffset to move the circles along the path. This only works with a single circle radius though, controlled via stroke-width.

The upside of this approach is that you may be able to eliminate a bunch of circle elements.

Upvotes: 0

liamness
liamness

Reputation: 742

The likely bottleneck is DOM manipulation (adding / removing nodes, editing attributes etc), so d3 will have the same problem. Using canvas instead of SVG (particularly with a WebGL context) will be much faster if you have a lot of things to draw.

Ways you could speed things up while sticking with SVG:

  • Reuse DOM nodes instead of removing them and adding new ones
  • Define the animations ahead of time using CSS.

Upvotes: 1

Related Questions