Reputation: 182
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
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
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