Dimitar
Dimitar

Reputation: 182

Will this method of spinning an SVG in IE9 cause a performance hit?

I have a task to make an SVG rotate in IE9.

I found the FakeSmile library which makes it rotate, but after the whole DOM is ready, which is not the behavior I want. I made an attempt to do it manually with JavaScript and ended with this code:

//init an array with values from 0 to 360 for degrees 
var degrees = [];
for(var i = 0; i <= 360; i++) {
    degress.push(i);
}
// function to rotate it, after it's fetched from the DOM
var rotate = function() {
    var deg = degrees.shift();
    element.style.msTransform = "rotate(" + deg + "deg)";
    degrees.push(deg);         
}
setInterval(rotate, 7);

Though it is working, I am worried if any performance hit will occur. Also if there is a better solution. Any suggestions are welcomed.

Upvotes: 1

Views: 104

Answers (2)

Emil S. J&#248;rgensen
Emil S. J&#248;rgensen

Reputation: 6366

A creator function and organized objects would be a good start. Remember you shouldn't pollute the global namespace if you can avoid it.

Also de-bounce request and animation. A request every 7 millisecond is two request per frame on a 60fps screen (the most common) and there is no need to calculate and throw away frames the user never sees.

In my example i use requestAnimationFrame because that will synchronize with the screens refreshrate. On every request i check if the handle is already drawing a frame and if it isn't i schedule a frame drawing.

Notice that you can still set JavaScript variables every 7 millisecond. It's just the DOM that's slows.

EDIT 1 - No requestAnimationFrame in IE9

My mistake about requestAnimationFrame, but de-bounce is still a good idea. With de-bounce, several factors can request a change and it will still only render when relevant.

I have replaced requestAnimationFrame with setTimeout(.... 1000/60) for close to 60 fps animation.

function createRotator(element) {
  var rotator;
  rotator = {
    degrees: 0,
    element: element,
    eventHandle: false,
    rotate: function rotate() {
      rotator.degrees = (rotator.degrees + 1) % 360;
      if (rotator.eventHandle === false)
        rotator.eventHandle = setTimeout(function() {
          rotator.element.style.transform = "rotate(" + rotator.degrees + "deg)";
          rotator.element.style.msTransform = "rotate(" + rotator.degrees + "deg)";
          rotator.eventHandle = false;
        }, 1000 / 60);
    }
  };
  return rotator;
}
//TEST
var nodes = 0;
var handle;
handle = setInterval(function() {
  nodes++;
  if (nodes > 10) {
    clearInterval(handle);
  }
  var testNode = document.body.appendChild(document.createElement("p"));
  testNode.innerHTML = "Hello dear World!";
  testNode.style.width = "115px";
  testNode.style.cssFloat = "left";
  testNode.style.marginTop = "100px";
  var rotator = createRotator(testNode);
  setInterval(rotator.rotate, 3);
}, 1000 / 4);

Upvotes: 1

TheCrzyMan
TheCrzyMan

Reputation: 1030

Yeah, with IE9, you're out of luck on CSS animations. My only suggestion would be a memory optimization

//init a variable to store the current angle
let angle = 0;

// function to rotate it
function rotate() {
    angle = (++angle)%360;
    element.style.msTransform = "rotate(" + angle+ "deg)";      
}
setInterval(rotate, 7);

This design change also lets you change the speed of the rotation on the fly without changing the interval length. All you would change is ++angle to angle + w where w is the angular velocity.

What is also unfortunate is that you can't use requestAnimationFrame instead of an interval. Oh well. It's not the end of the world.

EDIT: It was bugging me that the function was relying so heavily on global variables. So, here is a slightly "better", though heavier, way of doing it.

/** Takes in an element, an angular velocity, and an interval, and makes the element spin in IE9
PARAMS:
    element  : Element - The element we are spinning
    da       : Number  - The angular velocity in degrees per interval
    interval : Number  - The number of milliseconds per interval
RETURNS:
    Number - The ID of the interval that is created
**/
function makeRotate(element, da, interval){
    // Variable to store angle
    let a = 0;

    // If da isn't provided, make it 1
    da = da || 1;

    // If interval isn't provided, make it 7
    interval = interval || 7;

    // Get the ID and make the interval
    let id = window.setInterval(() => {

        // Increment the angle by the angular velocity, but wrap around 360
        a = (a + da)%360;

        // Apply the transform to the element
        element.style.msTransform = "rotate(" + a + "deg)";      
    }, interval);

    // Return the ID of the interval
    return id;
}
const intervalId = makeRotate(element, 1, 7);

Also, I made sure to return the interval id because it is always handy to be able to cancel those suckers! window.clearInterval(intervalId);

Upvotes: 0

Related Questions