From 9c684091f42675043e0135ae31a4155b96901b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Mon, 3 Dec 2018 12:51:31 +0100 Subject: [PATCH] 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 --- gulp/jsdoc | 2 +- src/{item => anim}/Tween.js | 114 ++++++++++++++++++++---------------- src/item/Item.js | 31 +++++++--- src/paper.js | 3 +- 4 files changed, 91 insertions(+), 59 deletions(-) rename src/{item => anim}/Tween.js (82%) diff --git a/gulp/jsdoc b/gulp/jsdoc index 2533ac8e..da249447 160000 --- a/gulp/jsdoc +++ b/gulp/jsdoc @@ -1 +1 @@ -Subproject commit 2533ac8e1863262f3c28cd29bc940c6d2ecdf147 +Subproject commit da249447ca037b67cad8193c59e8ce33fb40c61f diff --git a/src/item/Tween.js b/src/anim/Tween.js similarity index 82% rename from src/item/Tween.js rename to src/anim/Tween.js index 8dbd04c6..d9655723 100644 --- a/src/item/Tween.js +++ b/src/anim/Tween.js @@ -13,8 +13,16 @@ /** * @name Tween * - * @class Allows tweening {@link Item} properties between two states for a given - * duration. Tween instance is returned by {@link Item#tween(from,to,options)}. + * @class Allows tweening `Object` properties between two states for a given + * 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# */{ _class: 'Tween', @@ -99,7 +107,7 @@ var Tween = Base.extend(Emitter, /** @lends 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} to the state at the end 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 * @return {Tween} the newly created tween */ - initialize: function Tween(item, from, to, duration, easing, start) { - this.item = item; + initialize: function Tween(object, from, to, duration, easing, start) { + this.object = object; var type = typeof easing; var isFunction = type === 'function'; 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. - * @param {Function} function the function to execute when tween completes + * Set a function that will be executed when the tween completes. + * @param {Function} function the function to execute when the tween + * completes * @return {Tween} * - * @example {@paperscript} - * // Tweens chaining: - * var item = new Path.Circle({ - * center: view.center, - * radius: 50, - * fillColor: 'blue' + * @example {@paperscript} // Tweens chaining: var circle = new + * Path.Circle({center: view.center, radius: 50, fillColor: 'blue' * }); * // Tween color from blue to red. - * var tween = item.tweenTo({fillColor: 'red'}, 2000); - * // When first tween completes... - * tween.then(function(){ + * var tween = item.tweenTo({ fillColor: 'red' }, 2000); + * // When the first tween completes... + * tween.then(function() { * // ...tween color back to blue. - * item.tweenTo({fillColor: 'blue'}, 2000); + * item.tweenTo({ fillColor: 'blue' }, 2000); * }); */ then: function(then) { @@ -175,12 +169,12 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{ * * @example {@paperscript} * // Manually start tweening. - * var item = new Path.Circle({ + * var circle = new Path.Circle({ * center: view.center, * radius: 50, * fillColor: 'blue' * }); - * var tween = item.tweenTo( + * var tween = circle.tweenTo( * { fillColor: 'red' }, * { duration: 2000, start: false } * ); @@ -198,13 +192,13 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{ * * @example {@paperscript} * // Stop a tween before it completes. - * var item = new Path.Circle({ + * var circle = new Path.Circle({ * center: view.center, * radius: 50, * fillColor: 'blue' * }); * // 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... * setTimeout(function(){ * // ...stop tweening. @@ -216,6 +210,7 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{ return this; }, + // DOCS: Document Tween#update(progress) update: function(progress) { if (this.running) { if (progress > 1) { @@ -240,11 +235,12 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{ value = (from && to && from.__add && to.__add) ? to.__subtract(from).__multiply(factor).__add(from) : ((to - from) * factor) + from; - this._setItemProperty(this._parsedKeys[key], value); + this._setProperty(this._parsedKeys[key], value); } if (!this.running && this._then) { - this._then(this.item); + // TODO Look into what should be returned. + this._then(this.object); } if (this.responds('update')) { this.emit('update', new Base({ @@ -269,47 +265,67 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{ * * @example {@paperscript} * // Display tween progression values: - * var item = new Path.Circle({ + * var circle = new Path.Circle({ * center: view.center, - * radius: 50, + * radius: 40, * fillColor: 'blue' * }); - * var tween = item.tweenTo( + * var tween = circle.tweenTo( * { fillColor: 'red' }, - * { duration: 2000, easing: 'easeInCubic' } + * { + * duration: 2000, + * easing: 'easeInCubic' + * } * ); * var progressText = new PointText(view.center + [60, -10]); * var factorText = new PointText(view.center + [60, 10]); + * + * // Install event using onUpdate() property: * tween.onUpdate = function(event) { * 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: { 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) { var keys = this._keys, result = {}; for (var i = 0, l = keys.length; i < l; i++) { var key = keys[i], path = this._parsedKeys[key], - current = this._getItemProperty(path), + current = this._getProperty(path), value; if (state) { var resolved = this._resolveValue(current, state[key]); // Temporarily set the resolved value, so we can retrieve the // coerced value from paper's internal magic. - this._setItemProperty(path, resolved); - value = this._getItemProperty(path); + this._setProperty(path, resolved); + value = this._getProperty(path); // Clone the value if possible to prevent future changes. - value = value.clone ? value.clone() : value; - this._setItemProperty(path, current); + value = value && value.clone ? value.clone() : value; + this._setProperty(path, current); } else { // We want to get the current state at the time of the call, so // 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; } @@ -359,16 +375,16 @@ var Tween = Base.extend(Emitter, /** @lends Tween# */{ return parsed; }, - _getItemProperty: function(path, offset) { - var obj = this.item; + _getProperty: function(path, offset) { + var obj = this.object; for (var i = 0, l = path.length - (offset || 0); i < l && obj; i++) { obj = obj[path[i]]; } return obj; }, - _setItemProperty: function(path, value) { - var dest = this._getItemProperty(path, 1); + _setProperty: function(path, value) { + var dest = this._getProperty(path, 1); if (dest) { dest[path[path.length - 1]] = value; } diff --git a/src/item/Item.js b/src/item/Item.js index 65e24f70..f499367c 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -4695,7 +4695,22 @@ new function() { // Injection scope for hit-test functions shared with project * radius: view.bounds.height * 0.4, * 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. @@ -4771,7 +4786,7 @@ new function() { // Injection scope for hit-test functions shared with project ), tween = new Tween(this, from, to, duration, easing, start); function onFrame(event) { - tween.handleFrame(event.time * 1000); + tween._handleFrame(event.time * 1000); if (!tween.running) { this.off('frame', onFrame); } @@ -4787,14 +4802,14 @@ new function() { // Injection scope for hit-test functions shared with project * Tween item to a state. * * @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 * @return {Tween} * * @see Item#tween(to, options) */ - tweenTo: function(state, options) { - return this.tween(null, state, options); + tweenTo: function(to, 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. * * @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 * @return {Tween} * @@ -4817,7 +4832,7 @@ new function() { // Injection scope for hit-test functions shared with project * }); * path.tweenFrom({ fillColor: 'red' }, { duration: 1000 }); */ - tweenFrom: function(state, options) { - return this.tween(state, null, options); + tweenFrom: function(from, options) { + return this.tween(from, null, options); } }); diff --git a/src/paper.js b/src/paper.js index 1f5c153f..96c37775 100644 --- a/src/paper.js +++ b/src/paper.js @@ -65,7 +65,6 @@ var paper = function(self, undefined) { /*#*/ include('item/SymbolItem.js'); /*#*/ include('item/SymbolDefinition.js'); /*#*/ include('item/HitResult.js'); -/*#*/ include('item/Tween.js'); /*#*/ include('path/Segment.js'); /*#*/ include('path/SegmentPoint.js'); @@ -103,6 +102,8 @@ var paper = function(self, undefined) { /*#*/ include('tool/ToolEvent.js'); /*#*/ include('tool/Tool.js'); +/*#*/ include('anim/Tween.js'); + /*#*/ include('net/Http.js'); /*#*/ include('canvas/CanvasProvider.js');