【问题标题】:SVG start and edit animateTransform by JavascriptSVG 通过 Javascript 启动和编辑 animateTransform
【发布时间】:2014-04-07 18:10:27
【问题描述】:

我想通过转换矩阵(即动态决定)来转换 SVG 画布上的元素。我可以用 JQuery-SVG animate() 做到这一点,但它根本不会产生平滑的结果。所以我想用原生的SVG animateTransform,问题是:

  • 如何让它在我想要的时候启动(可能是 beginElement()),以及
  • 如何动态设置矩阵中的参数?

提前感谢:D

【问题讨论】:

    标签: javascript animation svg


    【解决方案1】:

    感谢您的回答! 因为我想使用原生 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 就可以了)。

    【讨论】:

      【解决方案2】:

      动画可以通过多种不同的方式完成。

      向图形/形状元素添加动画元素适用于预定义动画。 “动画元素”提供了非常简短的甜蜜解决方案,演示: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;
      } )();
      

      【讨论】:

        猜你喜欢
        • 2012-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-07
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多