Рафаэль бумажный зум анимация - PullRequest
10 голосов
/ 12 октября 2011

Мне удалось сделать некоторый взлом, чтобы увеличить документ Рафаэля, так как setviewbox не работал для меня, вот функция, которую я написал:

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));
} 

, где элемент viewport1 был определен как:

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

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

Тогда я могу позвонить: paper.zoomAndMove(minx,miny,zoomRatio);

Можно ли преобразовать функцию для плавного увеличения?

Ответы [ 4 ]

14 голосов
/ 26 июня 2012

Для любого (как я), который хотел бы плавно анимировать масштабирование и панорамирование, посмотрите здесь:

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

этот фрагмент помог мне автоматизировать и анимировать масштабирование и панорамированиев конкретную точку на холсте.(Реквизит Уилл Морган )

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);
    }

} 
11 голосов
/ 03 февраля 2012

См. этот пример JS Fiddle для использования jQuery и setViewBox Рафаэля, который плавно выполняет масштабирование и панорамирование.Мы используем точно такую ​​же функциональность в гораздо более сложном и широком контексте, и она отлично работает и остается гладкой даже при большом количестве элементов, отображаемых на экране.

По сути, не пытайтесь заново изобрести колесо.Я знаю, что это может быть не тот ответ, который вы ищете, но это почти наверняка ваш лучший вариант.

РЕДАКТИРОВАТЬ: я исправил прикрепленную скрипту (она была повреждена из-за изменений, внесенных в сайт JSFiddle), но, очевидно, SO не позволит мне сохранить ссылки JSFiddle без включения некоторого кода, так что ...

console.log("hello world!");
2 голосов
/ 03 июня 2015

Аналогично выше, но с отличиями:

  • Не зависит от внутренних органов (которые с тех пор изменились)
  • Не требует какой-либо глобальной настройки (она обрабатывается для вас)
  • Использует requestAnimationFrame, что приводит к гораздо более плавной анимации (но не работает в IE9 или ниже )
  • Использует Функции замедления Рафаэля (linear, easeIn, easeOut, easeInOut, backIn, backOut, elastic, bounce)

Так как это полное переписывание, я не изменил выше.

 Raphael.fn.animateViewBox = function(viewX, viewY, width, height, duration, callback, easing) {
    var start = window.performance.now(),
      canvas = this;

    easing = Raphael.easing_formulas[ easing || 'linear' ];
    duration = duration === undefined ? 250 : duration;

    if (canvas.currentViewBox == undefined) {
        canvas.currentViewBox = {
            x: 0,
            y: 0,
            width: this._viewBox ? this._viewBox[2] : canvas.width,
            height: this._viewBox ? this._viewBox[3] : canvas.height 
        }
    }

    function step(timestamp) {
        var progress = timestamp - start;
        var progressFraction = progress/duration;

        if (progressFraction > 1) {
            progressFraction = 1;
        }

        var easedProgress = easing( progressFraction );
        var newViewBox = {
            x: canvas.currentViewBox.x + (viewX - canvas.currentViewBox.x) * easedProgress,
            y: canvas.currentViewBox.y + (viewY - canvas.currentViewBox.y) * easedProgress,
            width: canvas.currentViewBox.width + (width - canvas.currentViewBox.width) * easedProgress,
            height: canvas.currentViewBox.height + (height - canvas.currentViewBox.height) * easedProgress
        };
        canvas.setViewBox(newViewBox.x, newViewBox.y, newViewBox.width, newViewBox.height, false);

        if (progressFraction < 1) {
            window.requestAnimationFrame(step);
        } else {
            canvas.currentViewBox = newViewBox;
            if (callback) {
                callback(newViewBox.x, newViewBox.y, newViewBox.width, newViewBox.height);
            }
        }
    }
    window.requestAnimationFrame(step);
}
2 голосов
/ 19 июня 2013

Незначительный мод для ответа Патрика, чтобы избавиться от «currentViewBox» ... это работает с Raphael 2.1.0:

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

    duration = duration || 250;

    //current viewBox Data from where the animation should start
    var originals = {
            x: this._viewBox[0], 
            y: this._viewBox[1], 
            width: this._viewBox[2], 
            height: this._viewBox[3]
    }, 
    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),
                        true
                );
                // 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);
    }
} 

Извините, если это плохой этикет - выкладывать мод. Не стесняйтесь сливать это в версию патрика, но тогда комментарии не имеют смысла.

...