使用fill =“freeze”时动态更改SVG动画值

时间:2011-06-28 13:13:16

标签: javascript animation svg

我在AJAX网络应用程序中使用SVG图表。当收到初始数据时,我想将图表元素(如条形图)从默认的0值设置为新的数据值。如果用户选择了新数据集,我会从服务器请求新数据,然后将条形图从上一个值设置为新值。

<rect x="0" y="0" width="1px" height="20px" fill="red">
    <animate id="anim" attributeName="width" attributeType="XML"
        begin="indefinite" from="0" to="100px" dur="0.8s" fill="remove"/>
</rect>

每次收到数据时,我都会设置fromto属性并致电beginElement()

如果我在SVG动画中设置fill="remove",则每次加载新数据集时,条形图都会正确设置动画,但当然,在动画之间,条形图会返回其默认宽度。

设置width.baseVal.value以在调用beginElement()之后或之前建立新的基值会导致非常讨厌的闪烁。

所以我尝试使用fill="freeze"让条形图在每个动画结束时保持宽度。问题是第一个动画有效,但每次对beginElement()的调用都会立即将栏恢复为默认宽度,动画将停止工作。

我正在使用Chrome 12.0进行测试。下面是一个示例,了解动画在使用冻结时如何中断。

http://jsfiddle.net/4ws9W/

<!DOCTYPE html>
<html>
  <head><title>Test SVG animation</title></head>

  <body>
    <svg width="200px" height="20px" xmlns="http://www.w3.org/2000/svg" version="1.1">
      <rect x="0" y="10px" width="200px" height="2px"/>

      <rect x="0" y="0" width="1px" height="20px" fill="red">
        <animate id="anim" attributeName="width" attributeType="XML" begin="indefinite" from="0" to="100px" dur="1.3s" fill="freeze"/>
      </rect>

      parent.anim = document.getElementById('anim');

    </svg>

    <br/>
    <a href="javascript:anim.beginElement();">anim.beginElement();</a>
    <br/>
    <a href="javascript:anim.endElement();">anim.endElement();</a>
    <br/>

    <br/>
    <a href="javascript:anim.setAttribute('to', '50px');">anim.setAttribute('to', '50px');</a>
    <br/>
    <a href="javascript:anim.setAttribute('to', '150px');">anim.setAttribute('to', '150px');</a>
    <br/>

    <br/>
    <a href="javascript:anim.setAttribute('fill', 'remove');">anim.setAttribute('fill', 'remove');</a>
    <br/>
    <a href="javascript:anim.setAttribute('fill', 'freeze');">anim.setAttribute('fill', 'freeze');</a>
    <br/>

    </body>
</html>

如何为条形图的宽度设置动画,让它保持新的宽度,然后在它们到达时反复将其设置为新值?

3 个答案:

答案 0 :(得分:1)

您可以在必要元素上调用suspendRedraw方法以避免闪烁。 HTH

答案 1 :(得分:1)

我认为当您更新下一个'to'值时,将当前'to'值更新为矩形对象的width属性以及动画的'from'属性。当你正在更新这个时,请确保你设置fill-&gt;删除,并在更改属性值后恢复fill-&gt;冻结。看看下面的代码是否有效。

    <!DOCTYPE html>
    <html>
    <head><title>Test SVG animation</title>
    <script type='text/javascript'> 
    var animNode = 0; 
    function OnEndHandler(evt)
    {
      if(!animNode)
         animNode = evt.target;      
       var previousToValue = animNode.getAttribute('to'); 
      animNode.parentNode.setAttribute('width', previousToValue);   
      animNode.setAttribute('from', previousToValue);     
   }  
   function OnBtnHandler(event)
   {
      if(!animNode)
          animNode = document.querySelector('#anim'); 
     if(event.target.id == 'nextBtn')
     {
         animNode.setAttribute('fill', 'remove');
         animNode.setAttribute('to', '150px');   
         animNode.setAttribute('fill', 'freeze');
         animNode.beginElement(); 
     }
     else if(event.target.id == 'startBtn')
     {
         animNode.setAttribute('to', '50px');    
        animNode.beginElement(); 
     }   
    }

   </script>
   </head>

   <body>
    <input id= 'startBtn' type='button' value='StartBar' onclick='OnBtnHandler(event)' />
      <input id='nextBtn'  type='button' value='NextBar'  onclick='OnBtnHandler(event)'        />       
     <svg width="200px" height="20px" xmlns="http://www.w3.org/2000/svg" version="1.1">
      <rect x="0" y="10px" width="200px" height="2px"/>
      <rect x="0" y="0" width="1px" height="20px" fill="red">
        <animate id="anim" attributeName="width" attributeType="XML" begin="indefinite"  from="0" to="100px" dur="1.3s" fill="freeze" onend='OnEndHandler(evt)' />
      </rect>
     </svg>

    <br/>
    <a href="javascript:anim.beginElement();">anim.beginElement();</a>
    <br/>
    <a href="javascript:anim.endElement();">anim.endElement();</a>
    <br/>

    <br/>
    <a href="javascript:anim.setAttribute('to', '50px');">anim.setAttribute('to',  '50px');</a>
    <br/>
    <a href="javascript:anim.setAttribute('to', '150px');">anim.setAttribute('to', '150px'); </a>
    <br/>

    <br/>
    <a href="javascript:anim.setAttribute('fill', 'remove');">anim.setAttribute('fill', 'remove');</a>
    <br/>
    <a href="javascript:anim.setAttribute('fill', 'freeze');">anim.setAttribute('fill', 'freeze');</a>
    <br/>

    </body>
</html>

答案 2 :(得分:0)

只是一个想法:设置&#39;开始&#39;属性是自页面加载以来经过的当前秒数 有点像:

function seconds_elapsed ()     { 
  var date_now = new Date (); 
  var time_now = date_now.getTime (); 
  var time_diff = time_now - startTime; 
  var seconds_elapsed = Math.floor ( time_diff / 1000 ); 
  return ( seconds_elapsed ); 
} 

和/或使用.appendChild()添加新动画,而不是摆弄现有值。