/* * SamplePlugin * Visit http://createjs.com/ for documentation, updates and examples. * * Copyright (c) 2010 gskinner.com, inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * @module TweenJS */ // namespace: this.createjs = this.createjs||{}; (function() { "use strict"; /** * A sample TweenJS plugin. This plugin is purely for demonstration, and contains documentation and helpful tips on * building plugins. * * It sets the y position of the target based on a sinusoidal function of its x position. * * NOTE: The code for this class is heavily commented. Please look at it if you'd like to write a plugin. * * A TweenJS plugin is simply an object that exposes two properties (id, priority), and three methods (init, step, and change). * Generally a plugin will also expose an <code>install</code> method as well, though this is not strictly necessary. * @class SamplePlugin * @constructor **/ function SamplePlugin() { throw("SamplePlugin cannot be instantiated."); }; var s = SamplePlugin; // static interface: /** * Used by TweenJS to determine when to call this plugin relative to others. * Plugins with higher priority read first, and write last. * * For example, if plugin A has `priority=0`, and plugin B has `priority=9` then B's `init` and `step` methods would * be called before A's, but B's `change` method would be called *after* A's. * @property priority * @type {Number} * @default 0 * @static **/ s.priority = 0; /** * READ-ONLY. A unique identifying string for this plugin. Used by TweenJS to ensure duplicate plugins are not installed on a tween. * @property ID * @type {String} * @static * @readonly **/ s.ID = "Sample"; // if you're going to be installing instances of this plugin, you should ensure they have the same id as the class: // s.prototype.ID = s.ID; /** * Installs this plugin for use with TweenJS. Call this once after TweenJS is loaded to enable this plugin. * @method install * @static **/ s.install = function() { // TODO: should we just do installPlugin vs Plugin.install? That's what our other libs do. createjs.Tween._installPlugin(SamplePlugin); }; /** * Called by TweenJS when a new property initializes on a tween. Generally, the call * to `Plugin.init` will be immediately followed by a call to `Plugin.step`. * * For example: * * foo.x = 0; * foo.y = 100; * Tween.get(foo) * .to({x:10}) // init called with prop = "x", value = 0 * .to({x:20}) // init is NOT called, since x was already inited * .to({y:200}) // init called with prop = "y", value = 100 * * @method init * @param {Tween} tween The related tween instance. * @param {String} prop The name of the property that is being initialized. * @param {any} value If another plugin has modified the starting value, it will be passed in. Otherwise value will be undefined. * @return {any} The modified starting tween value for the property. In most cases, you would simply wouldn't return anything, * but some plugins may need to modify the starting value. You can also return `Tween.IGNORE` to prevent this prop * from being added to the tween at all. * @static **/ s.init = function(tween, prop, value) { console.log("init: ", prop, value); // its good practice to let users opt out (or in some cases, maybe in) via pluginData: var data = tween.pluginData; if (data.Sample_disabled) { return; } // this tells the tween to not manage the "y" property: if (prop === "y") { return createjs.Tween.IGNORE; } // filter which properties you want to work on by using "prop": // in this case, we only want to operate on the x property: if (prop !== "x") { return; } // make sure to pass through value. // we know we want to operate on this tween, so we add the plugin to it: // most plugins can just be a single shared plugin class: tween._addPlugin(SamplePlugin); // you can also use pluginData to attach arbitrary data to the tween for later use: // we want to adjust y relative to it's initial value, so let's save that off in pluginData: tween.pluginData.Sample_y = tween.target.y; // NOTE: none of the code below actually does anything in this scenario, it's just to illustrate concepts: // but you can also add an instance, if you wanted to store data on the plugin: // if you do this, ensure that there is an `id` property on the instance that matches the one on the class. // tween.addPlugin(new SamplePlugin()); // note that it's also possible to create a plugin that doesn't add itself, but hooks into the "change" event instead. // you can grab the current value on the target using: var targetValue = tween.target[prop]; // this gets the current starting value for the property, using value from previous plugins if specified, or the target value if not: // this is a bit of a pain, but it prevents accessing target values that aren't needed, which can be very expensive (ex. width on a HTMLElement, when we actually want to grab it from style) var defaultValue = (value === undefined) ? targetValue : value; // this passes out a new initial value for the x property: // if (prop === "x") { return Math.round(defaultValue); } }; /** * Called when a new step is added to a tween (ie. a new "to" action is added to a tween). * * For example: * Tween.get(foo) * .to({x:10}) // step called * .wait(100) // step is NOT called * .to({x:20, y:200}) // step called * * @method step * @param {Tween} tween The related tween instance. * @param {TweenStep} step The related tween step. This class is currently undocumented. See the bottom of Tween.js for info. * @param {Object} props The props object that was passed to `to()`. * @static **/ s.step = function(tween, step, props) { // the function of this plugin doesn't require us to react or modify new steps, so we'll just log it out for reference: console.log("step: ", step, props); // NOTE: none of the code below actually does anything in this scenario, it's just to illustrate concepts: // props is the collection of properties that were changed in this step. // you can use this to decide whether to do anything: if (props.x === undefined) { return; } // no change to x // because other plugins may modify the end value for this step, you should access it // via the step object, not the props object: var endValue = step.props.x; // you can grab the start value from the previous step: var startValue = step.prev.props.x; // you can modify this step's end value: // this approach should only be used to modify a property value we are CERTAIN is already being tweened. // we know x is being tweened, because we checked for its existence in `props` above. // step.props.x = Math.max(0, Math.min(100, step.props.x)); // or specify other properties that you'd like to include in the tween: // this can be used to set the step's end value for a property we can't be certain it is already being tweened. // tween._injectProp("y", 200); // if this was a plugin instance, you could store step specific data using step.index: // this.steps[step.index] = {arbitraryData:foo}; }; /** * Called before a property is updated by the tween. * @method change * @param {Tween} tween The related tween instance. * @param {TweenStep} step The related tween step. This class is currently undocumented. See the bottom of Tween.js for info. * @param {String} prop The name of the property being tweened. * @param {any} value The current tweened value of the property, as calculated by TweenJS. Previous plugins may have modified this value. * @param {Number} ratio A value indicating the eased progress through the current step. This number is generally between 0 and 1, * though some eases will generate values outside this range. * @param {Boolean} end Indicates that the tween has reached the end and is about to deregister itself. * @return {any} Return the value that should be assigned to the target property. * @static **/ s.change = function(tween, step, prop, value, ratio, end) { // console.log("change", step, prop, value, ratio, end); // we want to manage the y property ourselves, so we can tell the tween to not update it: // Note that this is redundant here, because we told the tween to completely ignore y in `init`. if (prop === "y") { return createjs.Tween.IGNORE; } // filter which properties you want to work on by using "prop": if (prop !== "x") { return; } // set the y value on the target as a function of the x value: // use the pluginData value we saved earlier to make it relative to the starting y: tween.target.y = Math.sin(value/160*Math.PI)*50+tween.pluginData.Sample_y; // NOTE: none of the code below actually does anything in this scenario, it's just to illustrate concepts: // you can grab the end value for the step via its props object: var endValue = step.props[prop]; // similarly, you can grab the start value from previous step: var startValue = step.prev.props[prop]; // you could calculate the unmodified tweened value using the ratio: // this will be the same as "value" unless a previous plugin returned a modified value var unmodifiedValue = startValue + (endValue - startValue) * ratio; if (value !== unmodifiedValue) { /* a previous plugin modified the value */ } // check if the tween is currently in a "wait" by comparing the props objects of this and the previous step: var inWait = (step.props === step.prev.props); // you can return a modified value to be set on the target: // return Math.round(value); // or don't return anything to use the default value. }; createjs.SamplePlugin = s; }());