/*
* 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;
}());