SVG NG-repeat'ed元素SMIL动画只发生在页面加载 [英] SMIL animation on SVG ng-repeat'ed element only occurs on page load

查看:170
本文介绍了SVG NG-repeat'ed元素SMIL动画只发生在页面加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我产生了一些< RECT>在取值<动画>使用NG重复儿童指令。

在页面加载动画是否正确触发,一切都发生如预期。
然而,当我添加一个新的< RECT方式> 动画不会发生。

以下code代码演示了这种行为:

\r
\r

功能控制器($范围){\r
  $ scope.rects = [];\r
  VAR间距= 5;\r
  变种宽度= 10;\r
  VAR HEIGHT = 100;\r
  变种X = 10;\r
  变种Y = 10;\r
\r
  $ scope.newRect =功能(){\r
    $ scope.rects.push({\r
      X:X,\r
      Y:Y,\r
      宽度:宽度,\r
      身高:身高\r
    });\r
    X + =间距+宽度;\r
  };\r
\r
  为(变量I = 0; I&小于5;我++){\r
    $ scope.newRect();\r
  }\r
\r
}

\r

&LT;脚本SRC =htt​​ps://ajax.googleapis.com/ajax /libs/angularjs/1.2.23/angular.min.js\"></script>\r
\r
&LT; D​​IV NG-NG应用程序控制器=控制器&GT;\r
  &LT; SVG宽度=1000HEIGHT =200&GT;\r
    &所述;矩形纳克重复=矩形中rects×={{rect.x}}Y ={{rect.y}}高度={{rect.height}}宽度={{ rect.width}}&GT;\r
      &所述;动画的attributeName =y的从={{rect.height}}来={{rect.y}}DUR =1的repeatCount =1/&GT;\r
      &所述;动画的attributeName =高度从=0为={{rect.height}}DUR =1的repeatCount =1/&GT;\r
    &LT; / RECT&GT;\r
  &LT; / SVG&GT;\r
  &LT;按钮NG点击=newRect() - 酮详情&lt; /按钮&GT;\r
&LT; / DIV&GT;

\r

\r
\r

在加载的例子中,4 &LT;&RECT GT; 将出现,从底部到顶部动画。然而,当pressing一多按钮,新的&LT; RECT方式&gt; 无动画(行为在Firefox 35和Chrome 38测试)将被加入

我如何可以触发动画的新的&LT;&RECT GT; 取值


解决方案

默认的开始时间为动画元素(相当于开始=0)总是测量相对于SVG加载时间。这是真实的,即使你的页面加载后动态创建动画元素。

如果你需要的任何其他开始的时候,你将需要(一)明确设置为开始属性不同的值,或(b)使用 beginElement() beginElementAt(offsetTime) 动画元素DOM对象的方法。既然你使用脚本创建的元素,你希望他们将它们插入后立即启动, beginElement()方法可能是最简单的方法。

编辑补充:

如果 beginElement 不工作,因为角的js不为您提供直接访问创建的元素,你可以使用事件格式为开始属性。如果开始属性包含D​​OM事件的名称(或分号分隔的时间和事件名称列表),当事件发生时,动画将开始。默认情况下,该事件将被倾听该动画将影响-矩形你的情况元素。 (您可以使用 elementID.eventName 格式领带动画到不同的元素)。

的技巧,以获得动画,只要它被添加启动是将其链接到很少使用的 DOM的突变事件,特别是 DOMNodeInserted 。这样,当你添加了动画节点作为一个孩子的&LT; RECT&GT; ,或者当您添加&LT; RECT&GT; 到SVG的事件,然后动画将立即触发。

如果你想要插入元素,并触发动画之间的延迟,使用 eventName的+ timeOffset 格式。

这里是香草JS概念证明(如小提琴)

这是修改后的代码段; JS的code是一样的,只是角模板发生了变化:

\r
\r

功能控制器($范围){\r
  $ scope.rects = [];\r
  VAR间距= 5;\r
  变种宽度= 10;\r
  VAR HEIGHT = 100;\r
  变种X = 10;\r
  变种Y = 10;\r
\r
  $ scope.newRect =功能(){\r
    $ scope.rects.push({\r
      X:X,\r
      Y:Y,\r
      宽度:宽度,\r
      身高:身高\r
    });\r
    X + =间距+宽度;\r
  };\r
\r
  为(变量I = 0; I&小于5;我++){\r
    $ scope.newRect();\r
  }\r
\r
}

\r

&LT;脚本SRC =htt​​ps://ajax.googleapis.com/ajax /libs/angularjs/1.2.23/angular.min.js\"></script>\r
\r
&LT; D​​IV NG-NG应用程序控制器=控制器&GT;\r
  &LT; SVG宽度=1000HEIGHT =120&GT;\r
    &LT;矩形NG重复=矩形的rectsX ={{rect.x}}Y ={{rect.y}}\r
          高度={{rect.height}}宽度={{rect.width}}&GT;\r
      &LT;动画的attributeName =从=Y,{{rect.height}}为={{rect.y}}\r
               DUR =1的repeatCount =1开始=DOMNodeInserted/&GT;\r
      &所述;动画的attributeName =高度从=0为={{rect.height}}\r
               DUR =1的repeatCount =1开始=DOMNodeInserted/&GT;\r
    &LT; / RECT&GT;\r
  &LT; / SVG&GT;\r
  &LT;按钮NG点击=newRect() - 酮详情&lt; /按钮&GT;\r
&LT; / DIV&GT;

\r

\r
\r

我不知道是否有意想拥有酒吧开始10px的从底线偏移。如果是偶​​然的,你可以第一个动画的值设置为 rect.height + rect.y 。

我已经测试了最新的Chrome和Firefox的小提琴。如果你需要支持旧的浏览器,特别是如果你是支持老年IE与SMIL填充工具,你要测试,以确保DOM的突变事件是否被正确抛出。

I'm generating some <rect>s with <animate> children using the ng-repeat directive.

On page load the animations are correctly triggered and everything happens as expected. However, when I add a new <rect> the animation does not occur.

The following code snippet demonstrates this behaviour:

function Controller($scope) {
  $scope.rects = [];
  var spacing = 5;
  var width = 10;
  var height = 100;
  var x = 10;
  var y = 10;

  $scope.newRect = function() {
    $scope.rects.push({
      x: x,
      y: y,
      width: width,
      height: height
    });
    x += spacing + width;
  };

  for (var i = 0; i < 5; i++) {
    $scope.newRect();
  }

}

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app ng-controller="Controller">
  <svg width="1000" height="200">
    <rect ng-repeat="rect in rects" x="{{rect.x}}" y="{{rect.y}}" height="{{rect.height}}" width="{{rect.width}}">
      <animate attributeName="y" from="{{rect.height}}" to="{{rect.y}}" dur="1s" repeatCount="1" />
      <animate attributeName="height" from="0" to="{{rect.height}}" dur="1s" repeatCount="1" />
    </rect>
  </svg>
  <button ng-click="newRect()">One more</button>
</div>

Upon loading the example, 4 <rect> will appear, animating from the bottom to the top. However, when pressing the "One more" button, the new <rect> will be added without animation (behaviour tested on Firefox 35 and Chrome 38).

How can I trigger the animation for the new <rect>s?

解决方案

The default begin time for an animation element (equivalent to begin="0s") is always measured relative to the SVG load time. This is true even if you create the animation element dynamically after page load.

If you want any other begin time, you will need to either (a) explicitly set a different value for the begin attribute, or (b) use the beginElement() or beginElementAt(offsetTime) methods of the animation element DOM objects. Since you're creating the elements with scripts and you want them to start right after inserting them, the beginElement() method is probably the easiest approach.

Edited to add:

If beginElement isn't working because angular-js doesn't provide you with direct access to the created element, you can make use of the event format for the begin attribute. If the begin attribute contains the name of a DOM event (or a semi-colon separated list of times and event names), the animation will begin when that event occurs. By default, the event will be listened for on the element that the animation will affect—the rectangle in your case. (You can tie the animation to a different element using the elementID.eventName format).

The trick to get the animation to start as soon as it is added is to link it to one of the rarely used DOM-mutation events, specifically DOMNodeInserted. That way, when you add the animation node as a child of the <rect>, or when you add the <rect> to the SVG, the event and then the animation will be triggered immediately.

If you want a delay between inserting the element and triggering the animation, use the eventName + timeOffset format.

Here is the proof of concept with vanilla JS (as a fiddle).

And here is your modified snippet; the JS code is the same, only the angular template has changed:

function Controller($scope) {
  $scope.rects = [];
  var spacing = 5;
  var width = 10;
  var height = 100;
  var x = 10;
  var y = 10;

  $scope.newRect = function() {
    $scope.rects.push({
      x: x,
      y: y,
      width: width,
      height: height
    });
    x += spacing + width;
  };

  for (var i = 0; i < 5; i++) {
    $scope.newRect();
  }

}

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app ng-controller="Controller">
  <svg width="1000" height="120">
    <rect ng-repeat="rect in rects" x="{{rect.x}}" y="{{rect.y}}" 
          height="{{rect.height}}" width="{{rect.width}}">
      <animate attributeName="y" from="{{rect.height}}" to="{{rect.y}}" 
               dur="1s" repeatCount="1" begin="DOMNodeInserted"/>
      <animate attributeName="height" from="0" to="{{rect.height}}" 
               dur="1s" repeatCount="1" begin="DOMNodeInserted"/>
    </rect>
  </svg>
  <button ng-click="newRect()">One more</button>
</div>

I'm not sure whether you intentionally want to have the bars start 10px offset from the bottom line. If that was accidental you can fix it by setting the from value of the first animation to rect.height + rect.y.

I've tested the fiddle in the latest Chrome and Firefox. If you need to support older browsers, especially if you're supporting older IE with a SMIL polyfill, you'll want to test to make sure the DOM mutation events are being thrown correctly.

这篇关于SVG NG-repeat'ed元素SMIL动画只发生在页面加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆