UNPKG

redshift

Version:

A JavaScript UX framework. Handles animation, UI physics and user input tracking.

1,873 lines (1,449 loc) 148 kB
/******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /*!****************************!*\ !*** ./src/load/global.js ***! \****************************/ /***/ function(module, exports, __webpack_require__) { window.redshift = __webpack_require__(/*! ./module.js */ 1); /***/ }, /* 1 */ /*!****************************!*\ !*** ./src/load/module.js ***! \****************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; var redshift = __webpack_require__(/*! ../redshift.js */ 2); redshift // Add default Rubix processor modules .addRubix('fire', __webpack_require__(/*! ../rubix/fire.js */ 3)) .addRubix('link', __webpack_require__(/*! ../rubix/link.js */ 4)) .addRubix('play', __webpack_require__(/*! ../rubix/play.js */ 5)) .addRubix('run', __webpack_require__(/*! ../rubix/run.js */ 6)) .addRubix('seek', __webpack_require__(/*! ../rubix/seek.js */ 7)) .addRubix('track', __webpack_require__(/*! ../rubix/track.js */ 8)) // Add DOM value routes .addRoute('values', __webpack_require__(/*! ../routes/values.js */ 9)) .addRoute('css', __webpack_require__(/*! ../routes/css.js */ 10)) .addRoute('attr', __webpack_require__(/*! ../routes/attr.js */ 11)) .addRoute('path', __webpack_require__(/*! ../routes/path.js */ 12)); module.exports = redshift; /***/ }, /* 2 */ /*!*************************!*\ !*** ./src/redshift.js ***! \*************************/ /***/ function(module, exports, __webpack_require__) { /* Redshift core object Exposes methods to create new classes and define new modules */ "use strict"; var Action = __webpack_require__(/*! ./action/action.js */ 13), ActionGroup = __webpack_require__(/*! ./action-group/action-group.js */ 14), domGroup = __webpack_require__(/*! ./action-group/dom.js */ 15), Input = __webpack_require__(/*! ./input/input.js */ 16), Process = __webpack_require__(/*! ./process/process.js */ 17), presets = __webpack_require__(/*! ./action/presets.js */ 18), easing = __webpack_require__(/*! ./utils/easing.js */ 19), calc = __webpack_require__(/*! ./utils/calc.js */ 20), utils = __webpack_require__(/*! ./utils/utils.js */ 21), route = __webpack_require__(/*! ./action/routes.js */ 22), registerRubix = __webpack_require__(/*! ./core/register-rubix.js */ 23), registerSimulation = __webpack_require__(/*! ./core/register-simulation.js */ 24); module.exports = { /* Create a new Action controller @return [Action]: Newly-created Action */ newAction: function (props) { return (utils.isArray(props)) ? new ActionGroup(props) : new Action(props); }, /* Create a new Input controller @return [Input]: Newly-created Input */ newInput: function () { return new Input(arguments[0], arguments[1]); }, /* Create a new process @param [function]: Function to run every frame @param: Scope @return [Process] */ newProcess: function () { return new Process(arguments[0], arguments[1]); }, /* Create an Action Group prepopulated with DOM properties @param [string || NodeList || jQuery]: Selector, nodeList or jQuery selection */ dom: function (selector) { return domGroup(selector); }, /* Define a new Action preset Syntax .definePreset(name, preset) @param [string]: Name of preset @param [object]: Preset options/properties .definePreset(presets) @param [object]: Multiple presets as named object @return [Redshift] */ addPreset: function () { presets.add.apply(presets, arguments); return this; }, /* Add bezier curve function Add the specified bezier curve the EasingFunction's available easings My favourite bezier curve generator is Lea Verou's excellent http://cubic-bezier.com/ @param [string]: Name of the new easing function @params [number]: x/y coordinates of handles */ addBezier: function () { easing.add.apply(easing, arguments); return this; }, /* Add value route The default values object is .values, however any provided object will be parsed into values and given a .route property that is the name of its original object. For instance providing example: { test: 20 } will be parsed into values: { test: { current: 20, route: 'example' } } If we provide a custom route with this name, we can custom-parse values on the way in, and also on the way out. */ addRoute: function () { route.add.apply(route, arguments); return this; }, /* Add simulation @param [string]: Simulation name @param [function]: Method to calculate new velocity */ addSimulation: function () { registerSimulation.apply(this, arguments); return this; }, /* Add Rubix @param [string]: Rubix name @param [object]: Methods and properties */ addRubix: function () { registerRubix.apply(this, arguments); return this; }, // Expose calc and utils modules calc: calc, utils: utils }; /***/ }, /* 3 */ /*!***************************!*\ !*** ./src/rubix/fire.js ***! \***************************/ /***/ function(module, exports, __webpack_require__) { /* Return current value and immedietly end */ "use strict"; module.exports = { /* Process new value Return existing current @param [string]: Name of value @param [Value]: Current value */ process: function (key, value) { return value.current; }, /* Has Action ended? Returns true to end immedietly @return [boolean]: true */ hasEnded: function () { return true; } }; /***/ }, /* 4 */ /*!***************************!*\ !*** ./src/rubix/link.js ***! \***************************/ /***/ function(module, exports, __webpack_require__) { /* Link the calculations of on Value into the output of another. Activate by setting the link property of one value with the name of either an Input property or another Value. Map the linked value with mapLink and provide a corressponding mapTo array to translate values from one into the other. For instance: { link: 'x', mapLink: [0, 100, 200], mapTo: [-100, 0, -100] } An output value of 50 from 'x' will translate to -50 for this Value */ "use strict"; var calc = __webpack_require__(/*! ../utils/calc.js */ 20), STRING = 'string', /* Translate our mapLink value into mapTo @param [number]: Calculated value from linked value @param [Value || object]: Linked value or empty object if we're linking to input @param [array]: List of numbers relating to linked value @param [array]: List of numbers relating to this value */ findMappedValue = function (newValue, linkedValue, toValue, mapLink, mapTo) { var mapLength = mapLink.length, i = 1, lastLinkValue, thisLinkValue, lastToValue, thisToValue; for (; i < mapLength; i++) { // Assign values from array, or if they're strings, look for them in linkedValue lastLinkValue = (typeof mapLink[i - 1] === STRING) ? linkedValue[mapLink[i - 1]] : mapLink[i - 1]; thisLinkValue = (typeof mapLink[i] === STRING) ? linkedValue[mapLink[i]] : mapLink[i]; lastToValue = (typeof mapTo[i - 1] === STRING) ? toValue[mapTo[i - 1]] : mapTo[i - 1]; thisToValue = (typeof mapTo[i] === STRING) ? toValue[mapTo[i]] : mapTo[i]; // Check if we've gone past our calculated value, or if we're at the end of the array if (newValue < thisLinkValue || i === mapLength - 1) { newValue = calc.value(calc.restricted(calc.progress(newValue, lastLinkValue, thisLinkValue), 0, 1), lastToValue, thisToValue); break; } } return newValue; }; module.exports = { surpressMethod: true, /* Process this value First check if this value exists as a Value, if not check within Input (if we have one) @param [string]: Key of current value @param [Value]: Current value @param [object]: Collection of all Action values @param [object]: Action properties @param [Action]: Current Action @return [number]: Calculated value */ process: function (key, value, values, action) { var newValue = value.current, linkKey = value.link, linkedValue = values[linkKey] ? values[linkKey] : {}, inputOffset = action.inputOffset; // Then check values in Input if (inputOffset && inputOffset.hasOwnProperty(linkKey)) { newValue = value.origin + (inputOffset[linkKey] * value.amp); // First look at Action and check value isn't linking itself } else if (linkedValue.current !== undefined && key !== linkKey) { newValue = linkedValue.current; } // If we have mapLink and mapTo properties, translate the new value if (value.mapLink && value.mapTo) { newValue = findMappedValue(newValue, linkedValue, value, value.mapLink, value.mapTo); } return newValue; }, limit: function (output, value) { return calc.restricted(output, value.min, value.max); } }; /***/ }, /* 5 */ /*!***************************!*\ !*** ./src/rubix/play.js ***! \***************************/ /***/ function(module, exports, __webpack_require__) { /* Play rubix Translate numbers for a set amount of time, applying easing if defined */ "use strict"; var calc = __webpack_require__(/*! ../utils/calc.js */ 20), easing = __webpack_require__(/*! ../utils/easing.js */ 19), utils = __webpack_require__(/*! ../utils/utils.js */ 21), CURRENT = 'current', HAS_ENDED = 'hasEnded'; module.exports = { /* Update Action elapsed time @param [Action] @param [object]: Action properties @param [number]: Timestamp of current frame */ updateInput: function (action, frameDuration) { action.elapsed += (frameDuration * action.dilate) * action.playDirection; action[HAS_ENDED] = true; }, /* Calculate progress of value based on time elapsed, value delay/duration/stagger properties @param [string]: Key of current value @param [Value]: Current value @param [object]: Collection of all Action values @param [object]: Action properties @param [Action]: Current Action @param [number]: Duration of frame in ms @return [number]: Calculated value */ process: function (key, value, values, action) { var target = value.to, newValue = value[CURRENT], progress, progressTarget; // If we have a target, process if (target !== undefined) { progress = calc.restricted(calc.progress(action.elapsed - value.delay, value.duration) - value.stagger, 0, 1); progressTarget = (action.playDirection === 1) ? 1 : 0; // Mark Action as not ended if still in progress if (progress !== progressTarget) { action[HAS_ENDED] = false; // Or clear value target } else { value.to = undefined; } // Step progress if we're stepping if (value.steps) { progress = utils.stepProgress(progress, value.steps, value.stepDirection); } // Ease value with progress newValue = easing.withinRange(progress, value.origin, target, value.ease); } return newValue; }, /* Return hasEnded property @param [boolean]: Have all Values hit 1 progress? */ hasEnded: function (action) { return action[HAS_ENDED]; } }; /***/ }, /* 6 */ /*!**************************!*\ !*** ./src/rubix/run.js ***! \**************************/ /***/ function(module, exports, __webpack_require__) { /* Run physics simulation */ "use strict"; var calc = __webpack_require__(/*! ../utils/calc.js */ 20), simulate = __webpack_require__(/*! ../action/simulate.js */ 25); module.exports = { // [boolean]: Tell Redshift this rubix calculates a new velocity itself calculatesVelocity: true, /* Simulate the Value's per-frame movement @param [string]: Key of current value @param [Value]: Current value @param [object]: Collection of all Action values @param [object]: Action properties @param [Action]: Current Action @param [number]: Duration of frame in ms @return [number]: Calculated value */ process: function (key, value, values, action, frameDuration) { value.velocity = simulate(value.simulate, value, frameDuration, action.started); return value.current + calc.speedPerFrame(value.velocity, frameDuration); }, /* Has this action ended? Use a framecounter to see if Action has changed in the last x frames and declare ended if not @param [Action] @param [boolean]: Has Action changed? @return [boolean]: Has Action ended? */ hasEnded: function (action, hasChanged) { action.inactiveFrames = hasChanged ? 0 : action.inactiveFrames + 1; return (action.inactiveFrames > action.maxInactiveFrames); }, /* Limit output to value range, if any If velocity is at or more than range, and value has a bounce property, run the bounce simulation @param [number]: Calculated output @param [Value]: Current Value @return [number]: Limit-adjusted output */ limit: function (output, value) { var isOutsideMax = (output >= value.max), isOutsideMin = (output <= value.min), isOutsideRange = isOutsideMax || isOutsideMin; if (isOutsideRange) { output = calc.restricted(output, value.min, value.max); if (value.bounce) { value.velocity = simulate('bounce', value); } else if (value.capture) { simulate('capture', value, isOutsideMax ? value.max : value.min); } } return output; } }; /***/ }, /* 7 */ /*!***************************!*\ !*** ./src/rubix/seek.js ***! \***************************/ /***/ function(module, exports, __webpack_require__) { /* Return current value and immedietly end */ "use strict"; var playRubix = __webpack_require__(/*! ./play.js */ 5); module.exports = { /* Process new value Return existing current @param [string]: Name of value @param [Value]: Current value */ process: playRubix.process, /* Has Action ended? Returns true to end animation, and sets rubix to 'play' @return [boolean]: true */ hasEnded: function (action) { action.rubix = 'play'; return true; } }; /***/ }, /* 8 */ /*!****************************!*\ !*** ./src/rubix/track.js ***! \****************************/ /***/ function(module, exports, __webpack_require__) { /* Track user input */ "use strict"; var calc = __webpack_require__(/*! ../utils/calc.js */ 20), CURRENT = 'current', INPUT_OFFSET = 'inputOffset'; module.exports = { /* Update Input @param [Action] @param [object]: Action properties */ updateInput: function (action) { action[INPUT_OFFSET] = calc.offset(action.inputOrigin, action.input[CURRENT]); }, /* Move Value relative to Input movement @param [string]: Key of current value @param [Value]: Current value @param [object]: Collection of all Action values @param [object]: Action properties @param [Action]: Current Action @return [number]: Calculated value */ process: function (key, value, values, action) { return (action[INPUT_OFFSET].hasOwnProperty(key)) ? value.origin + action[INPUT_OFFSET][key] : value[CURRENT]; }, /* Has this Action ended? @return [boolean]: False to make user manually finish .track() */ hasEnded: function () { return false; } }; /***/ }, /* 9 */ /*!******************************!*\ !*** ./src/routes/values.js ***! \******************************/ /***/ function(module, exports, __webpack_require__) { /* Values route (Redshift default) Handles raw values and outputs to user-defined callbacks */ "use strict"; var fireCallback = function (name, bucket, action) { if (action[name]) { action[name].call(action.scope, bucket); } }; module.exports = { makeDefault: true, onStart: function (bucket, action) { if (action.onStart) { action.onStart.call(action.scope); } }, onFrame: function (bucket, action, values) { fireCallback('onFrame', bucket, action, values); }, onChange: function (bucket, action, values) { fireCallback('onChange', bucket, action, values); }, onEnd: function (bucket, action, values) { fireCallback('onEnd', bucket, action, values); } }; /***/ }, /* 10 */ /*!***************************!*\ !*** ./src/routes/css.js ***! \***************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; var build = __webpack_require__(/*! ./css/build.js */ 26), split = __webpack_require__(/*! ./css/split.js */ 27), css = 'css', cssOrder = css + 'Order', cssCache = css + 'Cache'; module.exports = { preprocess: function (key, value, action) { var values = split(key, value, action); action.updateOrder(key, false, cssOrder); return values; }, onChange: function (output, action, values) { action[cssCache] = action[cssCache] || {}; action.style(build(output, action[cssOrder], action[cssCache], values)); } }; /***/ }, /* 11 */ /*!****************************!*\ !*** ./src/routes/attr.js ***! \****************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; module.exports = { onChange: function (output, action) { var dom = action.dom; if (dom) { for (var key in output) { dom.setAttribute(key, output[key]); } } } }; /***/ }, /* 12 */ /*!****************************!*\ !*** ./src/routes/path.js ***! \****************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; var createStyles = __webpack_require__(/*! ./path/builder.js */ 28); module.exports = { onStart: function (bucket, action) { if (action.dom) { action.pathLength = action.dom.getTotalLength(); } }, onChange: function (output, action) { action.style(createStyles(output, action.pathLength)); } }; /***/ }, /* 13 */ /*!******************************!*\ !*** ./src/action/action.js ***! \******************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; var parseArgs = __webpack_require__(/*! ./parse-args.js */ 29), Value = __webpack_require__(/*! ../types/value.js */ 30), Queue = __webpack_require__(/*! ./queue.js */ 31), Process = __webpack_require__(/*! ../process/process.js */ 17), processor = __webpack_require__(/*! ./processor.js */ 32), routes = __webpack_require__(/*! ./routes.js */ 22), defaultProps = __webpack_require__(/*! ../defaults/action-props.js */ 33), defaultState = __webpack_require__(/*! ../defaults/action-state.js */ 34), utils = __webpack_require__(/*! ../utils/utils.js */ 21), styler = __webpack_require__(/*! ../routes/css/styler.js */ 35), namespace = function (key, space) { return (space && space !== routes.defaultRoute) ? key + '.' + space : key; }, Action = function () { var self = this; // Create value repo self.values = {}; this.scope = this; self.setProp(defaultState); self.resetProps(); // Register process wth cycl self.process = new Process(function (framestamp, frameDuration) { if (self.isActive()) { processor(self, framestamp, frameDuration); } }); self.queue = new Queue(); self.output = {}; self.set(parseArgs.generic.apply(self, arguments)); }; Action.prototype = { /* Play the provided actions as animations Syntax .play(playlist, [override]) @param [string]: Playlist of presets @param [object]: (optional) Override object .play(params) @param [object]: Action properties .play(params, [duration, easing, onEnd]) @param [object]: Action props @param [number]: Duration in ms @param [string]: Easing function to apply @param [function]: Function to run on end @return [Action] */ play: function () { var props = parseArgs.play.apply(this, arguments); if (!this.isActive()) { this.set(props, 'to'); this.start('play'); } else { this.queue.add.apply(this.queue, arguments); } return this; }, /* Set Action values and properties Syntax .set(params) @param [object]: Action properties @return [Action] */ set: function (props, defaultProp) { var self = this; // Reset properties to defaults this.resetProps(); // Remove current values from order list this.clearOrder(); // Update current properties this.setProp(props); // Set default property to current if it isn't set defaultProp = defaultProp || 'current'; // Loop over values and update routes.shard(function (route, routeValues) { var preprocessedValues = {}, valueBase = {}, value, base = { route: route.name }; for (var key in routeValues) { if (routeValues.hasOwnProperty(key)) { value = routeValues[key]; if (!utils.isObj(value)) { valueBase = { name: key }; valueBase[defaultProp] = value; } else { valueBase = value; valueBase.name = key; } valueBase = utils.merge(base, valueBase); // If no preprocess step, assign directly if (!route.preprocess) { self.setValue(key, valueBase, props, route.name, true); // Else preprocess and add each returned value } else { preprocessedValues = route.preprocess(key, valueBase, self, props); for (var subKey in preprocessedValues) { self.setValue(subKey, preprocessedValues[subKey], props, route.name, true); } } } } }, props); self.resetOrigins(); return self; }, /* Loop through all values and create origin points */ resetOrigins: function () { var values = this.values, key = ''; for (key in values) { if (values.hasOwnProperty(key)) { values[key].origin = values[key].current; } } }, /* Start Action @param [string]: Name of processing type to use @return [Action] */ start: function (processType) { var input = this.input; this.resetProgress(); if (processType) { this.rubix = processType; } if (processType !== 'track' && input && input.stop) { input.stop(); } this.activate(); return this; }, /* Stop current Action process */ stop: function () { this.queue.clear(); this.pause(); return this; }, /* Pause current Action */ pause: function () { var self = this, input = this.input; self.isActive(false); self.process.stop(); if (input && input.stop) { input.stop(); } return self; }, /* Move playhead to a specific location @param [number]: 0-1 */ seek: function (seekTo) { this.elapsed = this.duration * seekTo; if (!this.isActive()) { this.rubix = 'seek'; this.activate(); } return this; }, activate: function () { this.isActive(true); this.started = utils.currentTime() + this.delay; this.framestamp = this.started; this.firstFrame = true; this.process.start(); }, /* Resume a paused Action */ resume: function () { var self = this; self.started = utils.currentTime(); self.framestamp = self.started; self.isActive(true); self.process.start(); return self; }, /* Reset Action progress and values */ reset: function () { var self = this, values = self.values; self.resetProgress(); for (var key in values) { values[key].reset(); } return self; }, /* Reset Action progress */ resetProgress: function () { this.elapsed = (this.playDirection === 1) ? 0 : this.duration; this.started = utils.currentTime(); return this; }, /* Reverse Action progress and values */ reverse: function () { var values = this.values; this.playDirection = this.playDirection * -1; for (var key in values) { if (values.hasOwnProperty(key)) { values[key].retarget(); } } return this; }, /* Swap value origins and to */ flipValues: function () { var values = this.values; this.elapsed = this.duration - this.elapsed; for (var key in values) { values[key].flip(); } return this; }, toggle: function () { if (this.isActive()) { this.pause(); } else { this.resume(); } return this; }, /* Check for next steps and perform, stop if not */ next: function () { var self = this, nexts = [{ key: 'loop', callback: self.reset }, { key: 'yoyo', callback: self.reverse }, { key: 'flip', callback: self.flipValues }], possibles = nexts.length, hasNext = false; for (var i = 0; i < possibles; ++i) { if (self.checkNextStep(nexts[i].key, nexts[i].callback)) { hasNext = true; break; } } if (!hasNext && !self.playNext()) { self.stop(); } else { self.isActive(true); } return self; }, /* Check next step @param [string]: Name of step ('yoyo' or 'loop') @param [callback]: Function to run if we take this step */ checkNextStep: function (key, callback) { var COUNT = 'Count', stepTaken = false, step = this[key], count = this[key + COUNT], forever = (step === true); if (forever || utils.isNum(step)) { ++count; this[key + COUNT] = count; if (forever || count <= step) { callback.call(this); stepTaken = true; } } return stepTaken; }, /* Next in playlist */ playNext: function () { var stepTaken = false, nextInQueue = this.queue.next(this.playDirection); if (utils.isArray(nextInQueue)) { this.set(parseArgs.generic.apply(this, nextInQueue), 'to') .reset(); stepTaken = true; } return stepTaken; }, setValue: function (key, value, inherit, space, reset) { var existing = this.getValue(key, space); key = namespace(key, space); // Update if value exists if (existing) { // Overwrite with defaults if (reset) { existing.resetProps(); } existing.set(value, inherit); // Or create new if it doesn't } else { this.values[key] = new Value(key, value, inherit, this); } return this; }, getValue: function (key, space) { key = namespace(key, space); return this.values[key]; }, setProp: function (data, prop) { var multiArg = (arguments.length > 1), defaultRoute = routes.getName(), toSet = multiArg ? {} : data, key = ''; // If this is a key/value setter, add to toSet if (multiArg) { toSet[data] = prop; } // Loop over toSet and assign to our data store for (key in toSet) { if (toSet.hasOwnProperty(key) && key != defaultRoute) { this[key] = toSet[key]; } } return this; }, resetProps: function () { this.setProp(defaultProps); return this; }, /* Is Action active? @param [boolean] (optional): If provided, will set action to active/inactive @return [boolean]: Active status */ isActive: function (active) { var isActive = (active !== undefined) ? active : this.active; if (active === true) { this.hasChanged = active; } this.active = isActive; return isActive; }, /* Update order of value keys @param [string]: Key of value @param [boolean]: Whether to move value to back @param [string] (optional): Name of order array (if not default) */ updateOrder: function (key, moveToBack, orderName) { var pos, order; orderName = orderName || 'order'; order = this[orderName] = this[orderName] || []; pos = order.indexOf(key); if (pos === -1 || moveToBack) { order.push(key); if (pos !== -1) { order.splice(pos, 1); } } }, clearOrder: function () { this.order = []; }, /* Style our dom element Becomes get if props is string, set if object */ style: function (name, props) { var elementIsDefined = (arguments.length === 2), dom, returnVal; props = elementIsDefined ? props : name; name = elementIsDefined ? name : 'dom'; dom = this[name]; if (dom) { returnVal = styler(dom, props); } return (returnVal === false) ? this : returnVal; } }; module.exports = Action; /***/ }, /* 14 */ /*!******************************************!*\ !*** ./src/action-group/action-group.js ***! \******************************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; var Action = __webpack_require__(/*! ../action/action.js */ 13), generateMethodIterator = __webpack_require__(/*! ./generate-iterator.js */ 36), defaultDuration = 250, defaultEase = 'linear', /* Action group constructor */ ActionGroup = function (actions) { this.actions = actions || []; }, actionGroupPrototype = ActionGroup.prototype; /* Stagger the execution of the provided Action method @param [string]: Name of Action method to call @param [number] (optional): Duration between method calls @param [string || object] (optional): Argument to pass method @param [string] (optional): Easing */ actionGroupPrototype.stagger = function (method, duration, props, ease) { var self = this, numActions = this.actions.length, i = -1; this._stagger = this._stagger || new Action(); duration = duration || defaultDuration; ease = ease || defaultEase; this._stagger.stop().play({ values: { i: { current: i, to: numActions - 1 } }, round: true, onChange: function (output) { var newIndex = output.i; // If our new index is only one more than the last if (newIndex === i + 1) { self.actions[newIndex][method](props); // Or it's more than one more than the last, so fire all indecies } else { for (var index = i + 1; index <= newIndex; index++) { self.actions[index][method](props); } } i = newIndex; } }, duration * numActions, ease); return this; }; /* Add a new Action to the group @param [object]: Action properties */ actionGroupPrototype.add = function (props) { this.actions.push(new Action(props)); }; // Initialise Action Group methods (function () { for (var method in Action.prototype) { actionGroupPrototype[method] = generateMethodIterator(method); } })(); module.exports = ActionGroup; /***/ }, /* 15 */ /*!*********************************!*\ !*** ./src/action-group/dom.js ***! \*********************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; var ActionGroup = __webpack_require__(/*! ./action-group.js */ 14); module.exports = function (selector) { var actionGroup = new ActionGroup(), elements = [], numElements = 0, i = 0, domSelection = (typeof selector === 'string') ? document.querySelectorAll(selector) : selector; // if jQuery selection, get Array if (domSelection.get) { elements = domSelection.get(); // Or convert NodeList to Array } else if (domSelection.length) { elements = [].slice.call(domSelection); // Or put Element into array } else { elements.push(domSelection); } numElements = elements.length; for (; i < numElements; i++) { actionGroup.add({ dom: elements[i] }); } return actionGroup; }; /***/ }, /* 16 */ /*!****************************!*\ !*** ./src/input/input.js ***! \****************************/ /***/ function(module, exports, __webpack_require__) { /* Input controller */ "use strict"; var calc = __webpack_require__(/*! ../utils/calc.js */ 20), utils = __webpack_require__(/*! ../utils/utils.js */ 21), History = __webpack_require__(/*! ../utils/history.js */ 37), /* Input constructor Syntax newInput(name, value[, poll]) @param [string]: Name of to track @param [number]: Initial value @param [function] (optional): Function to poll Input data newInput(props[, poll]) @param [object]: Object of values @param [function] (optional): Function to poll Input data @return [Input] */ Input = function () { var pollPos = arguments.length - 1; this.current = {}; this.offset = {}; this.velocity = {}; this.history = new History(); this.update(arguments[0], arguments[1]); if (utils.isFunc(arguments[pollPos])) { this.poll = arguments[pollPos]; } }; Input.prototype = { // [number]: Number of frames of inactivity before velocity is turned to 0 maxInactiveFrames: 2, // [number]: Number of frames input hasn't been updated inactiveFrames: 0, /* Get latest input values @param [string] (optional): Name of specific property to return @return [object || number]: Latest input values or, if specified, single value */ get: function (prop) { var latest = this.history.get(), val = (prop !== undefined) ? latest[prop] : latest; return val; }, /* Update the input values Syntax input.update(name, value) @param [string]: Name of to track @param [number]: Initial value input.update(props) @param [object]: Object of values @return [Input] */ update: function (arg0, arg1) { var values = {}; if (utils.isNum(arg1)) { values[arg0] = arg1; } else { values = arg0; } this.history.add(utils.merge(this.current, values)); return this; }, /* Check for input movement and update pointer object's properties @param [number]: Timestamp of frame @return [Input] */ onFrame: function (timestamp) { var latest, hasChanged; // Check provided timestamp against lastFrame timestamp and return input has already been updated if (timestamp === this.lastFrame) { return; } latest = (this.poll) ? this.poll() : this.history.get(); hasChanged = utils.hasChanged(this.current, latest); // If input has changed between frames if (hasChanged) { this.velocity = calc.offset(this.current, latest); this.current = latest; this.inactiveFrames = 0; // Or it hasn't moved and our frame limit has been reached } else if (this.inactiveFrames >= this.maxInactiveFrames) { this.velocity = calc.offset(this.current, this.current); // Or input hasn't changed } else { this.inactiveFrames++; } this.lastFrame = timestamp; return this; } }; module.exports = Input; /***/ }, /* 17 */ /*!********************************!*\ !*** ./src/process/process.js ***! \********************************/ /***/ function(module, exports, __webpack_require__) { /* Process */ "use strict"; var manager = __webpack_require__(/*! ./manager.js */ 38), /* Process constructor Syntax var process = new Process(scope, callback); var process = new Process(callback); */ Process = function (arg0, arg1) { var hasScope = (arg1 !== undefined), callback = hasScope ? arg1 : arg0, scope = hasScope ? arg0 : this; this.setCallback(callback); this.setScope(scope); this.setId(manager.register(this)); }; Process.prototype = { /* [boolean]: Is this process currently active? */ isActive: false, /* [boolean]: Has this process been killed? */ isKilled: false, /* Fire callback @param [timestamp]: Timestamp of currently-executed frame @param [number]: Time since last frame */ fire: function (timestamp, elapsed) { // Check timers if (this.isActive) { this.callback.call(this.scope, timestamp, elapsed); } if (this.isInterval) { this.deactivate(); } return this; }, /* Set process callback @param [function]: Function to fire per frame @return [this] */ setCallback: function (callback) { this.callback = callback; return this; }, /* Set callback scope @param [function]: Fire callback in this context @return [this] */ setScope: function (scope) { this.scope = scope; return this; }, /* Start process @param [int]: Duration of process in ms, 0 if indefinite @return [this] */ start: function (duration) { var self = this; this.reset(); this.activate(); if (duration) { this.stopTimer = setTimeout(function () { self.stop(); }, duration); this.isStopTimerActive = true; } return this; }, /* Stop process @return [this] */ stop: function () { this.reset(); this.deactivate(); return this; }, /* Activate process @return [this] */ activate: function () { if (!this.isKilled) { this.isActive = true; manager.activate(this.id); } return this; }, /* Deactivate process @return [this] */ deactivate: function () { this.isActive = false; manager.deactivate(this.id); return this; }, /* Fire process every x ms @param [int]: Number of ms to wait between refiring process. @return [this] */ every: function (interval) { var self = this; this.reset(); this.isInterval = true; this.intervalTimer = setInterval(function () { self.activate(); }, interval); this.isIntervalTimeActive = true; return this; }, /* Clear all timers @param */ reset: function () { this.isInterval = false; if (this.isStopTimerActive) { clearTimeout(this.stopTimer); } if (this.isIntervalTimeActive) { clearInterval(this.intervalTimer); } return this; }, /* Kill function in manager, release for garbage collection */ kill: function () { this.stop(); this.isKilled = true; manager.kill(this.id); }, setId: function (id) { this.id = id; return this; } }; module.exports = Process; /***/ }, /* 18 */ /*!*******************************!*\ !*** ./src/action/presets.js ***! \*******************************/ /***/ function(module, exports, __webpack_require__) { "use strict"; var utils = __webpack_require__(/*! ../utils/utils.js */ 21), generateKeys = function (key) { var keys = key.split(DOT), keysLength = keys.length, lastKey = keys[0], i = 1; for (; i < keysLength; i++) { keys[i] = lastKey += DOT + keys[i]; } return keys; }, presetStore = {}, DOT = '.', Presets = function () {}; Presets.prototype = { /* Define a new Action preset Syntax .define(name, preset) @param [string]: Name of preset @param [object]: Preset options/properties .define(presets) @param [object]: Multiple presets as named object @return [Redshift] */ add: function (name, preset) { var presets = {}, key = ''; if (utils.isObj(name)) { presets = name; } else { presets[name] = preset; } for (key in presets) { if (presets.hasOwnProperty(key)) { presetStore[key] = presets[key]; } } }, /* Get defined action @param [string]: The name of the predefined action */ getDefined: function (key) { var props = {}, thisProp = {}, keys = generateKeys(key), keysLength = keys.length, i = 0; for (; i < keysLength; i++) { thisProp = presetStore[keys[i]]; if (thisProp) { props = utils.merge(props, thisProp); } } return props; } }; module.exports = new Presets(); /***/ }, /* 19 */ /*!*****************************!*\ !*** ./src/utils/easing.js ***! \*****************************/ /***/ function(module, exports, __webpack_require__) { /* Easing functions ---------------------------------------- Generates and provides easing functions based on baseFunction definitions A call to easingFunction.get('functionName') returns a function that can be passed: @param [number]: Progress 0-1 @param [number] (optional): Amp modifier, only accepted in some easing functions and is used to adjust overall strength @return [number]: Eased progress We can gener