Dynamic animation in IE9

Asked by pablo

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:
Last query:
Last reply:
Revision history for this message
Fenring (leunen-d) said :
#1

Hi Pablo,

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

David

Revision history for this message
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();
    }
  }
 }
}

Revision history for this message
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)

Revision history for this message
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>

Revision history for this message
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;
})();

Revision history for this message
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.

Revision history for this message
pablo (pablo-platt) said :
#7

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

Thanks