Raphael paper zoom animation

Yukulelix picture Yukulelix · Oct 12, 2011 · Viewed 9.4k times · Source

I managed to do some hack in order to zoom raphael paper, as setviewbox wasn't working for me, here is the function I wrote:

function setCTM(element, matrix) {
    var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";

    element.setAttribute("transform", s);
}

Raphael.fn.zoomAndMove = function(coordx,coordy,zoom) {

    var svg = document.getElementsByTagName("svg")[0];

    var z = zoom;

    var g = document.getElementById("viewport1");
    var p = svg.createSVGPoint();

    p.x = coordx; 
    p.y = coordy;

    p = p.matrixTransform(g.getCTM().inverse());

    var k = svg.createSVGMatrix().scale(z).translate(-p.x, -p.y);
    setCTM(g, g.getCTM().multiply(k));
} 

where the viewport1 element was defined as :

var gelem = document.createElementNS('http://www.w3.org/2000/svg', 'g');
gelem.id = 'viewport1';

paper.canvas.appendChild(gelem);
paper.canvas = gelem;

Then I can call: paper.zoomAndMove(minx,miny,zoomRatio);

Is it possible to transform the function to make it zoom smoothly?

Answer

patrics picture patrics · Jun 26, 2012

For anybody (like me) who wanted to have the zooming & panning smoothly animated have a look here:

https://groups.google.com/forum/?fromgroups#!topic/raphaeljs/7eA9xq4enDo

this snipped helped me to automate and animate zooming and panning to a specific point on the canvas. (Props to Will Morgan)

Raphael.fn.animateViewBox = function(currentViewBox, viewX, viewY, width, height, duration, callback) {

    duration = duration || 250;

    var originals = currentViewBox, //current viewBox Data from where the animation should start
        differences = {
                x: viewX - originals.x,
                y: viewY - originals.y,
                width: width - originals.width,
                height: height - originals.height
        },
        delay = 13,
        stepsNum = Math.ceil(duration / delay),
        stepped = {
                x: differences.x / stepsNum,
                y: differences.y / stepsNum,
                width: differences.width / stepsNum,
                height: differences.height / stepsNum
        }, i,
        canvas = this;

    /**
     * Using a lambda to protect a variable with its own scope.
     * Otherwise, the variable would be incremented inside the loop, but its
     * final value would be read at run time in the future.
     */
    function timerFn(iterator) {
            return function() {
                    canvas.setViewBox(
                            originals.x + (stepped.x * iterator),
                            originals.y + (stepped.y * iterator),
                            originals.width + (stepped.width * iterator),
                            originals.height + (stepped.height * iterator)
                    );
                    // Run the callback as soon as possible, in sync with the last step
                    if(iterator == stepsNum && callback) {
                            callback(viewX, viewY, width, height);
                    }
            }
    }

    // Schedule each animation step in to the future
    // Todo: use some nice easing
    for(i = 1; i <= stepsNum; ++i) {
            setTimeout(timerFn(i), i * delay);
    }

}