最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Dynamically change SVG animation values while using fill="freeze" - Stack Overflow

programmeradmin6浏览0评论

I am using SVG for charts in an AJAX web app. When the initial data is received I would like to animate chart elements (such as bars) from the default 0 values to the new data value. If the user selects a new dataset I request new data from the server and then would like to animate the bar from the previous value to the new value.

<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>

Each time data is received, I set the from and to attributes and call beginElement().

If I set fill="remove" in the SVG animation then the bar animates correctly each time a new dataset is loaded, but, of course, between animations the bar returns to its default width.

Setting width.baseVal.value to establish a new base value either before OR after calling beginElement() causes very nasty flickering.

So I tried using fill="freeze" to have the bar keep its width at the end of each animation. The problem is that the first animation works, but each subsequent call to beginElement() returns the bar to its default width immediately and animation stops working.

I am testing in Chrome 12.0. Here is a sample to see how animation breaks when using freeze.

/

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

  <body>
    <svg width="200px" height="20px" xmlns="" 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>

How can I animate a bar's width, have it keep the new width, and then repeatedly animate it to new values as they arrive?

I am using SVG for charts in an AJAX web app. When the initial data is received I would like to animate chart elements (such as bars) from the default 0 values to the new data value. If the user selects a new dataset I request new data from the server and then would like to animate the bar from the previous value to the new value.

<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>

Each time data is received, I set the from and to attributes and call beginElement().

If I set fill="remove" in the SVG animation then the bar animates correctly each time a new dataset is loaded, but, of course, between animations the bar returns to its default width.

Setting width.baseVal.value to establish a new base value either before OR after calling beginElement() causes very nasty flickering.

So I tried using fill="freeze" to have the bar keep its width at the end of each animation. The problem is that the first animation works, but each subsequent call to beginElement() returns the bar to its default width immediately and animation stops working.

I am testing in Chrome 12.0. Here is a sample to see how animation breaks when using freeze.

http://jsfiddle/4ws9W/

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

  <body>
    <svg width="200px" height="20px" xmlns="http://www.w3/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>

How can I animate a bar's width, have it keep the new width, and then repeatedly animate it to new values as they arrive?

Share Improve this question asked Jun 28, 2011 at 13:13 Allison LockAllison Lock 2,39315 silver badges17 bronze badges 1
  • Did you find a solution for this? I am having a similar issue continuing to animate color changes using fill=freeze. – ssawchenko Commented Jun 21, 2012 at 0:20
Add a ment  | 

3 Answers 3

Reset to default 1

You can call suspendRedraw method on the necessary elements to avoid flickering. HTH

I think when you are updating the next 'to' value, update the current 'to' value to the width attribute of the rectangle object as well as the 'from' attribute of the animation. while u are updating this make sure u set the fill->remove and after changing the attribute value revert the fill->freeze. see if the code below works.

    <!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/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>

Just an idea: set the 'begin' attributes to be the current amount of seconds elapsed since the page loaded.
Kinda like so:

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 ); 
} 

And/or add new animations with .appendChild() rather than fiddle with existing values.

发布评论

评论列表(0)

  1. 暂无评论