mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Move Tween class to anim namespace + changes
- Change from item to object, as it can be used to tween any property on any object really - Make _handleFrame() private - Minor documentation tweaks
This commit is contained in:
parent
104d5eeef1
commit
9c684091f4
4 changed files with 91 additions and 59 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit 2533ac8e1863262f3c28cd29bc940c6d2ecdf147
|
Subproject commit da249447ca037b67cad8193c59e8ce33fb40c61f
|
|
@ -13,8 +13,16 @@
|
||||||
/**
|
/**
|
||||||
* @name Tween
|
* @name Tween
|
||||||
*
|
*
|
||||||
* @class Allows tweening {@link Item} properties between two states for a given
|
* @class Allows tweening `Object` properties between two states for a given
|
||||||
* duration. Tween instance is returned by {@link Item#tween(from,to,options)}.
|
* duration. To tween properties on Paper.js {@link Item} instances,
|
||||||
|
* {@link Item#tween(from, to, options)} can be used, which returns created
|
||||||
|
* tween instance.
|
||||||
|
*
|
||||||
|
* @see Item#tween(from, to, options)
|
||||||
|
* @see Item#tween(to, options)
|
||||||
|
* @see Item#tween(options)
|
||||||
|
* @see Item#tweenTo(to, options)
|
||||||
|
* @see Item#tweenFrom(from, options)
|
||||||
*/
|
*/
|
||||||
var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
_class: 'Tween',
|
_class: 'Tween',
|
||||||
|
@ -99,7 +107,7 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
/**
|
/**
|
||||||
* Creates a new tween.
|
* Creates a new tween.
|
||||||
*
|
*
|
||||||
* @param {Item} item the item to tween
|
* @param {Object} object the object to tween the properties on
|
||||||
* @param {Object} from the state at the start of the tweening
|
* @param {Object} from the state at the start of the tweening
|
||||||
* @param {Object} to the state at the end of the tweening
|
* @param {Object} to the state at the end of the tweening
|
||||||
* @param {Number} duration the duration of the tweening
|
* @param {Number} duration the duration of the tweening
|
||||||
|
@ -108,8 +116,8 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
* @param {Boolean} [start=true] whether to start tweening automatically
|
* @param {Boolean} [start=true] whether to start tweening automatically
|
||||||
* @return {Tween} the newly created tween
|
* @return {Tween} the newly created tween
|
||||||
*/
|
*/
|
||||||
initialize: function Tween(item, from, to, duration, easing, start) {
|
initialize: function Tween(object, from, to, duration, easing, start) {
|
||||||
this.item = item;
|
this.object = object;
|
||||||
var type = typeof easing;
|
var type = typeof easing;
|
||||||
var isFunction = type === 'function';
|
var isFunction = type === 'function';
|
||||||
this.type = isFunction
|
this.type = isFunction
|
||||||
|
@ -133,35 +141,21 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleFrame: function(time) {
|
|
||||||
var startTime = this._startTime,
|
|
||||||
progress = startTime
|
|
||||||
? (time - startTime) / this.duration
|
|
||||||
: 0;
|
|
||||||
if (!startTime) {
|
|
||||||
this._startTime = time;
|
|
||||||
}
|
|
||||||
this.update(progress);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a function that will be executed when tween completes.
|
* Set a function that will be executed when the tween completes.
|
||||||
* @param {Function} function the function to execute when tween completes
|
* @param {Function} function the function to execute when the tween
|
||||||
|
* completes
|
||||||
* @return {Tween}
|
* @return {Tween}
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript} // Tweens chaining: var circle = new
|
||||||
* // Tweens chaining:
|
* Path.Circle({center: view.center, radius: 50, fillColor: 'blue'
|
||||||
* var item = new Path.Circle({
|
|
||||||
* center: view.center,
|
|
||||||
* radius: 50,
|
|
||||||
* fillColor: 'blue'
|
|
||||||
* });
|
* });
|
||||||
* // Tween color from blue to red.
|
* // Tween color from blue to red.
|
||||||
* var tween = item.tweenTo({fillColor: 'red'}, 2000);
|
* var tween = item.tweenTo({ fillColor: 'red' }, 2000);
|
||||||
* // When first tween completes...
|
* // When the first tween completes...
|
||||||
* tween.then(function(){
|
* tween.then(function() {
|
||||||
* // ...tween color back to blue.
|
* // ...tween color back to blue.
|
||||||
* item.tweenTo({fillColor: 'blue'}, 2000);
|
* item.tweenTo({ fillColor: 'blue' }, 2000);
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
then: function(then) {
|
then: function(then) {
|
||||||
|
@ -175,12 +169,12 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Manually start tweening.
|
* // Manually start tweening.
|
||||||
* var item = new Path.Circle({
|
* var circle = new Path.Circle({
|
||||||
* center: view.center,
|
* center: view.center,
|
||||||
* radius: 50,
|
* radius: 50,
|
||||||
* fillColor: 'blue'
|
* fillColor: 'blue'
|
||||||
* });
|
* });
|
||||||
* var tween = item.tweenTo(
|
* var tween = circle.tweenTo(
|
||||||
* { fillColor: 'red' },
|
* { fillColor: 'red' },
|
||||||
* { duration: 2000, start: false }
|
* { duration: 2000, start: false }
|
||||||
* );
|
* );
|
||||||
|
@ -198,13 +192,13 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Stop a tween before it completes.
|
* // Stop a tween before it completes.
|
||||||
* var item = new Path.Circle({
|
* var circle = new Path.Circle({
|
||||||
* center: view.center,
|
* center: view.center,
|
||||||
* radius: 50,
|
* radius: 50,
|
||||||
* fillColor: 'blue'
|
* fillColor: 'blue'
|
||||||
* });
|
* });
|
||||||
* // Start tweening from blue to red for 2 seconds.
|
* // Start tweening from blue to red for 2 seconds.
|
||||||
* var tween = item.tweenTo({ fillColor: 'red' }, 2000);
|
* var tween = circle.tweenTo({ fillColor: 'red' }, 2000);
|
||||||
* // After 1 second...
|
* // After 1 second...
|
||||||
* setTimeout(function(){
|
* setTimeout(function(){
|
||||||
* // ...stop tweening.
|
* // ...stop tweening.
|
||||||
|
@ -216,6 +210,7 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// DOCS: Document Tween#update(progress)
|
||||||
update: function(progress) {
|
update: function(progress) {
|
||||||
if (this.running) {
|
if (this.running) {
|
||||||
if (progress > 1) {
|
if (progress > 1) {
|
||||||
|
@ -240,11 +235,12 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
value = (from && to && from.__add && to.__add)
|
value = (from && to && from.__add && to.__add)
|
||||||
? to.__subtract(from).__multiply(factor).__add(from)
|
? to.__subtract(from).__multiply(factor).__add(from)
|
||||||
: ((to - from) * factor) + from;
|
: ((to - from) * factor) + from;
|
||||||
this._setItemProperty(this._parsedKeys[key], value);
|
this._setProperty(this._parsedKeys[key], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.running && this._then) {
|
if (!this.running && this._then) {
|
||||||
this._then(this.item);
|
// TODO Look into what should be returned.
|
||||||
|
this._then(this.object);
|
||||||
}
|
}
|
||||||
if (this.responds('update')) {
|
if (this.responds('update')) {
|
||||||
this.emit('update', new Base({
|
this.emit('update', new Base({
|
||||||
|
@ -269,47 +265,67 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Display tween progression values:
|
* // Display tween progression values:
|
||||||
* var item = new Path.Circle({
|
* var circle = new Path.Circle({
|
||||||
* center: view.center,
|
* center: view.center,
|
||||||
* radius: 50,
|
* radius: 40,
|
||||||
* fillColor: 'blue'
|
* fillColor: 'blue'
|
||||||
* });
|
* });
|
||||||
* var tween = item.tweenTo(
|
* var tween = circle.tweenTo(
|
||||||
* { fillColor: 'red' },
|
* { fillColor: 'red' },
|
||||||
* { duration: 2000, easing: 'easeInCubic' }
|
* {
|
||||||
|
* duration: 2000,
|
||||||
|
* easing: 'easeInCubic'
|
||||||
|
* }
|
||||||
* );
|
* );
|
||||||
* var progressText = new PointText(view.center + [60, -10]);
|
* var progressText = new PointText(view.center + [60, -10]);
|
||||||
* var factorText = new PointText(view.center + [60, 10]);
|
* var factorText = new PointText(view.center + [60, 10]);
|
||||||
|
*
|
||||||
|
* // Install event using onUpdate() property:
|
||||||
* tween.onUpdate = function(event) {
|
* tween.onUpdate = function(event) {
|
||||||
* progressText.content = 'progress: ' + event.progress.toFixed(2);
|
* progressText.content = 'progress: ' + event.progress.toFixed(2);
|
||||||
* factorText.content = 'factor: ' + event.factor.toFixed(2);
|
|
||||||
* };
|
* };
|
||||||
|
*
|
||||||
|
* // Install event using on('update') method:
|
||||||
|
* tween.on('update', function(event) {
|
||||||
|
* factorText.content = 'factor: ' + event.factor.toFixed(2);
|
||||||
|
* });
|
||||||
*/
|
*/
|
||||||
_events: {
|
_events: {
|
||||||
onUpdate: {}
|
onUpdate: {}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_handleFrame: function(time) {
|
||||||
|
var startTime = this._startTime,
|
||||||
|
progress = startTime
|
||||||
|
? (time - startTime) / this.duration
|
||||||
|
: 0;
|
||||||
|
if (!startTime) {
|
||||||
|
this._startTime = time;
|
||||||
|
}
|
||||||
|
this.update(progress);
|
||||||
|
},
|
||||||
|
|
||||||
_getState: function(state) {
|
_getState: function(state) {
|
||||||
var keys = this._keys,
|
var keys = this._keys,
|
||||||
result = {};
|
result = {};
|
||||||
for (var i = 0, l = keys.length; i < l; i++) {
|
for (var i = 0, l = keys.length; i < l; i++) {
|
||||||
var key = keys[i],
|
var key = keys[i],
|
||||||
path = this._parsedKeys[key],
|
path = this._parsedKeys[key],
|
||||||
current = this._getItemProperty(path),
|
current = this._getProperty(path),
|
||||||
value;
|
value;
|
||||||
if (state) {
|
if (state) {
|
||||||
var resolved = this._resolveValue(current, state[key]);
|
var resolved = this._resolveValue(current, state[key]);
|
||||||
// Temporarily set the resolved value, so we can retrieve the
|
// Temporarily set the resolved value, so we can retrieve the
|
||||||
// coerced value from paper's internal magic.
|
// coerced value from paper's internal magic.
|
||||||
this._setItemProperty(path, resolved);
|
this._setProperty(path, resolved);
|
||||||
value = this._getItemProperty(path);
|
value = this._getProperty(path);
|
||||||
// Clone the value if possible to prevent future changes.
|
// Clone the value if possible to prevent future changes.
|
||||||
value = value.clone ? value.clone() : value;
|
value = value && value.clone ? value.clone() : value;
|
||||||
this._setItemProperty(path, current);
|
this._setProperty(path, current);
|
||||||
} else {
|
} else {
|
||||||
// We want to get the current state at the time of the call, so
|
// We want to get the current state at the time of the call, so
|
||||||
// we have to clone if possible to prevent future changes.
|
// we have to clone if possible to prevent future changes.
|
||||||
value = current.clone ? current.clone() : current;
|
value = current && current.clone ? current.clone() : current;
|
||||||
}
|
}
|
||||||
result[key] = value;
|
result[key] = value;
|
||||||
}
|
}
|
||||||
|
@ -359,16 +375,16 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{
|
||||||
return parsed;
|
return parsed;
|
||||||
},
|
},
|
||||||
|
|
||||||
_getItemProperty: function(path, offset) {
|
_getProperty: function(path, offset) {
|
||||||
var obj = this.item;
|
var obj = this.object;
|
||||||
for (var i = 0, l = path.length - (offset || 0); i < l && obj; i++) {
|
for (var i = 0, l = path.length - (offset || 0); i < l && obj; i++) {
|
||||||
obj = obj[path[i]];
|
obj = obj[path[i]];
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
_setItemProperty: function(path, value) {
|
_setProperty: function(path, value) {
|
||||||
var dest = this._getItemProperty(path, 1);
|
var dest = this._getProperty(path, 1);
|
||||||
if (dest) {
|
if (dest) {
|
||||||
dest[path[path.length - 1]] = value;
|
dest[path[path.length - 1]] = value;
|
||||||
}
|
}
|
|
@ -4695,7 +4695,22 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
* radius: view.bounds.height * 0.4,
|
* radius: view.bounds.height * 0.4,
|
||||||
* center: view.center
|
* center: view.center
|
||||||
* });
|
* });
|
||||||
* path.tween({ fillColor: 'blue' }, { fillColor: 'red' }, 3000);
|
* path.tween(
|
||||||
|
* { fillColor: 'blue' },
|
||||||
|
* { fillColor: 'red' },
|
||||||
|
* 3000
|
||||||
|
* );
|
||||||
|
* @example {@paperscript height=100}
|
||||||
|
* // Tween rotation:
|
||||||
|
* var path = new Shape.Rectangle({
|
||||||
|
* fillColor: 'red',
|
||||||
|
* point: view.center,
|
||||||
|
* size: [50, 50]
|
||||||
|
* });
|
||||||
|
* path.tween({
|
||||||
|
* easing: 'easeInOutCubic',
|
||||||
|
* rotation: 180
|
||||||
|
* }, 2000);
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Tween item to a state.
|
* Tween item to a state.
|
||||||
|
@ -4771,7 +4786,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
),
|
),
|
||||||
tween = new Tween(this, from, to, duration, easing, start);
|
tween = new Tween(this, from, to, duration, easing, start);
|
||||||
function onFrame(event) {
|
function onFrame(event) {
|
||||||
tween.handleFrame(event.time * 1000);
|
tween._handleFrame(event.time * 1000);
|
||||||
if (!tween.running) {
|
if (!tween.running) {
|
||||||
this.off('frame', onFrame);
|
this.off('frame', onFrame);
|
||||||
}
|
}
|
||||||
|
@ -4787,14 +4802,14 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
* Tween item to a state.
|
* Tween item to a state.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
* @param {Object} state the state at the end of the tweening
|
* @param {Object} to the state at the end of the tweening
|
||||||
* @param {Object|Number} options the options or the duration
|
* @param {Object|Number} options the options or the duration
|
||||||
* @return {Tween}
|
* @return {Tween}
|
||||||
*
|
*
|
||||||
* @see Item#tween(to, options)
|
* @see Item#tween(to, options)
|
||||||
*/
|
*/
|
||||||
tweenTo: function(state, options) {
|
tweenTo: function(to, options) {
|
||||||
return this.tween(null, state, options);
|
return this.tween(null, to, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4802,7 +4817,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
* Tween item from a state to its state before the tweening.
|
* Tween item from a state to its state before the tweening.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
* @param {Object} state the state at the start of the tweening
|
* @param {Object} from the state at the start of the tweening
|
||||||
* @param {Object|Number} options the options or the duration
|
* @param {Object|Number} options the options or the duration
|
||||||
* @return {Tween}
|
* @return {Tween}
|
||||||
*
|
*
|
||||||
|
@ -4817,7 +4832,7 @@ new function() { // Injection scope for hit-test functions shared with project
|
||||||
* });
|
* });
|
||||||
* path.tweenFrom({ fillColor: 'red' }, { duration: 1000 });
|
* path.tweenFrom({ fillColor: 'red' }, { duration: 1000 });
|
||||||
*/
|
*/
|
||||||
tweenFrom: function(state, options) {
|
tweenFrom: function(from, options) {
|
||||||
return this.tween(state, null, options);
|
return this.tween(from, null, options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -65,7 +65,6 @@ var paper = function(self, undefined) {
|
||||||
/*#*/ include('item/SymbolItem.js');
|
/*#*/ include('item/SymbolItem.js');
|
||||||
/*#*/ include('item/SymbolDefinition.js');
|
/*#*/ include('item/SymbolDefinition.js');
|
||||||
/*#*/ include('item/HitResult.js');
|
/*#*/ include('item/HitResult.js');
|
||||||
/*#*/ include('item/Tween.js');
|
|
||||||
|
|
||||||
/*#*/ include('path/Segment.js');
|
/*#*/ include('path/Segment.js');
|
||||||
/*#*/ include('path/SegmentPoint.js');
|
/*#*/ include('path/SegmentPoint.js');
|
||||||
|
@ -103,6 +102,8 @@ var paper = function(self, undefined) {
|
||||||
/*#*/ include('tool/ToolEvent.js');
|
/*#*/ include('tool/ToolEvent.js');
|
||||||
/*#*/ include('tool/Tool.js');
|
/*#*/ include('tool/Tool.js');
|
||||||
|
|
||||||
|
/*#*/ include('anim/Tween.js');
|
||||||
|
|
||||||
/*#*/ include('net/Http.js');
|
/*#*/ include('net/Http.js');
|
||||||
|
|
||||||
/*#*/ include('canvas/CanvasProvider.js');
|
/*#*/ include('canvas/CanvasProvider.js');
|
||||||
|
|
Loading…
Reference in a new issue