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.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>
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?
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.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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With