Skip to content

Instantly share code, notes, and snippets.

@z-------------
Last active August 29, 2015 14:23
Show Gist options
  • Save z-------------/4d8b5f1d3e09932ec008 to your computer and use it in GitHub Desktop.
Save z-------------/4d8b5f1d3e09932ec008 to your computer and use it in GitHub Desktop.
element.animate() plus a couple improvements
HTMLElement.prototype.animateBase = HTMLElement.prototype.animate;
HTMLElement.prototype.animate = function(keyframes, options) {
function isNothing(thing) {
return thing === null || typeof thing === "undefined";
}
var elem = this;
var opts = {
duration: 300,
delay: 0,
iterations: 1
};
/* overwrite default options */
if (typeof options === "object" && !isNothing(options)) {
Object.keys(options).filter(function(key) {
return ["duration", "delay", "iterations"].indexOf(key) !== -1;
}).forEach(function(key) {
opts[key] = options[key];
});
} else if (typeof options === "number") {
opts.duration = options;
}
/* make list of animated props for filling in partial keyframes */
var animatedProps = [];
keyframes.forEach(function(keyframe, i) {
if (typeof keyframe === "object" && !isNothing(keyframe)) {
var props = Object.keys(keyframe);
props.forEach(function(prop) {
if (animatedProps.indexOf(prop) === -1) {
animatedProps.push(prop);
}
});
}
});
/* initial style keyframe to fill in partial keyframes */
var initialStyles = {};
(function() {
var computedStyle = getComputedStyle(elem);
animatedProps.forEach(function(prop) {
initialStyles[prop] = computedStyle.getPropertyValue(prop);
});
})();
/* fill in partial keyframes */
for (var k = 0; k < keyframes.length; k++) {
var keyframe = keyframes[k];
if (isNothing(keyframe)) {
keyframes[k] = initialStyles;
} else {
animatedProps.forEach(function(prop) {
if (!keyframe.hasOwnProperty(prop)) {
keyframes[k][prop] = initialStyles[prop];
}
});
}
}
/* set element style to first keyframe if necessary */
if (opts.duration > 0) {
var keyframeFirst = keyframes[0];
Object.keys(keyframeFirst).forEach(function(prop) {
elem.style[prop] = keyframeFirst[prop];
});
}
var animationPlayer = elem.animateBase(keyframes, opts);
/* set element style to last keyframe on animation finish */
animationPlayer.onfinish = function() {
var keyframeLast = keyframes[keyframes.length - 1];
Object.keys(keyframeLast).forEach(function(prop) {
elem.style[prop] = keyframeLast[prop];
});
};
/* return AnimationPlayer object */
return animationPlayer;
};

elementAnimate.js

elementAnimate.js takes the usual element.animate() arguments and plays an animation, with some handy improvements:

  • automatically fills in partial keyframes based on initial styles
  • set style before delayed animation
  • set style after animation finished

Examples

Fix partial keyframes

Say we have a div with background-color: red and color: white.

Running

div.animate([null, { "background-color": "blue" }, null, { "background-color": "pink"}], 300)

is equivalent to running

div.animateBase([{ "background-color": "red" }, { "background-color": "blue" }, { "background-color": "red" }, { "background-color": "pink"}], 300)

(animateBase is the original element.animate() function).

Setting styles before delayed animation

Before an animation with delay starts, the styles of the first keyframe is applied to the element.

Setting styles after animation

When an animation finishes, the styles of the final keyframe is applied to the element.


MIT license.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment