Dynamic animation in IE9

Asked by pablo on 2012-07-16

I'm trying to add animate element dynamically with javascript.
It works in FF and Chrome but I'm getting an error in IE9 with FakeSmile:
Object doesn't support property or method 'beginElement'
http://jsfiddle.net/DgMDV/13/

When removing the begin attribute
animation.setAttributeNS(null, 'begin', 'indefinite');
I can see the animation.

The static case works
http://jsfiddle.net/FG3PG/1/

Thanks

Question information

Language:
English Edit question
Status:
Solved
For:
FakeSmile Edit question
Assignee:
No assignee Edit question
Solved by:
pablo
Solved:
2012-07-29
Last query:
2012-07-29
Last reply:
2012-07-24
Fenring (leunen-d) said : #1

Hi Pablo,

FakeSmile doesn't work (yet) with animations that are created after FakeSmile is run.

David

pablo (pablo-platt) said : #2

How can I add a function to register dynamically created animate elements?
How can I call this function from the HTML document?

I think I need something similar to:

function smile_element(animates) {
 var impl = document.implementation;
 for (var i=0, j=animates.length; i<j; ++i) {
  if ((namespaceURI==svgns && !impl.hasFeature("http://www.w3.org/TR/SVG11/feature#SVG-animation", "1.1")) ||
   (namespaceURI==smilanimns && !impl.hasFeature(smilanimns, "1.1")) ||
   (namespaceURI==smil2ns && !impl.hasFeature(smil2ns, "2.0")) ||
   (namespaceURI==smil21ns && !impl.hasFeature(smil21ns, "2.1")) ||
   (namespaceURI==smil3ns && !impl.hasFeature(smil3ns, "3.0")) ||
   (namespaceURI==timesheetns && !impl.hasFeature(timesheetns, "1.0"))) {
    if (nodeName=="set" || nodeName=="animate" || nodeName=="animateColor" || nodeName=="animateMotion" || nodeName=="animateTransform") {
   var targets = getTargets(anim);
   var elAnimators = new Array();
   for (var k=0; k<targets.length; ++k) {
     var target = targets[k];
     var animator = new Animator(anim, target, k);
     animators.push(animator);
     elAnimators[k] = animator;
   }
   anim.animators = elAnimators;
   var id = anim.getAttribute("id");
   if (id)
     id2anim[id] = anim;

   animator.register();
    }
  }
 }
}

Fenring (leunen-d) said : #3

Hi Pablo,

yes.

You can try to add the following function :

function registerAnimation(anim) {
        var targets = getTargets(anim);
        var elAnimators = new Array();
        for(var i=0; i<targets.length ;i++) {
          var target = targets[i];
          var animator = new Animator(anim, target, i);
          animators.push(animator);
          elAnimators[i] = animator;
        }
        anim.animators = elAnimators;
        var id = anim.getAttribute("id");
        if (id)
          id2anim[id] = anim;
        for(var i=0; i<elAnimators.length ;i++)
          elAnimators[i].register();
}

(Note the two last lines that I added)

And then call it by passing your newly create element (it should be already added to the DOM) : registerAnimation(animateElement);

(The code above is not tested. Tell me if you succeed. If not, I'll look into it)

pablo (pablo-platt) said : #4

I've added your function and now animations works on IE9.

When using inline SVG all the functions and variables of fakesmil are in the global scope.
So my questions are:
1. Is it possible to put fakesmil in a closure so it won't affect the global scope like JQuery does?
2. Will it be possible to call the FakeSMIL.registerAnimation function when it is inside a closure and still make it work?

The following example works on IE9
http://jsbin.com/uxomel/

Thanks

<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" /><svg
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   version="1.0"
   viewBox="0 0 120 40"
    xml:space="preserve">
    <script type="text/ecmascript" xlink:href="path/to/smil.user.js" />
    <rect x="10" y="10" width="10" height="10" fill="#c66" />
</svg>
</body>
 <script>
  var svg = document.getElementsByTagName('svg')[0];
  var svgNS = svg.getAttribute('xmlns');
  var rect = document.getElementsByTagName('rect')[0];

  var animation = document.createElementNS(
   "http://www.w3.org/2000/svg", "animate");
  animation.setAttributeNS(null, 'attributeName', 'x');
  animation.setAttributeNS(null, 'dur', 0.5);
  animation.setAttributeNS(null, 'begin', 'indefinite');
  animation.setAttributeNS(null, 'fill', 'freeze');
  animation.setAttributeNS(null, 'to', 100);
  rect.appendChild(animation);
  registerAnimation(animation);
  animation.beginElement();
 </script>
</html>

pablo (pablo-platt) said : #5

I can wrap the fakesmile code with a closure and it works.
The only problem with this design is that we can only have 1 svg using fakesmile in the document.
Maybe we can have a global FakeSmil object that each instance will register to with the svg id?

// sizzle code here...

(function(){
// fakesmile code here...
FakeSmil = {};
FakeSmil.registerAnimation = registerAnimation;
window.FakeSmil = FakeSmil;
})();

Lthere (helder-magalhaes) said : #6

Regarding the registerAnimation utility method, I'd being the seperate-enable branch by doctormo to discussion, which apparently was already trying to implement this:
https://code.launchpad.net/~doctormo/smil/seperate-enable

Regarding using a closure, by coincidence I already had something like this in my working copy. According to the seperate-enable branch, apparently other methods could use being exposed once Fakesmile was wrapped in a closure. I'd suggest opening a feature request for tracking this.

pablo (pablo-platt) said : #7

You were being very helpful.
I hope both the registerAnimation and closure will be implemented.

Thanks