我正在生成一些<rect>
与<animate>
children 使用 ng-repeat 指令。
页面加载时,动画会正确触发,一切都会按预期发生。
但是,当我添加新的<rect>
时动画不会发生。
以下代码片段演示了此行为:
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>
加载示例后,4 <rect>
将会出现,从下到上有动画效果。然而,当按下“另一个”按钮时,新的 <rect>
将在没有动画的情况下添加(在 Firefox 35 和 Chrome 38 上测试行为)。
如何触发新 <rect>
的动画是吗?
最佳答案
动画元素的默认开始时间(相当于 begin="0s"
)始终相对于 SVG 加载时间进行测量。即使您在页面加载后动态创建动画元素也是如此。
如果您想要任何其他开始时间,则需要 (a) 为 begin
显式设置不同的值属性,或 (b) 使用 beginElement()
or beginElementAt(offsetTime)
动画元素 DOM 对象的方法。由于您使用脚本创建元素并且希望它们在插入后立即启动,因此 beginElement()
方法可能是最简单的方法。
编辑添加:
如果beginElement
不起作用,因为 angular-js 不提供对创建的元素的直接访问,您可以使用 begin
的事件格式属性。如果 begin 属性包含 DOM 事件的名称(或以分号分隔的时间和事件名称列表),则动画将在该事件发生时开始。默认情况下,将在动画将影响的元素(在您的例子中为矩形)上监听该事件。 (您可以使用 elementID.eventName
格式将动画绑定(bind)到不同的元素)。
添加动画后立即启动的技巧是将其链接到很少使用的 DOM-mutation events 之一。 ,具体来说DOMNodeInserted
。这样,当您将动画节点添加为 <rect>
的子节点时,或者当您添加 <rect>
时对于SVG,事件和动画将立即被触发。
如果您希望在插入元素和触发动画之间有延迟,请使用 eventName + timeOffset
格式。
Here is the proof of concept with vanilla JS (as a fiddle) .
这是您修改后的代码片段; JS 代码是相同的,只是 Angular 模板发生了变化:
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>
我不确定您是否故意想让条形从底线偏移 10px 开始。如果这是意外的,您可以通过设置 from
来修复它。第一个动画的值为 rect.height + rect.y
.
我已经在最新的 Chrome 和 Firefox 中测试了 fiddle。如果您需要支持较旧的浏览器,特别是如果您使用 SMIL polyfill 支持较旧的 IE,则需要进行测试以确保正确抛出 DOM 突变事件。
关于angularjs - SVG ng-repeat'ed 元素上的 SMIL 动画仅在页面加载时发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26614750/