2014-10-28 8 views
0

<rect>을 생성하고 ng-repeat 지시문을 사용하여 <animate> 자식을 생성합니다.SVG ng-repeat'ed 요소의 SMIL 애니메이션은 페이지로드에서만 발생합니다.

페이지로드시 애니메이션이 올바르게 트리거되고 모든 것이 예상대로 발생합니다. 그러나 새로 추가 할 때 <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>는 아래쪽에서 위쪽 애니메이션 나타납니다. 그러나 "One more"버튼을 누르면 새로운 <rect>이 애니메이션없이 추가됩니다 (Firefox 35 및 Chrome 38에서 동작 테스트 됨).

<rect>의 새 애니메이션을 어떻게 트리거 할 수 있습니까?

답변

3

애니메이션 요소의 기본 시작 시간 (begin="0s"에 해당)은 항상 SVG로드 시간을 기준으로 측정됩니다. 페이지로드 후에 애니메이션 요소를 동적으로 만들더라도 마찬가지입니다.

다른 시작 시간을 원하면 begin 속성에 다른 값을 명시 적으로 설정하거나 (b) 애니메이션 요소 DOM 객체의 beginElement() or beginElementAt(offsetTime) 메소드를 사용해야합니다. 스크립트를 사용하여 요소를 만들고이를 삽입 한 직후에 요소를 만들려면 beginElement() 메서드가 가장 쉬운 방법 일 것입니다.

편집은 추가 : 각-JS가 생성 된 요소에 직접 액세스를 제공하지 않기 때문에 작동하지 않습니다

beginElement 경우, begin 속성에 대한 이벤트 형식을 사용할 수있다. begin 속성에 DOM 이벤트의 이름 (또는 시간 및 이벤트 이름의 세미콜론으로 구분 된 목록)이 포함되어 있으면 해당 이벤트가 발생할 때 애니메이션이 시작됩니다. 기본적으로 이벤트는 애니메이션에 영향을 줄 요소 (사례의 사각형)에서 수신됩니다. (elementID.eventName 형식을 사용하여 애니메이션을 다른 요소에 묶을 수 있습니다.

애니메이션을 추가하자 마자 시작하려면 거의 사용하지 않는 DOM-mutation events 중 하나, 특히 DOMNodeInserted에 연결해야합니다. 그런 식으로 애니메이션 노드를 <rect>의 자식으로 추가하거나 <rect>을 SVG에 추가하면 이벤트가 발생하고 애니메이션이 즉시 트리거됩니다.

요소를 삽입하고 애니메이션을 트리거 할 때까지 지연 되려면 eventName + timeOffset 형식을 사용하십시오.

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

그리고 수정 된 스 니펫은 다음과 같습니다. JS 코드는 각 템플릿이 변경, 동일 :

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에서 바이올린을 테스트했습니다. 나이가 많은 브라우저를 지원해야하는 경우, 특히 SMIL polyfill로 이전 IE를 지원하는 경우 DOM 돌연변환 이벤트가 올바르게 발생하는지 테스트해야합니다.

+0

나는'beginElement()'접근법을 시도했다. 그러나, 나는 그것을 호출하기 전에''요소에 대한 자바 스크립트 액세스가 필요하기 때문에'setTimeout (fn, 0)'에 호출을 래핑해야했습니다. 경우에 따라 애니메이션이 실행되기 전에 사용자가 전체 ''을 볼 수있는 깜박임이 발생합니다. 이제는 단락을 쓰고 무의식적으로 답장을 보내고 싶습니다. 나는 (a) 접근 방식으로 무언가를 만들 수 있는지 알아 보려고 노력할 것이다. – Daniel

+0

@ 다니엘 아직 자신을 알아 내지 못했다면 수정 사항을 확인하십시오. – AmeliaBR

+0

그 해결책을 시도했지만, 무의식적으로'DOMNodeInserted' 대신에'this.DOMNodeInserted'를 썼습니다. 편집 해 주셔서 감사합니다. 엄청난 도움이되었습니다. 다른 점에 관해서는 : 10px 오프셋은 실제로 의도하지 않았지만 코드에서 수정했지만 문제의 중요성은 충분하지 않다고 판단했습니다. 두 번째 사항은 아니요, 오래된 IE는이 시점에서 문제가되지 않습니다. 다행히도. – Daniel