我想通过转换矩阵(即动态决定)转换SVG画布上的元素。我可以使用JQuery-SVG animate()来完成它,但它根本不会产生平滑。所以我想使用原生的SVG animateTransform,问题是:
提前感谢:D
答案 0 :(得分:2)
感谢您的回答! 由于我想使用原生的SVG动画,我找到了这个解决方案(仍然没有完美地工作)。这是现有的animateTransform的一种版本(attributeName =" transform" type =" matrix")
注意:我为group.transform中的每个元素保留svg转换,而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;
最后,更新元素的transform属性:
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 :(得分:1)
动画可以通过多种方式完成。
将动画元素添加到图形/形状元素适用于预定义的动画。 “animate elements”提供了非常简短的甜蜜解决方案,演示:http://jsfiddle.net/UjuR8
交互式动画需要更多手动解决方案和一些Javascript样板代码。您必须创建一个render
函数,该函数将在requestAnimationFrame
每秒调用60次(请参阅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;
} )();