New file |
0,0 → 1,464 |
if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
dojo._hasResource["dojo._base.fx"] = true; |
dojo.provide("dojo._base.fx"); |
dojo.require("dojo._base.Color"); |
dojo.require("dojo._base.connect"); |
dojo.require("dojo._base.declare"); |
dojo.require("dojo._base.lang"); |
dojo.require("dojo._base.html"); |
|
/* |
Animation losely package based on Dan Pupius' work, contributed under CLA: |
http://pupius.co.uk/js/Toolkit.Drawing.js |
*/ |
|
dojo._Line = function(/*int*/ start, /*int*/ end){ |
// summary: |
// dojo._Line is the object used to generate values from a start value |
// to an end value |
// start: int |
// Beginning value for range |
// end: int |
// Ending value for range |
this.start = start; |
this.end = end; |
this.getValue = function(/*float*/ n){ |
// summary: returns the point on the line |
// n: a floating point number greater than 0 and less than 1 |
return ((this.end - this.start) * n) + this.start; // Decimal |
} |
} |
|
dojo.declare("dojo._Animation", null, { |
// summary |
// A generic animation object that fires callbacks into it's handlers |
// object at various states |
// |
constructor: function(/*Object*/ args){ |
dojo.mixin(this, args); |
if(dojo.isArray(this.curve)){ |
/* curve: Array |
pId: a */ |
this.curve = new dojo._Line(this.curve[0], this.curve[1]); |
} |
}, |
|
// duration: Integer |
// The time in milliseonds the animation will take to run |
duration: 1000, |
|
/*===== |
// curve: dojo._Line||Array |
// A two element array of start and end values, or a dojo._Line instance to be |
// used in the Animation. |
curve: null, |
|
// easing: Function |
// A Function to adjust the acceleration (or deceleration) of the progress |
// across a dojo._Line |
easing: null, |
=====*/ |
|
// repeat: Integer |
// The number of times to loop the animation |
repeat: 0, |
|
// rate: Integer |
// the time in milliseconds to wait before advancing to next frame |
// (used as a fps timer: rate/1000 = fps) |
rate: 10 /* 100 fps */, |
|
/*===== |
// delay: Integer |
// The time in milliseconds to wait before starting animation after it has been .play()'ed |
delay: null, |
|
// events |
// |
// beforeBegin: Event |
// Synthetic event fired before a dojo._Animation begins playing (synhcronous) |
beforeBegin: null, |
|
// onBegin: Event |
// Synthetic event fired as a dojo._Animation begins playing (useful?) |
onBegin: null, |
|
// onAnimate: Event |
// Synthetic event fired at each interval of a dojo._Animation |
onAnimate: null, |
|
// onEnd: Event |
// Synthetic event fired after the final frame of a dojo._Animation |
onEnd: null, |
|
// ??? |
onPlay: null, |
|
// onPause: Event |
// Synthetic event fired when a dojo._Animation is paused |
onPause: null, |
|
// onStop: Event |
// Synthetic event fires when a dojo._Animation is stopped |
onStop: null, |
|
=====*/ |
|
_percent: 0, |
_startRepeatCount: 0, |
|
fire: function(/*Event*/ evt, /*Array?*/ args){ |
// summary: |
// Convenience function. Fire event "evt" and pass it the |
// arguments specified in "args". |
// evt: |
// The event to fire. |
// args: |
// The arguments to pass to the event. |
if(this[evt]){ |
this[evt].apply(this, args||[]); |
} |
return this; // dojo._Animation |
}, |
|
play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ |
// summary: |
// Start the animation. |
// delay: |
// How many milliseconds to delay before starting. |
// gotoStart: |
// If true, starts the animation from the beginning; otherwise, |
// starts it from its current position. |
var _t = this; |
if(gotoStart){ |
_t._stopTimer(); |
_t._active = _t._paused = false; |
_t._percent = 0; |
}else if(_t._active && !_t._paused){ |
return _t; // dojo._Animation |
} |
|
_t.fire("beforeBegin"); |
|
var d = delay||_t.delay; |
var _p = dojo.hitch(_t, "_play", gotoStart); |
if(d > 0){ |
setTimeout(_p, d); |
return _t; // dojo._Animation |
} |
_p(); |
return _t; |
}, |
|
_play: function(gotoStart){ |
var _t = this; |
_t._startTime = new Date().valueOf(); |
if(_t._paused){ |
_t._startTime -= _t.duration * _t._percent; |
} |
_t._endTime = _t._startTime + _t.duration; |
|
_t._active = true; |
_t._paused = false; |
|
var value = _t.curve.getValue(_t._percent); |
if(!_t._percent){ |
if(!_t._startRepeatCount){ |
_t._startRepeatCount = _t.repeat; |
} |
_t.fire("onBegin", [value]); |
} |
|
_t.fire("onPlay", [value]); |
|
_t._cycle(); |
return _t; // dojo._Animation |
}, |
|
pause: function(){ |
// summary: Pauses a running animation. |
this._stopTimer(); |
if(!this._active){ return this; /*dojo._Animation*/} |
this._paused = true; |
this.fire("onPause", [this.curve.getValue(this._percent)]); |
return this; // dojo._Animation |
}, |
|
gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){ |
// summary: |
// Sets the progress of the animation. |
// percent: |
// A percentage in decimal notation (between and including 0.0 and 1.0). |
// andPlay: |
// If true, play the animation after setting the progress. |
this._stopTimer(); |
this._active = this._paused = true; |
this._percent = percent; |
if(andPlay){ this.play(); } |
return this; // dojo._Animation |
}, |
|
stop: function(/*boolean?*/ gotoEnd){ |
// summary: Stops a running animation. |
// gotoEnd: If true, the animation will end. |
if(!this._timer){ return; } |
this._stopTimer(); |
if(gotoEnd){ |
this._percent = 1; |
} |
this.fire("onStop", [this.curve.getValue(this._percent)]); |
this._active = this._paused = false; |
return this; // dojo._Animation |
}, |
|
status: function(){ |
// summary: Returns a string token representation of the status of |
// the animation, one of: "paused", "playing", "stopped" |
if(this._active){ |
return this._paused ? "paused" : "playing"; // String |
} |
return "stopped"; // String |
}, |
|
_cycle: function(){ |
var _t = this; |
if(_t._active){ |
var curr = new Date().valueOf(); |
var step = (curr - _t._startTime) / (_t._endTime - _t._startTime); |
|
if(step >= 1){ |
step = 1; |
} |
_t._percent = step; |
|
// Perform easing |
if(_t.easing){ |
step = _t.easing(step); |
} |
|
_t.fire("onAnimate", [_t.curve.getValue(step)]); |
|
if(step < 1){ |
_t._startTimer(); |
}else{ |
_t._active = false; |
|
if(_t.repeat > 0){ |
_t.repeat--; |
_t.play(null, true); |
}else if(_t.repeat == -1){ |
_t.play(null, true); |
}else{ |
if(_t._startRepeatCount){ |
_t.repeat = _t._startRepeatCount; |
_t._startRepeatCount = 0; |
} |
} |
_t._percent = 0; |
_t.fire("onEnd"); |
} |
} |
return _t; // dojo._Animation |
} |
}); |
|
(function(){ |
var d = dojo; |
var ctr = 0; |
var _globalTimerList = []; |
var runner = { |
run: function(){} |
}; |
var timer = null; |
dojo._Animation.prototype._startTimer = function(){ |
// this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate); |
if(!this._timer){ |
this._timer = dojo.connect(runner, "run", this, "_cycle"); |
ctr++; |
} |
if(!timer){ |
timer = setInterval(dojo.hitch(runner, "run"), this.rate); |
} |
}; |
|
dojo._Animation.prototype._stopTimer = function(){ |
dojo.disconnect(this._timer); |
this._timer = null; |
ctr--; |
if(!ctr){ |
clearInterval(timer); |
timer = null; |
} |
}; |
|
var _makeFadeable = (d.isIE) ? function(node){ |
// only set the zoom if the "tickle" value would be the same as the |
// default |
var ns = node.style; |
if(!ns.zoom.length && d.style(node, "zoom") == "normal"){ |
// make sure the node "hasLayout" |
// NOTE: this has been tested with larger and smaller user-set text |
// sizes and works fine |
ns.zoom = "1"; |
// node.style.zoom = "normal"; |
} |
// don't set the width to auto if it didn't already cascade that way. |
// We don't want to f anyones designs |
if(!ns.width.length && d.style(node, "width") == "auto"){ |
ns.width = "auto"; |
} |
} : function(){}; |
|
dojo._fade = function(/*Object*/ args){ |
// summary: |
// Returns an animation that will fade the node defined by |
// args.node from the start to end values passed (args.start |
// args.end) (end is mandatory, start is optional) |
|
args.node = d.byId(args.node); |
var fArgs = d.mixin({ properties: {} }, args); |
var props = (fArgs.properties.opacity = {}); |
props.start = !("start" in fArgs) ? |
function(){ return Number(d.style(fArgs.node, "opacity")); } : fArgs.start; |
props.end = fArgs.end; |
|
var anim = d.animateProperty(fArgs); |
d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node)); |
|
return anim; // dojo._Animation |
} |
|
/*===== |
dojo.__fadeArgs = function(kwArgs){ |
// duration: Integer? |
// Duration of the animation in milliseconds. |
// easing: Function? |
// An easing function. |
} |
=====*/ |
|
dojo.fadeIn = function(/*dojo.__fadeArgs*/ args){ |
// summary: |
// Returns an animation that will fade node defined in 'args' from |
// its current opacity to fully opaque. |
return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation |
} |
|
dojo.fadeOut = function(/*dojo.__fadeArgs*/ args){ |
// summary: |
// Returns an animation that will fade node defined in 'args' |
// from its current opacity to fully transparent. |
return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation |
} |
|
dojo._defaultEasing = function(/*Decimal?*/ n){ |
// summary: The default easing function for dojo._Animation(s) |
return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2); |
} |
|
var PropLine = function(properties){ |
this._properties = properties; |
for(var p in properties){ |
var prop = properties[p]; |
if(prop.start instanceof d.Color){ |
// create a reusable temp color object to keep intermediate results |
prop.tempColor = new d.Color(); |
} |
} |
this.getValue = function(r){ |
var ret = {}; |
for(var p in this._properties){ |
var prop = this._properties[p]; |
var start = prop.start; |
if(start instanceof d.Color){ |
ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss(); |
}else if(!d.isArray(start)){ |
ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : ""); |
} |
} |
return ret; |
} |
} |
|
dojo.animateProperty = function(/*Object*/ args){ |
// summary: |
// Returns an animation that will transition the properties of |
// node defined in 'args' depending how they are defined in |
// 'args.properties' |
// |
// description: |
// The foundation of most dojo.fx animations, dojo.AnimateProperty |
// will take an object of "properties" corresponding to style |
// properties, and animate them in parallel over a set duration. |
// |
// args.node can be a String or a DomNode reference |
// |
// example: |
// | dojo.animateProperty({ node: node, duration:2000, |
// | properties: { |
// | width: { start: '200', end: '400', unit:"px" }, |
// | height: { start:'200', end: '400', unit:"px" }, |
// | paddingTop: { start:'5', end:'50', unit:"px" } |
// | } |
// | }).play(); |
// |
|
args.node = d.byId(args.node); |
if(!args.easing){ args.easing = d._defaultEasing; } |
|
var anim = new d._Animation(args); |
d.connect(anim, "beforeBegin", anim, function(){ |
var pm = {}; |
for(var p in this.properties){ |
// Make shallow copy of properties into pm because we overwrite some values below. |
// In particular if start/end are functions we don't want to overwrite them or |
// the functions won't be called if the animation is reused. |
var prop = (pm[p] = d.mixin({}, this.properties[p])); |
|
if(d.isFunction(prop.start)){ |
prop.start = prop.start(); |
} |
if(d.isFunction(prop.end)){ |
prop.end = prop.end(); |
} |
|
var isColor = (p.toLowerCase().indexOf("color") >= 0); |
function getStyle(node, p){ |
// dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable: |
var v = ({height: node.offsetHeight, width: node.offsetWidth})[p]; |
if(v !== undefined){ return v; } |
v = d.style(node, p); |
return (p=="opacity") ? Number(v) : parseFloat(v); |
} |
if(!("end" in prop)){ |
prop.end = getStyle(this.node, p); |
}else if(!("start" in prop)){ |
prop.start = getStyle(this.node, p); |
} |
|
if(isColor){ |
// console.debug("it's a color!"); |
prop.start = new d.Color(prop.start); |
prop.end = new d.Color(prop.end); |
}else{ |
prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start); |
} |
// console.debug("start:", prop.start); |
// console.debug("end:", prop.end); |
} |
this.curve = new PropLine(pm); |
}); |
d.connect(anim, "onAnimate", anim, function(propValues){ |
// try{ |
for(var s in propValues){ |
// console.debug(s, propValues[s], this.node.style[s]); |
d.style(this.node, s, propValues[s]); |
// this.node.style[s] = propValues[s]; |
} |
// }catch(e){ console.debug(dojo.toJson(e)); } |
}); |
return anim; // dojo._Animation |
} |
})(); |
|
} |