(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["OptimalSelect"] = factory(); else root["OptimalSelect"] = factory(); })(this, function() { return /******/ (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] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = 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; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 6); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertNodeList = convertNodeList; exports.escapeValue = escapeValue; /** * # Utilities * * Convenience helpers. */ /** * Create an array with the DOM nodes of the list * * @param {NodeList} nodes - [description] * @return {Array.} - [description] */ function convertNodeList(nodes) { var length = nodes.length; var arr = new Array(length); for (var i = 0; i < length; i++) { arr[i] = nodes[i]; } return arr; } /** * Escape special characters and line breaks as a simplified version of 'CSS.escape()' * * Description of valid characters: https://mathiasbynens.be/notes/css-escapes * * @param {String?} value - [description] * @return {String} - [description] */ function escapeValue(value) { return value && value.replace(/['"`\\/:\?&!#$%^()[\]{|}*+;,.<=>@~]/g, '\\$&').replace(/\n/g, '\A'); } /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getCommonAncestor = getCommonAncestor; exports.getCommonProperties = getCommonProperties; /** * # Common * * Process collections for similarities. */ /** * Find the last common ancestor of elements * * @param {Array.} elements - [description] * @return {HTMLElement} - [description] */ function getCommonAncestor(elements) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var _options$root = options.root, root = _options$root === undefined ? document : _options$root; var ancestors = []; elements.forEach(function (element, index) { var parents = []; while (element !== root) { element = element.parentNode; parents.unshift(element); } ancestors[index] = parents; }); ancestors.sort(function (curr, next) { return curr.length - next.length; }); var shallowAncestor = ancestors.shift(); var ancestor = null; var _loop = function _loop() { var parent = shallowAncestor[i]; var missing = ancestors.some(function (otherParents) { return !otherParents.some(function (otherParent) { return otherParent === parent; }); }); if (missing) { // TODO: find similar sub-parents, not the top root, e.g. sharing a class selector return 'break'; } ancestor = parent; }; for (var i = 0, l = shallowAncestor.length; i < l; i++) { var _ret = _loop(); if (_ret === 'break') break; } return ancestor; } /** * Get a set of common properties of elements * * @param {Array.} elements - [description] * @return {Object} - [description] */ function getCommonProperties(elements) { var commonProperties = { classes: [], attributes: {}, tag: null }; elements.forEach(function (element) { var commonClasses = commonProperties.classes, commonAttributes = commonProperties.attributes, commonTag = commonProperties.tag; // ~ classes if (commonClasses !== undefined) { var classes = element.getAttribute('class'); if (classes) { classes = classes.trim().split(' '); if (!commonClasses.length) { commonProperties.classes = classes; } else { commonClasses = commonClasses.filter(function (entry) { return classes.some(function (name) { return name === entry; }); }); if (commonClasses.length) { commonProperties.classes = commonClasses; } else { delete commonProperties.classes; } } } else { // TODO: restructure removal as 2x set / 2x delete, instead of modify always replacing with new collection delete commonProperties.classes; } } // ~ attributes if (commonAttributes !== undefined) { (function () { var elementAttributes = element.attributes; var attributes = Object.keys(elementAttributes).reduce(function (attributes, key) { var attribute = elementAttributes[key]; var attributeName = attribute.name; // NOTE: workaround detection for non-standard phantomjs NamedNodeMap behaviour // (issue: https://github.com/ariya/phantomjs/issues/14634) if (attribute && attributeName !== 'class') { attributes[attributeName] = attribute.value; } return attributes; }, {}); var attributesNames = Object.keys(attributes); var commonAttributesNames = Object.keys(commonAttributes); if (attributesNames.length) { if (!commonAttributesNames.length) { commonProperties.attributes = attributes; } else { commonAttributes = commonAttributesNames.reduce(function (nextCommonAttributes, name) { var value = commonAttributes[name]; if (value === attributes[name]) { nextCommonAttributes[name] = value; } return nextCommonAttributes; }, {}); if (Object.keys(commonAttributes).length) { commonProperties.attributes = commonAttributes; } else { delete commonProperties.attributes; } } } else { delete commonProperties.attributes; } })(); } // ~ tag if (commonTag !== undefined) { var tag = element.tagName.toLowerCase(); if (!commonTag) { commonProperties.tag = tag; } else if (tag !== commonTag) { delete commonProperties.tag; } } }); return commonProperties; } /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = optimize; var _adapt = __webpack_require__(3); var _adapt2 = _interopRequireDefault(_adapt); var _utilities = __webpack_require__(0); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Apply different optimization techniques * * @param {string} selector - [description] * @param {HTMLElement|Array.} element - [description] * @param {Object} options - [description] * @return {string} - [description] */ /** * # Optimize * * 1.) Improve efficiency through shorter selectors by removing redundancy * 2.) Improve robustness through selector transformation */ function optimize(selector, elements) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; // convert single entry and NodeList if (!Array.isArray(elements)) { elements = !elements.length ? [elements] : (0, _utilities.convertNodeList)(elements); } if (!elements.length || elements.some(function (element) { return element.nodeType !== 1; })) { throw new Error('Invalid input - to compare HTMLElements its necessary to provide a reference of the selected node(s)! (missing "elements")'); } var globalModified = (0, _adapt2.default)(elements[0], options); // chunk parts outside of quotes (http://stackoverflow.com/a/25663729) var path = selector.replace(/> /g, '>').split(/\s+(?=(?:(?:[^"]*"){2})*[^"]*$)/); if (path.length < 2) { return optimizePart('', selector, '', elements); } var shortened = [path.pop()]; while (path.length > 1) { var current = path.pop(); var prePart = path.join(' '); var postPart = shortened.join(' '); var pattern = prePart + ' ' + postPart; var matches = document.querySelectorAll(pattern); if (matches.length !== elements.length) { shortened.unshift(optimizePart(prePart, current, postPart, elements)); } } shortened.unshift(path[0]); path = shortened; // optimize start + end path[0] = optimizePart('', path[0], path.slice(1).join(' '), elements); path[path.length - 1] = optimizePart(path.slice(0, -1).join(' '), path[path.length - 1], '', elements); if (globalModified) { delete true; } return path.join(' ').replace(/>/g, '> ').trim(); } /** * Improve a chunk of the selector * * @param {string} prePart - [description] * @param {string} current - [description] * @param {string} postPart - [description] * @param {Array.} elements - [description] * @return {string} - [description] */ function optimizePart(prePart, current, postPart, elements) { if (prePart.length) prePart = prePart + ' '; if (postPart.length) postPart = ' ' + postPart; // robustness: attribute without value (generalization) if (/\[*\]/.test(current)) { var key = current.replace(/=.*$/, ']'); var pattern = '' + prePart + key + postPart; var matches = document.querySelectorAll(pattern); if (compareResults(matches, elements)) { current = key; } else { // robustness: replace specific key-value with base tag (heuristic) var references = document.querySelectorAll('' + prePart + key); var _loop = function _loop() { var reference = references[i]; if (elements.some(function (element) { return reference.contains(element); })) { var description = reference.tagName.toLowerCase(); pattern = '' + prePart + description + postPart; matches = document.querySelectorAll(pattern); if (compareResults(matches, elements)) { current = description; } return 'break'; } }; for (var i = 0, l = references.length; i < l; i++) { var pattern; var matches; var _ret = _loop(); if (_ret === 'break') break; } } } // robustness: descendant instead child (heuristic) if (/>/.test(current)) { var descendant = current.replace(/>/, ''); var pattern = '' + prePart + descendant + postPart; var matches = document.querySelectorAll(pattern); if (compareResults(matches, elements)) { current = descendant; } } // robustness: 'nth-of-type' instead 'nth-child' (heuristic) if (/:nth-child/.test(current)) { // TODO: consider complete coverage of 'nth-of-type' replacement var type = current.replace(/nth-child/g, 'nth-of-type'); var pattern = '' + prePart + type + postPart; var matches = document.querySelectorAll(pattern); if (compareResults(matches, elements)) { current = type; } } // efficiency: combinations of classname (partial permutations) if (/\.\S+\.\S+/.test(current)) { var names = current.trim().split('.').slice(1).map(function (name) { return '.' + name; }).sort(function (curr, next) { return curr.length - next.length; }); while (names.length) { var partial = current.replace(names.shift(), '').trim(); var pattern = ('' + prePart + partial + postPart).trim(); if (!pattern.length || pattern.charAt(0) === '>' || pattern.charAt(pattern.length - 1) === '>') { break; } var matches = document.querySelectorAll(pattern); if (compareResults(matches, elements)) { current = partial; } } // robustness: degrade complex classname (heuristic) names = current && current.match(/\./g); if (names && names.length > 2) { var _references = document.querySelectorAll('' + prePart + current); var _loop2 = function _loop2() { var reference = _references[i]; if (elements.some(function (element) { return reference.contains(element); })) { // TODO: // - check using attributes + regard excludes var description = reference.tagName.toLowerCase(); pattern = '' + prePart + description + postPart; matches = document.querySelectorAll(pattern); if (compareResults(matches, elements)) { current = description; } return 'break'; } }; for (var i = 0, l = _references.length; i < l; i++) { var pattern; var matches; var _ret2 = _loop2(); if (_ret2 === 'break') break; } } } return current; } /** * Evaluate matches with expected elements * * @param {Array.} matches - [description] * @param {Array.} elements - [description] * @return {Boolean} - [description] */ function compareResults(matches, elements) { var length = matches.length; return length === elements.length && elements.every(function (element) { for (var i = 0; i < length; i++) { if (matches[i] === element) { return true; } } return false; }); } module.exports = exports['default']; /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); exports.default = adapt; /** * # Adapt * * Check and extend the environment for universal usage. */ /** * Modify the context based on the environment * * @param {HTMLELement} element - [description] * @param {Object} options - [description] * @return {boolean} - [description] */ function adapt(element, options) { // detect environment setup if (true) { return false; } else { global.document = options.context || function () { var root = element; while (root.parent) { root = root.parent; } return root; }(); } // https://github.com/fb55/domhandler/blob/master/index.js#L75 var ElementPrototype = Object.getPrototypeOf(true); // alternative descriptor to access elements with filtering invalid elements (e.g. textnodes) if (!Object.getOwnPropertyDescriptor(ElementPrototype, 'childTags')) { Object.defineProperty(ElementPrototype, 'childTags', { enumerable: true, get: function get() { return this.children.filter(function (node) { // https://github.com/fb55/domelementtype/blob/master/index.js#L12 return node.type === 'tag' || node.type === 'script' || node.type === 'style'; }); } }); } if (!Object.getOwnPropertyDescriptor(ElementPrototype, 'attributes')) { // https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap Object.defineProperty(ElementPrototype, 'attributes', { enumerable: true, get: function get() { var attribs = this.attribs; var attributesNames = Object.keys(attribs); var NamedNodeMap = attributesNames.reduce(function (attributes, attributeName, index) { attributes[index] = { name: attributeName, value: attribs[attributeName] }; return attributes; }, {}); Object.defineProperty(NamedNodeMap, 'length', { enumerable: false, configurable: false, value: attributesNames.length }); return NamedNodeMap; } }); } if (!ElementPrototype.getAttribute) { // https://docs.webplatform.org/wiki/dom/Element/getAttribute // https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute ElementPrototype.getAttribute = function (name) { return this.attribs[name] || null; }; } if (!ElementPrototype.getElementsByTagName) { // https://docs.webplatform.org/wiki/dom/Document/getElementsByTagName // https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName ElementPrototype.getElementsByTagName = function (tagName) { var HTMLCollection = []; traverseDescendants(this.childTags, function (descendant) { if (descendant.name === tagName || tagName === '*') { HTMLCollection.push(descendant); } }); return HTMLCollection; }; } if (!ElementPrototype.getElementsByClassName) { // https://docs.webplatform.org/wiki/dom/Document/getElementsByClassName // https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByClassName ElementPrototype.getElementsByClassName = function (className) { var names = className.trim().replace(/\s+/g, ' ').split(' '); var HTMLCollection = []; traverseDescendants([this], function (descendant) { var descendantClassName = descendant.attribs.class; if (descendantClassName && names.every(function (name) { return descendantClassName.indexOf(name) > -1; })) { HTMLCollection.push(descendant); } }); return HTMLCollection; }; } if (!ElementPrototype.querySelectorAll) { // https://docs.webplatform.org/wiki/css/selectors_api/querySelectorAll // https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll ElementPrototype.querySelectorAll = function (selectors) { var _this = this; selectors = selectors.replace(/(>)(\S)/g, '$1 $2').trim(); // add space for '>' selector // using right to left execution => https://github.com/fb55/css-select#how-does-it-work var instructions = getInstructions(selectors); var discover = instructions.shift(); var total = instructions.length; return discover(this).filter(function (node) { var step = 0; while (step < total) { node = instructions[step](node, _this); if (!node) { // hierarchy doesn't match return false; } step += 1; } return true; }); }; } if (!ElementPrototype.contains) { // https://developer.mozilla.org/en-US/docs/Web/API/Node/contains ElementPrototype.contains = function (element) { var inclusive = false; traverseDescendants([this], function (descendant, done) { if (descendant === element) { inclusive = true; done(); } }); return inclusive; }; } return true; } /** * Retrieve transformation steps * * @param {Array.} selectors - [description] * @return {Array.} - [description] */ function getInstructions(selectors) { return selectors.split(' ').reverse().map(function (selector, step) { var discover = step === 0; var _selector$split = selector.split(':'), _selector$split2 = _slicedToArray(_selector$split, 2), type = _selector$split2[0], pseudo = _selector$split2[1]; var validate = null; var instruction = null; (function () { switch (true) { // child: '>' case />/.test(type): instruction = function checkParent(node) { return function (validate) { return validate(node.parent) && node.parent; }; }; break; // class: '.' case /^\./.test(type): var names = type.substr(1).split('.'); validate = function validate(node) { var nodeClassName = node.attribs.class; return nodeClassName && names.every(function (name) { return nodeClassName.indexOf(name) > -1; }); }; instruction = function checkClass(node, root) { if (discover) { return node.getElementsByClassName(names.join(' ')); } return typeof node === 'function' ? node(validate) : getAncestor(node, root, validate); }; break; // attribute: '[key="value"]' case /^\[/.test(type): var _type$replace$split = type.replace(/\[|\]|"/g, '').split('='), _type$replace$split2 = _slicedToArray(_type$replace$split, 2), attributeKey = _type$replace$split2[0], attributeValue = _type$replace$split2[1]; validate = function validate(node) { var hasAttribute = Object.keys(node.attribs).indexOf(attributeKey) > -1; if (hasAttribute) { // regard optional attributeValue if (!attributeValue || node.attribs[attributeKey] === attributeValue) { return true; } } return false; }; instruction = function checkAttribute(node, root) { if (discover) { var _ret2 = function () { var NodeList = []; traverseDescendants([node], function (descendant) { if (validate(descendant)) { NodeList.push(descendant); } }); return { v: NodeList }; }(); if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v; } return typeof node === 'function' ? node(validate) : getAncestor(node, root, validate); }; break; // id: '#' case /^#/.test(type): var id = type.substr(1); validate = function validate(node) { return node.attribs.id === id; }; instruction = function checkId(node, root) { if (discover) { var _ret3 = function () { var NodeList = []; traverseDescendants([node], function (descendant, done) { if (validate(descendant)) { NodeList.push(descendant); done(); } }); return { v: NodeList }; }(); if ((typeof _ret3 === 'undefined' ? 'undefined' : _typeof(_ret3)) === "object") return _ret3.v; } return typeof node === 'function' ? node(validate) : getAncestor(node, root, validate); }; break; // universal: '*' case /\*/.test(type): validate = function validate(node) { return true; }; instruction = function checkUniversal(node, root) { if (discover) { var _ret4 = function () { var NodeList = []; traverseDescendants([node], function (descendant) { return NodeList.push(descendant); }); return { v: NodeList }; }(); if ((typeof _ret4 === 'undefined' ? 'undefined' : _typeof(_ret4)) === "object") return _ret4.v; } return typeof node === 'function' ? node(validate) : getAncestor(node, root, validate); }; break; // tag: '...' default: validate = function validate(node) { return node.name === type; }; instruction = function checkTag(node, root) { if (discover) { var _ret5 = function () { var NodeList = []; traverseDescendants([node], function (descendant) { if (validate(descendant)) { NodeList.push(descendant); } }); return { v: NodeList }; }(); if ((typeof _ret5 === 'undefined' ? 'undefined' : _typeof(_ret5)) === "object") return _ret5.v; } return typeof node === 'function' ? node(validate) : getAncestor(node, root, validate); }; } })(); if (!pseudo) { return instruction; } var rule = pseudo.match(/-(child|type)\((\d+)\)$/); var kind = rule[1]; var index = parseInt(rule[2], 10) - 1; var validatePseudo = function validatePseudo(node) { if (node) { var compareSet = node.parent.childTags; if (kind === 'type') { compareSet = compareSet.filter(validate); } var nodeIndex = compareSet.findIndex(function (child) { return child === node; }); if (nodeIndex === index) { return true; } } return false; }; return function enhanceInstruction(node) { var match = instruction(node); if (discover) { return match.reduce(function (NodeList, matchedNode) { if (validatePseudo(matchedNode)) { NodeList.push(matchedNode); } return NodeList; }, []); } return validatePseudo(match) && match; }; }); } /** * Walking recursive to invoke callbacks * * @param {Array.} nodes - [description] * @param {Function} handler - [description] */ function traverseDescendants(nodes, handler) { nodes.forEach(function (node) { var progress = true; handler(node, function () { return progress = false; }); if (node.childTags && progress) { traverseDescendants(node.childTags, handler); } }); } /** * Bubble up from bottom to top * * @param {HTMLELement} node - [description] * @param {HTMLELement} root - [description] * @param {Function} validate - [description] * @return {HTMLELement} - [description] */ function getAncestor(node, root, validate) { while (node.parent) { node = node.parent; if (validate(node)) { return node; } if (node === root) { break; } } return null; } module.exports = exports['default']; /***/ }, /* 4 */ /***/ function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** * # Select * * Construct a unique CSS query selector to access the selected DOM element(s). * For longevity it applies different matching and optimization strategies. */ exports.getSingleSelector = getSingleSelector; exports.getMultiSelector = getMultiSelector; exports.default = getQuerySelector; var _adapt = __webpack_require__(3); var _adapt2 = _interopRequireDefault(_adapt); var _match = __webpack_require__(5); var _match2 = _interopRequireDefault(_match); var _optimize = __webpack_require__(2); var _optimize2 = _interopRequireDefault(_optimize); var _utilities = __webpack_require__(0); var _common = __webpack_require__(1); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Get a selector for the provided element * * @param {HTMLElement} element - [description] * @param {Object} options - [description] * @return {string} - [description] */ function getSingleSelector(element) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (element.nodeType === 3) { element = element.parentNode; } if (element.nodeType !== 1) { throw new Error('Invalid input - only HTMLElements or representations of them are supported! (not "' + (typeof element === 'undefined' ? 'undefined' : _typeof(element)) + '")'); } var globalModified = (0, _adapt2.default)(element, options); var selector = (0, _match2.default)(element, options); var optimized = (0, _optimize2.default)(selector, element, options); // debug // console.log(` // selector: ${selector} // optimized: ${optimized} // `) if (globalModified) { delete true; } return optimized; } /** * Get a selector to match multiple descendants from an ancestor * * @param {Array.|NodeList} elements - [description] * @param {Object} options - [description] * @return {string} - [description] */ function getMultiSelector(elements) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (!Array.isArray(elements)) { elements = (0, _utilities.convertNodeList)(elements); } if (elements.some(function (element) { return element.nodeType !== 1; })) { throw new Error('Invalid input - only an Array of HTMLElements or representations of them is supported!'); } var globalModified = (0, _adapt2.default)(elements[0], options); var ancestor = (0, _common.getCommonAncestor)(elements, options); var ancestorSelector = getSingleSelector(ancestor, options); // TODO: consider usage of multiple selectors + parent-child relation + check for part redundancy var commonSelectors = getCommonSelectors(elements); var descendantSelector = commonSelectors[0]; var selector = (0, _optimize2.default)(ancestorSelector + ' ' + descendantSelector, elements, options); var selectorMatches = (0, _utilities.convertNodeList)(document.querySelectorAll(selector)); if (!elements.every(function (element) { return selectorMatches.some(function (entry) { return entry === element; }); })) { // TODO: cluster matches to split into similar groups for sub selections return console.warn('\n The selected elements can\'t be efficiently mapped.\n Its probably best to use multiple single selectors instead!\n ', elements); } if (globalModified) { delete true; } return selector; } /** * Get selectors to describe a set of elements * * @param {Array.} elements - [description] * @return {string} - [description] */ function getCommonSelectors(elements) { var _getCommonProperties = (0, _common.getCommonProperties)(elements), classes = _getCommonProperties.classes, attributes = _getCommonProperties.attributes, tag = _getCommonProperties.tag; var selectorPath = []; if (tag) { selectorPath.push(tag); } if (classes) { var classSelector = classes.map(function (name) { return '.' + name; }).join(''); selectorPath.push(classSelector); } if (attributes) { var attributeSelector = Object.keys(attributes).reduce(function (parts, name) { parts.push('[' + name + '="' + attributes[name] + '"]'); return parts; }, []).join(''); selectorPath.push(attributeSelector); } if (selectorPath.length) { // TODO: check for parent-child relation } return [selectorPath.join('')]; } /** * Choose action depending on the input (multiple/single) * * NOTE: extended detection is used for special cases like the elements pass all the criteria regarding length and the first child having style, so we must also check to ensure the target isn't an HTML node itself. targets.splice(i--, 1); this._targets = targets = targets.concat(_slice(targ)); continue; } this._siblings[i] = _register(targ, this, false); if (overwrite === 1) if (this._siblings[i].length > 1) { _applyOverwrite(targ, this, null, 1, this._siblings[i]); } } } else { this._propLookup = {}; this._siblings = _register(target, this, false); if (overwrite === 1) if (this._siblings.length > 1) { _applyOverwrite(target, this, null, 1, this._siblings); } } if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) { this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render) this.render(Math.min(0, -this._delay)); //in case delay is negative } }, true), _isSelector = function(v) { return (v && v.length && v !== window && v[0] && (v[0] === window || (v[0].nodeType && v[0].style && !v.nodeType))); //we cannot check "nodeType" if the target is window from within an iframe, otherwise it will trigger a security error in some browsers like Firefox. }, _autoCSS = function(vars, target) { var css = {}, p; for (p in vars) { if (!_reservedProps[p] && (!(p in target) || p === "transform" || p === "x" || p === "y" || p === "width" || p === "height" || p === "className" || p === "border") && (!_plugins[p] || (_plugins[p] && _plugins[p]._autoCSS))) { //note: elements contain read-only "x" and "y" properties. We should also prioritize editing css width/height rather than the element's properties. css[p] = vars[p]; delete vars[p]; } } vars.css = css; }; p = TweenLite.prototype = new Animation(); p.constructor = TweenLite; p.kill()._gc = false; //----TweenLite defaults, overwrite management, and root updates ---------------------------------------------------- p.ratio = 0; p._firstPT = p._targets = p._overwrittenProps = p._startAt = null; p._notifyPluginsOfEnabled = p._lazy = false; TweenLite.version = "2.1.3"; TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1); TweenLite.defaultOverwrite = "auto"; TweenLite.ticker = _ticker; TweenLite.autoSleep = 120; TweenLite.lagSmoothing = function(threshold, adjustedLag) { _ticker.lagSmoothing(threshold, adjustedLag); }; TweenLite.selector = window.$ || window.jQuery || function(e) { var selector = window.$ || window.jQuery; if (selector) { TweenLite.selector = selector; return selector(e); } if (!_doc) { //in some dev environments (like Angular 6), GSAP gets loaded before the document is defined! So re-query it here if/when necessary. _doc = window.document; } return (!_doc) ? e : (_doc.querySelectorAll ? _doc.querySelectorAll(e) : _doc.getElementById((e.charAt(0) === "#") ? e.substr(1) : e)); }; var _lazyTweens = [], _lazyLookup = {}, _numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig, _relExp = /[\+-]=-?[\.\d]/, //_nonNumbersExp = /(?:([\-+](?!(\d|=)))|[^\d\-+=e]|(e(?![\-+][\d])))+/ig, _setRatio = function(v) { var pt = this._firstPT, min = 0.000001, val; while (pt) { val = !pt.blob ? pt.c * v + pt.s : (v === 1 && this.end != null) ? this.end : v ? this.join("") : this.start; if (pt.m) { val = pt.m.call(this._tween, val, this._target || pt.t, this._tween); } else if (val < min) if (val > -min && !pt.blob) { //prevents issues with converting very small numbers to strings in the browser val = 0; } if (!pt.f) { pt.t[pt.p] = val; } else if (pt.fp) { pt.t[pt.p](pt.fp, val); } else { pt.t[pt.p](val); } pt = pt._next; } }, _blobRound = function(v) { return (((v * 1000) | 0) / 1000) + ""; }, //compares two strings (start/end), finds the numbers that are different and spits back an array representing the whole value but with the changing values isolated as elements. For example, "rgb(0,0,0)" and "rgb(100,50,0)" would become ["rgb(", 0, ",", 50, ",0)"]. Notice it merges the parts that are identical (performance optimization). The array also has a linked list of PropTweens attached starting with _firstPT that contain the tweening data (t, p, s, c, f, etc.). It also stores the starting value as a "start" property so that we can revert to it if/when necessary, like when a tween rewinds fully. If the quantity of numbers differs between the start and end, it will always prioritize the end value(s). The pt parameter is optional - it's for a PropTween that will be appended to the end of the linked list and is typically for actually setting the value after all of the elements have been updated (with array.join("")). _blobDif = function(start, end, filter, pt) { var a = [], charIndex = 0, s = "", color = 0, startNums, endNums, num, i, l, nonNumbers, currentNum; a.start = start; a.end = end; start = a[0] = start + ""; //ensure values are strings end = a[1] = end + ""; if (filter) { filter(a); //pass an array with the starting and ending values and let the filter do whatever it needs to the values. start = a[0]; end = a[1]; } a.length = 0; startNums = start.match(_numbersExp) || []; endNums = end.match(_numbersExp) || []; if (pt) { pt._next = null; pt.blob = 1; a._firstPT = a._applyPT = pt; //apply last in the linked list (which means inserting it first) } l = endNums.length; for (i = 0; i < l; i++) { currentNum = endNums[i]; nonNumbers = end.substr(charIndex, end.indexOf(currentNum, charIndex)-charIndex); s += (nonNumbers || !i) ? nonNumbers : ","; //note: SVG spec allows omission of comma/space when a negative sign is wedged between two numbers, like 2.5-5.3 instead of 2.5,-5.3 but when tweening, the negative value may switch to positive, so we insert the comma just in case. charIndex += nonNumbers.length; if (color) { //sense rgba() values and round them. color = (color + 1) % 5; } else if (nonNumbers.substr(-5) === "rgba(") { color = 1; } if (currentNum === startNums[i] || startNums.length <= i) { s += currentNum; } else { if (s) { a.push(s); s = ""; } num = parseFloat(startNums[i]); a.push(num); a._firstPT = {_next: a._firstPT, t:a, p: a.length-1, s:num, c:((currentNum.charAt(1) === "=") ? parseInt(currentNum.charAt(0) + "1", 10) * parseFloat(currentNum.substr(2)) : (parseFloat(currentNum) - num)) || 0, f:0, m:(color && color < 4) ? Math.round : _blobRound}; //limiting to 3 decimal places and casting as a string can really help performance when array.join() is called! //note: we don't set _prev because we'll never need to remove individual PropTweens from this list. } charIndex += currentNum.length; } s += end.substr(charIndex); if (s) { a.push(s); } a.setRatio = _setRatio; if (_relExp.test(end)) { //if the end string contains relative values, delete it so that on the final render (in _setRatio()), we don't actually set it to the string with += or -= characters (forces it to use the calculated value). a.end = null; } return a; }, //note: "funcParam" is only necessary for function-based getters/setters that require an extra parameter like getAttribute("width") and setAttribute("width", value). In this example, funcParam would be "width". Used by AttrPlugin for example. _addPropTween = function(target, prop, start, end, overwriteProp, mod, funcParam, stringFilter, index) { if (typeof(end) === "function") { end = end(index || 0, target); } var type = typeof(target[prop]), getterName = (type !== "function") ? "" : ((prop.indexOf("set") || typeof(target["get" + prop.substr(3)]) !== "function") ? prop : "get" + prop.substr(3)), s = (start !== "get") ? start : !getterName ? target[prop] : funcParam ? target[getterName](funcParam) : target[getterName](), isRelative = (typeof(end) === "string" && end.charAt(1) === "="), pt = {t:target, p:prop, s:s, f:(type === "function"), pg:0, n:overwriteProp || prop, m:(!mod ? 0 : (typeof(mod) === "function") ? mod : Math.round), pr:0, c:isRelative ? parseInt(end.charAt(0) + "1", 10) * parseFloat(end.substr(2)) : (parseFloat(end) - s) || 0}, blob; if (typeof(s) !== "number" || (typeof(end) !== "number" && !isRelative)) { if (funcParam || isNaN(s) || (!isRelative && isNaN(end)) || typeof(s) === "boolean" || typeof(end) === "boolean") { //a blob (string that has multiple numbers in it) pt.fp = funcParam; blob = _blobDif(s, (isRelative ? (parseFloat(pt.s) + pt.c) + (pt.s + "").replace(/[0-9\-\.]/g, "") : end), stringFilter || TweenLite.defaultStringFilter, pt); pt = {t: blob, p: "setRatio", s: 0, c: 1, f: 2, pg: 0, n: overwriteProp || prop, pr: 0, m: 0}; //"2" indicates it's a Blob property tween. Needed for RoundPropsPlugin for example. } else { pt.s = parseFloat(s); if (!isRelative) { pt.c = (parseFloat(end) - pt.s) || 0; } } } if (pt.c) { //only add it to the linked list if there's a change. if ((pt._next = this._firstPT)) { pt._next._prev = pt; } this._firstPT = pt; return pt; } }, _internals = TweenLite._internals = {isArray:_isArray, isSelector:_isSelector, lazyTweens:_lazyTweens, blobDif:_blobDif}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object. _plugins = TweenLite._plugins = {}, _tweenLookup = _internals.tweenLookup = {}, _tweenLookupNum = 0, _reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUpdate:1, onUpdateParams:1, onUpdateScope:1, onStart:1, onStartParams:1, onStartScope:1, onReverseComplete:1, onReverseCompleteParams:1, onReverseCompleteScope:1, onRepeat:1, onRepeatParams:1, onRepeatScope:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, data:1, paused:1, reversed:1, autoCSS:1, lazy:1, onOverwrite:1, callbackScope:1, stringFilter:1, id:1, yoyoEase:1, stagger:1}, _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0}, _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(), _rootTimeline = Animation._rootTimeline = new SimpleTimeline(), _nextGCFrame = 30, _lazyRender = _internals.lazyRender = function() { var l = _lazyTweens.length, i, tween; _lazyLookup = {}; for (i = 0; i < l; i++) { tween = _lazyTweens[i]; if (tween && tween._lazy !== false) { tween.render(tween._lazy[0], tween._lazy[1], true); tween._lazy = false; } } _lazyTweens.length = 0; }; _rootTimeline._startTime = _ticker.time; _rootFramesTimeline._startTime = _ticker.frame; _rootTimeline._active = _rootFramesTimeline._active = true; setTimeout(_lazyRender, 1); //on some mobile devices, there isn't a "tick" before code runs which means any lazy renders wouldn't run before the next official "tick". Animation._updateRoot = TweenLite.render = function() { var i, a, p; if (_lazyTweens.length) { //if code is run outside of the requestAnimationFrame loop, there may be tweens queued AFTER the engine refreshed, so we need to ensure any pending renders occur before we refresh again. _lazyRender(); } _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false); _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false); if (_lazyTweens.length) { _lazyRender(); } if (_ticker.frame >= _nextGCFrame) { //dump garbage every 120 frames or whatever the user sets TweenLite.autoSleep to _nextGCFrame = _ticker.frame + (parseInt(TweenLite.autoSleep, 10) || 120); for (p in _tweenLookup) { a = _tweenLookup[p].tweens; i = a.length; while (--i > -1) { if (a[i]._gc) { a.splice(i, 1); } } if (a.length === 0) { delete _tweenLookup[p]; } } //if there are no more tweens in the root timelines, or if they're all paused, make the _timer sleep to reduce load on the CPU slightly p = _rootTimeline._first; if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) { while (p && p._paused) { p = p._next; } if (!p) { _ticker.sleep(); } } } }; _ticker.addEventListener("tick", Animation._updateRoot); var _register = function(target, tween, scrub) { var id = target._gsTweenID, a, i; if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) { _tweenLookup[id] = {target:target, tweens:[]}; } if (tween) { a = _tweenLookup[id].tweens; a[(i = a.length)] = tween; if (scrub) { while (--i > -1) { if (a[i] === tween) { a.splice(i, 1); } } } } return _tweenLookup[id].tweens; }, _onOverwrite = function(overwrittenTween, overwritingTween, target, killedProps) { var func = overwrittenTween.vars.onOverwrite, r1, r2; if (func) { r1 = func(overwrittenTween, overwritingTween, target, killedProps); } func = TweenLite.onOverwrite; if (func) { r2 = func(overwrittenTween, overwritingTween, target, killedProps); } return (r1 !== false && r2 !== false); }, _applyOverwrite = function(target, tween, props, mode, siblings) { var i, changed, curTween, l; if (mode === 1 || mode >= 4) { l = siblings.length; for (i = 0; i < l; i++) { if ((curTween = siblings[i]) !== tween) { if (!curTween._gc) { if (curTween._kill(null, target, tween)) { changed = true; } } } else if (mode === 5) { break; } } return changed; } //NOTE: Add tiny amount to overcome floating point errors that can cause the startTime to be VERY slightly off (when a tween's time() is set for example) var startTime = tween._startTime + _tinyNum, overlaps = [], oCount = 0, zeroDur = (tween._duration === 0), globalStart; i = siblings.length; while (--i > -1) { if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) { //ignore } else if (curTween._timeline !== tween._timeline) { globalStart = globalStart || _checkOverlap(tween, 0, zeroDur); if (_checkOverlap(curTween, globalStart, zeroDur) === 0) { overlaps[oCount++] = curTween; } } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= _tinyNum * 2)) { overlaps[oCount++] = curTween; } } i = oCount; while (--i > -1) { curTween = overlaps[i]; l = curTween._firstPT; //we need to discern if there were property tweens originally; if they all get removed in the next line's _kill() call, the tween should be killed. See https://github.com/greensock/GreenSock-JS/issues/278 if (mode === 2) if (curTween._kill(props, target, tween)) { changed = true; } if (mode !== 2 || (!curTween._firstPT && curTween._initted && l)) { if (mode !== 2 && !_onOverwrite(curTween, tween)) { continue; } if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween. changed = true; } } } return changed; }, _checkOverlap = function(tween, reference, zeroDur) { var tl = tween._timeline, ts = tl._timeScale, t = tween._startTime; while (tl._timeline) { t += tl._startTime; ts *= tl._timeScale; if (tl._paused) { return -100; } tl = tl._timeline; } t /= ts; return (t > reference) ? t - reference : ((zeroDur && t === reference) || (!tween._initted && t - reference < 2 * _tinyNum)) ? _tinyNum : ((t += tween.totalDuration() / tween._timeScale / ts) > reference + _tinyNum) ? 0 : t - reference - _tinyNum; }; //---- TweenLite instance methods ----------------------------------------------------------------------------- p._init = function() { var v = this.vars, op = this._overwrittenProps, dur = this._duration, immediate = !!v.immediateRender, ease = v.ease, startAt = this._startAt, i, initPlugins, pt, p, startVars, l; if (v.startAt) { if (startAt) { startAt.render(-1, true); //if we've run a startAt previously (when the tween instantiated), we should revert it so that the values re-instantiate correctly particularly for relative tweens. Without this, a TweenLite.fromTo(obj, 1, {x:"+=100"}, {x:"-=100"}), for example, would actually jump to +=200 because the startAt would run twice, doubling the relative change. startAt.kill(); } startVars = {}; for (p in v.startAt) { //copy the properties/values into a new object to avoid collisions, like var to = {x:0}, from = {x:500}; timeline.fromTo(e, 1, from, to).fromTo(e, 1, to, from); startVars[p] = v.startAt[p]; } startVars.data = "isStart"; startVars.overwrite = false; startVars.immediateRender = true; startVars.lazy = (immediate && v.lazy !== false); startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop). startVars.onUpdate = v.onUpdate; startVars.onUpdateParams = v.onUpdateParams; startVars.onUpdateScope = v.onUpdateScope || v.callbackScope || this; this._startAt = TweenLite.to(this.target || {}, 0, startVars); if (immediate) { if (this._time > 0) { this._startAt = null; //tweens that render immediately (like most from() and fromTo() tweens) shouldn't revert when their parent timeline's playhead goes backward past the startTime because the initial render could have happened anytime and it shouldn't be directly correlated to this tween's startTime. Imagine setting up a complex animation where the beginning states of various objects are rendered immediately but the tween doesn't happen for quite some time - if we revert to the starting values as soon as the playhead goes backward past the tween's startTime, it will throw things off visually. Reversion should only happen in TimelineLite/Max instances where immediateRender was false (which is the default in the convenience methods like from()). } else if (dur !== 0) { return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a TimelineLite or TimelineMax, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting. } } } else if (v.runBackwards && dur !== 0) { //from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards) if (startAt) { startAt.render(-1, true); startAt.kill(); this._startAt = null; } else { if (this._time !== 0) { //in rare cases (like if a from() tween runs and then is invalidate()-ed), immediateRender could be true but the initial forced-render gets skipped, so there's no need to force the render in this context when the _time is greater than 0 immediate = false; } pt = {}; for (p in v) { //copy props into a new object and skip any reserved props, otherwise onComplete or onUpdate or onStart could fire. We should, however, permit autoCSS to go through. if (!_reservedProps[p] || p === "autoCSS") { pt[p] = v[p]; } } pt.overwrite = 0; pt.data = "isFromStart"; //we tag the tween with as "isFromStart" so that if [inside a plugin] we need to only do something at the very END of a tween, we have a way of identifying this tween as merely the one that's setting the beginning values for a "from()" tween. For example, clearProps in CSSPlugin should only get applied at the very END of a tween and without this tag, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in. pt.lazy = (immediate && v.lazy !== false); pt.immediateRender = immediate; //zero-duration tweens render immediately by default, but if we're not specifically instructed to render this tween immediately, we should skip this and merely _init() to record the starting values (rendering them immediately would push them to completion which is wasteful in that case - we'd have to render(-1) immediately after) this._startAt = TweenLite.to(this.target, 0, pt); if (!immediate) { this._startAt._init(); //ensures that the initial values are recorded this._startAt._enabled(false); //no need to have the tween render on the next cycle. Disable it because we'll always manually control the renders of the _startAt tween. if (this.vars.immediateRender) { this._startAt = null; } } else if (this._time === 0) { return; } } } this._ease = ease = (!ease) ? TweenLite.defaultEase : (ease instanceof Ease) ? ease : (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase; if (v.easeParams instanceof Array && ease.config) { this._ease = ease.config.apply(ease, v.easeParams); } this._easeType = this._ease._type; this._easePower = this._ease._power; this._firstPT = null; if (this._targets) { l = this._targets.length; for (i = 0; i < l; i++) { if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null), i) ) { initPlugins = true; } } } else { initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op, 0); } if (initPlugins) { TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite } if (op) if (!this._firstPT) if (typeof(this.target) !== "function") { //if all tweening properties have been overwritten, kill the tween. If the target is a function, it's probably a delayedCall so let it live. this._enabled(false, false); } if (v.runBackwards) { pt = this._firstPT; while (pt) { pt.s += pt.c; pt.c = -pt.c; pt = pt._next; } } this._onUpdate = v.onUpdate; this._initted = true; }; p._initProps = function(target, propLookup, siblings, overwrittenProps, index) { var p, i, initPlugins, plugin, pt, v; if (target == null) { return false; } if (_lazyLookup[target._gsTweenID]) { _lazyRender(); //if other tweens of the same target have recently initted but haven't rendered yet, we've got to force the render so that the starting values are correct (imagine populating a timeline with a bunch of sequential tweens and then jumping to the end) } if (!this.vars.css) if (target.style) if (target !== window && target.nodeType) if (_plugins.css) if (this.vars.autoCSS !== false) { //it's so common to use TweenLite/Max to animate the css of DOM elements, we assume that if the target is a DOM element, that's what is intended (a convenience so that users don't have to wrap things in css:{}, although we still recommend it for a slight performance boost and better specificity). Note: we cannot check "nodeType" on the window inside an iframe. _autoCSS(this.vars, target); } for (p in this.vars) { v = this.vars[p]; if (_reservedProps[p]) { if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) { this.vars[p] = v = this._swapSelfInParams(v, this); } } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this, index)) { //t - target [object] //p - property [string] //s - start [number] //c - change [number] //f - isFunction [boolean] //n - name [string] //pg - isPlugin [boolean] //pr - priority [number] //m - mod [function | 0] this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:1, n:p, pg:1, pr:plugin._priority, m:0}; i = plugin._overwriteProps.length; while (--i > -1) { propLookup[plugin._overwriteProps[i]] = this._firstPT; } if (plugin._priority || plugin._onInitAllProps) { initPlugins = true; } if (plugin._onDisable || plugin._onEnable) { this._notifyPluginsOfEnabled = true; } if (pt._next) { pt._next._prev = pt; } } else { propLookup[p] = _addPropTween.call(this, target, p, "get", v, p, 0, null, this.vars.stringFilter, index); } } if (overwrittenProps) if (this._kill(overwrittenProps, target)) { //another tween may have tried to overwrite properties of this tween before init() was called (like if two tweens start at the same time, the one created second will run first) return this._initProps(target, propLookup, siblings, overwrittenProps, index); } if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) { this._kill(propLookup, target); return this._initProps(target, propLookup, siblings, overwrittenProps, index); } if (this._firstPT) if ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration)) { //zero duration tweens don't lazy render by default; everything else does. _lazyLookup[target._gsTweenID] = true; } return initPlugins; }; p.render = function(time, suppressEvents, force) { var self = this, prevTime = self._time, duration = self._duration, prevRawPrevTime = self._rawPrevTime, isComplete, callback, pt, rawPrevTime; if (time >= duration - _tinyNum && time >= 0) { //to work around occasional floating point math artifacts. self._totalTime = self._time = duration; self.ratio = self._ease._calcEnd ? self._ease.getRatio(1) : 1; if (!self._reversed ) { isComplete = true; callback = "onComplete"; force = (force || self._timeline.autoRemoveChildren); //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline. } if (duration === 0) if (self._initted || !self.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered. if (self._startTime === self._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent rounding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate. time = 0; } if (prevRawPrevTime < 0 || (time <= 0 && time >= -_tinyNum) || (prevRawPrevTime === _tinyNum && self.data !== "isPause")) if (prevRawPrevTime !== time) { //note: when this.data is "isPause", it's a callback added by addPause() on a timeline that we should not be triggered when LEAVING its exact start time. In other words, tl.addPause(1).play(1) shouldn't pause. force = true; if (prevRawPrevTime > _tinyNum) { callback = "onReverseComplete"; } } self._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. } } else if (time < _tinyNum) { //to work around occasional floating point math artifacts, round super small values to 0. self._totalTime = self._time = 0; self.ratio = self._ease._calcEnd ? self._ease.getRatio(0) : 0; if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0)) { callback = "onReverseComplete"; isComplete = self._reversed; } if (time > -_tinyNum) { time = 0; } else if (time < 0) { self._active = false; if (duration === 0) if (self._initted || !self.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered. if (prevRawPrevTime >= 0 && !(prevRawPrevTime === _tinyNum && self.data === "isPause")) { force = true; } self._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. } } if (!self._initted || (self._startAt && self._startAt.progress())) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately. Also, we check progress() because if startAt has already rendered at its end, we should force a render at its beginning. Otherwise, if you put the playhead directly on top of where a fromTo({immediateRender:false}) starts, and then move it backwards, the from() won't revert its values. force = true; } } else { self._totalTime = self._time = time; if (self._easeType) { var r = time / duration, type = self._easeType, pow = self._easePower; if (type === 1 || (type === 3 && r >= 0.5)) { r = 1 - r; } if (type === 3) { r *= 2; } if (pow === 1) { r *= r; } else if (pow === 2) { r *= r * r; } else if (pow === 3) { r *= r * r * r; } else if (pow === 4) { r *= r * r * r * r; } self.ratio = (type === 1) ? 1 - r : (type === 2) ? r : (time / duration < 0.5) ? r / 2 : 1 - (r / 2); } else { self.ratio = self._ease.getRatio(time / duration); } } if (self._time === prevTime && !force) { return; } else if (!self._initted) { self._init(); if (!self._initted || self._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example. return; } else if (!force && self._firstPT && ((self.vars.lazy !== false && self._duration) || (self.vars.lazy && !self._duration))) { self._time = self._totalTime = prevTime; self._rawPrevTime = prevRawPrevTime; _lazyTweens.push(self); self._lazy = [time, suppressEvents]; return; } //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently. if (self._time && !isComplete) { self.ratio = self._ease.getRatio(self._time / duration); } else if (isComplete && self._ease._calcEnd) { self.ratio = self._ease.getRatio((self._time === 0) ? 0 : 1); } } if (self._lazy !== false) { //in case a lazy render is pending, we should flush it because the new render is occurring now (imagine a lazy tween instantiating and then immediately the user calls tween.seek(tween.duration()), skipping to the end - the end render would be forced, and then if we didn't flush the lazy render, it'd fire AFTER the seek(), rendering it at the wrong time. self._lazy = false; } if (!self._active) if (!self._paused && self._time !== prevTime && time >= 0) { self._active = true; //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done. } if (prevTime === 0) { if (self._startAt) { if (time >= 0) { self._startAt.render(time, true, force); } else if (!callback) { callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area. } } if (self.vars.onStart) if (self._time !== 0 || duration === 0) if (!suppressEvents) { self._callback("onStart"); } } pt = self._firstPT; while (pt) { if (pt.f) { pt.t[pt.p](pt.c * self.ratio + pt.s); } else { pt.t[pt.p] = pt.c * self.ratio + pt.s; } pt = pt._next; } if (self._onUpdate) { if (time < 0) if (self._startAt && time !== -0.0001) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values. self._startAt.render(time, true, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete. } if (!suppressEvents) if (self._time !== prevTime || isComplete || force) { self._callback("onUpdate"); } } if (callback) if (!self._gc || force) { //check _gc because there's a chance that kill() could be called in an onUpdate if (time < 0 && self._startAt && !self._onUpdate && time !== -0.0001) { //-0.0001 is a special value that we use when looping back to the beginning of a repeated TimelineMax, in which case we shouldn't render the _startAt values. self._startAt.render(time, true, force); } if (isComplete) { if (self._timeline.autoRemoveChildren) { self._enabled(false, false); } self._active = false; } if (!suppressEvents && self.vars[callback]) { self._callback(callback); } if (duration === 0 && self._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon scenario, but possible nonetheless. self._rawPrevTime = 0; } } }; p._kill = function(vars, target, overwritingTween) { if (vars === "all") { vars = null; } if (vars == null) if (target == null || target === this.target) { this._lazy = false; return this._enabled(false, false); } target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target; var simultaneousOverwrite = (overwritingTween && this._time && overwritingTween._startTime === this._startTime && this._timeline === overwritingTween._timeline), firstPT = this._firstPT, i, overwrittenProps, p, pt, propLookup, changed, killProps, record, killed; if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") { i = target.length; while (--i > -1) { if (this._kill(vars, target[i], overwritingTween)) { changed = true; } } } else { if (this._targets) { i = this._targets.length; while (--i > -1) { if (target === this._targets[i]) { propLookup = this._propLookup[i] || {}; this._overwrittenProps = this._overwrittenProps || []; overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all"; break; } } } else if (target !== this.target) { return false; } else { propLookup = this._propLookup; overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all"; } if (propLookup) { killProps = vars || propLookup; record = (vars !== overwrittenProps && overwrittenProps !== "all" && vars !== propLookup && (typeof(vars) !== "object" || !vars._tempKill)); //_tempKill is a super-secret way to delete a particular tweening property but NOT have it remembered as an official overwritten property (like in BezierPlugin) if (overwritingTween && (TweenLite.onOverwrite || this.vars.onOverwrite)) { for (p in killProps) { if (propLookup[p]) { if (!killed) { killed = []; } killed.push(p); } } if ((killed || !vars) && !_onOverwrite(this, overwritingTween, target, killed)) { //if the onOverwrite returned false, that means the user wants to override the overwriting (cancel it). return false; } } for (p in killProps) { if ((pt = propLookup[p])) { if (simultaneousOverwrite) { //if another tween overwrites this one and they both start at exactly the same time, yet this tween has already rendered once (for example, at 0.001) because it's first in the queue, we should revert the values to where they were at 0 so that the starting values aren't contaminated on the overwriting tween. if (pt.f) { pt.t[pt.p](pt.s); } else { pt.t[pt.p] = pt.s; } changed = true; } if (pt.pg && pt.t._kill(killProps)) { changed = true; //some plugins need to be notified so they can perform cleanup tasks first } if (!pt.pg || pt.t._overwriteProps.length === 0) { if (pt._prev) { pt._prev._next = pt._next; } else if (pt === this._firstPT) { this._firstPT = pt._next; } if (pt._next) { pt._next._prev = pt._prev; } pt._next = pt._prev = null; } delete propLookup[p]; } if (record) { overwrittenProps[p] = 1; } } if (!this._firstPT && this._initted && firstPT) { //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening. this._enabled(false, false); } } } return changed; }; p.invalidate = function() { if (this._notifyPluginsOfEnabled) { TweenLite._onPluginEvent("_onDisable", this); } var t = this._time; this._firstPT = this._overwrittenProps = this._startAt = this._onUpdate = null; this._notifyPluginsOfEnabled = this._active = this._lazy = false; this._propLookup = (this._targets) ? {} : []; Animation.prototype.invalidate.call(this); if (this.vars.immediateRender) { this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render) this.render(t, false, this.vars.lazy !== false); } return this; }; p._enabled = function(enabled, ignoreTimeline) { if (!_tickerActive) { _ticker.wake(); } if (enabled && this._gc) { var targets = this._targets, i; if (targets) { i = targets.length; while (--i > -1) { this._siblings[i] = _register(targets[i], this, true); } } else { this._siblings = _register(this.target, this, true); } } Animation.prototype._enabled.call(this, enabled, ignoreTimeline); if (this._notifyPluginsOfEnabled) if (this._firstPT) { return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this); } return false; }; //----TweenLite static methods ----------------------------------------------------- TweenLite.to = function(target, duration, vars) { return new TweenLite(target, duration, vars); }; TweenLite.from = function(target, duration, vars) { vars.runBackwards = true; vars.immediateRender = (vars.immediateRender != false); return new TweenLite(target, duration, vars); }; TweenLite.fromTo = function(target, duration, fromVars, toVars) { toVars.startAt = fromVars; toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); return new TweenLite(target, duration, toVars); }; TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) { return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, callbackScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, immediateRender:false, lazy:false, useFrames:useFrames, overwrite:0}); }; TweenLite.set = function(target, vars) { return new TweenLite(target, 0, vars); }; TweenLite.getTweensOf = function(target, onlyActive) { if (target == null) { return []; } target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target; var i, a, j, t; if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") { i = target.length; a = []; while (--i > -1) { a = a.concat(TweenLite.getTweensOf(target[i], onlyActive)); } i = a.length; //now get rid of any duplicates (tweens of arrays of objects could cause duplicates) while (--i > -1) { t = a[i]; j = i; while (--j > -1) { if (t === a[j]) { a.splice(i, 1); } } } } else if (target._gsTweenID) { a = _register(target).concat(); i = a.length; while (--i > -1) { if (a[i]._gc || (onlyActive && !a[i].isActive())) { a.splice(i, 1); } } } return a || []; }; TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) { if (typeof(onlyActive) === "object") { vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted) onlyActive = false; } var a = TweenLite.getTweensOf(target, onlyActive), i = a.length; while (--i > -1) { a[i]._kill(vars, target); } }; /* * ---------------------------------------------------------------- * TweenPlugin (could easily be split out as a separate file/class, but included for ease of use (so that people don't need to include another script call before loading plugins which is easy to forget) * ---------------------------------------------------------------- */ var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) { this._overwriteProps = (props || "").split(","); this._propName = this._overwriteProps[0]; this._priority = priority || 0; this._super = TweenPlugin.prototype; }, true); p = TweenPlugin.prototype; TweenPlugin.version = "1.19.0"; TweenPlugin.API = 2; p._firstPT = null; p._addTween = _addPropTween; p.setRatio = _setRatio; p._kill = function(lookup) { var a = this._overwriteProps, pt = this._firstPT, i; if (lookup[this._propName] != null) { this._overwriteProps = []; } else { i = a.length; while (--i > -1) { if (lookup[a[i]] != null) { a.splice(i, 1); } } } while (pt) { if (lookup[pt.n] != null) { if (pt._next) { pt._next._prev = pt._prev; } if (pt._prev) { pt._prev._next = pt._next; pt._prev = null; } else if (this._firstPT === pt) { this._firstPT = pt._next; } } pt = pt._next; } return false; }; p._mod = p._roundProps = function(lookup) { var pt = this._firstPT, val; while (pt) { val = lookup[this._propName] || (pt.n != null && lookup[ pt.n.split(this._propName + "_").join("") ]); if (val && typeof(val) === "function") { //some properties that are very plugin-specific add a prefix named after the _propName plus an underscore, so we need to ignore that extra stuff here. if (pt.f === 2) { pt.t._applyPT.m = val; } else { pt.m = val; } } pt = pt._next; } }; TweenLite._onPluginEvent = function(type, tween) { var pt = tween._firstPT, changed, pt2, first, last, next; if (type === "_onInitAllProps") { //sorts the PropTween linked list in order of priority because some plugins need to render earlier/later than others, like MotionBlurPlugin applies its effects after all x/y/alpha tweens have rendered on each frame. while (pt) { next = pt._next; pt2 = first; while (pt2 && pt2.pr > pt.pr) { pt2 = pt2._next; } if ((pt._prev = pt2 ? pt2._prev : last)) { pt._prev._next = pt; } else { first = pt; } if ((pt._next = pt2)) { pt2._prev = pt; } else { last = pt; } pt = next; } pt = tween._firstPT = first; } while (pt) { if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) { changed = true; } pt = pt._next; } return changed; }; TweenPlugin.activate = function(plugins) { var i = plugins.length; while (--i > -1) { if (plugins[i].API === TweenPlugin.API) { _plugins[(new plugins[i]())._propName] = plugins[i]; } } return true; }; //provides a more concise way to define plugins that have no dependencies besides TweenPlugin and TweenLite, wrapping common boilerplate stuff into one function (added in 1.9.0). You don't NEED to use this to define a plugin - the old way still works and can be useful in certain (rare) situations. _gsDefine.plugin = function(config) { if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; } var propName = config.propName, priority = config.priority || 0, overwriteProps = config.overwriteProps, map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_mod", mod:"_mod", initAll:"_onInitAllProps"}, Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin", function() { TweenPlugin.call(this, propName, priority); this._overwriteProps = overwriteProps || []; }, (config.global === true)), p = Plugin.prototype = new TweenPlugin(propName), prop; p.constructor = Plugin; Plugin.API = config.API; for (prop in map) { if (typeof(config[prop]) === "function") { p[map[prop]] = config[prop]; } } Plugin.version = config.version; TweenPlugin.activate([Plugin]); return Plugin; }; //now run through all the dependencies discovered and if any are missing, log that to the console as a warning. This is why it's best to have TweenLite load last - it can check all the dependencies for you. a = window._gsQueue; if (a) { for (i = 0; i < a.length; i++) { a[i](); } for (p in _defLookup) { if (!_defLookup[p].func) { window.console.log("GSAP encountered missing dependency: " + p); } } } _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated })((typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window, "TweenMax"); /*! * VERSION: 2.1.3 * DATE: 2019-05-17 * UPDATES AND DOCS AT: http://greensock.com * * @license Copyright (c) 2008-2019, GreenSock. All rights reserved. * This work is subject to the terms at http://greensock.com/standard-license or for * Club GreenSock members, the software agreement that was issued with your membership. * * @author: Jack Doyle, jack@greensock.com */ /* eslint-disable */ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node (_gsScope._gsQueue || (_gsScope._gsQueue = [])).push( function() { "use strict"; _gsScope._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) { var TimelineMax = function(vars) { TimelineLite.call(this, vars); this._repeat = this.vars.repeat || 0; this._repeatDelay = this.vars.repeatDelay || 0; this._cycle = 0; this._yoyo = !!this.vars.yoyo; this._dirty = true; }, _tinyNum = 0.00000001, TweenLiteInternals = TweenLite._internals, _lazyTweens = TweenLiteInternals.lazyTweens, _lazyRender = TweenLiteInternals.lazyRender, _globals = _gsScope._gsDefine.globals, _easeNone = new Ease(null, null, 1, 0), p = TimelineMax.prototype = new TimelineLite(); p.constructor = TimelineMax; p.kill()._gc = false; TimelineMax.version = "2.1.3"; p.invalidate = function() { this._yoyo = !!this.vars.yoyo; this._repeat = this.vars.repeat || 0; this._repeatDelay = this.vars.repeatDelay || 0; this._uncache(true); return TimelineLite.prototype.invalidate.call(this); }; p.addCallback = function(callback, position, params, scope) { return this.add( TweenLite.delayedCall(0, callback, params, scope), position); }; p.removeCallback = function(callback, position) { if (callback) { if (position == null) { this._kill(null, callback); } else { var a = this.getTweensOf(callback, false), i = a.length, time = this._parseTimeOrLabel(position); while (--i > -1) { if (a[i]._startTime === time) { a[i]._enabled(false, false); } } } } return this; }; p.removePause = function(position) { return this.removeCallback(TimelineLite._internals.pauseCallback, position); }; p.tweenTo = function(position, vars) { vars = vars || {}; var copy = {ease:_easeNone, useFrames:this.usesFrames(), immediateRender:false, lazy:false}, Engine = (vars.repeat && _globals.TweenMax) || TweenLite, duration, p, t; for (p in vars) { copy[p] = vars[p]; } copy.time = this._parseTimeOrLabel(position); duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001; t = new Engine(this, duration, copy); copy.onStart = function() { t.target.paused(true); if (t.vars.time !== t.target.time() && duration === t.duration() && !t.isFromTo) { //don't make the duration zero - if it's supposed to be zero, don't worry because it's already initting the tween and will complete immediately, effectively making the duration zero anyway. If we make duration zero, the tween won't run at all. t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale ).render(t.time(), true, true); //render() right away to ensure that things look right, especially in the case of .tweenTo(0). } if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it. vars.onStart.apply(vars.onStartScope || vars.callbackScope || t, vars.onStartParams || []); //don't use t._callback("onStart") or it'll point to the copy.onStart and we'll get a recursion error. } }; return t; }; p.tweenFromTo = function(fromPosition, toPosition, vars) { vars = vars || {}; fromPosition = this._parseTimeOrLabel(fromPosition); vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], callbackScope:this}; vars.immediateRender = (vars.immediateRender !== false); var t = this.tweenTo(toPosition, vars); t.isFromTo = 1; //to ensure we don't mess with the duration in the onStart (we've got the start and end values here, so lock it in) return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001); }; p.render = function(time, suppressEvents, force) { if (this._gc) { this._enabled(true, false); } var self = this, prevTime = self._time, totalDur = (!self._dirty) ? self._totalDuration : self.totalDuration(), dur = self._duration, prevTotalTime = self._totalTime, prevStart = self._startTime, prevTimeScale = self._timeScale, prevRawPrevTime = self._rawPrevTime, prevPaused = self._paused, prevCycle = self._cycle, tween, isComplete, next, callback, internalForce, cycleDuration, pauseTween, curTime, pauseTime; if (prevTime !== self._time) { //if totalDuration() finds a child with a negative startTime and smoothChildTiming is true, things get shifted around internally so we need to adjust the time accordingly. For example, if a tween starts at -30 we must shift EVERYTHING forward 30 seconds and move this timeline's startTime backward by 30 seconds so that things align with the playhead (no jump). time += self._time - prevTime; } if (time >= totalDur - _tinyNum && time >= 0) { //to work around occasional floating point math artifacts. if (!self._locked) { self._totalTime = totalDur; self._cycle = self._repeat; } if (!self._reversed) if (!self._hasPausedChild()) { isComplete = true; callback = "onComplete"; internalForce = !!self._timeline.autoRemoveChildren; //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline. if (self._duration === 0) if ((time <= 0 && time >= -_tinyNum) || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && self._first) { internalForce = true; if (prevRawPrevTime > _tinyNum) { callback = "onReverseComplete"; } } } self._rawPrevTime = (self._duration || !suppressEvents || time || self._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. if (self._yoyo && (self._cycle & 1)) { self._time = time = 0; } else { self._time = dur; time = dur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7. We cannot do less then 0.0001 because the same issue can occur when the duration is extremely large like 999999999999 in which case adding 0.00000001, for example, causes it to act like nothing was added. } } else if (time < _tinyNum) { //to work around occasional floating point math artifacts, round super small values to 0. if (!self._locked) { self._totalTime = self._cycle = 0; } self._time = 0; if (time > -_tinyNum) { time = 0; } if (prevTime !== 0 || (dur === 0 && prevRawPrevTime !== _tinyNum && (prevRawPrevTime > 0 || (time < 0 && prevRawPrevTime >= 0)) && !self._locked)) { //edge case for checking time < 0 && prevRawPrevTime >= 0: a zero-duration fromTo() tween inside a zero-duration timeline (yeah, very rare) callback = "onReverseComplete"; isComplete = self._reversed; } if (time < 0) { self._active = false; if (self._timeline.autoRemoveChildren && self._reversed) { internalForce = isComplete = true; callback = "onReverseComplete"; } else if (prevRawPrevTime >= 0 && self._first) { //when going back beyond the start, force a render so that zero-duration tweens that sit at the very beginning render their start values properly. Otherwise, if the parent timeline's playhead lands exactly at this timeline's startTime, and then moves backwards, the zero-duration tweens at the beginning would still be at their end state. internalForce = true; } self._rawPrevTime = time; } else { self._rawPrevTime = (dur || !suppressEvents || time || self._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. if (time === 0 && isComplete) { //if there's a zero-duration tween at the very beginning of a timeline and the playhead lands EXACTLY at time 0, that tween will correctly render its end values, but we need to keep the timeline alive for one more render so that the beginning values render properly as the parent's playhead keeps moving beyond the begining. Imagine obj.x starts at 0 and then we do tl.set(obj, {x:100}).to(obj, 1, {x:200}) and then later we tl.reverse()...the goal is to have obj.x revert to 0. If the playhead happens to land on exactly 0, without this chunk of code, it'd complete the timeline and remove it from the rendering queue (not good). tween = self._first; while (tween && tween._startTime === 0) { if (!tween._duration) { isComplete = false; } tween = tween._next; } } time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline) if (!self._initted) { internalForce = true; } } } else { if (dur === 0 && prevRawPrevTime < 0) { //without this, zero-duration repeating timelines (like with a simple callback nested at the very beginning and a repeatDelay) wouldn't render the first time through. internalForce = true; } self._time = self._rawPrevTime = time; if (!self._locked) { self._totalTime = time; if (self._repeat !== 0) { cycleDuration = dur + self._repeatDelay; self._cycle = (self._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but it gets reported as 0.79999999!) if (self._cycle) if (self._cycle === self._totalTime / cycleDuration && prevTotalTime <= time) { self._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning) } self._time = self._totalTime - (self._cycle * cycleDuration); if (self._yoyo) if (self._cycle & 1) { self._time = dur - self._time; } if (self._time > dur) { self._time = dur; time = dur + 0.0001; //to avoid occasional floating point rounding error } else if (self._time < 0) { self._time = time = 0; } else { time = self._time; } } } } if (self._hasPause && !self._forcingPlayhead && !suppressEvents) { time = self._time; if (time > prevTime || (self._repeat && prevCycle !== self._cycle)) { tween = self._first; while (tween && tween._startTime <= time && !pauseTween) { if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) { pauseTween = tween; } tween = tween._next; } } else { tween = self._last; while (tween && tween._startTime >= time && !pauseTween) { if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) { pauseTween = tween; } tween = tween._prev; } } if (pauseTween) { pauseTime = self._startTime + (self._reversed ? self._duration - pauseTween._startTime : pauseTween._startTime) / self._timeScale; if (pauseTween._startTime < dur) { self._time = self._rawPrevTime = time = pauseTween._startTime; self._totalTime = time + (self._cycle * (self._totalDuration + self._repeatDelay)); } } } if (self._cycle !== prevCycle) if (!self._locked) { /* make sure children at the end/beginning of the timeline are rendered properly. If, for example, a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which would get translated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must ensure that zero-duration tweens at the very beginning or end of the TimelineMax work. */ var backwards = (self._yoyo && (prevCycle & 1) !== 0), wrap = (backwards === (self._yoyo && (self._cycle & 1) !== 0)), recTotalTime = self._totalTime, recCycle = self._cycle, recRawPrevTime = self._rawPrevTime, recTime = self._time; self._totalTime = prevCycle * dur; if (self._cycle < prevCycle) { backwards = !backwards; } else { self._totalTime += dur; } self._time = prevTime; //temporarily revert _time so that render() renders the children in the correct order. Without this, tweens won't rewind correctly. We could arhictect things in a "cleaner" way by splitting out the rendering queue into a separate method but for performance reasons, we kept it all inside this method. self._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime; self._cycle = prevCycle; self._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render() prevTime = (backwards) ? 0 : dur; self.render(prevTime, suppressEvents, (dur === 0)); if (!suppressEvents) if (!self._gc) { if (self.vars.onRepeat) { self._cycle = recCycle; //in case the onRepeat alters the playhead or invalidates(), we shouldn't stay locked or use the previous cycle. self._locked = false; self._callback("onRepeat"); } } if (prevTime !== self._time) { //in case there's a callback like onComplete in a nested tween/timeline that changes the playhead position, like via seek(), we should just abort. return; } if (wrap) { self._cycle = prevCycle; //if there's an onRepeat, we reverted this above, so make sure it's set properly again. We also unlocked in that scenario, so reset that too. self._locked = true; prevTime = (backwards) ? dur + 0.0001 : -0.0001; self.render(prevTime, true, false); } self._locked = false; if (self._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible) return; } self._time = recTime; self._totalTime = recTotalTime; self._cycle = recCycle; self._rawPrevTime = recRawPrevTime; } if ((self._time === prevTime || !self._first) && !force && !internalForce && !pauseTween) { if (prevTotalTime !== self._totalTime) if (self._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate. self._callback("onUpdate"); } return; } else if (!self._initted) { self._initted = true; } if (!self._active) if (!self._paused && self._totalTime !== prevTotalTime && time > 0) { self._active = true; //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example. } if (prevTotalTime === 0) if (self.vars.onStart) if (self._totalTime !== 0 || !self._totalDuration) if (!suppressEvents) { self._callback("onStart"); } curTime = self._time; if (curTime >= prevTime) { tween = self._first; while (tween) { next = tween._next; //record it here because the value could change after rendering... if (curTime !== self._time || (self._paused && !prevPaused)) { //in case a tween pauses or seeks the timeline when rendering, like inside of an onUpdate/onComplete break; } else if (tween._active || (tween._startTime <= self._time && !tween._paused && !tween._gc)) { if (pauseTween === tween) { self.pause(); self._pauseTime = pauseTime; //so that when we resume(), it's starting from exactly the right spot (the pause() method uses the rawTime for the parent, but that may be a bit too far ahead) } if (!tween._reversed) { tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); } else { tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); } } tween = next; } } else { tween = self._last; while (tween) { next = tween._prev; //record it here because the value could change after rendering... if (curTime !== self._time || (self._paused && !prevPaused)) { //in case a tween pauses or seeks the timeline when rendering, like inside of an onUpdate/onComplete break; } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) { if (pauseTween === tween) { pauseTween = tween._prev; //the linked list is organized by _startTime, thus it's possible that a tween could start BEFORE the pause and end after it, in which case it would be positioned before the pause tween in the linked list, but we should render it before we pause() the timeline and cease rendering. This is only a concern when going in reverse. while (pauseTween && pauseTween.endTime() > self._time) { pauseTween.render( (pauseTween._reversed ? pauseTween.totalDuration() - ((time - pauseTween._startTime) * pauseTween._timeScale) : (time - pauseTween._startTime) * pauseTween._timeScale), suppressEvents, force); pauseTween = pauseTween._prev; } pauseTween = null; self.pause(); self._pauseTime = pauseTime; //so that when we resume(), it's starting from exactly the right spot (the pause() method uses the rawTime for the parent, but that may be a bit too far ahead) } if (!tween._reversed) { tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); } else { tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); } } tween = next; } } if (self._onUpdate) if (!suppressEvents) { if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onUpdate on a timeline that reports/checks tweened values. _lazyRender(); } self._callback("onUpdate"); } if (callback) if (!self._locked) if (!self._gc) if (prevStart === self._startTime || prevTimeScale !== self._timeScale) if (self._time === 0 || totalDur >= self.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate if (isComplete) { if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onComplete on a timeline that reports/checks tweened values. _lazyRender(); } if (self._timeline.autoRemoveChildren) { self._enabled(false, false); } self._active = false; } if (!suppressEvents && self.vars[callback]) { self._callback(callback); } } }; p.getActive = function(nested, tweens, timelines) { var a = [], all = this.getChildren(nested || (nested == null), tweens || (nested == null), !!timelines), cnt = 0, l = all.length, i, tween; for (i = 0; i < l; i++) { tween = all[i]; if (tween.isActive()) { a[cnt++] = tween; } } return a; }; p.getLabelAfter = function(time) { if (!time) if (time !== 0) { //faster than isNan() time = this._time; } var labels = this.getLabelsArray(), l = labels.length, i; for (i = 0; i < l; i++) { if (labels[i].time > time) { return labels[i].name; } } return null; }; p.getLabelBefore = function(time) { if (time == null) { time = this._time; } var labels = this.getLabelsArray(), i = labels.length; while (--i > -1) { if (labels[i].time < time) { return labels[i].name; } } return null; }; p.getLabelsArray = function() { var a = [], cnt = 0, p; for (p in this._labels) { a[cnt++] = {time:this._labels[p], name:p}; } a.sort(function(a,b) { return a.time - b.time; }); return a; }; p.invalidate = function() { this._locked = false; //unlock and set cycle in case invalidate() is called from inside an onRepeat return TimelineLite.prototype.invalidate.call(this); }; //---- GETTERS / SETTERS ------------------------------------------------------------------------------------------------------- p.progress = function(value, suppressEvents) { return (!arguments.length) ? (this._time / this.duration()) || 0 : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), suppressEvents); }; p.totalProgress = function(value, suppressEvents) { return (!arguments.length) ? (this._totalTime / this.totalDuration()) || 0 : this.totalTime( this.totalDuration() * value, suppressEvents); }; p.totalDuration = function(value) { if (!arguments.length) { if (this._dirty) { TimelineLite.prototype.totalDuration.call(this); //just forces refresh //Instead of Infinity, we use 999999999999 so that we can accommodate reverses. this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat); } return this._totalDuration; } return (this._repeat === -1 || !value) ? this : this.timeScale( this.totalDuration() / value ); }; p.time = function(value, suppressEvents) { if (!arguments.length) { return this._time; } if (this._dirty) { this.totalDuration(); } var duration = this._duration, cycle = this._cycle, cycleDur = cycle * (duration + this._repeatDelay); if (value > duration) { value = duration; } return this.totalTime((this._yoyo && (cycle & 1)) ? duration - value + cycleDur : this._repeat ? value + cycleDur : value, suppressEvents); }; p.repeat = function(value) { if (!arguments.length) { return this._repeat; } this._repeat = value; return this._uncache(true); }; p.repeatDelay = function(value) { if (!arguments.length) { return this._repeatDelay; } this._repeatDelay = value; return this._uncache(true); }; p.yoyo = function(value) { if (!arguments.length) { return this._yoyo; } this._yoyo = value; return this; }; p.currentLabel = function(value) { if (!arguments.length) { return this.getLabelBefore(this._time + _tinyNum); } return this.seek(value, true); }; return TimelineMax; }, true); /* * ---------------------------------------------------------------- * TimelineLite * ---------------------------------------------------------------- */ _gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) { var TimelineLite = function(vars) { SimpleTimeline.call(this, vars); var self = this, v = self.vars, val, p; self._labels = {}; self.autoRemoveChildren = !!v.autoRemoveChildren; self.smoothChildTiming = !!v.smoothChildTiming; self._sortChildren = true; self._onUpdate = v.onUpdate; for (p in v) { val = v[p]; if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) { v[p] = self._swapSelfInParams(val); } } if (_isArray(v.tweens)) { self.add(v.tweens, 0, v.align, v.stagger); } }, _tinyNum = 0.00000001, TweenLiteInternals = TweenLite._internals, _internals = TimelineLite._internals = {}, _isSelector = TweenLiteInternals.isSelector, _isArray = TweenLiteInternals.isArray, _lazyTweens = TweenLiteInternals.lazyTweens, _lazyRender = TweenLiteInternals.lazyRender, _globals = _gsScope._gsDefine.globals, _copy = function(vars) { var copy = {}, p; for (p in vars) { copy[p] = vars[p]; } return copy; }, _applyCycle = function(vars, targets, i) { var alt = vars.cycle, p, val; for (p in alt) { val = alt[p]; vars[p] = (typeof(val) === "function") ? val(i, targets[i], targets) : val[i % val.length]; } delete vars.cycle; }, _pauseCallback = _internals.pauseCallback = function() {}, _slice = function(a) { //don't use [].slice because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll() var b = [], l = a.length, i; for (i = 0; i !== l; b.push(a[i++])); return b; }, _defaultImmediateRender = function(tl, toVars, fromVars, defaultFalse) { //default to immediateRender:true unless otherwise set in toVars, fromVars or if defaultFalse is passed in as true var ir = "immediateRender"; if (!(ir in toVars)) { toVars[ir] = !((fromVars && fromVars[ir] === false) || defaultFalse); } return toVars; }, //for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following _distribute = function(v) { if (typeof(v) === "function") { return v; } var vars = (typeof(v) === "object") ? v : {each:v}, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all. ease = vars.ease, from = vars.from || 0, base = vars.base || 0, cache = {}, isFromKeyword = isNaN(from), axis = vars.axis, ratio = {center:0.5, end:1}[from] || 0; return function(i, target, a) { var l = (a || vars).length, distances = cache[l], originX, originY, x, y, d, j, max, min, wrap; if (!distances) { wrap = (vars.grid === "auto") ? 0 : (vars.grid || [Infinity])[0]; if (!wrap) { max = -Infinity; while (max < (max = a[wrap++].getBoundingClientRect().left) && wrap < l) { } wrap--; } distances = cache[l] = []; originX = isFromKeyword ? (Math.min(wrap, l) * ratio) - 0.5 : from % wrap; originY = isFromKeyword ? l * ratio / wrap - 0.5 : (from / wrap) | 0; max = 0; min = Infinity; for (j = 0; j < l; j++) { x = (j % wrap) - originX; y = originY - ((j / wrap) | 0); distances[j] = d = !axis ? Math.sqrt(x * x + y * y) : Math.abs((axis === "y") ? y : x); if (d > max) { max = d; } if (d < min) { min = d; } } distances.max = max - min; distances.min = min; distances.v = l = vars.amount || (vars.each * (wrap > l ? l - 1 : !axis ? Math.max(wrap, l / wrap) : axis === "y" ? l / wrap : wrap)) || 0; distances.b = (l < 0) ? base - l : base; } l = (distances[i] - distances.min) / distances.max; return distances.b + (ease ? ease.getRatio(l) : l) * distances.v; }; }, p = TimelineLite.prototype = new SimpleTimeline(); TimelineLite.version = "2.1.3"; TimelineLite.distribute = _distribute; p.constructor = TimelineLite; p.kill()._gc = p._forcingPlayhead = p._hasPause = false; /* might use later... //translates a local time inside an animation to the corresponding time on the root/global timeline, factoring in all nesting and timeScales. function localToGlobal(time, animation) { while (animation) { time = (time / animation._timeScale) + animation._startTime; animation = animation.timeline; } return time; } //translates the supplied time on the root/global timeline into the corresponding local time inside a particular animation, factoring in all nesting and timeScales function globalToLocal(time, animation) { var scale = 1; time -= localToGlobal(0, animation); while (animation) { scale *= animation._timeScale; animation = animation.timeline; } return time * scale; } */ p.to = function(target, duration, vars, position) { var Engine = (vars.repeat && _globals.TweenMax) || TweenLite; return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position); }; p.from = function(target, duration, vars, position) { return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, _defaultImmediateRender(this, vars)), position); }; p.fromTo = function(target, duration, fromVars, toVars, position) { var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite; toVars = _defaultImmediateRender(this, toVars, fromVars); return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position); }; p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, callbackScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}), staggerFunc = _distribute(vars.stagger || stagger), startAt = vars.startAt, cycle = vars.cycle, copy, i; if (typeof(targets) === "string") { targets = TweenLite.selector(targets) || targets; } targets = targets || []; if (_isSelector(targets)) { //if the targets object is a selector, translate it into an array. targets = _slice(targets); } for (i = 0; i < targets.length; i++) { copy = _copy(vars); if (startAt) { copy.startAt = _copy(startAt); if (startAt.cycle) { _applyCycle(copy.startAt, targets, i); } } if (cycle) { _applyCycle(copy, targets, i); if (copy.duration != null) { duration = copy.duration; delete copy.duration; } } tl.to(targets[i], duration, copy, staggerFunc(i, targets[i], targets)); } return this.add(tl, position); }; p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { vars.runBackwards = true; return this.staggerTo(targets, duration, _defaultImmediateRender(this, vars), stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope); }; p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { toVars.startAt = fromVars; return this.staggerTo(targets, duration, _defaultImmediateRender(this, toVars, fromVars), stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope); }; p.call = function(callback, params, scope, position) { return this.add( TweenLite.delayedCall(0, callback, params, scope), position); }; p.set = function(target, vars, position) { return this.add( new TweenLite(target, 0, _defaultImmediateRender(this, vars, null, true)), position); }; TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) { vars = vars || {}; if (vars.smoothChildTiming == null) { vars.smoothChildTiming = true; } var tl = new TimelineLite(vars), root = tl._timeline, hasNegativeStart, time, tween, next; if (ignoreDelayedCalls == null) { ignoreDelayedCalls = true; } root._remove(tl, true); tl._startTime = 0; tl._rawPrevTime = tl._time = tl._totalTime = root._time; tween = root._first; while (tween) { next = tween._next; if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) { time = tween._startTime - tween._delay; if (time < 0) { hasNegativeStart = 1; } tl.add(tween, time); } tween = next; } root.add(tl, 0); if (hasNegativeStart) { //calling totalDuration() will force the adjustment necessary to shift the children forward so none of them start before zero, and moves the timeline backwards the same amount, so the playhead is still aligned where it should be globally, but the timeline doesn't have illegal children that start before zero. tl.totalDuration(); } return tl; }; p.add = function(value, position, align, stagger) { var self = this, curTime, l, i, child, tl, beforeRawTime; if (typeof(position) !== "number") { position = self._parseTimeOrLabel(position, 0, true, value); } if (!(value instanceof Animation)) { if ((value instanceof Array) || (value && value.push && _isArray(value))) { align = align || "normal"; stagger = stagger || 0; curTime = position; l = value.length; for (i = 0; i < l; i++) { if (_isArray(child = value[i])) { child = new TimelineLite({tweens:child}); } self.add(child, curTime); if (typeof(child) !== "string" && typeof(child) !== "function") { if (align === "sequence") { curTime = child._startTime + (child.totalDuration() / child._timeScale); } else if (align === "start") { child._startTime -= child.delay(); } } curTime += stagger; } return self._uncache(true); } else if (typeof(value) === "string") { return self.addLabel(value, position); } else if (typeof(value) === "function") { value = TweenLite.delayedCall(0, value); } else { throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string."); } } SimpleTimeline.prototype.add.call(self, value, position); if (value._time || (!value._duration && value._initted)) { //in case, for example, the _startTime is moved on a tween that has already rendered. Imagine it's at its end state, then the startTime is moved WAY later (after the end of this timeline), it should render at its beginning. curTime = (self.rawTime() - value._startTime) * value._timeScale; if (!value._duration || Math.abs(Math.max(0, Math.min(value.totalDuration(), curTime))) - value._totalTime > 0.00001) { value.render(curTime, false, false); } } //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly. We should also align the playhead with the parent timeline's when appropriate. if (self._gc || self._time === self._duration) if (!self._paused) if (self._duration < self.duration()) { //in case any of the ancestors had completed but should now be enabled... tl = self; beforeRawTime = (tl.rawTime() > value._startTime); //if the tween is placed on the timeline so that it starts BEFORE the current rawTime, we should align the playhead (move the timeline). This is because sometimes users will create a timeline, let it finish, and much later append a tween and expect it to run instead of jumping to its end state. While technically one could argue that it should jump to its end state, that's not what users intuitively expect. while (tl._timeline) { if (beforeRawTime && tl._timeline.smoothChildTiming) { tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it. } else if (tl._gc) { tl._enabled(true, false); } tl = tl._timeline; } } return self; }; p.remove = function(value) { if (value instanceof Animation) { this._remove(value, false); var tl = value._timeline = value.vars.useFrames ? Animation._rootFramesTimeline : Animation._rootTimeline; //now that it's removed, default it to the root timeline so that if it gets played again, it doesn't jump back into this timeline. value._startTime = (value._paused ? value._pauseTime : tl._time) - ((!value._reversed ? value._totalTime : value.totalDuration() - value._totalTime) / value._timeScale); //ensure that if it gets played again, the timing is correct. return this; } else if (value instanceof Array || (value && value.push && _isArray(value))) { var i = value.length; while (--i > -1) { this.remove(value[i]); } return this; } else if (typeof(value) === "string") { return this.removeLabel(value); } return this.kill(null, value); }; p._remove = function(tween, skipDisable) { SimpleTimeline.prototype._remove.call(this, tween, skipDisable); var last = this._last; if (!last) { this._time = this._totalTime = this._duration = this._totalDuration = 0; } else if (this._time > this.duration()) { this._time = this._duration; this._totalTime = this._totalDuration; } return this; }; p.append = function(value, offsetOrLabel) { return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value)); }; p.insert = p.insertMultiple = function(value, position, align, stagger) { return this.add(value, position || 0, align, stagger); }; p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) { return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger); }; p.addLabel = function(label, position) { this._labels[label] = this._parseTimeOrLabel(position); return this; }; p.addPause = function(position, callback, params, scope) { var t = TweenLite.delayedCall(0, _pauseCallback, params, scope || this); t.vars.onComplete = t.vars.onReverseComplete = callback; t.data = "isPause"; this._hasPause = true; return this.add(t, position); }; p.removeLabel = function(label) { delete this._labels[label]; return this; }; p.getLabelTime = function(label) { return (this._labels[label] != null) ? this._labels[label] : -1; }; p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) { var clippedDuration, i; //if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration(). if (ignore instanceof Animation && ignore.timeline === this) { this.remove(ignore); } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) { i = ignore.length; while (--i > -1) { if (ignore[i] instanceof Animation && ignore[i].timeline === this) { this.remove(ignore[i]); } } } clippedDuration = (typeof(timeOrLabel) === "number" && !offsetOrLabel) ? 0 : (this.duration() > 99999999999) ? this.recent().endTime(false) : this._duration; //in case there's a child that infinitely repeats, users almost never intend for the insertion point of a new child to be based on a SUPER long value like that so we clip it and assume the most recently-added child's endTime should be used instead. if (typeof(offsetOrLabel) === "string") { return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - clippedDuration : 0, appendIfAbsent); } offsetOrLabel = offsetOrLabel || 0; if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value). i = timeOrLabel.indexOf("="); if (i === -1) { if (this._labels[timeOrLabel] == null) { return appendIfAbsent ? (this._labels[timeOrLabel] = clippedDuration + offsetOrLabel) : offsetOrLabel; } return this._labels[timeOrLabel] + offsetOrLabel; } offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1)); timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : clippedDuration; } else if (timeOrLabel == null) { timeOrLabel = clippedDuration; } return Number(timeOrLabel) + offsetOrLabel; }; p.seek = function(position, suppressEvents) { return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false)); }; p.stop = function() { return this.paused(true); }; p.gotoAndPlay = function(position, suppressEvents) { return this.play(position, suppressEvents); }; p.gotoAndStop = function(position, suppressEvents) { return this.pause(position, suppressEvents); }; p.render = function(time, suppressEvents, force) { if (this._gc) { this._enabled(true, false); } var self = this, prevTime = self._time, totalDur = (!self._dirty) ? self._totalDuration : self.totalDuration(), prevStart = self._startTime, prevTimeScale = self._timeScale, prevPaused = self._paused, tween, isComplete, next, callback, internalForce, pauseTween, curTime, pauseTime; if (prevTime !== self._time) { //if totalDuration() finds a child with a negative startTime and smoothChildTiming is true, things get shifted around internally so we need to adjust the time accordingly. For example, if a tween starts at -30 we must shift EVERYTHING forward 30 seconds and move this timeline's startTime backward by 30 seconds so that things align with the playhead (no jump). time += self._time - prevTime; } if (self._hasPause && !self._forcingPlayhead && !suppressEvents) { if (time > prevTime) { tween = self._first; while (tween && tween._startTime <= time && !pauseTween) { if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && self._rawPrevTime === 0)) { pauseTween = tween; } tween = tween._next; } } else { tween = self._last; while (tween && tween._startTime >= time && !pauseTween) { if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) { pauseTween = tween; } tween = tween._prev; } } if (pauseTween) { self._time = self._totalTime = time = pauseTween._startTime; pauseTime = self._startTime + (self._reversed ? self._duration - time : time) / self._timeScale; } } if (time >= totalDur - _tinyNum && time >= 0) { //to work around occasional floating point math artifacts. self._totalTime = self._time = totalDur; if (!self._reversed) if (!self._hasPausedChild()) { isComplete = true; callback = "onComplete"; internalForce = !!self._timeline.autoRemoveChildren; //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline. if (self._duration === 0) if ((time <= 0 && time >= -_tinyNum) || self._rawPrevTime < 0 || self._rawPrevTime === _tinyNum) if (self._rawPrevTime !== time && self._first) { internalForce = true; if (self._rawPrevTime > _tinyNum) { callback = "onReverseComplete"; } } } self._rawPrevTime = (self._duration || !suppressEvents || time || self._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. time = totalDur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7. } else if (time < _tinyNum) { //to work around occasional floating point math artifacts, round super small values to 0. self._totalTime = self._time = 0; if (time > -_tinyNum) { time = 0; } if (prevTime !== 0 || (self._duration === 0 && self._rawPrevTime !== _tinyNum && (self._rawPrevTime > 0 || (time < 0 && self._rawPrevTime >= 0)))) { callback = "onReverseComplete"; isComplete = self._reversed; } if (time < 0) { self._active = false; if (self._timeline.autoRemoveChildren && self._reversed) { //ensures proper GC if a timeline is resumed after it's finished reversing. internalForce = isComplete = true; callback = "onReverseComplete"; } else if (self._rawPrevTime >= 0 && self._first) { //when going back beyond the start, force a render so that zero-duration tweens that sit at the very beginning render their start values properly. Otherwise, if the parent timeline's playhead lands exactly at this timeline's startTime, and then moves backwards, the zero-duration tweens at the beginning would still be at their end state. internalForce = true; } self._rawPrevTime = time; } else { self._rawPrevTime = (self._duration || !suppressEvents || time || self._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. if (time === 0 && isComplete) { //if there's a zero-duration tween at the very beginning of a timeline and the playhead lands EXACTLY at time 0, that tween will correctly render its end values, but we need to keep the timeline alive for one more render so that the beginning values render properly as the parent's playhead keeps moving beyond the begining. Imagine obj.x starts at 0 and then we do tl.set(obj, {x:100}).to(obj, 1, {x:200}) and then later we tl.reverse()...the goal is to have obj.x revert to 0. If the playhead happens to land on exactly 0, without this chunk of code, it'd complete the timeline and remove it from the rendering queue (not good). tween = self._first; while (tween && tween._startTime === 0) { if (!tween._duration) { isComplete = false; } tween = tween._next; } } time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline) if (!self._initted) { internalForce = true; } } } else { self._totalTime = self._time = self._rawPrevTime = time; } if ((self._time === prevTime || !self._first) && !force && !internalForce && !pauseTween) { return; } else if (!self._initted) { self._initted = true; } if (!self._active) if (!self._paused && self._time !== prevTime && time > 0) { self._active = true; //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example. } if (prevTime === 0) if (self.vars.onStart) if (self._time !== 0 || !self._duration) if (!suppressEvents) { self._callback("onStart"); } curTime = self._time; if (curTime >= prevTime) { tween = self._first; while (tween) { next = tween._next; //record it here because the value could change after rendering... if (curTime !== self._time || (self._paused && !prevPaused)) { //in case a tween pauses or seeks the timeline when rendering, like inside of an onUpdate/onComplete break; } else if (tween._active || (tween._startTime <= curTime && !tween._paused && !tween._gc)) { if (pauseTween === tween) { self.pause(); self._pauseTime = pauseTime; //so that when we resume(), it's starting from exactly the right spot (the pause() method uses the rawTime for the parent, but that may be a bit too far ahead) } if (!tween._reversed) { tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); } else { tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); } } tween = next; } } else { tween = self._last; while (tween) { next = tween._prev; //record it here because the value could change after rendering... if (curTime !== self._time || (self._paused && !prevPaused)) { //in case a tween pauses or seeks the timeline when rendering, like inside of an onUpdate/onComplete break; } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) { if (pauseTween === tween) { pauseTween = tween._prev; //the linked list is organized by _startTime, thus it's possible that a tween could start BEFORE the pause and end after it, in which case it would be positioned before the pause tween in the linked list, but we should render it before we pause() the timeline and cease rendering. This is only a concern when going in reverse. while (pauseTween && pauseTween.endTime() > self._time) { pauseTween.render( (pauseTween._reversed ? pauseTween.totalDuration() - ((time - pauseTween._startTime) * pauseTween._timeScale) : (time - pauseTween._startTime) * pauseTween._timeScale), suppressEvents, force); pauseTween = pauseTween._prev; } pauseTween = null; self.pause(); self._pauseTime = pauseTime; //so that when we resume(), it's starting from exactly the right spot (the pause() method uses the rawTime for the parent, but that may be a bit too far ahead) } if (!tween._reversed) { tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); } else { tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); } } tween = next; } } if (self._onUpdate) if (!suppressEvents) { if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onUpdate on a timeline that reports/checks tweened values. _lazyRender(); } self._callback("onUpdate"); } if (callback) if (!self._gc) if (prevStart === self._startTime || prevTimeScale !== self._timeScale) if (self._time === 0 || totalDur >= self.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate if (isComplete) { if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onComplete on a timeline that reports/checks tweened values. _lazyRender(); } if (self._timeline.autoRemoveChildren) { self._enabled(false, false); } self._active = false; } if (!suppressEvents && self.vars[callback]) { self._callback(callback); } } }; p._hasPausedChild = function() { var tween = this._first; while (tween) { if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) { return true; } tween = tween._next; } return false; }; p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) { ignoreBeforeTime = ignoreBeforeTime || -9999999999; var a = [], tween = this._first, cnt = 0; while (tween) { if (tween._startTime < ignoreBeforeTime) { //do nothing } else if (tween instanceof TweenLite) { if (tweens !== false) { a[cnt++] = tween; } } else { if (timelines !== false) { a[cnt++] = tween; } if (nested !== false) { a = a.concat(tween.getChildren(true, tweens, timelines)); cnt = a.length; } } tween = tween._next; } return a; }; p.getTweensOf = function(target, nested) { var disabled = this._gc, a = [], cnt = 0, tweens, i; if (disabled) { this._enabled(true, true); //getTweensOf() filters out disabled tweens, and we have to mark them as _gc = true when the timeline completes in order to allow clean garbage collection, so temporarily re-enable the timeline here. } tweens = TweenLite.getTweensOf(target); i = tweens.length; while (--i > -1) { if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) { a[cnt++] = tweens[i]; } } if (disabled) { this._enabled(false, true); } return a; }; p.recent = function() { return this._recent; }; p._contains = function(tween) { var tl = tween.timeline; while (tl) { if (tl === this) { return true; } tl = tl.timeline; } return false; }; p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) { ignoreBeforeTime = ignoreBeforeTime || 0; var tween = this._first, labels = this._labels, p; while (tween) { if (tween._startTime >= ignoreBeforeTime) { tween._startTime += amount; } tween = tween._next; } if (adjustLabels) { for (p in labels) { if (labels[p] >= ignoreBeforeTime) { labels[p] += amount; } } } return this._uncache(true); }; p._kill = function(vars, target) { if (!vars && !target) { return this._enabled(false, false); } var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target), i = tweens.length, changed = false; while (--i > -1) { if (tweens[i]._kill(vars, target)) { changed = true; } } return changed; }; p.clear = function(labels) { var tweens = this.getChildren(false, true, true), i = tweens.length; this._time = this._totalTime = 0; while (--i > -1) { tweens[i]._enabled(false, false); } if (labels !== false) { this._labels = {}; } return this._uncache(true); }; p.invalidate = function() { var tween = this._first; while (tween) { tween.invalidate(); tween = tween._next; } return Animation.prototype.invalidate.call(this);; }; p._enabled = function(enabled, ignoreTimeline) { if (enabled === this._gc) { var tween = this._first; while (tween) { tween._enabled(enabled, true); tween = tween._next; } } return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline); }; p.totalTime = function(time, suppressEvents, uncapped) { this._forcingPlayhead = true; var val = Animation.prototype.totalTime.apply(this, arguments); this._forcingPlayhead = false; return val; }; p.duration = function(value) { if (!arguments.length) { if (this._dirty) { this.totalDuration(); //just triggers recalculation } return this._duration; } if (this.duration() !== 0 && value !== 0) { this.timeScale(this._duration / value); } return this; }; p.totalDuration = function(value) { if (!arguments.length) { if (this._dirty) { var max = 0, self = this, tween = self._last, prevStart = 999999999999, prev, end; while (tween) { prev = tween._prev; //record it here in case the tween changes position in the sequence... if (tween._dirty) { tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it. } if (tween._startTime > prevStart && self._sortChildren && !tween._paused && !self._calculatingDuration) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence self._calculatingDuration = 1; //prevent endless recursive calls - there are methods that get triggered that check duration/totalDuration when we add(), like _parseTimeOrLabel(). self.add(tween, tween._startTime - tween._delay); self._calculatingDuration = 0; } else { prevStart = tween._startTime; } if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found. max -= tween._startTime; if (self._timeline.smoothChildTiming) { self._startTime += tween._startTime / self._timeScale; self._time -= tween._startTime; self._totalTime -= tween._startTime; self._rawPrevTime -= tween._startTime; } self.shiftChildren(-tween._startTime, false, -9999999999); prevStart = 0; } end = tween._startTime + (tween._totalDuration / tween._timeScale); if (end > max) { max = end; } tween = prev; } self._duration = self._totalDuration = max; self._dirty = false; } return this._totalDuration; } return (value && this.totalDuration()) ? this.timeScale(this._totalDuration / value) : this; }; p.paused = function(value) { if (value === false && this._paused) { //if there's a pause directly at the spot from where we're unpausing, skip it. var tween = this._first; while (tween) { if (tween._startTime === this._time && tween.data === "isPause") { tween._rawPrevTime = 0; //remember, _rawPrevTime is how zero-duration tweens/callbacks sense directionality and determine whether or not to fire. If _rawPrevTime is the same as _startTime on the next render, it won't fire. } tween = tween._next; } } return Animation.prototype.paused.apply(this, arguments); }; p.usesFrames = function() { var tl = this._timeline; while (tl._timeline) { tl = tl._timeline; } return (tl === Animation._rootFramesTimeline); }; p.rawTime = function(wrapRepeats) { return (wrapRepeats && (this._paused || (this._repeat && this.time() > 0 && this.totalProgress() < 1))) ? this._totalTime % (this._duration + this._repeatDelay) : this._paused ? this._totalTime : (this._timeline.rawTime(wrapRepeats) - this._startTime) * this._timeScale; }; return TimelineLite; }, true); }); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date) (function(name) { "use strict"; var getGlobal = function() { return (_gsScope.GreenSockGlobals || _gsScope)[name]; }; if (typeof(module) !== "undefined" && module.exports) { //node require("./TweenLite.js"); //dependency module.exports = getGlobal(); } else if (typeof(define) === "function" && define.amd) { //AMD define(["TweenLite"], getGlobal); } }("TimelineMax")); (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o difference ? difference : change; this.object.rotation += delta * sign; } } }]); return face; }(wait); module.exports = face; },{"./wait":11,"yy-angle":22}],3:[function(require,module,exports){ 'use strict'; var Ease = { list: require('./list'), wait: require('./wait'), to: require('./to'), shake: require('./shake'), tint: require('./tint'), face: require('./face'), angle: require('./angle'), target: require('./target'), movie: require('./movie'), load: require('./load') }; PIXI.extras.Ease = Ease; module.exports = Ease; },{"./angle":1,"./face":2,"./list":4,"./load":5,"./movie":6,"./shake":7,"./target":8,"./tint":9,"./to":10,"./wait":11}],4:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Events = require('eventemitter3'); var Angle = require('./angle'); var Face = require('./face'); var Load = require('./load'); var Movie = require('./movie'); var Shake = require('./shake'); var Target = require('./target'); var Tint = require('./tint'); var To = require('./to'); var Wait = require('./wait'); var Ease = function (_Events) { _inherits(Ease, _Events); /** * Main class for creating eases * @param {object} [options] * @param {boolean} [options.noTicker] don't add the update function to PIXI.ticker * @param {PIXI.ticker} [options.ticker=PIXI.ticker.shared] use this PIXI.ticker for the list * @extends eventemitter * @fire done * @fire each */ function Ease(options) { _classCallCheck(this, Ease); options = options || {}; var _this = _possibleConstructorReturn(this, (Ease.__proto__ || Object.getPrototypeOf(Ease)).call(this)); if (!options.noTicker) { var ticker = options.ticker || PIXI.ticker.shared; ticker.add(function () { return _this.update(ticker.elapsedMS); }); } _this.list = []; _this.empty = true; _this.removeWaiting = []; _this.removeAllWaiting = false; return _this; } /** * Add animation(s) to animation list * @param {(object|object[])} any animation class * @return {object} first animation */ _createClass(Ease, [{ key: 'add', value: function add() { var first = void 0; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = arguments[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var arg = _step.value; if (Array.isArray(arg)) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = arg[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var entry = _step2.value; if (!first) { first = entry; } this.list.push(entry); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } else { first = arg; this.list.push(arg); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } this.empty = false; return first; } /** * remove animation(s) * @param {object|array} animate - the animation (or array of animations) to remove; can be null */ }, { key: 'remove', value: function remove(animate) { if (this.inUpdate) { this.removeWaiting.push(animate); } else { var index = this.list.indexOf(animate); if (index !== -1) { this.list.splice(index, 1); } } } /** * remove all animations from list * @inherited from yy-loop */ }, { key: 'removeAll', value: function removeAll() { if (this.inUpdate) { this.removeAllWaiting = true; } else { this.list = []; } } /** * update frame * this is automatically added to PIXI.ticker unless options.noTicker is set * if using options.noTicker, this should be called manually * @param {number} elasped time in MS since last update */ }, { key: 'update', value: function update(elapsed) { this.inUpdate = true; for (var i = 0, _i = this.list.length; i < _i; i++) { if (this.list[i] && this.list[i].update(elapsed)) { this.list.splice(i, 1); i--; _i--; } } this.emit('each', this); if (this.list.length === 0 && !this.empty) { this.emit('done', this); this.empty = true; } this.inUpdate = false; if (this.removeAllWaiting) { this.removeAll(); this.removeAllWaiting = false; } while (this.removeWaiting.length) { this.remove(this.removeWaiting.pop()); } } /** * number of animations * @type {number} */ }, { key: 'to', /** * default options for all eases * @typedef {object} EaseOptions * @param {object} [EaseOptions.options] * @param {number} [EaseOptions.options.wait=0] n milliseconds before starting animation (can also be used to pause animation for a length of time) * @param {boolean} [EaseOptions.options.pause] start the animation paused * @param {boolean|number} [EaseOptions.options.repeat] true: repeat animation forever n: repeat animation n times * @param {boolean|number} [EaseOptions.options.reverse] true: reverse animation (if combined with repeat, then pulse) n: reverse animation n times * @param {Function} [EaseOptions.options.load] loads an animation using an .save() object note the * parameters below cannot be loaded and must be re-set * @param {string|Function} [EaseOptions.options.ease] name or function from easing.js (see http://easings.net for examples) */ /** * ease parameters of object * @param {PIXI.DisplayObject} object to animate * @param {object} goto - parameters to animate, e.g.: {alpha: 5, scale: {3, 5}, scale: 5, rotation: Math.PI} * @param {number} duration - time to run * @fires done * @fires wait * @fires first * @fires each * @fires loop * @fires reverse */ value: function to() { return this.add(new (Function.prototype.bind.apply(To, [null].concat(Array.prototype.slice.call(arguments))))()); } /** * animate object's {x, y} using an angle * @param {object} object to animate * @param {number} angle in radians * @param {number} speed in pixels/millisecond * @param {number} [duration=0] in milliseconds; if 0, then continues forever * @param {object} [options] @see {@link Wait} */ }, { key: 'angle', value: function angle() { return this.add(new (Function.prototype.bind.apply(Angle, [null].concat(Array.prototype.slice.call(arguments))))()); } /** helper to add to the list a new Ease.face class; see Ease.to class below for parameters */ }, { key: 'face', value: function face() { return this.add(new (Function.prototype.bind.apply(Face, [null].concat(Array.prototype.slice.call(arguments))))()); } /** helper to add to the list a new Ease.load class; see Ease.to class below for parameters */ }, { key: 'load', value: function load() { return this.add(new (Function.prototype.bind.apply(Load, [null].concat(Array.prototype.slice.call(arguments))))()); } /** helper to add to the list a new Ease.movie class; see Ease.to class below for parameters */ }, { key: 'movie', value: function movie() { return this.add(new (Function.prototype.bind.apply(Movie, [null].concat(Array.prototype.slice.call(arguments))))()); } /** helper to add to the list a new Ease.shake class; see Ease.to class below for parameters */ }, { key: 'shake', value: function shake() { return this.add(new (Function.prototype.bind.apply(Shake, [null].concat(Array.prototype.slice.call(arguments))))()); } /** helper to add to the list a new Ease.target class; see Ease.to class below for parameters */ }, { key: 'target', value: function target() { return this.add(new (Function.prototype.bind.apply(Target, [null].concat(Array.prototype.slice.call(arguments))))()); } /** helper to add to the list a new Ease.angle tint; see Ease.to class below for parameters */ }, { key: 'tint', value: function tint() { return this.add(new (Function.prototype.bind.apply(Tint, [null].concat(Array.prototype.slice.call(arguments))))()); } /** helper to add to the list a new Ease.wait class; see Ease.to class below for parameters */ }, { key: 'wait', value: function wait() { return this.add(new (Function.prototype.bind.apply(Wait, [null].concat(Array.prototype.slice.call(arguments))))()); } }, { key: 'count', get: function get() { return this.list.length; } /** * number of active animations * @type {number} */ }, { key: 'countRunning', get: function get() { var count = 0; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = this.list[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var entry = _step3.value; if (!entry.pause) { count++; } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } return count; } }]); return Ease; }(Events); module.exports = Ease; },{"./angle":1,"./face":2,"./load":5,"./movie":6,"./shake":7,"./target":8,"./tint":9,"./to":10,"./wait":11,"eventemitter3":12}],5:[function(require,module,exports){ 'use strict'; var wait = require('./wait'); var to = require('./to'); var tint = require('./tint'); var shake = require('./shake'); var angle = require('./angle'); var face = require('./face'); var target = require('./target'); var movie = require('./movie'); /** * restart an animation = requires a saved state * @param {object} object(s) to animate */ function load(object, load) { if (!load) { return null; } var options = { load: load }; switch (load.type) { case 'Wait': return new wait(object, options); case 'To': return new to(object, null, null, options); case 'Tint': return new tint(object, null, null, options); case 'Shake': return new shake(object, null, null, options); case 'Angle': return new angle(object, null, null, null, options); case 'Face': return new face(object[0], object[1], null, options); case 'Target': return new target(object[0], object[1], null, options); case 'Movie': return new movie(object, object[1], null, options); } } module.exports = load; },{"./angle":1,"./face":2,"./movie":6,"./shake":7,"./target":8,"./tint":9,"./to":10,"./wait":11}],6:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var wait = require('./wait'); /** * animate a movie of textures */ var movie = function (_wait) { _inherits(movie, _wait); /** * @param {object} object to animate * @param {PIXI.Texture[]} textures * @param {number} [duration=0] time to run (use 0 for infinite duration--should only be used with customized easing functions) * @param {object} [options] * @param {number} [options.wait=0] n milliseconds before starting animation (can also be used to pause animation for a length of time) * @param {boolean} [options.pause] start the animation paused * @param {(boolean|number)} [options.repeat] true: repeat animation forever n: repeat animation n times * @param {(boolean|number)} [options.reverse] true: reverse animation (if combined with repeat, then pulse) n: reverse animation n times * @param {(boolean|number)} [options.continue] true: continue animation with new starting values n: continue animation n times * @param {Function} [options.load] loads an animation using a .save() object note the * parameters below cannot be loaded and must be re-set * @param {Function} [options.ease] function from easing.js (see http://easings.net for examples) * @emits {done} animation expires * @emits {wait} each update during a wait * @emits {first} first update when animation starts * @emits {each} each update while animation is running * @emits {loop} when animation is repeated * @emits {reverse} when animation is reversed */ function movie(object, textures, duration, options) { _classCallCheck(this, movie); options = options || {}; var _this = _possibleConstructorReturn(this, (movie.__proto__ || Object.getPrototypeOf(movie)).call(this, object, options)); _this.type = 'Movie'; if (Array.isArray(object)) { _this.list = object; _this.object = _this.list[0]; } if (options.load) { _this.load(options.load); } else { _this.textures = textures; _this.duration = duration; _this.current = 0; _this.length = textures.length; _this.interval = duration / _this.length; _this.isReverse = false; _this.restart(); } return _this; } _createClass(movie, [{ key: 'save', value: function save() { var save = _get(movie.prototype.__proto__ || Object.getPrototypeOf(movie.prototype), 'save', this).call(this); save.goto = this.goto; save.current = this.current; save.length = this.length; save.interval = this.interval; return save; } }, { key: 'load', value: function load(_load) { _get(movie.prototype.__proto__ || Object.getPrototypeOf(movie.prototype), 'load', this).call(this, _load); this.goto = _load.goto; this.current = _load.current; this.interval = _load.current; } }, { key: 'restart', value: function restart() { this.current = 0; this.time = 0; this.isReverse = false; } }, { key: 'reverse', value: function reverse() { this.isReverse = !this.isReverse; } }, { key: 'calculate', value: function calculate() { var index = Math.round(this.options.ease(this.time, 0, this.length - 1, this.duration)); if (this.isReverse) { index = this.length - 1 - index; } if (this.list) { for (var i = 0; i < this.list.length; i++) { this.list[i].texture = this.textures[index]; } } else { this.object.texture = this.textures[index]; } } }]); return movie; }(wait); module.exports = movie; },{"./wait":11}],7:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var wait = require('./wait'); /** * shakes an object or list of objects */ var shake = function (_wait) { _inherits(shake, _wait); /** * @param {object|array} object or list of objects to shake * @param {number} amount to shake * @param {number} duration (in milliseconds) to shake * @param {object} options (see Animate.wait) */ function shake(object, amount, duration, options) { _classCallCheck(this, shake); options = options || {}; var _this = _possibleConstructorReturn(this, (shake.__proto__ || Object.getPrototypeOf(shake)).call(this, object, options)); _this.type = 'Shake'; if (Array.isArray(object)) { _this.array = true; _this.list = object; } if (options.load) { _this.load(options.load); } else { if (_this.list) { _this.start = []; for (var i = 0; i < object.length; i++) { var target = object[i]; _this.start[i] = { x: target.x, y: target.y }; } } else { _this.start = { x: object.x, y: object.y }; } _this.amount = amount; _this.duration = duration; } return _this; } _createClass(shake, [{ key: 'save', value: function save() { var save = _get(shake.prototype.__proto__ || Object.getPrototypeOf(shake.prototype), 'save', this).call(this); save.start = this.start; save.amount = this.amount; return save; } }, { key: 'load', value: function load(_load) { _get(shake.prototype.__proto__ || Object.getPrototypeOf(shake.prototype), 'load', this).call(this, _load); this.start = _load.start; this.amount = _load.amount; } }, { key: 'calculate', value: function calculate() /*elapsed*/{ var object = this.object; var start = this.start; var amount = this.amount; if (this.array) { var list = this.list; for (var i = 0; i < list.length; i++) { var _object = list[i]; var actual = start[i]; _object.x = actual.x + Math.floor(Math.random() * amount * 2) - amount; _object.y = actual.y + Math.floor(Math.random() * amount * 2) - amount; } } object.x = start.x + Math.floor(Math.random() * amount * 2) - amount; object.y = start.y + Math.floor(Math.random() * amount * 2) - amount; } }, { key: 'done', value: function done() { var object = this.object; var start = this.start; if (this.array) { var list = this.list; for (var i = 0; i < list.length; i++) { var _object2 = list[i]; var actual = start[i]; _object2.x = actual.x; _object2.y = actual.y; } } else { object.x = start.x; object.y = start.y; } } }]); return shake; }(wait); module.exports = shake; },{"./wait":11}],8:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var wait = require('./wait'); /** move an object to a target's location */ var target = function (_wait) { _inherits(target, _wait); /** * move to a target * @param {object} object - object to animate * @param {object} target - object needs to contain {x: x, y: y} * @param {number} speed - number of pixels to move per millisecond * @param {object} [options] @see {@link Wait} * @param {boolean} [options.keepAlive] don't cancel the animation when target is reached */ function target(object, _target, speed, options) { _classCallCheck(this, target); options = options || {}; var _this = _possibleConstructorReturn(this, (target.__proto__ || Object.getPrototypeOf(target)).call(this, object, options)); _this.type = 'Target'; _this.target = _target; if (options.load) { _this.load(options.load); } else { _this.speed = speed; } return _this; } _createClass(target, [{ key: 'save', value: function save() { var save = _get(target.prototype.__proto__ || Object.getPrototypeOf(target.prototype), 'save', this).call(this); save.speed = this.speed; save.keepAlive = this.options.keepAlive; return save; } }, { key: 'load', value: function load(_load) { _get(target.prototype.__proto__ || Object.getPrototypeOf(target.prototype), 'load', this).call(this, _load); this.speed = _load.speed; this.options.keepAlive = _load.keepAlive; } }, { key: 'calculate', value: function calculate(elapsed) { var deltaX = this.target.x - this.object.x; var deltaY = this.target.y - this.object.y; if (deltaX === 0 && deltaY === 0) { this.emit('done', this.object); if (!this.options.keepAlive) { return true; } } else { var angle = Math.atan2(deltaY, deltaX); this.object.x += Math.cos(angle) * elapsed * this.speed; this.object.y += Math.sin(angle) * elapsed * this.speed; if (deltaX >= 0 !== this.target.x - this.object.x >= 0) { this.object.x = this.target.x; } if (deltaY >= 0 !== this.target.y - this.object.y >= 0) { this.object.y = this.target.y; } } } }]); return target; }(wait); module.exports = target; },{"./wait":11}],9:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Color = require('yy-color'); var wait = require('./wait'); var tint = function (_wait) { _inherits(tint, _wait); /** * @param {PIXI.DisplayObject|PIXI.DisplayObject[]} object * @param {number|number[]} tint * @param {number} [duration] in milliseconds * @param {object} [options] @see {@link Wait} */ function tint(object, _tint, duration, options) { _classCallCheck(this, tint); options = options || {}; var _this = _possibleConstructorReturn(this, (tint.__proto__ || Object.getPrototypeOf(tint)).call(this, object, options)); _this.type = 'Tint'; if (Array.isArray(object)) { _this.list = object; _this.object = _this.list[0]; } _this.duration = duration; if (options.load) { _this.load(options.load); } else if (Array.isArray(_tint)) { _this.tints = [_this.object.tint].concat(_toConsumableArray(_tint)); } else { _this.start = _this.object.tint; _this.to = _tint; } return _this; } _createClass(tint, [{ key: 'save', value: function save() { var save = _get(tint.prototype.__proto__ || Object.getPrototypeOf(tint.prototype), 'save', this).call(this); save.start = this.start; save.to = this.to; return save; } }, { key: 'load', value: function load(_load) { _get(tint.prototype.__proto__ || Object.getPrototypeOf(tint.prototype), 'load', this).call(this, _load); this.start = _load.start; this.to = _load.to; } }, { key: 'calculate', value: function calculate() { var percent = this.options.ease(this.time, 0, 1, this.duration); if (this.tints) { var each = 1 / (this.tints.length - 1); var per = each; for (var i = 1; i < this.tints.length; i++) { if (percent <= per) { var color = Color.blend(1 - (per - percent) / each, this.tints[i - 1], this.tints[i]); if (this.list) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this.list[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var object = _step.value; object.tint = color; } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } else { this.object.tint = color; } break; } per += each; } } else { var _color = Color.blend(percent, this.start, this.to); if (this.list) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = this.list[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _object = _step2.value; _object.tint = _color; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } else { this.object.tint = _color; } } } }, { key: 'reverse', value: function reverse() { if (this.tints) { var tints = []; for (var i = this.tints.length - 1; i >= 0; i--) { tints.push(this.tints[i]); } this.tints = tints; } else { var swap = this.to; this.to = this.start; this.start = swap; } } }]); return tint; }(wait); module.exports = tint; },{"./wait":11,"yy-color":23}],10:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var wait = require('./wait'); /** animate any numeric parameter of an object or array of objects */ var to = function (_wait) { _inherits(to, _wait); /** * @private * @param {object} object to animate * @param {object} goto - parameters to animate, e.g.: {alpha: 5, scale: {3, 5}, scale: 5, rotation: Math.PI} * @param {number} duration - time to run * @param {object} [options] * @param {number} [options.wait=0] n milliseconds before starting animation (can also be used to pause animation for a length of time) * @param {boolean} [options.pause] start the animation paused * @param {boolean|number} [options.repeat] true: repeat animation forever n: repeat animation n times * @param {boolean|number} [options.reverse] true: reverse animation (if combined with repeat, then pulse) n: reverse animation n times * @param {Function} [options.load] loads an animation using an .save() object note the * parameters below cannot be loaded and must be re-set * @param {string|Function} [options.ease] name or function from easing.js (see http://easings.net for examples) * @emits to:done animation expires * @emits to:wait each update during a wait * @emits to:first first update when animation starts * @emits to:each each update while animation is running * @emits to:loop when animation is repeated * @emits to:reverse when animation is reversed */ function to(object, goto, duration, options) { _classCallCheck(this, to); options = options || {}; var _this = _possibleConstructorReturn(this, (to.__proto__ || Object.getPrototypeOf(to)).call(this, object, options)); _this.type = 'To'; if (Array.isArray(object)) { _this.list = object; _this.object = _this.list[0]; } if (options.load) { _this.load(options.load); } else { _this.goto = goto; _this.fixScale(); _this.duration = duration; _this.restart(); } return _this; } /** * converts scale from { scale: n } to { scale: { x: n, y: n }} * @private */ _createClass(to, [{ key: 'fixScale', value: function fixScale() { if (typeof this.goto['scale'] !== 'undefined' && !Number.isNaN(this.goto['scale'])) { this.goto['scale'] = { x: this.goto['scale'], y: this.goto['scale'] }; } } }, { key: 'save', value: function save() { var save = _get(to.prototype.__proto__ || Object.getPrototypeOf(to.prototype), 'save', this).call(this); save.goto = this.goto; save.start = this.start; save.delta = this.delta; save.keys = this.keys; return save; } }, { key: 'load', value: function load(_load) { _get(to.prototype.__proto__ || Object.getPrototypeOf(to.prototype), 'load', this).call(this, _load); this.goto = _load.goto; this.start = _load.start; this.delta = _load.delta; this.keys = _load.keys; } }, { key: 'restart', value: function restart() { var i = 0; var start = this.start = []; var delta = this.delta = []; var keys = this.keys = []; var goto = this.goto; var object = this.object; // loops through all keys in goto object for (var key in goto) { // handles keys with one additional level e.g.: goto = {scale: {x: 5, y: 3}} if (isNaN(goto[key])) { keys[i] = { key: key, children: [] }; start[i] = []; delta[i] = []; var j = 0; for (var key2 in goto[key]) { keys[i].children[j] = key2; start[i][j] = parseFloat(object[key][key2]); start[i][j] = this._correctDOM(key2, start[i][j]); start[i][j] = isNaN(this.start[i][j]) ? 0 : start[i][j]; delta[i][j] = goto[key][key2] - start[i][j]; j++; } } else { start[i] = parseFloat(object[key]); start[i] = this._correctDOM(key, start[i]); start[i] = isNaN(this.start[i]) ? 0 : start[i]; delta[i] = goto[key] - start[i]; keys[i] = key; } i++; } this.time = 0; } }, { key: 'reverse', value: function reverse() { var object = this.object; var keys = this.keys; var goto = this.goto; var delta = this.delta; var start = this.start; for (var i = 0, _i = keys.length; i < _i; i++) { var key = keys[i]; if (isNaN(goto[key])) { for (var j = 0, _j = key.children.length; j < _j; j++) { delta[i][j] = -delta[i][j]; start[i][j] = parseFloat(object[key.key][key.children[j]]); start[i][j] = isNaN(start[i][j]) ? 0 : start[i][j]; } } else { delta[i] = -delta[i]; start[i] = parseFloat(object[key]); start[i] = isNaN(start[i]) ? 0 : start[i]; } } } }, { key: 'calculate', value: function calculate() /*elapsed*/{ var object = this.object; var list = this.list; var keys = this.keys; var goto = this.goto; var time = this.time; var start = this.start; var delta = this.delta; var duration = this.duration; var ease = this.options.ease; for (var i = 0, _i = this.keys.length; i < _i; i++) { var key = keys[i]; if (isNaN(goto[key])) { var key1 = key.key; for (var j = 0, _j = key.children.length; j < _j; j++) { var key2 = key.children[j]; var others = object[key1][key2] = time >= duration ? start[i][j] + delta[i][j] : ease(time, start[i][j], delta[i][j], duration); if (list) { for (var k = 1, _k = list.length; k < _k; k++) { list[k][key1][key2] = others; } } } } else { var _key = keys[i]; var _others = object[_key] = time >= duration ? start[i] + delta[i] : ease(time, start[i], delta[i], duration); if (list) { for (var _j2 = 1, _j3 = this.list.length; _j2 < _j3; _j2++) { list[_j2][_key] = _others; } } } } } }]); return to; }(wait); module.exports = to; },{"./wait":11}],11:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Easing = require('penner'); var EventEmitter = require('eventemitter3'); var wait = function (_EventEmitter) { _inherits(wait, _EventEmitter); /** * @param {object|object[]} object or list of objects to animate * @param {object} [options] * @param {number} [options.wait=0] n milliseconds before starting animation (can also be used to pause animation for a length of time) * @param {boolean} [options.pause] start the animation paused * @param {(boolean|number)} [options.repeat] true: repeat animation forever n: repeat animation n times * @param {(boolean|number)} [options.reverse] true: reverse animation (if combined with repeat, then pulse) n: reverse animation n times * * @param {number} [options.id] user-generated id (e.g., I use it to properly load animations when an object has multiple animations running) * @param {Function} [options.load] loads an animation using an .save() object note the * parameters below cannot be loaded and must be re-set * @param {Function|string} [options.ease] function (or penner function name) from easing.js (see http://easings.net for examples)* * * @emits {done} animation expires * @emits {wait} each update during a wait * @emits {first} first update when animation starts * @emits {each} each update while animation is running * @emits {loop} when animation is repeated * @emits {reverse} when animation is reversed */ function wait(object, options) { _classCallCheck(this, wait); var _this = _possibleConstructorReturn(this, (wait.__proto__ || Object.getPrototypeOf(wait)).call(this)); _this.object = object; _this.options = options || {}; _this.type = 'Wait'; if (_this.options.load) { _this.load(_this.options.load); } else { _this.time = 0; } if (_this.options.ease && typeof _this.options.ease !== 'function') { _this.options.easeName = _this.options.ease; _this.options.ease = Easing[_this.options.ease]; } if (!_this.options.ease) { _this.options.ease = Easing['linear']; } return _this; } _createClass(wait, [{ key: 'save', value: function save() { var save = { type: this.type, time: this.time, duration: this.duration, ease: this.options.easeName }; var options = this.options; if (options.wait) { save.wait = options.wait; } if (typeof options.id !== 'undefined') { save.id = options.id; } if (options.pause) { save.pause = options.pause; } if (options.repeat) { save.repeat = options.repeat; } if (options.reverse) { save.reverse = options.reverse; } return save; } }, { key: 'load', value: function load(_load) { this.options.wait = _load.wait; this.options.pause = _load.pause; this.options.repeat = _load.repeat; this.options.reverse = _load.reverse; this.options.id = _load.id; this.options.ease = _load.ease; if (this.options.ease && typeof this.options.ease !== 'function') { this.options.easeName = this.options.ease; this.options.ease = Easing[this.options.ease]; } if (!this.options.ease) { this.options.ease = Easing['linear']; } this.time = _load.time; this.duration = _load.duration; } /** * pause this entry * @type {boolean} */ }, { key: 'end', value: function end(leftOver) { if (this.options.reverse) { this.reverse(); this.time = leftOver; if (!this.options.repeat) { if (this.options.reverse === true) { this.options.reverse = false; } else { this.options.reverse--; } } else { if (this.options.repeat !== true) { this.options.repeat--; } } this.emit('loop', this.list || this.object); } else if (this.options.repeat) { this.time = leftOver; if (this.options.repeat !== true) { this.options.repeat--; } this.emit('loop', this.list || this.object); } else { this.done(); this.emit('done', this.list || this.object, leftOver); // this.list = this.object = null return true; } } }, { key: 'update', value: function update(elapsed) { var options = this.options; if (options.pause) { return; } if (options.wait) { options.wait -= elapsed; if (options.wait <= 0) { elapsed = -options.wait; options.wait = false; } else { this.emit('wait', elapsed, this.list || this.object); return; } } if (!this.first) { this.first = true; this.emit('first', this.list || this.object); } this.time += elapsed; var leftOver = 0; var duration = this.duration; var time = this.time; if (duration !== 0 && time > duration) { leftOver = time - duration; this.time = time = duration; } var force = this.calculate(elapsed); this.emit('each', elapsed, this.list || this.object, this); if (this.type === 'Wait' || duration !== 0 && time === duration) { return this.end(leftOver); } return force || time === duration; } // correct certain DOM values }, { key: '_correctDOM', value: function _correctDOM(key, value) { switch (key) { case 'opacity': return isNaN(value) ? 1 : value; } return value; } }, { key: 'reverse', value: function reverse() {} }, { key: 'calculate', value: function calculate() {} }, { key: 'done', value: function done() {} }, { key: 'pause', set: function set(value) { this.options.pause = value; }, get: function get() { return this.options.pause; } }]); return wait; }(EventEmitter); module.exports = wait; },{"eventemitter3":12,"penner":13}],12:[function(require,module,exports){ 'use strict'; var has = Object.prototype.hasOwnProperty , prefix = '~'; /** * Constructor to create a storage for our `EE` objects. * An `Events` instance is a plain object whose properties are event names. * * @constructor * @private */ function Events() {} // // We try to not inherit from `Object.prototype`. In some engines creating an // instance in this way is faster than calling `Object.create(null)` directly. // If `Object.create(null)` is not supported we prefix the event names with a // character to make sure that the built-in object properties are not // overridden or used as an attack vector. // if (Object.create) { Events.prototype = Object.create(null); // // This hack is needed because the `__proto__` property is still inherited in // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. // if (!new Events().__proto__) prefix = false; } /** * Representation of a single event listener. * * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} [once=false] Specify if the listener is a one-time listener. * @constructor * @private */ function EE(fn, context, once) { this.fn = fn; this.context = context; this.once = once || false; } /** * Add a listener for a given event. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} once Specify if the listener is a one-time listener. * @returns {EventEmitter} * @private */ function addListener(emitter, event, fn, context, once) { if (typeof fn !== 'function') { throw new TypeError('The listener must be a function'); } var listener = new EE(fn, context || emitter, once) , evt = prefix ? prefix + event : event; if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++; else if (!emitter._events[evt].fn) emitter._events[evt].push(listener); else emitter._events[evt] = [emitter._events[evt], listener]; return emitter; } /** * Clear event by name. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} evt The Event name. * @private */ function clearEvent(emitter, evt) { if (--emitter._eventsCount === 0) emitter._events = new Events(); else delete emitter._events[evt]; } /** * Minimal `EventEmitter` interface that is molded against the Node.js * `EventEmitter` interface. * * @constructor * @public */ function EventEmitter() { this._events = new Events(); this._eventsCount = 0; } /** * Return an array listing the events for which the emitter has registered * listeners. * * @returns {Array} * @public */ EventEmitter.prototype.eventNames = function eventNames() { var names = [] , events , name; if (this._eventsCount === 0) return names; for (name in (events = this._events)) { if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); } if (Object.getOwnPropertySymbols) { return names.concat(Object.getOwnPropertySymbols(events)); } return names; }; /** * Return the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Array} The registered listeners. * @public */ EventEmitter.prototype.listeners = function listeners(event) { var evt = prefix ? prefix + event : event , handlers = this._events[evt]; if (!handlers) return []; if (handlers.fn) return [handlers.fn]; for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) { ee[i] = handlers[i].fn; } return ee; }; /** * Return the number of listeners listening to a given event. * * @param {(String|Symbol)} event The event name. * @returns {Number} The number of listeners. * @public */ EventEmitter.prototype.listenerCount = function listenerCount(event) { var evt = prefix ? prefix + event : event , listeners = this._events[evt]; if (!listeners) return 0; if (listeners.fn) return 1; return listeners.length; }; /** * Calls each of the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Boolean} `true` if the event had listeners, else `false`. * @public */ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return false; var listeners = this._events[evt] , len = arguments.length , args , i; if (listeners.fn) { if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); switch (len) { case 1: return listeners.fn.call(listeners.context), true; case 2: return listeners.fn.call(listeners.context, a1), true; case 3: return listeners.fn.call(listeners.context, a1, a2), true; case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; } for (i = 1, args = new Array(len -1); i < len; i++) { args[i - 1] = arguments[i]; } listeners.fn.apply(listeners.context, args); } else { var length = listeners.length , j; for (i = 0; i < length; i++) { if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true); switch (len) { case 1: listeners[i].fn.call(listeners[i].context); break; case 2: listeners[i].fn.call(listeners[i].context, a1); break; case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; default: if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { args[j - 1] = arguments[j]; } listeners[i].fn.apply(listeners[i].context, args); } } } return true; }; /** * Add a listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.on = function on(event, fn, context) { return addListener(this, event, fn, context, false); }; /** * Add a one-time listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.once = function once(event, fn, context) { return addListener(this, event, fn, context, true); }; /** * Remove the listeners of a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn Only remove the listeners that match this function. * @param {*} context Only remove the listeners that have this context. * @param {Boolean} once Only remove one-time listeners. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return this; if (!fn) { clearEvent(this, evt); return this; } var listeners = this._events[evt]; if (listeners.fn) { if ( listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context) ) { clearEvent(this, evt); } } else { for (var i = 0, events = [], length = listeners.length; i < length; i++) { if ( listeners[i].fn !== fn || (once && !listeners[i].once) || (context && listeners[i].context !== context) ) { events.push(listeners[i]); } } // // Reset the array, or remove it completely if we have no more listeners. // if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; else clearEvent(this, evt); } return this; }; /** * Remove all listeners, or those of the specified event. * * @param {(String|Symbol)} [event] The event name. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { var evt; if (event) { evt = prefix ? prefix + event : event; if (this._events[evt]) clearEvent(this, evt); } else { this._events = new Events(); this._eventsCount = 0; } return this; }; // // Alias methods names because people roll like that. // EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.addListener = EventEmitter.prototype.on; // // Expose the prefix. // EventEmitter.prefixed = prefix; // // Allow `EventEmitter` to be imported as module namespace. // EventEmitter.EventEmitter = EventEmitter; // // Expose the module. // if ('undefined' !== typeof module) { module.exports = EventEmitter; } },{}],13:[function(require,module,exports){ /* Copyright © 2001 Robert Penner All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function() { var penner, umd; umd = function(factory) { if (typeof exports === 'object') { return module.exports = factory; } else if (typeof define === 'function' && define.amd) { return define([], factory); } else { return this.penner = factory; } }; penner = { linear: function(t, b, c, d) { return c * t / d + b; }, easeInQuad: function(t, b, c, d) { return c * (t /= d) * t + b; }, easeOutQuad: function(t, b, c, d) { return -c * (t /= d) * (t - 2) + b; }, easeInOutQuad: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t + b; } else { return -c / 2 * ((--t) * (t - 2) - 1) + b; } }, easeInCubic: function(t, b, c, d) { return c * (t /= d) * t * t + b; }, easeOutCubic: function(t, b, c, d) { return c * ((t = t / d - 1) * t * t + 1) + b; }, easeInOutCubic: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t + b; } else { return c / 2 * ((t -= 2) * t * t + 2) + b; } }, easeInQuart: function(t, b, c, d) { return c * (t /= d) * t * t * t + b; }, easeOutQuart: function(t, b, c, d) { return -c * ((t = t / d - 1) * t * t * t - 1) + b; }, easeInOutQuart: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t * t + b; } else { return -c / 2 * ((t -= 2) * t * t * t - 2) + b; } }, easeInQuint: function(t, b, c, d) { return c * (t /= d) * t * t * t * t + b; }, easeOutQuint: function(t, b, c, d) { return c * ((t = t / d - 1) * t * t * t * t + 1) + b; }, easeInOutQuint: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t * t * t + b; } else { return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; } }, easeInSine: function(t, b, c, d) { return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; }, easeOutSine: function(t, b, c, d) { return c * Math.sin(t / d * (Math.PI / 2)) + b; }, easeInOutSine: function(t, b, c, d) { return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; }, easeInExpo: function(t, b, c, d) { if (t === 0) { return b; } else { return c * Math.pow(2, 10 * (t / d - 1)) + b; } }, easeOutExpo: function(t, b, c, d) { if (t === d) { return b + c; } else { return c * (-Math.pow(2, -10 * t / d) + 1) + b; } }, easeInOutExpo: function(t, b, c, d) { if (t === 0) { b; } if (t === d) { b + c; } if ((t /= d / 2) < 1) { return c / 2 * Math.pow(2, 10 * (t - 1)) + b; } else { return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; } }, easeInCirc: function(t, b, c, d) { return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; }, easeOutCirc: function(t, b, c, d) { return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; }, easeInOutCirc: function(t, b, c, d) { if ((t /= d / 2) < 1) { return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; } else { return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; } }, easeInElastic: function(t, b, c, d) { var a, p, s; s = 1.70158; p = 0; a = c; if (t === 0) { b; } else if ((t /= d) === 1) { b + c; } if (!p) { p = d * .3; } if (a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b; }, easeOutElastic: function(t, b, c, d) { var a, p, s; s = 1.70158; p = 0; a = c; if (t === 0) { b; } else if ((t /= d) === 1) { b + c; } if (!p) { p = d * .3; } if (a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b; }, easeInOutElastic: function(t, b, c, d) { var a, p, s; s = 1.70158; p = 0; a = c; if (t === 0) { b; } else if ((t /= d / 2) === 2) { b + c; } if (!p) { p = d * (.3 * 1.5); } if (a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } if (t < 1) { return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b; } else { return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b; } }, easeInBack: function(t, b, c, d, s) { if (s === void 0) { s = 1.70158; } return c * (t /= d) * t * ((s + 1) * t - s) + b; }, easeOutBack: function(t, b, c, d, s) { if (s === void 0) { s = 1.70158; } return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; }, easeInOutBack: function(t, b, c, d, s) { if (s === void 0) { s = 1.70158; } if ((t /= d / 2) < 1) { return c / 2 * (t * t * (((s *= 1.525) + 1) * t - s)) + b; } else { return c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b; } }, easeInBounce: function(t, b, c, d) { var v; v = penner.easeOutBounce(d - t, 0, c, d); return c - v + b; }, easeOutBounce: function(t, b, c, d) { if ((t /= d) < 1 / 2.75) { return c * (7.5625 * t * t) + b; } else if (t < 2 / 2.75) { return c * (7.5625 * (t -= 1.5 / 2.75) * t + .75) + b; } else if (t < 2.5 / 2.75) { return c * (7.5625 * (t -= 2.25 / 2.75) * t + .9375) + b; } else { return c * (7.5625 * (t -= 2.625 / 2.75) * t + .984375) + b; } }, easeInOutBounce: function(t, b, c, d) { var v; if (t < d / 2) { v = penner.easeInBounce(t * 2, 0, c, d); return v * .5 + b; } else { v = penner.easeOutBounce(t * 2 - d, 0, c, d); return v * .5 + c * .5 + b; } } }; umd(penner); }).call(this); },{}],14:[function(require,module,exports){ // A library of seedable RNGs implemented in Javascript. // // Usage: // // var seedrandom = require('seedrandom'); // var random = seedrandom(1); // or any seed. // var x = random(); // 0 <= x < 1. Every bit is random. // var x = random.quick(); // 0 <= x < 1. 32 bits of randomness. // alea, a 53-bit multiply-with-carry generator by Johannes Baagøe. // Period: ~2^116 // Reported to pass all BigCrush tests. var alea = require('./lib/alea'); // xor128, a pure xor-shift generator by George Marsaglia. // Period: 2^128-1. // Reported to fail: MatrixRank and LinearComp. var xor128 = require('./lib/xor128'); // xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl. // Period: 2^192-2^32 // Reported to fail: CollisionOver, SimpPoker, and LinearComp. var xorwow = require('./lib/xorwow'); // xorshift7, by François Panneton and Pierre L'ecuyer, takes // a different approach: it adds robustness by allowing more shifts // than Marsaglia's original three. It is a 7-shift generator // with 256 bits, that passes BigCrush with no systmatic failures. // Period 2^256-1. // No systematic BigCrush failures reported. var xorshift7 = require('./lib/xorshift7'); // xor4096, by Richard Brent, is a 4096-bit xor-shift with a // very long period that also adds a Weyl generator. It also passes // BigCrush with no systematic failures. Its long period may // be useful if you have many generators and need to avoid // collisions. // Period: 2^4128-2^32. // No systematic BigCrush failures reported. var xor4096 = require('./lib/xor4096'); // Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random // number generator derived from ChaCha, a modern stream cipher. // https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf // Period: ~2^127 // No systematic BigCrush failures reported. var tychei = require('./lib/tychei'); // The original ARC4-based prng included in this library. // Period: ~2^1600 var sr = require('./seedrandom'); sr.alea = alea; sr.xor128 = xor128; sr.xorwow = xorwow; sr.xorshift7 = xorshift7; sr.xor4096 = xor4096; sr.tychei = tychei; module.exports = sr; },{"./lib/alea":15,"./lib/tychei":16,"./lib/xor128":17,"./lib/xor4096":18,"./lib/xorshift7":19,"./lib/xorwow":20,"./seedrandom":21}],15:[function(require,module,exports){ // A port of an algorithm by Johannes Baagøe , 2010 // http://baagoe.com/en/RandomMusings/javascript/ // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror // Original work is under MIT license - // Copyright (C) 2010 by Johannes Baagøe // // 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. (function(global, module, define) { function Alea(seed) { var me = this, mash = Mash(); me.next = function() { var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32 me.s0 = me.s1; me.s1 = me.s2; return me.s2 = t - (me.c = t | 0); }; // Apply the seeding algorithm from Baagoe. me.c = 1; me.s0 = mash(' '); me.s1 = mash(' '); me.s2 = mash(' '); me.s0 -= mash(seed); if (me.s0 < 0) { me.s0 += 1; } me.s1 -= mash(seed); if (me.s1 < 0) { me.s1 += 1; } me.s2 -= mash(seed); if (me.s2 < 0) { me.s2 += 1; } mash = null; } function copy(f, t) { t.c = f.c; t.s0 = f.s0; t.s1 = f.s1; t.s2 = f.s2; return t; } function impl(seed, opts) { var xg = new Alea(seed), state = opts && opts.state, prng = xg.next; prng.int32 = function() { return (xg.next() * 0x100000000) | 0; } prng.double = function() { return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 }; prng.quick = prng; if (state) { if (typeof(state) == 'object') copy(state, xg); prng.state = function() { return copy(xg, {}); } } return prng; } function Mash() { var n = 0xefc8249d; var mash = function(data) { data = data.toString(); for (var i = 0; i < data.length; i++) { n += data.charCodeAt(i); var h = 0.02519603282416938 * n; n = h >>> 0; h -= n; h *= n; n = h >>> 0; h -= n; n += h * 0x100000000; // 2^32 } return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 }; return mash; } if (module && module.exports) { module.exports = impl; } else if (define && define.amd) { define(function() { return impl; }); } else { this.alea = impl; } })( this, (typeof module) == 'object' && module, // present in node.js (typeof define) == 'function' && define // present with an AMD loader ); },{}],16:[function(require,module,exports){ // A Javascript implementaion of the "Tyche-i" prng algorithm by // Samuel Neves and Filipe Araujo. // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf (function(global, module, define) { function XorGen(seed) { var me = this, strseed = ''; // Set up generator function. me.next = function() { var b = me.b, c = me.c, d = me.d, a = me.a; b = (b << 25) ^ (b >>> 7) ^ c; c = (c - d) | 0; d = (d << 24) ^ (d >>> 8) ^ a; a = (a - b) | 0; me.b = b = (b << 20) ^ (b >>> 12) ^ c; me.c = c = (c - d) | 0; me.d = (d << 16) ^ (c >>> 16) ^ a; return me.a = (a - b) | 0; }; /* The following is non-inverted tyche, which has better internal * bit diffusion, but which is about 25% slower than tyche-i in JS. me.next = function() { var a = me.a, b = me.b, c = me.c, d = me.d; a = (me.a + me.b | 0) >>> 0; d = me.d ^ a; d = d << 16 ^ d >>> 16; c = me.c + d | 0; b = me.b ^ c; b = b << 12 ^ d >>> 20; me.a = a = a + b | 0; d = d ^ a; me.d = d = d << 8 ^ d >>> 24; me.c = c = c + d | 0; b = b ^ c; return me.b = (b << 7 ^ b >>> 25); } */ me.a = 0; me.b = 0; me.c = 2654435769 | 0; me.d = 1367130551; if (seed === Math.floor(seed)) { // Integer seed. me.a = (seed / 0x100000000) | 0; me.b = seed | 0; } else { // String seed. strseed += seed; } // Mix in string seed, then discard an initial batch of 64 values. for (var k = 0; k < strseed.length + 20; k++) { me.b ^= strseed.charCodeAt(k) | 0; me.next(); } } function copy(f, t) { t.a = f.a; t.b = f.b; t.c = f.c; t.d = f.d; return t; }; function impl(seed, opts) { var xg = new XorGen(seed), state = opts && opts.state, prng = function() { return (xg.next() >>> 0) / 0x100000000; }; prng.double = function() { do { var top = xg.next() >>> 11, bot = (xg.next() >>> 0) / 0x100000000, result = (top + bot) / (1 << 21); } while (result === 0); return result; }; prng.int32 = xg.next; prng.quick = prng; if (state) { if (typeof(state) == 'object') copy(state, xg); prng.state = function() { return copy(xg, {}); } } return prng; } if (module && module.exports) { module.exports = impl; } else if (define && define.amd) { define(function() { return impl; }); } else { this.tychei = impl; } })( this, (typeof module) == 'object' && module, // present in node.js (typeof define) == 'function' && define // present with an AMD loader ); },{}],17:[function(require,module,exports){ // A Javascript implementaion of the "xor128" prng algorithm by // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper (function(global, module, define) { function XorGen(seed) { var me = this, strseed = ''; me.x = 0; me.y = 0; me.z = 0; me.w = 0; // Set up generator function. me.next = function() { var t = me.x ^ (me.x << 11); me.x = me.y; me.y = me.z; me.z = me.w; return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8); }; if (seed === (seed | 0)) { // Integer seed. me.x = seed; } else { // String seed. strseed += seed; } // Mix in string seed, then discard an initial batch of 64 values. for (var k = 0; k < strseed.length + 64; k++) { me.x ^= strseed.charCodeAt(k) | 0; me.next(); } } function copy(f, t) { t.x = f.x; t.y = f.y; t.z = f.z; t.w = f.w; return t; } function impl(seed, opts) { var xg = new XorGen(seed), state = opts && opts.state, prng = function() { return (xg.next() >>> 0) / 0x100000000; }; prng.double = function() { do { var top = xg.next() >>> 11, bot = (xg.next() >>> 0) / 0x100000000, result = (top + bot) / (1 << 21); } while (result === 0); return result; }; prng.int32 = xg.next; prng.quick = prng; if (state) { if (typeof(state) == 'object') copy(state, xg); prng.state = function() { return copy(xg, {}); } } return prng; } if (module && module.exports) { module.exports = impl; } else if (define && define.amd) { define(function() { return impl; }); } else { this.xor128 = impl; } })( this, (typeof module) == 'object' && module, // present in node.js (typeof define) == 'function' && define // present with an AMD loader ); },{}],18:[function(require,module,exports){ // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm. // // This fast non-cryptographic random number generator is designed for // use in Monte-Carlo algorithms. It combines a long-period xorshift // generator with a Weyl generator, and it passes all common batteries // of stasticial tests for randomness while consuming only a few nanoseconds // for each prng generated. For background on the generator, see Brent's // paper: "Some long-period random number generators using shifts and xors." // http://arxiv.org/pdf/1004.3115v1.pdf // // Usage: // // var xor4096 = require('xor4096'); // random = xor4096(1); // Seed with int32 or string. // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits. // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits. // // For nonzero numeric keys, this impelementation provides a sequence // identical to that by Brent's xorgens 3 implementaion in C. This // implementation also provides for initalizing the generator with // string seeds, or for saving and restoring the state of the generator. // // On Chrome, this prng benchmarks about 2.1 times slower than // Javascript's built-in Math.random(). (function(global, module, define) { function XorGen(seed) { var me = this; // Set up generator function. me.next = function() { var w = me.w, X = me.X, i = me.i, t, v; // Update Weyl generator. me.w = w = (w + 0x61c88647) | 0; // Update xor generator. v = X[(i + 34) & 127]; t = X[i = ((i + 1) & 127)]; v ^= v << 13; t ^= t << 17; v ^= v >>> 15; t ^= t >>> 12; // Update Xor generator array state. v = X[i] = v ^ t; me.i = i; // Result is the combination. return (v + (w ^ (w >>> 16))) | 0; }; function init(me, seed) { var t, v, i, j, w, X = [], limit = 128; if (seed === (seed | 0)) { // Numeric seeds initialize v, which is used to generates X. v = seed; seed = null; } else { // String seeds are mixed into v and X one character at a time. seed = seed + '\0'; v = 0; limit = Math.max(limit, seed.length); } // Initialize circular array and weyl value. for (i = 0, j = -32; j < limit; ++j) { // Put the unicode characters into the array, and shuffle them. if (seed) v ^= seed.charCodeAt((j + 32) % seed.length); // After 32 shuffles, take v as the starting w value. if (j === 0) w = v; v ^= v << 10; v ^= v >>> 15; v ^= v << 4; v ^= v >>> 13; if (j >= 0) { w = (w + 0x61c88647) | 0; // Weyl. t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array. i = (0 == t) ? i + 1 : 0; // Count zeroes. } } // We have detected all zeroes; make the key nonzero. if (i >= 128) { X[(seed && seed.length || 0) & 127] = -1; } // Run the generator 512 times to further mix the state before using it. // Factoring this as a function slows the main generator, so it is just // unrolled here. The weyl generator is not advanced while warming up. i = 127; for (j = 4 * 128; j > 0; --j) { v = X[(i + 34) & 127]; t = X[i = ((i + 1) & 127)]; v ^= v << 13; t ^= t << 17; v ^= v >>> 15; t ^= t >>> 12; X[i] = v ^ t; } // Storing state as object members is faster than using closure variables. me.w = w; me.X = X; me.i = i; } init(me, seed); } function copy(f, t) { t.i = f.i; t.w = f.w; t.X = f.X.slice(); return t; }; function impl(seed, opts) { if (seed == null) seed = +(new Date); var xg = new XorGen(seed), state = opts && opts.state, prng = function() { return (xg.next() >>> 0) / 0x100000000; }; prng.double = function() { do { var top = xg.next() >>> 11, bot = (xg.next() >>> 0) / 0x100000000, result = (top + bot) / (1 << 21); } while (result === 0); return result; }; prng.int32 = xg.next; prng.quick = prng; if (state) { if (state.X) copy(state, xg); prng.state = function() { return copy(xg, {}); } } return prng; } if (module && module.exports) { module.exports = impl; } else if (define && define.amd) { define(function() { return impl; }); } else { this.xor4096 = impl; } })( this, // window object or global (typeof module) == 'object' && module, // present in node.js (typeof define) == 'function' && define // present with an AMD loader ); },{}],19:[function(require,module,exports){ // A Javascript implementaion of the "xorshift7" algorithm by // François Panneton and Pierre L'ecuyer: // "On the Xorgshift Random Number Generators" // http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf (function(global, module, define) { function XorGen(seed) { var me = this; // Set up generator function. me.next = function() { // Update xor generator. var X = me.x, i = me.i, t, v, w; t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24); t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10); t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3); t = X[(i + 4) & 7]; v ^= t ^ (t << 7); t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9); X[i] = v; me.i = (i + 1) & 7; return v; }; function init(me, seed) { var j, w, X = []; if (seed === (seed | 0)) { // Seed state array using a 32-bit integer. w = X[0] = seed; } else { // Seed state using a string. seed = '' + seed; for (j = 0; j < seed.length; ++j) { X[j & 7] = (X[j & 7] << 15) ^ (seed.charCodeAt(j) + X[(j + 1) & 7] << 13); } } // Enforce an array length of 8, not all zeroes. while (X.length < 8) X.push(0); for (j = 0; j < 8 && X[j] === 0; ++j); if (j == 8) w = X[7] = -1; else w = X[j]; me.x = X; me.i = 0; // Discard an initial 256 values. for (j = 256; j > 0; --j) { me.next(); } } init(me, seed); } function copy(f, t) { t.x = f.x.slice(); t.i = f.i; return t; } function impl(seed, opts) { if (seed == null) seed = +(new Date); var xg = new XorGen(seed), state = opts && opts.state, prng = function() { return (xg.next() >>> 0) / 0x100000000; }; prng.double = function() { do { var top = xg.next() >>> 11, bot = (xg.next() >>> 0) / 0x100000000, result = (top + bot) / (1 << 21); } while (result === 0); return result; }; prng.int32 = xg.next; prng.quick = prng; if (state) { if (state.x) copy(state, xg); prng.state = function() { return copy(xg, {}); } } return prng; } if (module && module.exports) { module.exports = impl; } else if (define && define.amd) { define(function() { return impl; }); } else { this.xorshift7 = impl; } })( this, (typeof module) == 'object' && module, // present in node.js (typeof define) == 'function' && define // present with an AMD loader ); },{}],20:[function(require,module,exports){ // A Javascript implementaion of the "xorwow" prng algorithm by // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper (function(global, module, define) { function XorGen(seed) { var me = this, strseed = ''; // Set up generator function. me.next = function() { var t = (me.x ^ (me.x >>> 2)); me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v; return (me.d = (me.d + 362437 | 0)) + (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0; }; me.x = 0; me.y = 0; me.z = 0; me.w = 0; me.v = 0; if (seed === (seed | 0)) { // Integer seed. me.x = seed; } else { // String seed. strseed += seed; } // Mix in string seed, then discard an initial batch of 64 values. for (var k = 0; k < strseed.length + 64; k++) { me.x ^= strseed.charCodeAt(k) | 0; if (k == strseed.length) { me.d = me.x << 10 ^ me.x >>> 4; } me.next(); } } function copy(f, t) { t.x = f.x; t.y = f.y; t.z = f.z; t.w = f.w; t.v = f.v; t.d = f.d; return t; } function impl(seed, opts) { var xg = new XorGen(seed), state = opts && opts.state, prng = function() { return (xg.next() >>> 0) / 0x100000000; }; prng.double = function() { do { var top = xg.next() >>> 11, bot = (xg.next() >>> 0) / 0x100000000, result = (top + bot) / (1 << 21); } while (result === 0); return result; }; prng.int32 = xg.next; prng.quick = prng; if (state) { if (typeof(state) == 'object') copy(state, xg); prng.state = function() { return copy(xg, {}); } } return prng; } if (module && module.exports) { module.exports = impl; } else if (define && define.amd) { define(function() { return impl; }); } else { this.xorwow = impl; } })( this, (typeof module) == 'object' && module, // present in node.js (typeof define) == 'function' && define // present with an AMD loader ); },{}],21:[function(require,module,exports){ /* Copyright 2014 David Bau. 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. */ (function (pool, math) { // // The following constants are related to IEEE 754 limits. // var global = this, width = 256, // each RC4 output is 0 <= x < 256 chunks = 6, // at least six RC4 outputs for each double digits = 52, // there are 52 significant digits in a double rngname = 'random', // rngname: name for Math.random and Math.seedrandom startdenom = math.pow(width, chunks), significance = math.pow(2, digits), overflow = significance * 2, mask = width - 1, nodecrypto; // node.js crypto module, initialized at the bottom. // // seedrandom() // This is the seedrandom function described above. // function seedrandom(seed, options, callback) { var key = []; options = (options == true) ? { entropy: true } : (options || {}); // Flatten the seed string or build one from local entropy if needed. var shortseed = mixkey(flatten( options.entropy ? [seed, tostring(pool)] : (seed == null) ? autoseed() : seed, 3), key); // Use the seed to initialize an ARC4 generator. var arc4 = new ARC4(key); // This function returns a random double in [0, 1) that contains // randomness in every bit of the mantissa of the IEEE 754 value. var prng = function() { var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 d = startdenom, // and denominator d = 2 ^ 48. x = 0; // and no 'extra last byte'. while (n < significance) { // Fill up all significant digits by n = (n + x) * width; // shifting numerator and d *= width; // denominator and generating a x = arc4.g(1); // new least-significant-byte. } while (n >= overflow) { // To avoid rounding up, before adding n /= 2; // last byte, shift everything d /= 2; // right using integer math until x >>>= 1; // we have exactly the desired bits. } return (n + x) / d; // Form the number within [0, 1). }; prng.int32 = function() { return arc4.g(4) | 0; } prng.quick = function() { return arc4.g(4) / 0x100000000; } prng.double = prng; // Mix the randomness into accumulated entropy. mixkey(tostring(arc4.S), pool); // Calling convention: what to return as a function of prng, seed, is_math. return (options.pass || callback || function(prng, seed, is_math_call, state) { if (state) { // Load the arc4 state from the given state if it has an S array. if (state.S) { copy(state, arc4); } // Only provide the .state method if requested via options.state. prng.state = function() { return copy(arc4, {}); } } // If called as a method of Math (Math.seedrandom()), mutate // Math.random because that is how seedrandom.js has worked since v1.0. if (is_math_call) { math[rngname] = prng; return seed; } // Otherwise, it is a newer calling convention, so return the // prng directly. else return prng; })( prng, shortseed, 'global' in options ? options.global : (this == math), options.state); } math['seed' + rngname] = seedrandom; // // ARC4 // // An ARC4 implementation. The constructor takes a key in the form of // an array of at most (width) integers that should be 0 <= x < (width). // // The g(count) method returns a pseudorandom integer that concatenates // the next (count) outputs from ARC4. Its return value is a number x // that is in the range 0 <= x < (width ^ count). // function ARC4(key) { var t, keylen = key.length, me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; // The empty key [] is treated as [0]. if (!keylen) { key = [keylen++]; } // Set up S using the standard key scheduling algorithm. while (i < width) { s[i] = i++; } for (i = 0; i < width; i++) { s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; s[j] = t; } // The "g" method returns the next (count) outputs as one number. (me.g = function(count) { // Using instance members instead of closure state nearly doubles speed. var t, r = 0, i = me.i, j = me.j, s = me.S; while (count--) { t = s[i = mask & (i + 1)]; r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; } me.i = i; me.j = j; return r; // For robust unpredictability, the function call below automatically // discards an initial batch of values. This is called RC4-drop[256]. // See http://google.com/search?q=rsa+fluhrer+response&btnI })(width); } // // copy() // Copies internal state of ARC4 to or from a plain object. // function copy(f, t) { t.i = f.i; t.j = f.j; t.S = f.S.slice(); return t; }; // // flatten() // Converts an object tree to nested arrays of strings. // function flatten(obj, depth) { var result = [], typ = (typeof obj), prop; if (depth && typ == 'object') { for (prop in obj) { try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} } } return (result.length ? result : typ == 'string' ? obj : obj + '\0'); } // // mixkey() // Mixes a string seed into a key that is an array of integers, and // returns a shortened string seed that is equivalent to the result key. // function mixkey(seed, key) { var stringseed = seed + '', smear, j = 0; while (j < stringseed.length) { key[mask & j] = mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); } return tostring(key); } // // autoseed() // Returns an object for autoseeding, using window.crypto and Node crypto // module if available. // function autoseed() { try { var out; if (nodecrypto && (out = nodecrypto.randomBytes)) { // The use of 'out' to remember randomBytes makes tight minified code. out = out(width); } else { out = new Uint8Array(width); (global.crypto || global.msCrypto).getRandomValues(out); } return tostring(out); } catch (e) { var browser = global.navigator, plugins = browser && browser.plugins; return [+new Date, global, plugins, global.screen, tostring(pool)]; } } // // tostring() // Converts an array of charcodes to a string // function tostring(a) { return String.fromCharCode.apply(0, a); } // // When seedrandom.js is loaded, we immediately mix a few bits // from the built-in RNG into the entropy pool. Because we do // not want to interfere with deterministic PRNG state later, // seedrandom will not call math.random on its own again after // initialization. // mixkey(math.random(), pool); // // Nodejs and AMD support: export the implementation as a module using // either convention. // if ((typeof module) == 'object' && module.exports) { module.exports = seedrandom; // When in node.js, try using crypto package for autoseeding. try { nodecrypto = require('crypto'); } catch (ex) {} } else if ((typeof define) == 'function' && define.amd) { define(function() { return seedrandom; }); } // End anonymous scope, and pass initial values. })( [], // pool: entropy pool starts empty Math // math: package containing random, pow, and seedrandom ); },{"crypto":25}],22:[function(require,module,exports){ // angle.js // Released under MIT license // Author: David Figatner // Copyright (c) 2016-17 YOPEY YOPEY LLC var _toDegreeConversion = 180 / Math.PI var _toRadianConversion = Math.PI / 180 /** @constant {number} */ var UP = Math.PI / 2 var DOWN = 3 * Math.PI / 2 var LEFT = Math.PI var RIGHT = 0 var NORTH = UP var SOUTH = DOWN var WEST = LEFT var EAST = RIGHT var PI_2 = Math.PI * 2 var PI_QUARTER = Math.PI / 4 var PI_HALF = Math.PI / 2 /** * converts from radians to degrees (all other functions expect radians) * @param {number} radians * @return {number} degrees */ function toDegrees(radians) { return radians * _toDegreeConversion } /** * converts from degrees to radians (all other functions expect radians) * @param {number} degrees * @return {number} radians */ function toRadians(degrees) { return degrees * _toRadianConversion } /** * returns whether the target angle is between angle1 and angle2 (in radians) * (based on: http://stackoverflow.com/questions/11406189/determine-if-angle-lies-between-2-other-angles) * @param {number} target angle * @param {number} angle1 * @param {number} angle2 * @return {boolean} */ function isAngleBetween(target, angle1, angle2) { var rAngle = ((angle2 - angle1) % PI_2 + PI_2) % PI_2 if (rAngle >= Math.PI) { var swap = angle1 angle1 = angle2 angle2 = swap } if (angle1 <= angle2) { return target >= angle1 && target <= angle2 } else { return target >= angle1 || target <= angle2 } } /** * returns +1 or -1 based on whether the difference between two angles is positive or negative (in radians) * @param {number} target angle * @param {number} source angle * @return {number} 1 or -1 */ function differenceAnglesSign(target, source) { function mod(a, n) { return (a % n + n) % n } var a = target - source return mod((a + Math.PI), PI_2) - Math.PI > 0 ? 1 : -1 } /** * returns the normalized difference between two angles (in radians) * @param {number} a - first angle * @param {number} b - second angle * @return {number} normalized difference between a and b */ function differenceAngles(a, b) { var c = Math.abs(a - b) % PI_2 return c > Math.PI ? (PI_2 - c) : c } /** * returns a target angle that is the shortest way to rotate an object between start and to--may choose a negative angle * @param {number} start * @param {number} to * @return {number} shortest target angle */ function shortestAngle(start, to) { var difference = differenceAngles(to, start) var sign = differenceAnglesSign(to, start) var delta = difference * sign return delta + start } /** * returns the normalized angle (0 - PI x 2) * @param {number} radians * @return {number} normalized angle in radians */ function normalize(radians) { return radians - PI_2 * Math.floor(radians / PI_2) } /** * returns angle between two points (in radians) * @param {Point} [point1] {x: x, y: y} * @param {Point} [point2] {x: x, y: y} * @param {number} [x1] * @param {number} [y1] * @param {number} [x2] * @param {number} [y2] * @return {number} angle */ function angleTwoPoints(/* (point1, point2) OR (x1, y1, x2, y2) */) { if (arguments.length === 4) { return Math.atan2(arguments[3] - arguments[1], arguments[2] - arguments[0]) } else { return Math.atan2(arguments[1].y - arguments[0].y, arguments[1].x - arguments[0].x) } } /** * returns distance between two points * @param {Point} [point1] {x: x, y: y} * @param {Point} [point2] {x: x, y: y} * @param {number} [x1] * @param {number} [y1] * @param {number} [x2] * @param {number} [y2] * @return {number} distance */ function distanceTwoPoints(/* (point1, point2) OR (x1, y1, x2, y2) */) { if (arguments.length === 2) { return Math.sqrt(Math.pow(arguments[1].x - arguments[0].x, 2) + Math.pow(arguments[1].y - arguments[0].y, 2)) } else { return Math.sqrt(Math.pow(arguments[2] - arguments[0], 2) + Math.pow(arguments[3] - arguments[1], 2)) } } /** * returns the squared distance between two points * @param {Point} [point1] {x: x, y: y} * @param {Point} [point2] {x: x, y: y} * @param {number} [x1] * @param {number} [y1] * @param {number} [x2] * @param {number} [y2] * @return {number} squared distance */ function distanceTwoPointsSquared(/* (point1, point2) OR (x1, y1, x2, y2) */) { if (arguments.length === 2) { return Math.pow(arguments[1].x - arguments[0].x, 2) + Math.pow(arguments[1].y - arguments[0].y, 2) } else { return Math.pow(arguments[2] - arguments[0], 2) + Math.pow(arguments[3] - arguments[1], 2) } } /** * returns the closest cardinal (N, S, E, W) to the given angle (in radians) * @param {number} angle * @return {number} closest cardinal in radians */ function closestAngle(angle) { var left = differenceAngles(angle, LEFT) var right = differenceAngles(angle, RIGHT) var up = differenceAngles(angle, UP) var down = differenceAngles(angle, DOWN) if (left <= right && left <= up && left <= down) { return LEFT } else if (right <= up && right <= down) { return RIGHT } else if (up <= down) { return UP } else { return DOWN } } /** * checks whether angles a1 and a2 are equal (after normalizing) * @param {number} a1 * @param {number} a2 * @param {number} [wiggle] return true if the difference between the angles is <= wiggle * @return {boolean} a1 === a2 */ function equals(a1, a2, wiggle) { if (wiggle) { return differenceAngles(a1, a2) < wiggle } else { return normalize(a1) === normalize(a2) } } /** * return a text representation of the cardinal direction * @param {number} angle * @returns {string} UP, DOWN, LEFT, RIGHT, or NOT CARDINAL */ function explain(angle) { switch (angle) { case UP: return 'UP' case DOWN: return 'DOWN' case LEFT: return 'LEFT' case RIGHT: return 'RIGHT' default: return 'NOT CARDINAL' } } module.exports = { UP: UP, DOWN: DOWN, LEFT: LEFT, RIGHT: RIGHT, NORTH: NORTH, SOUTH: SOUTH, WEST: WEST, EAST: EAST, PI_2: PI_2, PI_QUARTER: PI_QUARTER, PI_HALF: PI_HALF, toDegrees: toDegrees, toRadians: toRadians, isAngleBetween: isAngleBetween, differenceAnglesSign: differenceAnglesSign, differenceAngles: differenceAngles, shortestAngle: shortestAngle, normalize: normalize, angleTwoPoints: angleTwoPoints, distanceTwoPoints: distanceTwoPoints, distanceTwoPointsSquared: distanceTwoPointsSquared, closestAngle: closestAngle, equals: equals, explain: explain } },{}],23:[function(require,module,exports){ // yy-color // by David Figatner // MIT License // (c) YOPEY YOPEY LLC 2017 // https://github.com/davidfig/color var Random = require('yy-random') /** * converts a #FFFFFF to 0x123456 * @param {string} color * @return {string} */ function poundToHex(color) { return '0x' + parseInt(color.substr(1)).toString(16) } /** * converts a 0x123456 to #FFFFFF * @param {string} color * @return {string} */ function hexToPound(color) { return '#' + color.substr(2) } /** * converts a number to #FFFFFF * @param {number} color * @return {string} */ function valueToPound(color) { return '#' + color.toString(16) } /** * based on tinycolor * https://github.com/bgrins/TinyColor * BSD license: https://github.com/bgrins/TinyColor/blob/master/LICENSE * @param {string} color * @returns {object} */ function hexToHsl (color) { var rgb = this.hexToRgb(color), r = rgb.r, g = rgb.g, b = rgb.b var max = Math.max(r, g, b), min = Math.min(r, g, b) var h, s, l = (max + min) / 2 if (max === min) { h = s = 0 // achromatic } else { var d = max - min s = l > 0.5 ? d / (2 - max - min) : d / (max + min) switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break case g: h = (b - r) / d + 2; break case b: h = (r - g) / d + 4; break } h /= 6 } return { h: h, s: s, l: l } } /** based on tinycolor * https://github.com/bgrins/TinyColor * BSD license: https://github.com/bgrins/TinyColor/blob/master/LICENSE * @param {object|number} color {h, s, b} or h * @param {number} [s] * @param {number} [l] * @returns number */ function hslToHex(color) { var r, g, b, h, s, l if (arguments.length === 1) { h = color.h, s = color.s, l = color.l } else { h = arguments[0] s = arguments[1] l = arguments[2] } function hue2rgb(p, q, t) { if (t < 0) t += 1 if (t > 1) t -= 1 if (t < 1/6) return p + (q - p) * 6 * t if (t < 1/2) return q if (t < 2/3) return p + (q - p) * (2/3 - t) * 6 return p } if (s === 0) { r = g = b = l // achromatic } else { var q = l < 0.5 ? l * (1 + s) : l + s - l * s var p = 2 * l - q r = hue2rgb(p, q, h + 1/3) g = hue2rgb(p, q, h) b = hue2rgb(p, q, h - 1/3) } return this.rgbToHex(r * 255, g * 255, b * 255) } /* darkens a color by the percentage * @param {object} color in hex (0xabcdef) * @param {number} amount * @return {number} */ function darken(color, amount) { return this.blend(amount, color, 0) } /** based on tinycolor * https://github.com/bgrins/TinyColor * BSD license: https://github.com/bgrins/TinyColor/blob/master/LICENSE * @param {object} color * @param {number} amount */ function saturate(color, amount) { amount = (amount === 0) ? 0 : (amount || 10) var hsl = this.hexToHsl(color) hsl.s += amount / 100 hsl.s = Math.min(1, Math.max(0, hsl.s)) return this.hslToHex(hsl) } /** based on tinycolor * https://github.com/bgrins/TinyColor * BSD license: https://github.com/bgrins/TinyColor/blob/master/LICENSE * @param {object} color * @param {number} amount */ function desaturate(color, amount) { amount = (amount === 0) ? 0 : (amount || 10) var hsl = this.hexToHsl(color) hsl.s -= amount / 100 hsl.s = Math.min(1, Math.max(0, hsl.s)) return this.hslToHex(hsl) } /** * blends two colors together * @param {number} percent [0.0 - 1.0] * @param {string} color1 first color in 0x123456 format * @param {string} color2 second color in 0x123456 format * @return {number} */ function blend(percent, color1, color2) { if (percent === 0) { return color1 } if (percent === 1) { return color2 } var r1 = color1 >> 16 var g1 = color1 >> 8 & 0x0000ff var b1 = color1 & 0x0000ff var r2 = color2 >> 16 var g2 = color2 >> 8 & 0x0000ff var b2 = color2 & 0x0000ff var percent1 = 1 - percent var r = percent1 * r1 + percent * r2 var g = percent1 * g1 + percent * g2 var b = percent1 * b1 + percent * b2 return r << 16 | g << 8 | b } /** * returns a hex color into an rgb value * @param {number} hex * @return {string} */ function hexToRgb(hex) { if (hex === 0) { hex = '0x000000' } else if (typeof hex !== 'string') { var s = '000000' + hex.toString(16) hex = '0x' + s.substr(s.length - 6) } var result = /^0x?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null } /** * rgb color to hex in the form of 0x123456 * @param {(number|string)} r first number or 'rgb(...)' string * @param {(number|null)} g * @param {(number|null)} b * @return {string} */ function rgbToHex(r, g, b) { if (arguments.length === 1) { if (Array.isArray(arguments[0])) { var number = arguments[0] r = number[0] g = number[1] b = number[2] } else { var parse = r.replace(/( *rgb *\( *)|( )|(\) *;?)/,'') var numbers = parse.split(',') r = numbers[0] g = numbers[1] b = numbers[2] } } return '0x' + ((1 << 24) + (parseInt(r) << 16) + (parseInt(g) << 8) + parseInt(b)).toString(16).slice(1) } /** * returns a random color with balanced r, g, b values (i.e., r, g, b either have the same value or are 0) * @param {number} min value for random number * @param {number} max value for random number * @return {number} color */ function random(min, max) { function random() { return Random.range(min, max) } var colors = [{r:1, g:1, b:1}, {r:1, g:1, b:0}, {r:1,g:0,b:1}, {r:0,g:1,b:1}, {r:1,g:0,b:0}, {r:0,g:1,b:0}, {r:0,g:0,b:1}] var color = Random.pick(colors) min = min || 0 max = max || 255 return this.rgbToHex(color.r ? random() : 0, color.g ? random() : 0, color.b ? random() : 0) } // h: 0-360, s: 0-1, l: 0-1 /** * returns a random color based on hsl * @param {number} hMin [0, 360] * @param {number} hMax [hMin, 360] * @param {number} sMin [0, 1] * @param {number} sMax [sMin, 1] * @param {number} lMin [0, 1] * @param {number} lMax [lMin, 1] */ function randomHSL(hMin, hMax, sMin, sMax, lMin, lMax) { var color = { h: Random.range(hMin, hMax), s: Random.range(sMin, sMax, true), l: Random.range(lMin, lMax, true) } return this.hslToHex(color) } /** * returns random colors based on HSL with different hues * based on http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ * @returns {number[]} colors in hex format (0x123456) */ function randomGoldenRatioHSL(count, saturation, luminosity) { var goldenRatio = 0.618033988749895 var h = Random.get(1, true) var colors = [] for (var i = 0; i < count; i++) { colors.push(this.hslToHex(h, saturation, luminosity)) h = (h + goldenRatio) % 1 } return colors } module.exports = { poundToHex: poundToHex, hexToPound: hexToPound, valueToPound: valueToPound, hexToHsl: hexToHsl, hslToHex: hslToHex, hexToRgb: hexToRgb, rgbToHex: rgbToHex, darken: darken, saturate: saturate, desaturate: desaturate, blend: blend, random: random, randomHSL: randomHSL, randomGoldenRatioHSL: randomGoldenRatioHSL } },{"yy-random":24}],24:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // yy-random // by David Figatner // MIT license // copyright YOPEY YOPEY LLC 2016-17 // https://github.com/davidfig/random var seedrandom = require('seedrandom'); var Random = function () { function Random() { _classCallCheck(this, Random); this.generator = Math.random; } /** * generates a seeded number * @param {number} seed * @param {object} [options] * @param {string} [PRNG="alea"] - name of algorithm, see https://github.com/davidbau/seedrandom * @param {boolean} [save=true] */ _createClass(Random, [{ key: 'seed', value: function seed(_seed, options) { options = options || {}; this.generator = seedrandom[options.PRNG || 'alea'](_seed, { state: options.state }); this.options = options; } /** * saves the state of the random generator * can only be used after Random.seed() is called * @returns {number} state */ }, { key: 'save', value: function save() { if (this.generator !== Math.random) { return this.generator.state(); } } /** * restores the state of the random generator * @param {number} state */ }, { key: 'restore', value: function restore(state) { this.generator = seedrandom[this.options.PRNG || 'alea']('', { state: state }); } /** * changes the generator to use the old Math.sin-based random function * based on : http://stackoverflow.com/questions/521295/javascript-random-seeds * (deprecated) Use only for compatibility purposes * @param {number} seed */ }, { key: 'seedOld', value: function seedOld(seed) { this.generator = function () { var x = Math.sin(seed++) * 10000; return x - Math.floor(x); }; } /** * create a separate random generator using the seed * @param {number} seed * @return {object} */ }, { key: 'separateSeed', value: function separateSeed(seed) { var random = new Random(); random.seed(seed); return random; } /** * resets the random number this.generator to Math.random() */ }, { key: 'reset', value: function reset() { this.generator = Math.random; } /** * returns a random number using the this.generator between [0, ceiling - 1] * @param {number} ceiling * @param {boolean} [useFloat=false] * @return {number} */ }, { key: 'get', value: function get(ceiling, useFloat) { var negative = ceiling < 0 ? -1 : 1; ceiling *= negative; var result = void 0; if (useFloat) { result = this.generator() * ceiling; } else { result = Math.floor(this.generator() * ceiling); } return result * negative; } /** * returns a random integer between 0 - Number.MAX_SAFE_INTEGER * @return {number} */ }, { key: 'getHuge', value: function getHuge() { return this.get(Number.MAX_SAFE_INTEGER); } /** * random number [middle - range, middle + range] * @param {number} middle * @param {number} delta * @param {boolean} [useFloat=false] * @return {number} */ }, { key: 'middle', value: function middle(_middle, delta, useFloat) { var half = delta / 2; return this.range(_middle - half, _middle + half, useFloat); } /** * random number [start, end] * @param {number} start * @param {number} end * @param {boolean} [useFloat=false] if true, then range is (start, end)--i.e., not inclusive to start and end * @return {number} */ }, { key: 'range', value: function range(start, end, useFloat) { // case where there is no range if (end === start) { return end; } if (useFloat) { return this.get(end - start, true) + start; } else { var range = void 0; if (start < 0 && end > 0) { range = -start + end + 1; } else if (start === 0 && end > 0) { range = end + 1; } else if (start < 0 && end === 0) { range = start - 1; start = 1; } else if (start < 0 && end < 0) { range = end - start - 1; } else { range = end - start + 1; } return Math.floor(this.generator() * range) + start; } } /** * an array of random numbers between [start, end] * @param {number} start * @param {number} end * @param {number} count * @param {boolean} [useFloat=false] * @return {number[]} */ }, { key: 'rangeMultiple', value: function rangeMultiple(start, end, count, useFloat) { var array = []; for (var i = 0; i < count; i++) { array.push(this.range(start, end, useFloat)); } return array; } /** * an array of random numbers between [middle - range, middle + range] * @param {number} middle * @param {number} range * @param {number} count * @param {boolean} [useFloat=false] * @return {number[]} */ }, { key: 'middleMultiple', value: function middleMultiple(middle, range, count, useFloat) { var array = []; for (var i = 0; i < count; i++) { array.push(middle(middle, range, useFloat)); } return array; } /** * @param {number} [chance=0.5] * returns random sign (either +1 or -1) * @return {number} */ }, { key: 'sign', value: function sign(chance) { chance = chance || 0.5; return this.generator() < chance ? 1 : -1; } /** * tells you whether a random chance was achieved * @param {number} [percent=0.5] * @return {boolean} */ }, { key: 'chance', value: function chance(percent) { return this.generator() < (percent || 0.5); } /** * returns a random angle in radians [0 - 2 * Math.PI) */ }, { key: 'angle', value: function angle() { return this.get(Math.PI * 2, true); } /** * Shuffle array (either in place or copied) * from http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array * @param {Array} array * @param {boolean} [copy=false] whether to shuffle in place (default) or return a new shuffled array * @return {Array} a shuffled array */ }, { key: 'shuffle', value: function shuffle(array, copy) { if (copy) { array = array.slice(); } if (array.length === 0) { return array; } var currentIndex = array.length, temporaryValue = void 0, randomIndex = void 0; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = this.get(currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } /** * picks a random element from an array * @param {Array} array * @return {*} */ }, { key: 'pick', value: function pick(array, remove) { if (!remove) { return array[this.get(array.length)]; } else { var pick = this.get(array.length); var temp = array[pick]; array.splice(pick, 1); return temp; } } /** * returns a random property from an object * from http://stackoverflow.com/questions/2532218/pick-random-property-from-a-javascript-object * @param {object} obj * @return {*} */ }, { key: 'property', value: function property(obj) { var result; var count = 0; for (var prop in obj) { if (this.chance(1 / ++count)) { result = prop; } } return result; } /** * creates a random set where each entry is a value between [min, max] * @param {number} min * @param {number} max * @param {number} amount of numbers in set * @param {number[]} */ }, { key: 'set', value: function set(min, max, amount) { var set = [], all = [], i; for (i = min; i < max; i++) { all.push(i); } for (i = 0; i < amount; i++) { var found = this.get(all.length); set.push(all[found]); all.splice(found, 1); } return set; } /** * returns a set of numbers with a randomly even distribution (i.e., no overlapping and filling the space) * @param {number} start position * @param {number} end position * @param {number} count of non-start/end points * @param {boolean} [includeStart=false] includes start point (count++) * @param {boolean} [includeEnd=false] includes end point (count++) * @param {boolean} [useFloat=false] * @param {number[]} */ }, { key: 'distribution', value: function distribution(start, end, count, includeStart, includeEnd, useFloat) { var interval = Math.floor((end - start) / count); var halfInterval = interval / 2; var quarterInterval = interval / 4; var set = []; if (includeStart) { set.push(start); } for (var i = 0; i < count; i++) { set.push(start + i * interval + halfInterval + this.range(-quarterInterval, quarterInterval, useFloat)); } if (includeEnd) { set.push(end); } return set; } /** * returns a random number based on weighted probability between [min, max] * from http://stackoverflow.com/questions/22656126/javascript-random-number-with-weighted-probability * @param {number} min value * @param {number} max value * @param {number} target for average value * @param {number} stddev - standard deviation */ }, { key: 'weightedProbabilityInt', value: function weightedProbabilityInt(min, max, target, stddev) { function normRand() { var x1 = void 0, x2 = void 0, rad = void 0; do { x1 = 2 * this.get(1, true) - 1; x2 = 2 * this.get(1, true) - 1; rad = x1 * x1 + x2 * x2; } while (rad >= 1 || rad === 0); var c = Math.sqrt(-2 * Math.log(rad) / rad); return x1 * c; } stddev = stddev || 1; if (Math.random() < 0.81546) { while (true) { var sample = normRand() * stddev + target; if (sample >= min && sample <= max) { return sample; } } } else { return this.range(min, max); } } /* * returns a random hex color (0 - 0xffffff) * @return {number} */ }, { key: 'color', value: function color() { return this.get(0xffffff); } }]); return Random; }(); module.exports = new Random(); },{"seedrandom":14}],25:[function(require,module,exports){ },{}]},{},[3]); (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= this.time) { this.parent.x = toX.end; this.toX = null; this.parent.emit('bounce-x-end', this.parent); } else { this.parent.x = this.ease(toX.time, toX.start, toX.delta, this.time); } this.parent.dirty = true; } if (this.toY) { var toY = this.toY; toY.time += elapsed; this.parent.emit('moved', { viewport: this.parent, type: 'bounce-y' }); if (toY.time >= this.time) { this.parent.y = toY.end; this.toY = null; this.parent.emit('bounce-y-end', this.parent); } else { this.parent.y = this.ease(toY.time, toY.start, toY.delta, this.time); } this.parent.dirty = true; } } }, { key: 'calcUnderflowX', value: function calcUnderflowX() { var x = void 0; switch (this.underflowX) { case -1: x = 0; break; case 1: x = this.parent.screenWidth - this.parent.screenWorldWidth; break; default: x = (this.parent.screenWidth - this.parent.screenWorldWidth) / 2; } return x; } }, { key: 'calcUnderflowY', value: function calcUnderflowY() { var y = void 0; switch (this.underflowY) { case -1: y = 0; break; case 1: y = this.parent.screenHeight - this.parent.screenWorldHeight; break; default: y = (this.parent.screenHeight - this.parent.screenWorldHeight) / 2; } return y; } }, { key: 'bounce', value: function bounce() { if (this.paused) { return; } var oob = void 0; var decelerate = this.parent.plugins['decelerate']; if (decelerate && (decelerate.x || decelerate.y)) { if (decelerate.x && decelerate.percentChangeX === decelerate.friction || decelerate.y && decelerate.percentChangeY === decelerate.friction) { oob = this.parent.OOB(); if (oob.left && this.left || oob.right && this.right) { decelerate.percentChangeX = this.friction; } if (oob.top && this.top || oob.bottom && this.bottom) { decelerate.percentChangeY = this.friction; } } } var drag = this.parent.plugins['drag'] || {}; var pinch = this.parent.plugins['pinch'] || {}; decelerate = decelerate || {}; if (!drag.active && !pinch.active && (!this.toX || !this.toY) && (!decelerate.x || !decelerate.y)) { oob = oob || this.parent.OOB(); var point = oob.cornerPoint; if (!this.toX && !decelerate.x) { var x = null; if (oob.left && this.left) { x = this.parent.screenWorldWidth < this.parent.screenWidth ? this.calcUnderflowX() : 0; } else if (oob.right && this.right) { x = this.parent.screenWorldWidth < this.parent.screenWidth ? this.calcUnderflowX() : -point.x; } if (x !== null && this.parent.x !== x) { this.toX = { time: 0, start: this.parent.x, delta: x - this.parent.x, end: x }; this.parent.emit('bounce-x-start', this.parent); } } if (!this.toY && !decelerate.y) { var y = null; if (oob.top && this.top) { y = this.parent.screenWorldHeight < this.parent.screenHeight ? this.calcUnderflowY() : 0; } else if (oob.bottom && this.bottom) { y = this.parent.screenWorldHeight < this.parent.screenHeight ? this.calcUnderflowY() : -point.y; } if (y !== null && this.parent.y !== y) { this.toY = { time: 0, start: this.parent.y, delta: y - this.parent.y, end: y }; this.parent.emit('bounce-y-start', this.parent); } } } } }, { key: 'reset', value: function reset() { this.toX = this.toY = null; } }]); return Bounce; }(Plugin); },{"./plugin":9,"./utils":12}],2:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Plugin = require('./plugin'); module.exports = function (_Plugin) { _inherits(ClampZoom, _Plugin); /** * @private * @param {object} [options] * @param {number} [options.minWidth] minimum width * @param {number} [options.minHeight] minimum height * @param {number} [options.maxWidth] maximum width * @param {number} [options.maxHeight] maximum height */ function ClampZoom(parent, options) { _classCallCheck(this, ClampZoom); var _this = _possibleConstructorReturn(this, (ClampZoom.__proto__ || Object.getPrototypeOf(ClampZoom)).call(this, parent)); _this.minWidth = options.minWidth; _this.minHeight = options.minHeight; _this.maxWidth = options.maxWidth; _this.maxHeight = options.maxHeight; return _this; } _createClass(ClampZoom, [{ key: 'resize', value: function resize() { this.clamp(); } }, { key: 'clamp', value: function clamp() { if (this.paused) { return; } var width = this.parent.worldScreenWidth; var height = this.parent.worldScreenHeight; if (this.minWidth && width < this.minWidth) { this.parent.fitWidth(this.minWidth); width = this.parent.worldScreenWidth; height = this.parent.worldScreenHeight; this.parent.emit('zoomed', { viewport: this.parent, type: 'clamp-zoom' }); } if (this.maxWidth && width > this.maxWidth) { this.parent.fitWidth(this.maxWidth); width = this.parent.worldScreenWidth; height = this.parent.worldScreenHeight; this.parent.emit('zoomed', { viewport: this.parent, type: 'clamp-zoom' }); } if (this.minHeight && height < this.minHeight) { this.parent.fitHeight(this.minHeight); width = this.parent.worldScreenWidth; height = this.parent.worldScreenHeight; this.parent.emit('zoomed', { viewport: this.parent, type: 'clamp-zoom' }); } if (this.maxHeight && height > this.maxHeight) { this.parent.fitHeight(this.maxHeight); this.parent.emit('zoomed', { viewport: this.parent, type: 'clamp-zoom' }); } } }]); return ClampZoom; }(Plugin); },{"./plugin":9}],3:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Plugin = require('./plugin'); var utils = require('./utils'); module.exports = function (_Plugin) { _inherits(clamp, _Plugin); /** * @private * @param {object} options * @param {(number|boolean)} [options.left] clamp left; true=0 * @param {(number|boolean)} [options.right] clamp right; true=viewport.worldWidth * @param {(number|boolean)} [options.top] clamp top; true=0 * @param {(number|boolean)} [options.bottom] clamp bottom; true=viewport.worldHeight * @param {string} [options.direction] (all, x, or y) using clamps of [0, viewport.worldWidth/viewport.worldHeight]; replaces left/right/top/bottom if set * @param {string} [options.underflow=center] (top/bottom/center and left/right/center, or center) where to place world if too small for screen */ function clamp(parent, options) { _classCallCheck(this, clamp); options = options || {}; var _this = _possibleConstructorReturn(this, (clamp.__proto__ || Object.getPrototypeOf(clamp)).call(this, parent)); if (typeof options.direction === 'undefined') { _this.left = utils.defaults(options.left, null); _this.right = utils.defaults(options.right, null); _this.top = utils.defaults(options.top, null); _this.bottom = utils.defaults(options.bottom, null); } else { _this.left = options.direction === 'x' || options.direction === 'all'; _this.right = options.direction === 'x' || options.direction === 'all'; _this.top = options.direction === 'y' || options.direction === 'all'; _this.bottom = options.direction === 'y' || options.direction === 'all'; } _this.parseUnderflow(options.underflow || 'center'); _this.move(); return _this; } _createClass(clamp, [{ key: 'parseUnderflow', value: function parseUnderflow(clamp) { clamp = clamp.toLowerCase(); if (clamp === 'center') { this.underflowX = 0; this.underflowY = 0; } else { this.underflowX = clamp.indexOf('left') !== -1 ? -1 : clamp.indexOf('right') !== -1 ? 1 : 0; this.underflowY = clamp.indexOf('top') !== -1 ? -1 : clamp.indexOf('bottom') !== -1 ? 1 : 0; } } }, { key: 'move', value: function move() { this.update(); } }, { key: 'update', value: function update() { if (this.paused) { return; } var decelerate = this.parent.plugins['decelerate'] || {}; if (this.left !== null || this.right !== null) { var moved = void 0; if (this.parent.screenWorldWidth < this.parent.screenWidth) { switch (this.underflowX) { case -1: if (this.parent.x !== 0) { this.parent.x = 0; moved = true; } break; case 1: if (this.parent.x !== this.parent.screenWidth - this.parent.screenWorldWidth) { this.parent.x = this.parent.screenWidth - this.parent.screenWorldWidth; moved = true; } break; default: if (this.parent.x !== (this.parent.screenWidth - this.parent.screenWorldWidth) / 2) { this.parent.x = (this.parent.screenWidth - this.parent.screenWorldWidth) / 2; moved = true; } } } else { if (this.left !== null) { if (this.parent.left < (this.left === true ? 0 : this.left)) { this.parent.x = -(this.left === true ? 0 : this.left) * this.parent.scale.x; decelerate.x = 0; moved = true; } } if (this.right !== null) { if (this.parent.right > (this.right === true ? this.parent.worldWidth : this.right)) { this.parent.x = -(this.right === true ? this.parent.worldWidth : this.right) * this.parent.scale.x + this.parent.screenWidth; decelerate.x = 0; moved = true; } } } if (moved) { this.parent.emit('moved', { viewport: this.parent, type: 'clamp-x' }); } } if (this.top !== null || this.bottom !== null) { var _moved = void 0; if (this.parent.screenWorldHeight < this.parent.screenHeight) { switch (this.underflowY) { case -1: if (this.parent.y !== 0) { this.parent.y = 0; _moved = true; } break; case 1: if (this.parent.y !== this.parent.screenHeight - this.parent.screenWorldHeight) { this.parent.y = this.parent.screenHeight - this.parent.screenWorldHeight; _moved = true; } break; default: if (this.parent.y !== (this.parent.screenHeight - this.parent.screenWorldHeight) / 2) { this.parent.y = (this.parent.screenHeight - this.parent.screenWorldHeight) / 2; _moved = true; } } } else { if (this.top !== null) { if (this.parent.top < (this.top === true ? 0 : this.top)) { this.parent.y = -(this.top === true ? 0 : this.top) * this.parent.scale.y; decelerate.y = 0; _moved = true; } } if (this.bottom !== null) { if (this.parent.bottom > (this.bottom === true ? this.parent.worldHeight : this.bottom)) { this.parent.y = -(this.bottom === true ? this.parent.worldHeight : this.bottom) * this.parent.scale.y + this.parent.screenHeight; decelerate.y = 0; _moved = true; } } } if (_moved) { this.parent.emit('moved', { viewport: this.parent, type: 'clamp-y' }); } } } }]); return clamp; }(Plugin); },{"./plugin":9,"./utils":12}],4:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var utils = require('./utils'); var Plugin = require('./plugin'); module.exports = function (_Plugin) { _inherits(Decelerate, _Plugin); /** * @private * @param {Viewport} parent * @param {object} [options] * @param {number} [options.friction=0.95] percent to decelerate after movement * @param {number} [options.bounce=0.8] percent to decelerate when past boundaries (only applicable when viewport.bounce() is active) * @param {number} [options.minSpeed=0.01] minimum velocity before stopping/reversing acceleration */ function Decelerate(parent, options) { _classCallCheck(this, Decelerate); var _this = _possibleConstructorReturn(this, (Decelerate.__proto__ || Object.getPrototypeOf(Decelerate)).call(this, parent)); options = options || {}; _this.friction = options.friction || 0.95; _this.bounce = options.bounce || 0.5; _this.minSpeed = typeof options.minSpeed !== 'undefined' ? options.minSpeed : 0.01; _this.saved = []; return _this; } _createClass(Decelerate, [{ key: 'down', value: function down() { this.saved = []; this.x = this.y = false; } }, { key: 'move', value: function move() { if (this.paused) { return; } var count = this.parent.countDownPointers(); if (count === 1 || count > 1 && !this.parent.plugins['pinch']) { this.saved.push({ x: this.parent.x, y: this.parent.y, time: performance.now() }); if (this.saved.length > 60) { this.saved.splice(0, 30); } } } }, { key: 'up', value: function up() { if (this.parent.countDownPointers() === 0 && this.saved.length) { var now = performance.now(); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this.saved[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var save = _step.value; if (save.time >= now - 100) { var time = now - save.time; this.x = (this.parent.x - save.x) / time; this.y = (this.parent.y - save.y) / time; this.percentChangeX = this.percentChangeY = this.friction; break; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } } /** * manually activate plugin * @param {object} options * @param {number} [options.x] * @param {number} [options.y] */ }, { key: 'activate', value: function activate(options) { options = options || {}; if (typeof options.x !== 'undefined') { this.x = options.x; this.percentChangeX = this.friction; } if (typeof options.y !== 'undefined') { this.y = options.y; this.percentChangeY = this.friction; } } }, { key: 'update', value: function update(elapsed) { if (this.paused) { return; } var moved = void 0; if (this.x) { this.parent.x += this.x * elapsed; this.x *= this.percentChangeX; if (Math.abs(this.x) < this.minSpeed) { this.x = 0; } moved = true; } if (this.y) { this.parent.y += this.y * elapsed; this.y *= this.percentChangeY; if (Math.abs(this.y) < this.minSpeed) { this.y = 0; } moved = true; } if (moved) { this.parent.dirty = true; this.parent.emit('moved', { viewport: this.parent, type: 'decelerate' }); } } }, { key: 'reset', value: function reset() { this.x = this.y = null; } }]); return Decelerate; }(Plugin); },{"./plugin":9,"./utils":12}],5:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var utils = require('./utils'); var Plugin = require('./plugin'); module.exports = function (_Plugin) { _inherits(Drag, _Plugin); /** * enable one-finger touch to drag * @private * @param {Viewport} parent * @param {object} [options] * @param {string} [options.direction=all] direction to drag (all, x, or y) * @param {boolean} [options.wheel=true] use wheel to scroll in y direction (unless wheel plugin is active) * @param {number} [options.wheelScroll=1] number of pixels to scroll with each wheel spin * @param {boolean} [options.reverse] reverse the direction of the wheel scroll * @param {boolean|string} [options.clampWheel] (true, x, or y) clamp wheel (to avoid weird bounce with mouse wheel) * @param {string} [options.underflow=center] (top/bottom/center and left/right/center, or center) where to place world if too small for screen */ function Drag(parent, options) { _classCallCheck(this, Drag); options = options || {}; var _this = _possibleConstructorReturn(this, (Drag.__proto__ || Object.getPrototypeOf(Drag)).call(this, parent)); _this.moved = false; _this.wheelActive = utils.defaults(options.wheel, true); _this.wheelScroll = options.wheelScroll || 1; _this.reverse = options.reverse ? 1 : -1; _this.clampWheel = options.clampWheel; _this.xDirection = !options.direction || options.direction === 'all' || options.direction === 'x'; _this.yDirection = !options.direction || options.direction === 'all' || options.direction === 'y'; _this.parseUnderflow(options.underflow || 'center'); return _this; } _createClass(Drag, [{ key: 'parseUnderflow', value: function parseUnderflow(clamp) { clamp = clamp.toLowerCase(); if (clamp === 'center') { this.underflowX = 0; this.underflowY = 0; } else { this.underflowX = clamp.indexOf('left') !== -1 ? -1 : clamp.indexOf('right') !== -1 ? 1 : 0; this.underflowY = clamp.indexOf('top') !== -1 ? -1 : clamp.indexOf('bottom') !== -1 ? 1 : 0; } } }, { key: 'down', value: function down(e) { if (this.paused) { return; } var count = this.parent.countDownPointers(); if ((count === 1 || count > 1 && !this.parent.plugins['pinch']) && this.parent.parent) { var parent = this.parent.parent.toLocal(e.data.global); this.last = { x: e.data.global.x, y: e.data.global.y, parent: parent }; this.current = e.data.pointerId; } else { this.last = null; } } }, { key: 'move', value: function move(e) { if (this.paused) { return; } if (this.last && this.current === e.data.pointerId) { var x = e.data.global.x; var y = e.data.global.y; var count = this.parent.countDownPointers(); if (count === 1 || count > 1 && !this.parent.plugins['pinch']) { var distX = x - this.last.x; var distY = y - this.last.y; if (this.moved || this.xDirection && this.parent.checkThreshold(distX) || this.yDirection && this.parent.checkThreshold(distY)) { var newParent = this.parent.parent.toLocal(e.data.global); if (this.xDirection) { this.parent.x += newParent.x - this.last.parent.x; } if (this.yDirection) { this.parent.y += newParent.y - this.last.parent.y; } this.last = { x: x, y: y, parent: newParent }; if (!this.moved) { this.parent.emit('drag-start', { screen: this.last, world: this.parent.toWorld(this.last), viewport: this.parent }); } this.moved = true; this.parent.dirty = true; this.parent.emit('moved', { viewport: this.parent, type: 'drag' }); } } else { this.moved = false; } } } }, { key: 'up', value: function up() { var touches = this.parent.getTouchPointers(); if (touches.length === 1) { var pointer = touches[0]; if (pointer.last) { var parent = this.parent.parent.toLocal(pointer.last); this.last = { x: pointer.last.x, y: pointer.last.y, parent: parent }; this.current = pointer.last.data.pointerId; } this.moved = false; } else if (this.last) { if (this.moved) { this.parent.emit('drag-end', { screen: this.last, world: this.parent.toWorld(this.last), viewport: this.parent }); this.last = this.moved = false; } } } }, { key: 'wheel', value: function wheel(e) { if (this.paused) { return; } if (this.wheelActive) { var wheel = this.parent.plugins['wheel']; if (!wheel) { this.parent.x += e.deltaX * this.wheelScroll * this.reverse; this.parent.y += e.deltaY * this.wheelScroll * this.reverse; if (this.clampWheel) { this.clamp(); } this.parent.emit('wheel-scroll', this.parent); this.parent.emit('moved', this.parent); this.parent.dirty = true; e.preventDefault(); return true; } } } }, { key: 'resume', value: function resume() { this.last = null; this.paused = false; } }, { key: 'clamp', value: function clamp() { var decelerate = this.parent.plugins['decelerate'] || {}; if (this.clampWheel !== 'y') { if (this.parent.screenWorldWidth < this.parent.screenWidth) { switch (this.underflowX) { case -1: this.parent.x = 0; break; case 1: this.parent.x = this.parent.screenWidth - this.parent.screenWorldWidth; break; default: this.parent.x = (this.parent.screenWidth - this.parent.screenWorldWidth) / 2; } } else { if (this.parent.left < 0) { this.parent.x = 0; decelerate.x = 0; } else if (this.parent.right > this.parent.worldWidth) { this.parent.x = -this.parent.worldWidth * this.parent.scale.x + this.parent.screenWidth; decelerate.x = 0; } } } if (this.clampWheel !== 'x') { if (this.parent.screenWorldHeight < this.parent.screenHeight) { switch (this.underflowY) { case -1: this.parent.y = 0; break; case 1: this.parent.y = this.parent.screenHeight - this.parent.screenWorldHeight; break; default: this.parent.y = (this.parent.screenHeight - this.parent.screenWorldHeight) / 2; } } else { if (this.parent.top < 0) { this.parent.y = 0; decelerate.y = 0; } if (this.parent.bottom > this.parent.worldHeight) { this.parent.y = -this.parent.worldHeight * this.parent.scale.y + this.parent.screenHeight; decelerate.y = 0; } } } } }, { key: 'active', get: function get() { return this.moved; } }]); return Drag; }(Plugin); },{"./plugin":9,"./utils":12}],6:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Plugin = require('./plugin'); module.exports = function (_Plugin) { _inherits(Follow, _Plugin); /** * @private * @param {Viewport} parent * @param {PIXI.DisplayObject} target to follow (object must include {x: x-coordinate, y: y-coordinate}) * @param {object} [options] * @param {number} [options.speed=0] to follow in pixels/frame (0=teleport to location) * @param {number} [options.radius] radius (in world coordinates) of center circle where movement is allowed without moving the viewport */ function Follow(parent, target, options) { _classCallCheck(this, Follow); var _this = _possibleConstructorReturn(this, (Follow.__proto__ || Object.getPrototypeOf(Follow)).call(this, parent)); options = options || {}; _this.speed = options.speed || 0; _this.target = target; _this.radius = options.radius; return _this; } _createClass(Follow, [{ key: 'update', value: function update() { if (this.paused) { return; } var center = this.parent.center; var toX = this.target.x, toY = this.target.y; if (this.radius) { var distance = Math.sqrt(Math.pow(this.target.y - center.y, 2) + Math.pow(this.target.x - center.x, 2)); if (distance > this.radius) { var angle = Math.atan2(this.target.y - center.y, this.target.x - center.x); toX = this.target.x - Math.cos(angle) * this.radius; toY = this.target.y - Math.sin(angle) * this.radius; } else { return; } } if (this.speed) { var deltaX = toX - center.x; var deltaY = toY - center.y; if (deltaX || deltaY) { var _angle = Math.atan2(toY - center.y, toX - center.x); var changeX = Math.cos(_angle) * this.speed; var changeY = Math.sin(_angle) * this.speed; var x = Math.abs(changeX) > Math.abs(deltaX) ? toX : center.x + changeX; var y = Math.abs(changeY) > Math.abs(deltaY) ? toY : center.y + changeY; this.parent.moveCenter(x, y); this.parent.emit('moved', { viewport: this.parent, type: 'follow' }); } } else { this.parent.moveCenter(toX, toY); this.parent.emit('moved', { viewport: this.parent, type: 'follow' }); } } }]); return Follow; }(Plugin); },{"./plugin":9}],7:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var utils = require('./utils'); var Plugin = require('./plugin'); module.exports = function (_Plugin) { _inherits(MouseEdges, _Plugin); /** * Scroll viewport when mouse hovers near one of the edges. * @private * @param {Viewport} parent * @param {object} [options] * @param {number} [options.radius] distance from center of screen in screen pixels * @param {number} [options.distance] distance from all sides in screen pixels * @param {number} [options.top] alternatively, set top distance (leave unset for no top scroll) * @param {number} [options.bottom] alternatively, set bottom distance (leave unset for no top scroll) * @param {number} [options.left] alternatively, set left distance (leave unset for no top scroll) * @param {number} [options.right] alternatively, set right distance (leave unset for no top scroll) * @param {number} [options.speed=8] speed in pixels/frame to scroll viewport * @param {boolean} [options.reverse] reverse direction of scroll * @param {boolean} [options.noDecelerate] don't use decelerate plugin even if it's installed * @param {boolean} [options.linear] if using radius, use linear movement (+/- 1, +/- 1) instead of angled movement (Math.cos(angle from center), Math.sin(angle from center)) * * @event mouse-edge-start(Viewport) emitted when mouse-edge starts * @event mouse-edge-end(Viewport) emitted when mouse-edge ends */ function MouseEdges(parent, options) { _classCallCheck(this, MouseEdges); var _this = _possibleConstructorReturn(this, (MouseEdges.__proto__ || Object.getPrototypeOf(MouseEdges)).call(this, parent)); options = options || {}; _this.options = options; _this.reverse = options.reverse ? 1 : -1; _this.noDecelerate = options.noDecelerate; _this.linear = options.linear; _this.radiusSquared = Math.pow(options.radius, 2); _this.resize(); _this.speed = options.speed || 8; return _this; } _createClass(MouseEdges, [{ key: 'resize', value: function resize() { var options = this.options; var distance = options.distance; if (utils.exists(distance)) { this.left = distance; this.top = distance; this.right = window.innerWidth - distance; this.bottom = window.innerHeight - distance; } else if (!this.radius) { this.left = utils.exists(options.left) ? options.left : null; this.top = utils.exists(options.top) ? options.top : null; this.right = utils.exists(options.right) ? window.innerWidth - options.right : null; this.bottom = utils.exists(options.bottom) ? window.innerHeight - options.bottom : null; } } }, { key: 'down', value: function down() { this.horizontal = this.vertical = null; } }, { key: 'move', value: function move(e) { if (e.data.identifier !== 'MOUSE' || e.data.buttons !== 0) { return; } var x = e.data.global.x; var y = e.data.global.y; if (this.radiusSquared) { var center = this.parent.toScreen(this.parent.center); var distance = Math.pow(center.x - x, 2) + Math.pow(center.y - y, 2); if (distance >= this.radiusSquared) { var angle = Math.atan2(center.y - y, center.x - x); if (this.linear) { this.horizontal = Math.round(Math.cos(angle)) * this.speed * this.reverse * (60 / 1000); this.vertical = Math.round(Math.sin(angle)) * this.speed * this.reverse * (60 / 1000); } else { this.horizontal = Math.cos(angle) * this.speed * this.reverse * (60 / 1000); this.vertical = Math.sin(angle) * this.speed * this.reverse * (60 / 1000); } } else { if (this.horizontal) { this.decelerateHorizontal(); } if (this.vertical) { this.decelerateVertical(); } this.horizontal = this.vertical = 0; } } else { if (utils.exists(this.left) && x < this.left) { this.horizontal = 1 * this.reverse * this.speed * (60 / 1000); } else if (utils.exists(this.right) && x > this.right) { this.horizontal = -1 * this.reverse * this.speed * (60 / 1000); } else { this.decelerateHorizontal(); this.horizontal = 0; } if (utils.exists(this.top) && y < this.top) { this.vertical = 1 * this.reverse * this.speed * (60 / 1000); } else if (utils.exists(this.bottom) && y > this.bottom) { this.vertical = -1 * this.reverse * this.speed * (60 / 1000); } else { this.decelerateVertical(); this.vertical = 0; } } } }, { key: 'decelerateHorizontal', value: function decelerateHorizontal() { var decelerate = this.parent.plugins['decelerate']; if (this.horizontal && decelerate && !this.noDecelerate) { decelerate.activate({ x: this.horizontal * this.speed * this.reverse / (1000 / 60) }); } } }, { key: 'decelerateVertical', value: function decelerateVertical() { var decelerate = this.parent.plugins['decelerate']; if (this.vertical && decelerate && !this.noDecelerate) { decelerate.activate({ y: this.vertical * this.speed * this.reverse / (1000 / 60) }); } } }, { key: 'up', value: function up() { if (this.horizontal) { this.decelerateHorizontal(); } if (this.vertical) { this.decelerateVertical(); } this.horizontal = this.vertical = null; } }, { key: 'update', value: function update() { if (this.paused) { return; } if (this.horizontal || this.vertical) { var center = this.parent.center; if (this.horizontal) { center.x += this.horizontal * this.speed; } if (this.vertical) { center.y += this.vertical * this.speed; } this.parent.moveCenter(center); this.parent.emit('moved', { viewport: this.parent, type: 'mouse-edges' }); } } }]); return MouseEdges; }(Plugin); },{"./plugin":9,"./utils":12}],8:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Plugin = require('./plugin'); module.exports = function (_Plugin) { _inherits(Pinch, _Plugin); /** * @private * @param {Viewport} parent * @param {object} [options] * @param {boolean} [options.noDrag] disable two-finger dragging * @param {number} [options.percent=1.0] percent to modify pinch speed * @param {PIXI.Point} [options.center] place this point at center during zoom instead of center of two fingers */ function Pinch(parent, options) { _classCallCheck(this, Pinch); var _this = _possibleConstructorReturn(this, (Pinch.__proto__ || Object.getPrototypeOf(Pinch)).call(this, parent)); options = options || {}; _this.percent = options.percent || 1.0; _this.noDrag = options.noDrag; _this.center = options.center; return _this; } _createClass(Pinch, [{ key: 'down', value: function down() { if (this.parent.countDownPointers() >= 2) { this.active = true; } } }, { key: 'move', value: function move(e) { if (this.paused || !this.active) { return; } var x = e.data.global.x; var y = e.data.global.y; var pointers = this.parent.getTouchPointers(); if (pointers.length >= 2) { var first = pointers[0]; var second = pointers[1]; var last = first.last && second.last ? Math.sqrt(Math.pow(second.last.x - first.last.x, 2) + Math.pow(second.last.y - first.last.y, 2)) : null; if (first.pointerId === e.data.pointerId) { first.last = { x: x, y: y, data: e.data }; } else if (second.pointerId === e.data.pointerId) { second.last = { x: x, y: y, data: e.data }; } if (last) { var oldPoint = void 0; var point = { x: first.last.x + (second.last.x - first.last.x) / 2, y: first.last.y + (second.last.y - first.last.y) / 2 }; if (!this.center) { oldPoint = this.parent.toLocal(point); } var dist = Math.sqrt(Math.pow(second.last.x - first.last.x, 2) + Math.pow(second.last.y - first.last.y, 2)); var change = (dist - last) / this.parent.screenWidth * this.parent.scale.x * this.percent; this.parent.scale.x += change; this.parent.scale.y += change; this.parent.emit('zoomed', { viewport: this.parent, type: 'pinch' }); var clamp = this.parent.plugins['clamp-zoom']; if (clamp) { clamp.clamp(); } if (this.center) { this.parent.moveCenter(this.center); } else { var newPoint = this.parent.toGlobal(oldPoint); this.parent.x += point.x - newPoint.x; this.parent.y += point.y - newPoint.y; this.parent.emit('moved', { viewport: this.parent, type: 'pinch' }); } if (!this.noDrag && this.lastCenter) { this.parent.x += point.x - this.lastCenter.x; this.parent.y += point.y - this.lastCenter.y; this.parent.emit('moved', { viewport: this.parent, type: 'pinch' }); } this.lastCenter = point; this.moved = true; } else { if (!this.pinching) { this.parent.emit('pinch-start', this.parent); this.pinching = true; } } this.parent.dirty = true; } } }, { key: 'up', value: function up() { if (this.pinching) { if (this.parent.touches.length <= 1) { this.active = false; this.lastCenter = null; this.pinching = false; this.moved = false; this.parent.emit('pinch-end', this.parent); } } } }]); return Pinch; }(Plugin); },{"./plugin":9}],9:[function(require,module,exports){ "use strict"; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } module.exports = function () { function Plugin(parent) { _classCallCheck(this, Plugin); this.parent = parent; this.paused = false; } _createClass(Plugin, [{ key: "down", value: function down() {} }, { key: "move", value: function move() {} }, { key: "up", value: function up() {} }, { key: "wheel", value: function wheel() {} }, { key: "update", value: function update() {} }, { key: "resize", value: function resize() {} }, { key: "reset", value: function reset() {} }, { key: "pause", value: function pause() { this.paused = true; } }, { key: "resume", value: function resume() { this.paused = false; } }]); return Plugin; }(); },{}],10:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Plugin = require('./plugin'); var utils = require('./utils'); module.exports = function (_Plugin) { _inherits(SnapZoom, _Plugin); /** * @private * @param {Viewport} parent * @param {object} [options] * @param {number} [options.width] the desired width to snap (to maintain aspect ratio, choose only width or height) * @param {number} [options.height] the desired height to snap (to maintain aspect ratio, choose only width or height) * @param {number} [options.time=1000] * @param {string|function} [options.ease=easeInOutSine] ease function or name (see http://easings.net/ for supported names) * @param {PIXI.Point} [options.center] place this point at center during zoom instead of center of the viewport * @param {boolean} [options.interrupt=true] pause snapping with any user input on the viewport * @param {boolean} [options.removeOnComplete] removes this plugin after snapping is complete * @param {boolean} [options.removeOnInterrupt] removes this plugin if interrupted by any user input * @param {boolean} [options.forceStart] starts the snap immediately regardless of whether the viewport is at the desired zoom * @param {boolean} [options.noMove] zoom but do not move * * @event snap-zoom-start(Viewport) emitted each time a fit animation starts * @event snap-zoom-end(Viewport) emitted each time fit reaches its target * @event snap-zoom-end(Viewport) emitted each time fit reaches its target */ function SnapZoom(parent, options) { _classCallCheck(this, SnapZoom); var _this = _possibleConstructorReturn(this, (SnapZoom.__proto__ || Object.getPrototypeOf(SnapZoom)).call(this, parent)); options = options || {}; _this.width = options.width; _this.height = options.height; if (_this.width > 0) { _this.x_scale = parent._screenWidth / _this.width; } if (_this.height > 0) { _this.y_scale = parent._screenHeight / _this.height; } _this.xIndependent = utils.exists(_this.x_scale); _this.yIndependent = utils.exists(_this.y_scale); _this.x_scale = _this.xIndependent ? _this.x_scale : _this.y_scale; _this.y_scale = _this.yIndependent ? _this.y_scale : _this.x_scale; _this.time = utils.defaults(options.time, 1000); _this.ease = utils.ease(options.ease, 'easeInOutSine'); _this.center = options.center; _this.noMove = options.noMove; _this.stopOnResize = options.stopOnResize; _this.removeOnInterrupt = options.removeOnInterrupt; _this.removeOnComplete = utils.defaults(options.removeOnComplete, true); _this.interrupt = utils.defaults(options.interrupt, true); if (_this.time === 0) { parent.container.scale.x = _this.x_scale; parent.container.scale.y = _this.y_scale; if (_this.removeOnComplete) { _this.parent.removePlugin('snap-zoom'); } } else if (options.forceStart) { _this.createSnapping(); } return _this; } _createClass(SnapZoom, [{ key: 'createSnapping', value: function createSnapping() { var scale = this.parent.scale; this.snapping = { time: 0, startX: scale.x, startY: scale.y, deltaX: this.x_scale - scale.x, deltaY: this.y_scale - scale.y }; this.parent.emit('snap-zoom-start', this.parent); } }, { key: 'resize', value: function resize() { this.snapping = null; if (this.width > 0) { this.x_scale = this.parent._screenWidth / this.width; } if (this.height > 0) { this.y_scale = this.parent._screenHeight / this.height; } this.x_scale = this.xIndependent ? this.x_scale : this.y_scale; this.y_scale = this.yIndependent ? this.y_scale : this.x_scale; } }, { key: 'reset', value: function reset() { this.snapping = null; } }, { key: 'wheel', value: function wheel() { if (this.removeOnInterrupt) { this.parent.removePlugin('snap-zoom'); } } }, { key: 'down', value: function down() { if (this.removeOnInterrupt) { this.parent.removePlugin('snap-zoom'); } else if (this.interrupt) { this.snapping = null; } } }, { key: 'update', value: function update(elapsed) { if (this.paused) { return; } if (this.interrupt && this.parent.countDownPointers() !== 0) { return; } var oldCenter = void 0; if (!this.center && !this.noMove) { oldCenter = this.parent.center; } if (!this.snapping) { if (this.parent.scale.x !== this.x_scale || this.parent.scale.y !== this.y_scale) { this.createSnapping(); } } else if (this.snapping) { var snapping = this.snapping; snapping.time += elapsed; if (snapping.time >= this.time) { this.parent.scale.set(this.x_scale, this.y_scale); if (this.removeOnComplete) { this.parent.removePlugin('snap-zoom'); } this.parent.emit('snap-zoom-end', this.parent); this.snapping = null; } else { var _snapping = this.snapping; this.parent.scale.x = this.ease(_snapping.time, _snapping.startX, _snapping.deltaX, this.time); this.parent.scale.y = this.ease(_snapping.time, _snapping.startY, _snapping.deltaY, this.time); } var clamp = this.parent.plugins['clamp-zoom']; if (clamp) { clamp.clamp(); } if (!this.noMove) { if (!this.center) { this.parent.moveCenter(oldCenter); } else { this.parent.moveCenter(this.center); } } } } }, { key: 'resume', value: function resume() { this.snapping = null; _get(SnapZoom.prototype.__proto__ || Object.getPrototypeOf(SnapZoom.prototype), 'resume', this).call(this); } }]); return SnapZoom; }(Plugin); },{"./plugin":9,"./utils":12}],11:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Plugin = require('./plugin'); var utils = require('./utils'); module.exports = function (_Plugin) { _inherits(Snap, _Plugin); /** * @private * @param {Viewport} parent * @param {number} x * @param {number} y * @param {object} [options] * @param {boolean} [options.topLeft] snap to the top-left of viewport instead of center * @param {number} [options.friction=0.8] friction/frame to apply if decelerate is active * @param {number} [options.time=1000] * @param {string|function} [options.ease=easeInOutSine] ease function or name (see http://easings.net/ for supported names) * @param {boolean} [options.interrupt=true] pause snapping with any user input on the viewport * @param {boolean} [options.removeOnComplete] removes this plugin after snapping is complete * @param {boolean} [options.removeOnInterrupt] removes this plugin if interrupted by any user input * @param {boolean} [options.forceStart] starts the snap immediately regardless of whether the viewport is at the desired location * * @event snap-start(Viewport) emitted each time a snap animation starts * @event snap-restart(Viewport) emitted each time a snap resets because of a change in viewport size * @event snap-end(Viewport) emitted each time snap reaches its target * @event snap-remove(Viewport) emitted if snap plugin is removed */ function Snap(parent, x, y, options) { _classCallCheck(this, Snap); var _this = _possibleConstructorReturn(this, (Snap.__proto__ || Object.getPrototypeOf(Snap)).call(this, parent)); options = options || {}; _this.friction = options.friction || 0.8; _this.time = options.time || 1000; _this.ease = utils.ease(options.ease, 'easeInOutSine'); _this.x = x; _this.y = y; _this.topLeft = options.topLeft; _this.interrupt = utils.defaults(options.interrupt, true); _this.removeOnComplete = options.removeOnComplete; _this.removeOnInterrupt = options.removeOnInterrupt; if (options.forceStart) { _this.startEase(); } return _this; } _createClass(Snap, [{ key: 'snapStart', value: function snapStart() { this.percent = 0; this.snapping = { time: 0 }; var current = this.topLeft ? this.parent.corner : this.parent.center; this.deltaX = this.x - current.x; this.deltaY = this.y - current.y; this.startX = current.x; this.startY = current.y; this.parent.emit('snap-start', this.parent); } }, { key: 'wheel', value: function wheel() { if (this.removeOnInterrupt) { this.parent.removePlugin('snap'); } } }, { key: 'down', value: function down() { if (this.removeOnInterrupt) { this.parent.removePlugin('snap'); } else if (this.interrupt) { this.snapping = null; } } }, { key: 'up', value: function up() { if (this.parent.countDownPointers() === 0) { var decelerate = this.parent.plugins['decelerate']; if (decelerate && (decelerate.x || decelerate.y)) { decelerate.percentChangeX = decelerate.percentChangeY = this.friction; } } } }, { key: 'update', value: function update(elapsed) { if (this.paused) { return; } if (this.interrupt && this.parent.countDownPointers() !== 0) { return; } if (!this.snapping) { var current = this.topLeft ? this.parent.corner : this.parent.center; if (current.x !== this.x || current.y !== this.y) { this.snapStart(); } } else { var snapping = this.snapping; snapping.time += elapsed; var finished = void 0, x = void 0, y = void 0; if (snapping.time > this.time) { finished = true; x = this.startX + this.deltaX; y = this.startY + this.deltaY; } else { var percent = this.ease(snapping.time, 0, 1, this.time); x = this.startX + this.deltaX * percent; y = this.startY + this.deltaY * percent; } if (this.topLeft) { this.parent.moveCorner(x, y); } else { this.parent.moveCenter(x, y); } this.parent.emit('moved', { viewport: this.parent, type: 'snap' }); if (finished) { if (this.removeOnComplete) { this.parent.removePlugin('snap'); } this.parent.emit('snap-end', this.parent); this.snapping = null; } } } }]); return Snap; }(Plugin); },{"./plugin":9,"./utils":12}],12:[function(require,module,exports){ 'use strict'; var Penner = require('penner'); function exists(a) { return a !== undefined && a !== null; } function defaults(a, defaults) { return a !== undefined && a !== null ? a : defaults; } /** * @param {(function|string)} [ease] * @param {string} defaults for pennr equation * @private * @returns {function} correct penner equation */ function ease(ease, defaults) { if (!exists(ease)) { return Penner[defaults]; } else if (typeof ease === 'function') { return ease; } else if (typeof ease === 'string') { return Penner[ease]; } } module.exports = { exists: exists, defaults: defaults, ease: ease }; },{"penner":15}],13:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var utils = require('./utils'); var Drag = require('./drag'); var Pinch = require('./pinch'); var Clamp = require('./clamp'); var ClampZoom = require('./clamp-zoom'); var Decelerate = require('./decelerate'); var Bounce = require('./bounce'); var Snap = require('./snap'); var SnapZoom = require('./snap-zoom'); var Follow = require('./follow'); var Wheel = require('./wheel'); var MouseEdges = require('./mouse-edges'); var PLUGIN_ORDER = ['drag', 'pinch', 'wheel', 'follow', 'mouse-edges', 'decelerate', 'bounce', 'snap-zoom', 'clamp-zoom', 'snap', 'clamp']; var Viewport = function (_PIXI$Container) { _inherits(Viewport, _PIXI$Container); /** * @extends PIXI.Container * @extends EventEmitter * @param {object} [options] * @param {number} [options.screenWidth=window.innerWidth] * @param {number} [options.screenHeight=window.innerHeight] * @param {number} [options.worldWidth=this.width] * @param {number} [options.worldHeight=this.height] * @param {number} [options.threshold = 5] number of pixels to move to trigger an input event (e.g., drag, pinch) * @param {(PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle)} [options.forceHitArea] change the default hitArea from world size to a new value * @param {PIXI.ticker.Ticker} [options.ticker=PIXI.ticker.shared] use this PIXI.ticker for updates * @param {PIXI.InteractionManager} [options.interaction=null] InteractionManager, available from instantiated WebGLRenderer/CanvasRenderer.plugins.interaction - used to calculate pointer postion relative to canvas location on screen * @param {HTMLElement} [options.divWheel=document.body] div to attach the wheel event * @fires clicked * @fires drag-start * @fires drag-end * @fires drag-remove * @fires pinch-start * @fires pinch-end * @fires pinch-remove * @fires snap-start * @fires snap-end * @fires snap-remove * @fires snap-zoom-start * @fires snap-zoom-end * @fires snap-zoom-remove * @fires bounce-x-start * @fires bounce-x-end * @fires bounce-y-start * @fires bounce-y-end * @fires bounce-remove * @fires wheel * @fires wheel-remove * @fires wheel-scroll * @fires wheel-scroll-remove * @fires mouse-edge-start * @fires mouse-edge-end * @fires mouse-edge-remove * @fires moved */ function Viewport(options) { _classCallCheck(this, Viewport); options = options || {}; var _this = _possibleConstructorReturn(this, (Viewport.__proto__ || Object.getPrototypeOf(Viewport)).call(this)); _this.plugins = {}; _this.pluginsList = []; _this._screenWidth = options.screenWidth; _this._screenHeight = options.screenHeight; _this._worldWidth = options.worldWidth; _this._worldHeight = options.worldHeight; _this.hitAreaFullScreen = utils.defaults(options.hitAreaFullScreen, true); _this.forceHitArea = options.forceHitArea; _this.threshold = utils.defaults(options.threshold, 5); _this.interaction = options.interaction || null; _this.div = options.divWheel || document.body; _this.listeners(_this.div); /** * active touch point ids on the viewport * @type {number[]} * @readonly */ _this.touches = []; _this.ticker = options.ticker || PIXI.ticker.shared; _this.tickerFunction = function () { return _this.update(); }; _this.ticker.add(_this.tickerFunction); return _this; } /** * removes all event listeners from viewport * (useful for cleanup of wheel and ticker events when removing viewport) */ _createClass(Viewport, [{ key: 'removeListeners', value: function removeListeners() { this.ticker.remove(this.tickerFunction); this.div.removeEventListener('wheel', this.wheelFunction); } /** * overrides PIXI.Container's destroy to also remove the 'wheel' and PIXI.Ticker listeners */ }, { key: 'destroy', value: function destroy(options) { _get(Viewport.prototype.__proto__ || Object.getPrototypeOf(Viewport.prototype), 'destroy', this).call(this, options); this.removeListeners(); } /** * update animations * @private */ }, { key: 'update', value: function update() { if (!this.pause) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this.pluginsList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var plugin = _step.value; plugin.update(this.ticker.elapsedMS); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } if (!this.forceHitArea) { this.hitArea.x = this.left; this.hitArea.y = this.top; this.hitArea.width = this.worldScreenWidth; this.hitArea.height = this.worldScreenHeight; } } /** * use this to set screen and world sizes--needed for pinch/wheel/clamp/bounce * @param {number} screenWidth * @param {number} screenHeight * @param {number} [worldWidth] * @param {number} [worldHeight] */ }, { key: 'resize', value: function resize(screenWidth, screenHeight, worldWidth, worldHeight) { this._screenWidth = screenWidth || window.innerWidth; this._screenHeight = screenHeight || window.innerHeight; this._worldWidth = worldWidth; this._worldHeight = worldHeight; this.resizePlugins(); } /** * called after a worldWidth/Height change * @private */ }, { key: 'resizePlugins', value: function resizePlugins() { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = this.pluginsList[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var plugin = _step2.value; plugin.resize(); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } /** * screen width in screen pixels * @type {number} */ }, { key: 'listeners', /** * add input listeners * @private */ value: function listeners(div) { var _this2 = this; this.interactive = true; if (!this.forceHitArea) { this.hitArea = new PIXI.Rectangle(0, 0, this.worldWidth, this.worldHeight); } this.on('pointerdown', this.down); this.on('pointermove', this.move); this.on('pointerup', this.up); this.on('pointerupoutside', this.up); this.on('pointercancel', this.up); this.on('pointerout', this.up); this.wheelFunction = function (e) { return _this2.handleWheel(e); }; div.addEventListener('wheel', this.wheelFunction); this.leftDown = false; } /** * handle down events * @private */ }, { key: 'down', value: function down(e) { if (this.pause) { return; } if (e.data.pointerType === 'mouse') { if (e.data.originalEvent.button == 0) { this.leftDown = true; } } else { this.touches.push(e.data.pointerId); } if (this.countDownPointers() === 1) { this.last = { x: e.data.global.x, y: e.data.global.y // clicked event does not fire if viewport is decelerating or bouncing };var decelerate = this.plugins['decelerate']; var bounce = this.plugins['bounce']; if ((!decelerate || !decelerate.x && !decelerate.y) && (!bounce || !bounce.toX && !bounce.toY)) { this.clickedAvailable = true; } } else { this.clickedAvailable = false; } var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = this.pluginsList[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var plugin = _step3.value; plugin.down(e); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } /** * whether change exceeds threshold * @private * @param {number} change */ }, { key: 'checkThreshold', value: function checkThreshold(change) { if (Math.abs(change) >= this.threshold) { return true; } return false; } /** * handle move events * @private */ }, { key: 'move', value: function move(e) { if (this.pause) { return; } var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = this.pluginsList[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var plugin = _step4.value; plugin.move(e); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } if (this.clickedAvailable) { var distX = e.data.global.x - this.last.x; var distY = e.data.global.y - this.last.y; if (this.checkThreshold(distX) || this.checkThreshold(distY)) { this.clickedAvailable = false; } } } /** * handle up events * @private */ }, { key: 'up', value: function up(e) { if (this.pause) { return; } if (e.data.originalEvent instanceof MouseEvent && e.data.originalEvent.button == 0) { this.leftDown = false; } if (e.data.pointerType !== 'mouse') { for (var i = 0; i < this.touches.length; i++) { if (this.touches[i] === e.data.pointerId) { this.touches.splice(i, 1); break; } } } var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = this.pluginsList[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var plugin = _step5.value; plugin.up(e); } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } if (this.clickedAvailable && this.countDownPointers() === 0) { this.emit('clicked', { screen: this.last, world: this.toWorld(this.last), viewport: this }); this.clickedAvailable = false; } } /** * gets pointer position if this.interaction is set * @param {UIEvent} evt * @private */ }, { key: 'getPointerPosition', value: function getPointerPosition(evt) { var point = new PIXI.Point(); if (this.interaction) { this.interaction.mapPositionToPoint(point, evt.clientX, evt.clientY); } else { point.x = evt.clientX; point.y = evt.clientY; } return point; } /** * handle wheel events * @private */ }, { key: 'handleWheel', value: function handleWheel(e) { if (this.pause) { return; } // only handle wheel events where the mouse is over the viewport var point = this.toLocal(this.getPointerPosition(e)); if (this.left <= point.x && point.x <= this.right && this.top <= point.y && point.y <= this.bottom) { var result = void 0; var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = this.pluginsList[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var plugin = _step6.value; if (plugin.wheel(e)) { result = true; } } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } return result; } } /** * change coordinates from screen to world * @param {number|PIXI.Point} x * @param {number} [y] * @returns {PIXI.Point} */ }, { key: 'toWorld', value: function toWorld() { if (arguments.length === 2) { var x = arguments[0]; var y = arguments[1]; return this.toLocal({ x: x, y: y }); } else { return this.toLocal(arguments[0]); } } /** * change coordinates from world to screen * @param {number|PIXI.Point} x * @param {number} [y] * @returns {PIXI.Point} */ }, { key: 'toScreen', value: function toScreen() { if (arguments.length === 2) { var x = arguments[0]; var y = arguments[1]; return this.toGlobal({ x: x, y: y }); } else { var point = arguments[0]; return this.toGlobal(point); } } /** * screen width in world coordinates * @type {number} * @readonly */ }, { key: 'moveCenter', /** * move center of viewport to point * @param {(number|PIXI.PointLike)} x or point * @param {number} [y] * @return {Viewport} this */ value: function moveCenter() /*x, y | PIXI.Point*/{ var x = void 0, y = void 0; if (!isNaN(arguments[0])) { x = arguments[0]; y = arguments[1]; } else { x = arguments[0].x; y = arguments[0].y; } this.position.set((this.worldScreenWidth / 2 - x) * this.scale.x, (this.worldScreenHeight / 2 - y) * this.scale.y); this._reset(); return this; } /** * top-left corner * @type {PIXI.PointLike} */ }, { key: 'moveCorner', /** * move viewport's top-left corner; also clamps and resets decelerate and bounce (as needed) * @param {number|PIXI.Point} x|point * @param {number} y * @return {Viewport} this */ value: function moveCorner() /*x, y | point*/{ if (arguments.length === 1) { this.position.set(-arguments[0].x * this.scale.x, -arguments[0].y * this.scale.y); } else { this.position.set(-arguments[0] * this.scale.x, -arguments[1] * this.scale.y); } this._reset(); return this; } /** * change zoom so the width fits in the viewport * @param {number} [width=this._worldWidth] in world coordinates * @param {boolean} [center] maintain the same center * @return {Viewport} this */ }, { key: 'fitWidth', value: function fitWidth(width, center) { var save = void 0; if (center) { save = this.center; } width = width || this.worldWidth; this.scale.x = this.screenWidth / width; this.scale.y = this.scale.x; if (center) { this.moveCenter(save); } return this; } /** * change zoom so the height fits in the viewport * @param {number} [height=this._worldHeight] in world coordinates * @param {boolean} [center] maintain the same center of the screen after zoom * @return {Viewport} this */ }, { key: 'fitHeight', value: function fitHeight(height, center) { var save = void 0; if (center) { save = this.center; } height = height || this.worldHeight; this.scale.y = this.screenHeight / height; this.scale.x = this.scale.y; if (center) { this.moveCenter(save); } return this; } /** * change zoom so it fits the entire world in the viewport * @param {boolean} [center] maintain the same center of the screen after zoom * @return {Viewport} this */ }, { key: 'fitWorld', value: function fitWorld(center) { var save = void 0; if (center) { save = this.center; } this.scale.x = this._screenWidth / this._worldWidth; this.scale.y = this._screenHeight / this._worldHeight; if (this.scale.x < this.scale.y) { this.scale.y = this.scale.x; } else { this.scale.x = this.scale.y; } if (center) { this.moveCenter(save); } return this; } /** * change zoom so it fits the size or the entire world in the viewport * @param {boolean} [center] maintain the same center of the screen after zoom * @param {number} [width] desired width * @param {number} [height] desired height * @return {Viewport} this */ }, { key: 'fit', value: function fit(center, width, height) { var save = void 0; if (center) { save = this.center; } width = width || this.worldWidth; height = height || this.worldHeight; this.scale.x = this.screenWidth / width; this.scale.y = this.screenHeight / height; if (this.scale.x < this.scale.y) { this.scale.y = this.scale.x; } else { this.scale.x = this.scale.y; } if (center) { this.moveCenter(save); } return this; } /** * zoom viewport by a certain percent (in both x and y direction) * @param {number} percent change (e.g., 0.25 would increase a starting scale of 1.0 to 1.25) * @param {boolean} [center] maintain the same center of the screen after zoom * @return {Viewport} the viewport */ }, { key: 'zoomPercent', value: function zoomPercent(percent, center) { var save = void 0; if (center) { save = this.center; } var scale = this.scale.x + this.scale.x * percent; this.scale.set(scale); if (center) { this.moveCenter(save); } return this; } /** * zoom viewport by increasing/decreasing width by a certain number of pixels * @param {number} change in pixels * @param {boolean} [center] maintain the same center of the screen after zoom * @return {Viewport} the viewport */ }, { key: 'zoom', value: function zoom(change, center) { this.fitWidth(change + this.worldScreenWidth, center); return this; } /** * @param {object} [options] * @param {number} [options.width] the desired width to snap (to maintain aspect ratio, choose only width or height) * @param {number} [options.height] the desired height to snap (to maintain aspect ratio, choose only width or height) * @param {number} [options.time=1000] * @param {string|function} [options.ease=easeInOutSine] ease function or name (see http://easings.net/ for supported names) * @param {PIXI.Point} [options.center] place this point at center during zoom instead of center of the viewport * @param {boolean} [options.interrupt=true] pause snapping with any user input on the viewport * @param {boolean} [options.removeOnComplete] removes this plugin after snapping is complete * @param {boolean} [options.removeOnInterrupt] removes this plugin if interrupted by any user input * @param {boolean} [options.forceStart] starts the snap immediately regardless of whether the viewport is at the desired zoom */ }, { key: 'snapZoom', value: function snapZoom(options) { this.plugins['snap-zoom'] = new SnapZoom(this, options); this.pluginsSort(); return this; } /** * @private * @typedef OutOfBounds * @type {object} * @property {boolean} left * @property {boolean} right * @property {boolean} top * @property {boolean} bottom */ /** * is container out of world bounds * @return {OutOfBounds} * @private */ }, { key: 'OOB', value: function OOB() { var result = {}; result.left = this.left < 0; result.right = this.right > this._worldWidth; result.top = this.top < 0; result.bottom = this.bottom > this._worldHeight; result.cornerPoint = { x: this._worldWidth * this.scale.x - this._screenWidth, y: this._worldHeight * this.scale.y - this._screenHeight }; return result; } /** * world coordinates of the right edge of the screen * @type {number} */ }, { key: 'countDownPointers', /** * count of mouse/touch pointers that are down on the viewport * @private * @return {number} */ value: function countDownPointers() { return (this.leftDown ? 1 : 0) + this.touches.length; } /** * array of touch pointers that are down on the viewport * @private * @return {PIXI.InteractionTrackingData[]} */ }, { key: 'getTouchPointers', value: function getTouchPointers() { var results = []; var pointers = this.trackedPointers; for (var key in pointers) { var pointer = pointers[key]; if (this.touches.indexOf(pointer.pointerId) !== -1) { results.push(pointer); } } return results; } /** * array of pointers that are down on the viewport * @private * @return {PIXI.InteractionTrackingData[]} */ }, { key: 'getPointers', value: function getPointers() { var results = []; var pointers = this.trackedPointers; for (var key in pointers) { results.push(pointers[key]); } return results; } /** * clamps and resets bounce and decelerate (as needed) after manually moving viewport * @private */ }, { key: '_reset', value: function _reset() { if (this.plugins['bounce']) { this.plugins['bounce'].reset(); this.plugins['bounce'].bounce(); } if (this.plugins['decelerate']) { this.plugins['decelerate'].reset(); } if (this.plugins['snap']) { this.plugins['snap'].reset(); } if (this.plugins['clamp']) { this.plugins['clamp'].update(); } if (this.plugins['clamp-zoom']) { this.plugins['clamp-zoom'].clamp(); } this.dirty = true; } // PLUGINS /** * removes installed plugin * @param {string} type of plugin (e.g., 'drag', 'pinch') */ }, { key: 'removePlugin', value: function removePlugin(type) { if (this.plugins[type]) { this.plugins[type] = null; this.emit(type + '-remove'); this.pluginsSort(); } } /** * pause plugin * @param {string} type of plugin (e.g., 'drag', 'pinch') */ }, { key: 'pausePlugin', value: function pausePlugin(type) { if (this.plugins[type]) { this.plugins[type].pause(); } } /** * resume plugin * @param {string} type of plugin (e.g., 'drag', 'pinch') */ }, { key: 'resumePlugin', value: function resumePlugin(type) { if (this.plugins[type]) { this.plugins[type].resume(); } } /** * sort plugins for updates * @private */ }, { key: 'pluginsSort', value: function pluginsSort() { this.pluginsList = []; var _iteratorNormalCompletion7 = true; var _didIteratorError7 = false; var _iteratorError7 = undefined; try { for (var _iterator7 = PLUGIN_ORDER[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { var plugin = _step7.value; if (this.plugins[plugin]) { this.pluginsList.push(this.plugins[plugin]); } } } catch (err) { _didIteratorError7 = true; _iteratorError7 = err; } finally { try { if (!_iteratorNormalCompletion7 && _iterator7.return) { _iterator7.return(); } } finally { if (_didIteratorError7) { throw _iteratorError7; } } } } /** * enable one-finger touch to drag * @param {object} [options] * @param {string} [options.direction=all] direction to drag (all, x, or y) * @param {boolean} [options.wheel=true] use wheel to scroll in y direction (unless wheel plugin is active) * @param {number} [options.wheelScroll=10] number of pixels to scroll with each wheel spin * @param {boolean} [options.reverse] reverse the direction of the wheel scroll * @param {string} [options.underflow=center] (top/bottom/center and left/right/center, or center) where to place world if too small for screen */ }, { key: 'drag', value: function drag(options) { this.plugins['drag'] = new Drag(this, options); this.pluginsSort(); return this; } /** * clamp to world boundaries or other provided boundaries * NOTES: * clamp is disabled if called with no options; use { direction: 'all' } for all edge clamping * screenWidth, screenHeight, worldWidth, and worldHeight needs to be set for this to work properly * @param {object} [options] * @param {(number|boolean)} [options.left] clamp left; true=0 * @param {(number|boolean)} [options.right] clamp right; true=viewport.worldWidth * @param {(number|boolean)} [options.top] clamp top; true=0 * @param {(number|boolean)} [options.bottom] clamp bottom; true=viewport.worldHeight * @param {string} [options.direction] (all, x, or y) using clamps of [0, viewport.worldWidth/viewport.worldHeight]; replaces left/right/top/bottom if set * @param {string} [options.underflow=center] (top/bottom/center and left/right/center, or center) where to place world if too small for screen * @return {Viewport} this */ }, { key: 'clamp', value: function clamp(options) { this.plugins['clamp'] = new Clamp(this, options); this.pluginsSort(); return this; } /** * decelerate after a move * @param {object} [options] * @param {number} [options.friction=0.95] percent to decelerate after movement * @param {number} [options.bounce=0.8] percent to decelerate when past boundaries (only applicable when viewport.bounce() is active) * @param {number} [options.minSpeed=0.01] minimum velocity before stopping/reversing acceleration * @return {Viewport} this */ }, { key: 'decelerate', value: function decelerate(options) { this.plugins['decelerate'] = new Decelerate(this, options); this.pluginsSort(); return this; } /** * bounce on borders * NOTE: screenWidth, screenHeight, worldWidth, and worldHeight needs to be set for this to work properly * @param {object} [options] * @param {string} [options.sides=all] all, horizontal, vertical, or combination of top, bottom, right, left (e.g., 'top-bottom-right') * @param {number} [options.friction=0.5] friction to apply to decelerate if active * @param {number} [options.time=150] time in ms to finish bounce * @param {string|function} [options.ease=easeInOutSine] ease function or name (see http://easings.net/ for supported names) * @param {string} [options.underflow=center] (top/bottom/center and left/right/center, or center) where to place world if too small for screen * @return {Viewport} this */ }, { key: 'bounce', value: function bounce(options) { this.plugins['bounce'] = new Bounce(this, options); this.pluginsSort(); return this; } /** * enable pinch to zoom and two-finger touch to drag * NOTE: screenWidth, screenHeight, worldWidth, and worldHeight needs to be set for this to work properly * @param {number} [options.percent=1.0] percent to modify pinch speed * @param {boolean} [options.noDrag] disable two-finger dragging * @param {PIXI.Point} [options.center] place this point at center during zoom instead of center of two fingers * @return {Viewport} this */ }, { key: 'pinch', value: function pinch(options) { this.plugins['pinch'] = new Pinch(this, options); this.pluginsSort(); return this; } /** * snap to a point * @param {number} x * @param {number} y * @param {object} [options] * @param {boolean} [options.topLeft] snap to the top-left of viewport instead of center * @param {number} [options.friction=0.8] friction/frame to apply if decelerate is active * @param {number} [options.time=1000] * @param {string|function} [options.ease=easeInOutSine] ease function or name (see http://easings.net/ for supported names) * @param {boolean} [options.interrupt=true] pause snapping with any user input on the viewport * @param {boolean} [options.removeOnComplete] removes this plugin after snapping is complete * @param {boolean} [options.removeOnInterrupt] removes this plugin if interrupted by any user input * @param {boolean} [options.forceStart] starts the snap immediately regardless of whether the viewport is at the desired location * @return {Viewport} this */ }, { key: 'snap', value: function snap(x, y, options) { this.plugins['snap'] = new Snap(this, x, y, options); this.pluginsSort(); return this; } /** * follow a target * @param {PIXI.DisplayObject} target to follow (object must include {x: x-coordinate, y: y-coordinate}) * @param {object} [options] * @param {number} [options.speed=0] to follow in pixels/frame (0=teleport to location) * @param {number} [options.radius] radius (in world coordinates) of center circle where movement is allowed without moving the viewport * @return {Viewport} this */ }, { key: 'follow', value: function follow(target, options) { this.plugins['follow'] = new Follow(this, target, options); this.pluginsSort(); return this; } /** * zoom using mouse wheel * @param {object} [options] * @param {number} [options.percent=0.1] percent to scroll with each spin * @param {boolean} [options.reverse] reverse the direction of the scroll * @param {PIXI.Point} [options.center] place this point at center during zoom instead of current mouse position * @return {Viewport} this */ }, { key: 'wheel', value: function wheel(options) { this.plugins['wheel'] = new Wheel(this, options); this.pluginsSort(); return this; } /** * enable clamping of zoom to constraints * NOTE: screenWidth, screenHeight, worldWidth, and worldHeight needs to be set for this to work properly * @param {object} [options] * @param {number} [options.minWidth] minimum width * @param {number} [options.minHeight] minimum height * @param {number} [options.maxWidth] maximum width * @param {number} [options.maxHeight] maximum height * @return {Viewport} this */ }, { key: 'clampZoom', value: function clampZoom(options) { this.plugins['clamp-zoom'] = new ClampZoom(this, options); this.pluginsSort(); return this; } /** * Scroll viewport when mouse hovers near one of the edges or radius-distance from center of screen. * @param {object} [options] * @param {number} [options.radius] distance from center of screen in screen pixels * @param {number} [options.distance] distance from all sides in screen pixels * @param {number} [options.top] alternatively, set top distance (leave unset for no top scroll) * @param {number} [options.bottom] alternatively, set bottom distance (leave unset for no top scroll) * @param {number} [options.left] alternatively, set left distance (leave unset for no top scroll) * @param {number} [options.right] alternatively, set right distance (leave unset for no top scroll) * @param {number} [options.speed=8] speed in pixels/frame to scroll viewport * @param {boolean} [options.reverse] reverse direction of scroll * @param {boolean} [options.noDecelerate] don't use decelerate plugin even if it's installed * @param {boolean} [options.linear] if using radius, use linear movement (+/- 1, +/- 1) instead of angled movement (Math.cos(angle from center), Math.sin(angle from center)) */ }, { key: 'mouseEdges', value: function mouseEdges(options) { this.plugins['mouse-edges'] = new MouseEdges(this, options); this.pluginsSort(); return this; } /** * pause viewport (including animation updates such as decelerate) * NOTE: when setting pause=true, all touches and mouse actions are cleared (i.e., if mousedown was active, it becomes inactive for purposes of the viewport) * @type {boolean} */ }, { key: 'screenWidth', get: function get() { return this._screenWidth; }, set: function set(value) { this._screenWidth = value; } /** * screen height in screen pixels * @type {number} */ }, { key: 'screenHeight', get: function get() { return this._screenHeight; }, set: function set(value) { this._screenHeight = value; } /** * world width in pixels * @type {number} */ }, { key: 'worldWidth', get: function get() { if (this._worldWidth) { return this._worldWidth; } else { return this.width; } }, set: function set(value) { this._worldWidth = value; this.resizePlugins(); } /** * world height in pixels * @type {number} */ }, { key: 'worldHeight', get: function get() { if (this._worldHeight) { return this._worldHeight; } else { return this.height; } }, set: function set(value) { this._worldHeight = value; this.resizePlugins(); } }, { key: 'worldScreenWidth', get: function get() { return this._screenWidth / this.scale.x; } /** * screen height in world coordinates * @type {number} * @readonly */ }, { key: 'worldScreenHeight', get: function get() { return this._screenHeight / this.scale.y; } /** * world width in screen coordinates * @type {number} * @readonly */ }, { key: 'screenWorldWidth', get: function get() { return this._worldWidth * this.scale.x; } /** * world height in screen coordinates * @type {number} * @readonly */ }, { key: 'screenWorldHeight', get: function get() { return this._worldHeight * this.scale.y; } /** * get center of screen in world coordinates * @type {PIXI.PointLike} */ }, { key: 'center', get: function get() { return { x: this.worldScreenWidth / 2 - this.x / this.scale.x, y: this.worldScreenHeight / 2 - this.y / this.scale.y }; }, set: function set(value) { this.moveCenter(value); } }, { key: 'corner', get: function get() { return { x: -this.x / this.scale.x, y: -this.y / this.scale.y }; }, set: function set(value) { this.moveCorner(value); } }, { key: 'right', get: function get() { return -this.x / this.scale.x + this.worldScreenWidth; }, set: function set(value) { this.x = -value * this.scale.x + this.screenWidth; this._reset(); } /** * world coordinates of the left edge of the screen * @type {number} */ }, { key: 'left', get: function get() { return -this.x / this.scale.x; }, set: function set(value) { this.x = -value * this.scale.x; this._reset(); } /** * world coordinates of the top edge of the screen * @type {number} */ }, { key: 'top', get: function get() { return -this.y / this.scale.y; }, set: function set(value) { this.y = -value * this.scale.y; this._reset(); } /** * world coordinates of the bottom edge of the screen * @type {number} */ }, { key: 'bottom', get: function get() { return -this.y / this.scale.y + this.worldScreenHeight; }, set: function set(value) { this.y = -value * this.scale.y + this.screenHeight; this._reset(); } /** * determines whether the viewport is dirty (i.e., needs to be renderered to the screen because of a change) * @type {boolean} */ }, { key: 'dirty', get: function get() { return this._dirty; }, set: function set(value) { this._dirty = value; } /** * permanently changes the Viewport's hitArea *

NOTE: normally the hitArea = PIXI.Rectangle(Viewport.left, Viewport.top, Viewport.worldScreenWidth, Viewport.worldScreenHeight)

* @type {(PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle)} */ }, { key: 'forceHitArea', get: function get() { return this._forceHitArea; }, set: function set(value) { if (value) { this._forceHitArea = value; this.hitArea = value; } else { this._forceHitArea = false; this.hitArea = new PIXI.Rectangle(0, 0, this.worldWidth, this.worldHeight); } } }, { key: 'pause', get: function get() { return this._pause; }, set: function set(value) { this._pause = value; if (value) { this.touches = []; this.leftDown = false; } } }]); return Viewport; }(PIXI.Container); /** * fires after a mouse or touch click * @event Viewport#clicked * @type {object} * @property {PIXI.PointLike} screen * @property {PIXI.PointLike} world * @property {Viewport} viewport */ /** * fires when a drag starts * @event Viewport#drag-start * @type {object} * @property {PIXI.PointLike} screen * @property {PIXI.PointLike} world * @property {Viewport} viewport */ /** * fires when a drag ends * @event Viewport#drag-end * @type {object} * @property {PIXI.PointLike} screen * @property {PIXI.PointLike} world * @property {Viewport} viewport */ /** * fires when a pinch starts * @event Viewport#pinch-start * @type {Viewport} */ /** * fires when a pinch end * @event Viewport#pinch-end * @type {Viewport} */ /** * fires when a snap starts * @event Viewport#snap-start * @type {Viewport} */ /** * fires when a snap ends * @event Viewport#snap-end * @type {Viewport} */ /** * fires when a snap-zoom starts * @event Viewport#snap-zoom-start * @type {Viewport} */ /** * fires when a snap-zoom ends * @event Viewport#snap-zoom-end * @type {Viewport} */ /** * fires when a bounce starts in the x direction * @event Viewport#bounce-x-start * @type {Viewport} */ /** * fires when a bounce ends in the x direction * @event Viewport#bounce-x-end * @type {Viewport} */ /** * fires when a bounce starts in the y direction * @event Viewport#bounce-y-start * @type {Viewport} */ /** * fires when a bounce ends in the y direction * @event Viewport#bounce-y-end * @type {Viewport} */ /** * fires when for a mouse wheel event * @event Viewport#wheel * @type {object} * @property {object} wheel * @property {number} wheel.dx * @property {number} wheel.dy * @property {number} wheel.dz * @property {Viewport} viewport */ /** * fires when a wheel-scroll occurs * @event Viewport#wheel-scroll * @type {Viewport} */ /** * fires when a mouse-edge starts to scroll * @event Viewport#mouse-edge-start * @type {Viewport} */ /** * fires when the mouse-edge scrolling ends * @event Viewport#mouse-edge-end * @type {Viewport} */ /** * fires when viewport moves through UI interaction, deceleration, or follow * @event Viewport#moved * @type {object} * @property {Viewport} viewport * @property {string} type (drag, snap, pinch, follow, bounce-x, bounce-y, clamp-x, clamp-y, decelerate, mouse-edges, wheel) */ /** * fires when viewport moves through UI interaction, deceleration, or follow * @event Viewport#zoomed * @type {object} * @property {Viewport} viewport * @property {string} type (drag-zoom, pinch, wheel, clamp-zoom) */ PIXI.extras.Viewport = Viewport; module.exports = Viewport; },{"./bounce":1,"./clamp":3,"./clamp-zoom":2,"./decelerate":4,"./drag":5,"./follow":6,"./mouse-edges":7,"./pinch":8,"./snap":11,"./snap-zoom":10,"./utils":12,"./wheel":14}],14:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Plugin = require('./plugin'); module.exports = function (_Plugin) { _inherits(Wheel, _Plugin); /** * @private * @param {Viewport} parent * @param {object} [options] * @param {number} [options.percent=0.1] percent to scroll with each spin * @param {boolean} [options.reverse] reverse the direction of the scroll * @param {PIXI.Point} [options.center] place this point at center during zoom instead of current mouse position * * @event wheel({wheel: {dx, dy, dz}, event, viewport}) */ function Wheel(parent, options) { _classCallCheck(this, Wheel); var _this = _possibleConstructorReturn(this, (Wheel.__proto__ || Object.getPrototypeOf(Wheel)).call(this, parent)); options = options || {}; _this.percent = options.percent || 0.1; _this.center = options.center; _this.reverse = options.reverse; return _this; } _createClass(Wheel, [{ key: 'wheel', value: function wheel(e) { if (this.paused) { return; } var change = void 0; if (this.reverse) { change = e.deltaY > 0 ? 1 + this.percent : 1 - this.percent; } else { change = e.deltaY > 0 ? 1 - this.percent : 1 + this.percent; } var point = this.parent.getPointerPosition(e); var oldPoint = void 0; if (!this.center) { oldPoint = this.parent.toLocal(point); } this.parent.scale.x *= change; this.parent.scale.y *= change; this.parent.emit('zoomed', { viewport: this.parent, type: 'wheel' }); var clamp = this.parent.plugins['clamp-zoom']; if (clamp) { clamp.clamp(); } if (this.center) { this.parent.moveCenter(this.center); } else { var newPoint = this.parent.toGlobal(oldPoint); this.parent.x += point.x - newPoint.x; this.parent.y += point.y - newPoint.y; } this.parent.emit('moved', { viewport: this.parent, type: 'wheel' }); this.parent.emit('wheel', { wheel: { dx: e.deltaX, dy: e.deltaY, dz: e.deltaZ }, event: e, viewport: this.parent }); e.preventDefault(); } }]); return Wheel; }(Plugin); },{"./plugin":9}],15:[function(require,module,exports){ /* Copyright © 2001 Robert Penner All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function() { var penner, umd; umd = function(factory) { if (typeof exports === 'object') { return module.exports = factory; } else if (typeof define === 'function' && define.amd) { return define([], factory); } else { return this.penner = factory; } }; penner = { linear: function(t, b, c, d) { return c * t / d + b; }, easeInQuad: function(t, b, c, d) { return c * (t /= d) * t + b; }, easeOutQuad: function(t, b, c, d) { return -c * (t /= d) * (t - 2) + b; }, easeInOutQuad: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t + b; } else { return -c / 2 * ((--t) * (t - 2) - 1) + b; } }, easeInCubic: function(t, b, c, d) { return c * (t /= d) * t * t + b; }, easeOutCubic: function(t, b, c, d) { return c * ((t = t / d - 1) * t * t + 1) + b; }, easeInOutCubic: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t + b; } else { return c / 2 * ((t -= 2) * t * t + 2) + b; } }, easeInQuart: function(t, b, c, d) { return c * (t /= d) * t * t * t + b; }, easeOutQuart: function(t, b, c, d) { return -c * ((t = t / d - 1) * t * t * t - 1) + b; }, easeInOutQuart: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t * t + b; } else { return -c / 2 * ((t -= 2) * t * t * t - 2) + b; } }, easeInQuint: function(t, b, c, d) { return c * (t /= d) * t * t * t * t + b; }, easeOutQuint: function(t, b, c, d) { return c * ((t = t / d - 1) * t * t * t * t + 1) + b; }, easeInOutQuint: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t * t * t + b; } else { return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; } }, easeInSine: function(t, b, c, d) { return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; }, easeOutSine: function(t, b, c, d) { return c * Math.sin(t / d * (Math.PI / 2)) + b; }, easeInOutSine: function(t, b, c, d) { return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; }, easeInExpo: function(t, b, c, d) { if (t === 0) { return b; } else { return c * Math.pow(2, 10 * (t / d - 1)) + b; } }, easeOutExpo: function(t, b, c, d) { if (t === d) { return b + c; } else { return c * (-Math.pow(2, -10 * t / d) + 1) + b; } }, easeInOutExpo: function(t, b, c, d) { if (t === 0) { b; } if (t === d) { b + c; } if ((t /= d / 2) < 1) { return c / 2 * Math.pow(2, 10 * (t - 1)) + b; } else { return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; } }, easeInCirc: function(t, b, c, d) { return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; }, easeOutCirc: function(t, b, c, d) { return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; }, easeInOutCirc: function(t, b, c, d) { if ((t /= d / 2) < 1) { return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; } else { return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; } }, easeInElastic: function(t, b, c, d) { var a, p, s; s = 1.70158; p = 0; a = c; if (t === 0) { b; } else if ((t /= d) === 1) { b + c; } if (!p) { p = d * .3; } if (a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b; }, easeOutElastic: function(t, b, c, d) { var a, p, s; s = 1.70158; p = 0; a = c; if (t === 0) { b; } else if ((t /= d) === 1) { b + c; } if (!p) { p = d * .3; } if (a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b; }, easeInOutElastic: function(t, b, c, d) { var a, p, s; s = 1.70158; p = 0; a = c; if (t === 0) { b; } else if ((t /= d / 2) === 2) { b + c; } if (!p) { p = d * (.3 * 1.5); } if (a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } if (t < 1) { return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b; } else { return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b; } }, easeInBack: function(t, b, c, d, s) { if (s === void 0) { s = 1.70158; } return c * (t /= d) * t * ((s + 1) * t - s) + b; }, easeOutBack: function(t, b, c, d, s) { if (s === void 0) { s = 1.70158; } return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; }, easeInOutBack: function(t, b, c, d, s) { if (s === void 0) { s = 1.70158; } if ((t /= d / 2) < 1) { return c / 2 * (t * t * (((s *= 1.525) + 1) * t - s)) + b; } else { return c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b; } }, easeInBounce: function(t, b, c, d) { var v; v = penner.easeOutBounce(d - t, 0, c, d); return c - v + b; }, easeOutBounce: function(t, b, c, d) { if ((t /= d) < 1 / 2.75) { return c * (7.5625 * t * t) + b; } else if (t < 2 / 2.75) { return c * (7.5625 * (t -= 1.5 / 2.75) * t + .75) + b; } else if (t < 2.5 / 2.75) { return c * (7.5625 * (t -= 2.25 / 2.75) * t + .9375) + b; } else { return c * (7.5625 * (t -= 2.625 / 2.75) * t + .984375) + b; } }, easeInOutBounce: function(t, b, c, d) { var v; if (t < d / 2) { v = penner.easeInBounce(t * 2, 0, c, d); return v * .5 + b; } else { v = penner.easeOutBounce(t * 2 - d, 0, c, d); return v * .5 + c * .5 + b; } } }; umd(penner); }).call(this); },{}]},{},[13]); /*jslint plusplus: true, vars: true, indent: 2 */ /* convertPointFromPageToNode.js from convertPointFromPageToNode(element, event.pageX, event.pageY) -> {x, y} returns coordinate in element's local coordinate system (works properly with css transforms without perspective projection) convertPointFromNodeToPage(element, offsetX, offsetY) -> {x, y} returns coordinate in window's coordinate system (works properly with css transforms without perspective projection) */ (function () { 'use strict' var I = (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix() : new WebKitCSSMatrix() function Point(x, y, z) { this.x = x this.y = y this.z = z } Point.prototype.transformBy = function (matrix) { var tmp = matrix.multiply(I.translate(this.x, this.y, this.z)) return new Point(tmp.m41, tmp.m42, tmp.m43) } function createMatrix(transform) { try { return (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform) } catch(e) { console.warn(transform) console.warn(e.toString()) return I } } function getTransformationMatrix(element) { var transformationMatrix = I var x = element while (x != undefined && x !== x.ownerDocument.documentElement) { var computedStyle = window.getComputedStyle(x, undefined) var transform = computedStyle.transform || 'none' var c = transform === 'none' ? I : createMatrix(transform) transformationMatrix = c.multiply(transformationMatrix) x = x.parentNode } var w = element.offsetWidth var h = element.offsetHeight var i = 4 var left = +Infinity var top = +Infinity while (--i >= 0) { var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h, 0).transformBy(transformationMatrix) if (p.x < left) { left = p.x } if (p.y < top) { top = p.y } } var rect = element.getBoundingClientRect() transformationMatrix = I.translate(window.pageXOffset + rect.left - left, window.pageYOffset + rect.top - top, 0) .multiply(transformationMatrix) return transformationMatrix } window.convertPointFromPageToNode = function (element, pageX, pageY) { return new Point(pageX, pageY, 0).transformBy( getTransformationMatrix(element).inverse()) } window.convertPointFromNodeToPage = function (element, offsetX, offsetY) { return new Point(offsetX, offsetY, 0).transformBy( getTransformationMatrix(element)) } }())