2012-01-12 3 views
3

Я хотел бы преобразовать элемент на холсте SVG с помощью матрицы преобразования (которая определяется на лету). Я могу сделать это с помощью JQuery-SVG animate(), но это не приведет к гладкой вообще. Так я думал использовать родной SVG AnimateTransform, и вопрос:SVG начать и редактировать animateTransform по Javascript

  • как я могу сделать это начать, когда я хочу (возможно beginElement()), и
  • , как я могу установить параметры из матрицы на лету?

заранее спасибо: D

ответ

2

Спасибо за ваш ответ! Поскольку я хотел использовать собственные анимации SVG, я нашел это решение (все еще не работает отлично). Это своего рода версия не существующего animateTransform (attributeName = "transform" type = "matrix")

ПРИМЕЧАНИЕ: я сохраняю преобразование svg для каждого элемента в group.transform, а group.transform.matrix() возвращает просто матрица преобразования этого элемента.

Я сначала добавить эти элементы к элементу я хочу анимировать:

<animateTransform id="canvTranslate" begin="indefinite" attributeName="transform" type="translate" to="" dur="1s" additive="sum" fill="freeze"/> 
<animateTransform id="canvRotate" begin="indefinite" attributeName="transform" type="rotate" to="" dur="1s" additive="sum" fill="freeze"/> 
<animateTransform id="canvScale" begin="indefinite" attributeName="transform" type="scale" to="" dur="1s" additive="sum" fill="freeze"/> 

Тогда я сделать:

var tMatrix = transformation.matrix(); //this is the transformation i want to obtain 
    var cMatrix = group.transform.matrix(); //this is the actual CTM of the element 

    //getting the animations 
    var animTrans = document.getElementById('canvTranslate'); 
    var animRotaz = document.getElementById('canvRotate'); 
    var animScale = document.getElementById('canvScale'); 

    //setting duration (it's got somewhere before) 
    animTrans.setAttribute('dur', duration/1000+'s'); 
    animRotaz.setAttribute('dur', duration/1000+'s'); 
    animScale.setAttribute('dur', duration/1000+'s'); 

    //calculating the 'from' attribute 
    var transX = cMatrix.e; 
    var transY = cMatrix.f; 
    var scaleX = Math.sqrt(Math.pow(cMatrix.a, 2)+Math.pow(cMatrix.b, 2)); 
     var rotate = Math.atan(cMatrix.c/cMatrix.d); 

    animTrans.setAttribute('from', transX+','+transY); 
    animRotaz.setAttribute('from', -rotate*180/Math.PI); 
    animScale.setAttribute('from', scaleX); 
    //end 'from' 

    //calculating the 'to' attribute to set 
    var transX = tMatrix.e; 
    var transY = tMatrix.f; 
    var scaleX = Math.sqrt(Math.pow(tMatrix.a, 2)+Math.pow(tMatrix.b, 2)); 
    var rotate = Math.atan(tMatrix.c/tMatrix.d); 

    animTrans.setAttribute('to', transX+','+transY); 
    animRotaz.setAttribute('to', -rotate*180/Math.PI); 
    animScale.setAttribute('to', scaleX); 
    //end 'to' 

    animTrans.beginElement(); 
    animRotaz.beginElement(); 
    animScale.beginElement(); 

group.transform = transformation; и, наконец, обновить преобразование атрибута элемента:

setTimeout(function(){ //i will change this somehow better :) 

     //this is a problematic step. with it animations work on Chrome, without it they work good on firefox and opera too 
     $(group).attr('transform', 'matrix('+tMatrix.a+','+tMatrix.b+','+tMatrix.c+','+tMatrix.d+','+tMatrix.e+','+tMatrix.f+')'); 
    }, duration+100); 

Этот последний шаг является проблематичным. Я не могу понять, почему с ним отлично работает в Chrome, в то время как анимация заканчивается гораздо более масштабируемой в Firefox и Opera (где не вызывается setTimeout работает отлично).

1

Анимации может быть сделано по-разному.

Добавление элементов анимации в элементы графики/формы подходит для предопределенных анимаций. «Анимированные элементы» представляют действительно короткие сладкие решения, демо: http://jsfiddle.net/UjuR8

Интерактивная анимация требует более ручных решений с довольно некоторым шаблоном Javascript. Вы должны создать функцию render, которая будет вызываться 60 раз в секунду на requestAnimationFrame (см. http://paulirish.com/2011/requestanimationframe-for-smart-animating/). В render вы можете получить «текущую матрицу преобразования» (CTM) и применить к ней изменения. Это действительно небольшое доказательство концепции: http://jsfiddle.net/PaSD8/.

В большом проекте я бы рекомендовал обернуть элементы SVG и, возможно, сделать анимацию без конкатенации строк и вместо этого напрямую работать с матрицами и преобразованиями. Это пример класса, в котором я лежал:

var SVG, Object2D; 

SVG = document.querySelector('svg'); 

// ... 

Object2D = (function() { 
    var proto; 

    function Object2D (domElement) { 
    this.domElement = domElement; 
    this.transform = SVG.createSVGTransform(); 
    this.matrix  = SVG.createSVGMatrix(); 
    this.position = SVG.createSVGPoint(); 
    this.rotation = 0; 
    this.scale  = 1; 
    } 


    proto = Object2D.prototype; 


    proto.draw = function (timestamp) { 
    // update scale and position, apply rotation 
    var transform = this.transform, 
     matrix = this.matrix, 
     position = this.position, 
     rotation = this.rotation, 
     scale  = this.scale; 

    matrix.a = scale; 
    matrix.d = scale; 
    matrix.e = position.x; 
    matrix.f = position.y; 

    transform.setMatrix(matrix.multiply(rotation)); 
    this.domElement.transform.baseVal.initialize(transform); // clear then put 
    }; 


    return Object2D; 
})();