1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-15 01:50:55 +01:00
phorge-phorge/webroot/rsrc/externals/javelin/ext/fx/FX.js
epriestley 07c113a0f3 Make animations set their initial values immediately
Summary:
Currently, it takes one frame for animations to set their first value. For fading stuff in, that means it briefly appears at 100% opacity, then jumps to 0%, then fades in from there.

Instead, immediately tween to the initial value.

Test Plan: Comments in Pholio fade in nicely. Preview is still a janky pile of mess until D6267.

Reviewers: btrahan, chad

Reviewed By: chad

CC: aran

Differential Revision: https://secure.phabricator.com/D6268
2013-06-21 18:57:10 -07:00

217 lines
5.4 KiB
JavaScript

/**
* @provides javelin-fx
* @requires javelin-color javelin-install javelin-util
* @javelin
*
* Based on moo.fx (moofx.mad4milk.net).
*/
JX.install('FX', {
events: ['start', 'complete'],
construct: function(element) {
this._config = {};
this.setElement(element);
this.setTransition(JX.FX.Transitions.sine);
},
properties: {
fps: 50,
wait: true,
duration: 500,
element: null,
property: null,
transition: null
},
members: {
_to: null,
_now: null,
_from: null,
_start: null,
_config: null,
_interval: null,
start: function(config) {
if (__DEV__) {
if (!config) {
throw new Error('What styles do you want to animate?');
}
if (!this.getElement()) {
throw new Error('What element do you want to animate?');
}
}
if (this._interval && this.getWait()) {
return;
}
var from = {};
var to = {};
for (var prop in config) {
from[prop] = config[prop][0];
to[prop] = config[prop][1];
if (/color/i.test(prop)) {
from[prop] = JX.Color.hexToRgb(from[prop], true);
to[prop] = JX.Color.hexToRgb(to[prop], true);
}
}
this._animate(from, to);
return this;
},
stop: function() {
clearInterval(this._interval);
this._interval = null;
return this;
},
then: function(func) {
var token = this.listen('complete', function() {
token.remove();
func();
});
return this;
},
_animate: function(from, to) {
if (!this.getWait()) {
this.stop();
}
if (this._interval) {
return;
}
setTimeout(JX.bind(this, this.invoke, 'start'), 10);
this._from = from;
this._to = to;
this._start = JX.now();
this._interval = setInterval(
JX.bind(this, this._tween),
Math.round(1000 / this.getFps()));
// Immediately update to the initial values.
this._tween();
},
_tween: function() {
var now = JX.now();
var prop;
if (now < this._start + this.getDuration()) {
this._now = now - this._start;
for (prop in this._from) {
this._config[prop] = this._compute(this._from[prop], this._to[prop]);
}
} else {
setTimeout(JX.bind(this, this.invoke, 'complete'), 10);
// Compute the final position using the transition function, in case
// the function applies transformations.
this._now = this.getDuration();
for (prop in this._from) {
this._config[prop] = this._compute(this._from[prop], this._to[prop]);
}
this.stop();
}
this._render();
},
_compute: function(from, to) {
if (JX.isArray(from)) {
return from.map(function(value, ii) {
return Math.round(this._compute(value, to[ii]));
}, this);
}
var delta = to - from;
return this.getTransition()(this._now, from, delta, this.getDuration());
},
_render: function() {
var style = this.getElement().style;
for (var prop in this._config) {
var value = this._config[prop];
if (prop == 'opacity') {
value = parseInt(100 * value, 10);
if (window.ActiveXObject) {
style.filter = 'alpha(opacity=' + value + ')';
} else {
style.opacity = value / 100;
}
} else if (/color/i.test(prop)) {
style[prop] = 'rgb(' + value + ')';
} else {
style[prop] = value + 'px';
}
}
}
},
statics: {
fade: function(element, visible) {
return new JX.FX(element).setDuration(250).start({
opacity: visible ? [0, 1] : [1, 0]
});
},
highlight: function(element, color) {
color = color || '#fff8dd';
return new JX.FX(element).setDuration(1000).start({
backgroundColor: [color, '#fff']
});
},
/**
* Easing equations based on work by Robert Penner
* http://www.robertpenner.com/easing/
*/
Transitions: {
linear: function(t, b, c, d) {
return c * t / d + b;
},
sine: function(t, b, c, d) {
return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
},
sineIn: function(t, b, c, d) {
if (t == d) {
return c + b;
}
return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
},
sineOut: function(t, b, c, d) {
if (t == d) {
return c + b;
}
return c * Math.sin(t / d * (Math.PI / 2)) + b;
},
elastic: function(t, b, c, d, a, p) {
if (t === 0) { return b; }
if ((t /= d) == 1) { return b + c; }
if (!p) { p = d * 0.3; }
if (!a) { a = 1; }
var s;
if (a < Math.abs(c)) {
a = c;
s = p / 4;
} else {
s = p / (2 * Math.PI) * Math.asin(c / a);
}
return a * Math.pow(2, -10 * t) *
Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
},
bounce: function(t, b, c, d) {
if ((t /= d) < (1 / 2.75)) {
return c * (7.5625 * t * t) + b;
} else if (t < (2 / 2.75)) {
return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
} else if (t < (2.5 / 2.75)) {
return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
} else {
return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
}
}
}
}
});