From 40cfcd45797cc675d54850df3106f559673badd0 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Fri, 10 Jul 2015 09:16:03 +0200 Subject: [PATCH] Fix progress bug --- library/benchmark.js | 3919 ------------------------------ library/cal.js | 4473 +++++++++++++++++++---------------- settings/user_settings.json | 18 +- src/paths.js | 2 +- src/slicer.js | 57 +- 5 files changed, 2486 insertions(+), 5983 deletions(-) delete mode 100644 library/benchmark.js diff --git a/library/benchmark.js b/library/benchmark.js deleted file mode 100644 index c17b365..0000000 --- a/library/benchmark.js +++ /dev/null @@ -1,3919 +0,0 @@ -/*! - * Benchmark.js v1.0.0 - * Copyright 2010-2012 Mathias Bynens - * Based on JSLitmus.js, copyright Robert Kieffer - * Modified by John-David Dalton - * Available under MIT license - */ -;(function(window, undefined) { - 'use strict'; - - /** Used to assign each benchmark an incrimented id */ - var counter = 0; - - /** Detect DOM document object */ - var doc = isHostType(window, 'document') && document; - - /** Detect free variable `define` */ - var freeDefine = typeof define == 'function' && - typeof define.amd == 'object' && define.amd && define; - - /** Detect free variable `exports` */ - var freeExports = typeof exports == 'object' && exports && - (typeof global == 'object' && global && global == global.global && (window = global), exports); - - /** Detect free variable `require` */ - var freeRequire = typeof require == 'function' && require; - - /** Used to crawl all properties regardless of enumerability */ - var getAllKeys = Object.getOwnPropertyNames; - - /** Used to get property descriptors */ - var getDescriptor = Object.getOwnPropertyDescriptor; - - /** Used in case an object doesn't have its own method */ - var hasOwnProperty = {}.hasOwnProperty; - - /** Used to check if an object is extensible */ - var isExtensible = Object.isExtensible || function() { return true; }; - - /** Used to access Wade Simmons' Node microtime module */ - var microtimeObject = req('microtime'); - - /** Used to access the browser's high resolution timer */ - var perfObject = isHostType(window, 'performance') && performance; - - /** Used to call the browser's high resolution timer */ - var perfName = perfObject && ( - perfObject.now && 'now' || - perfObject.webkitNow && 'webkitNow' - ); - - /** Used to access Node's high resolution timer */ - var processObject = isHostType(window, 'process') && process; - - /** Used to check if an own property is enumerable */ - var propertyIsEnumerable = {}.propertyIsEnumerable; - - /** Used to set property descriptors */ - var setDescriptor = Object.defineProperty; - - /** Used to resolve a value's internal [[Class]] */ - var toString = {}.toString; - - /** Used to prevent a `removeChild` memory leak in IE < 9 */ - var trash = doc && doc.createElement('div'); - - /** Used to integrity check compiled tests */ - var uid = 'uid' + (+new Date); - - /** Used to avoid infinite recursion when methods call each other */ - var calledBy = {}; - - /** Used to avoid hz of Infinity */ - var divisors = { - '1': 4096, - '2': 512, - '3': 64, - '4': 8, - '5': 0 - }; - - /** - * T-Distribution two-tailed critical values for 95% confidence - * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm - */ - var tTable = { - '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, - '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, - '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, - '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064, - '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042, - 'infinity': 1.96 - }; - - /** - * Critical Mann-Whitney U-values for 95% confidence - * http://www.saburchill.com/IBbiology/stats/003.html - */ - var uTable = { - '5': [0, 1, 2], - '6': [1, 2, 3, 5], - '7': [1, 3, 5, 6, 8], - '8': [2, 4, 6, 8, 10, 13], - '9': [2, 4, 7, 10, 12, 15, 17], - '10': [3, 5, 8, 11, 14, 17, 20, 23], - '11': [3, 6, 9, 13, 16, 19, 23, 26, 30], - '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], - '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], - '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], - '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], - '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], - '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], - '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], - '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], - '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127], - '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142], - '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158], - '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175], - '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192], - '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211], - '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230], - '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250], - '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272], - '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294], - '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317] - }; - - /** - * An object used to flag environments/features. - * - * @static - * @memberOf Benchmark - * @type Object - */ - var support = {}; - - (function() { - - /** - * Detect Adobe AIR. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject'); - - /** - * Detect if `arguments` objects have the correct internal [[Class]] value. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.argumentsClass = isClassOf(arguments, 'Arguments'); - - /** - * Detect if in a browser environment. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.browser = doc && isHostType(window, 'navigator'); - - /** - * Detect if strings support accessing characters by index. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.charByIndex = - // IE 8 supports indexes on string literals but not string objects - ('x'[0] + Object('x')[0]) == 'xx'; - - /** - * Detect if strings have indexes as own properties. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.charByOwnIndex = - // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on - // strings but don't detect them as own properties - support.charByIndex && hasKey('x', '0'); - - /** - * Detect if Java is enabled/exposed. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.java = isClassOf(window.java, 'JavaPackage'); - - /** - * Detect if the Timers API exists. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout'); - - /** - * Detect if functions support decompilation. - * - * @name decompilation - * @memberOf Benchmark.support - * @type Boolean - */ - try { - // Safari 2.x removes commas in object literals - // from Function#toString results - // http://webk.it/11609 - // Firefox 3.6 and Opera 9.25 strip grouping - // parentheses from Function#toString results - // http://bugzil.la/559438 - support.decompilation = Function( - 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')' - )()(0).x === '1'; - } catch(e) { - support.decompilation = false; - } - - /** - * Detect ES5+ property descriptor API. - * - * @name descriptors - * @memberOf Benchmark.support - * @type Boolean - */ - try { - var o = {}; - support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o)); - } catch(e) { - support.descriptors = false; - } - - /** - * Detect ES5+ Object.getOwnPropertyNames(). - * - * @name getAllKeys - * @memberOf Benchmark.support - * @type Boolean - */ - try { - support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype)); - } catch(e) { - support.getAllKeys = false; - } - - /** - * Detect if own properties are iterated before inherited properties (all but IE < 9). - * - * @name iteratesOwnLast - * @memberOf Benchmark.support - * @type Boolean - */ - support.iteratesOwnFirst = (function() { - var props = []; - function ctor() { this.x = 1; } - ctor.prototype = { 'y': 1 }; - for (var prop in new ctor) { props.push(prop); } - return props[0] == 'x'; - }()); - - /** - * Detect if a node's [[Class]] is resolvable (all but IE < 9) - * and that the JS engine errors when attempting to coerce an object to a - * string without a `toString` property value of `typeof` "function". - * - * @name nodeClass - * @memberOf Benchmark.support - * @type Boolean - */ - try { - support.nodeClass = ({ 'toString': 0 } + '', toString.call(doc || 0) != '[object Object]'); - } catch(e) { - support.nodeClass = true; - } - }()); - - /** - * Timer object used by `clock()` and `Deferred#resolve`. - * - * @private - * @type Object - */ - var timer = { - - /** - * The timer namespace object or constructor. - * - * @private - * @memberOf timer - * @type Function|Object - */ - 'ns': Date, - - /** - * Starts the deferred timer. - * - * @private - * @memberOf timer - * @param {Object} deferred The deferred instance. - */ - 'start': null, // lazy defined in `clock()` - - /** - * Stops the deferred timer. - * - * @private - * @memberOf timer - * @param {Object} deferred The deferred instance. - */ - 'stop': null // lazy defined in `clock()` - }; - - /** Shortcut for inverse results */ - var noArgumentsClass = !support.argumentsClass, - noCharByIndex = !support.charByIndex, - noCharByOwnIndex = !support.charByOwnIndex; - - /** Math shortcuts */ - var abs = Math.abs, - floor = Math.floor, - max = Math.max, - min = Math.min, - pow = Math.pow, - sqrt = Math.sqrt; - - /*--------------------------------------------------------------------------*/ - - /** - * The Benchmark constructor. - * - * @constructor - * @param {String} name A name to identify the benchmark. - * @param {Function|String} fn The test to benchmark. - * @param {Object} [options={}] Options object. - * @example - * - * // basic usage (the `new` operator is optional) - * var bench = new Benchmark(fn); - * - * // or using a name first - * var bench = new Benchmark('foo', fn); - * - * // or with options - * var bench = new Benchmark('foo', fn, { - * - * // displayed by Benchmark#toString if `name` is not available - * 'id': 'xyz', - * - * // called when the benchmark starts running - * 'onStart': onStart, - * - * // called after each run cycle - * 'onCycle': onCycle, - * - * // called when aborted - * 'onAbort': onAbort, - * - * // called when a test errors - * 'onError': onError, - * - * // called when reset - * 'onReset': onReset, - * - * // called when the benchmark completes running - * 'onComplete': onComplete, - * - * // compiled/called before the test loop - * 'setup': setup, - * - * // compiled/called after the test loop - * 'teardown': teardown - * }); - * - * // or name and options - * var bench = new Benchmark('foo', { - * - * // a flag to indicate the benchmark is deferred - * 'defer': true, - * - * // benchmark test function - * 'fn': function(deferred) { - * // call resolve() when the deferred test is finished - * deferred.resolve(); - * } - * }); - * - * // or options only - * var bench = new Benchmark({ - * - * // benchmark name - * 'name': 'foo', - * - * // benchmark test as a string - * 'fn': '[1,2,3,4].sort()' - * }); - * - * // a test's `this` binding is set to the benchmark instance - * var bench = new Benchmark('foo', function() { - * 'My name is '.concat(this.name); // My name is foo - * }); - */ - function Benchmark(name, fn, options) { - var me = this; - - // allow instance creation without the `new` operator - if (me == null || me.constructor != Benchmark) { - return new Benchmark(name, fn, options); - } - // juggle arguments - if (isClassOf(name, 'Object')) { - // 1 argument (options) - options = name; - } - else if (isClassOf(name, 'Function')) { - // 2 arguments (fn, options) - options = fn; - fn = name; - } - else if (isClassOf(fn, 'Object')) { - // 2 arguments (name, options) - options = fn; - fn = null; - me.name = name; - } - else { - // 3 arguments (name, fn [, options]) - me.name = name; - } - setOptions(me, options); - me.id || (me.id = ++counter); - me.fn == null && (me.fn = fn); - me.stats = deepClone(me.stats); - me.times = deepClone(me.times); - } - - /** - * The Deferred constructor. - * - * @constructor - * @memberOf Benchmark - * @param {Object} clone The cloned benchmark instance. - */ - function Deferred(clone) { - var me = this; - if (me == null || me.constructor != Deferred) { - return new Deferred(clone); - } - me.benchmark = clone; - clock(me); - } - - /** - * The Event constructor. - * - * @constructor - * @memberOf Benchmark - * @param {String|Object} type The event type. - */ - function Event(type) { - var me = this; - return (me == null || me.constructor != Event) - ? new Event(type) - : (type instanceof Event) - ? type - : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type); - } - - /** - * The Suite constructor. - * - * @constructor - * @memberOf Benchmark - * @param {String} name A name to identify the suite. - * @param {Object} [options={}] Options object. - * @example - * - * // basic usage (the `new` operator is optional) - * var suite = new Benchmark.Suite; - * - * // or using a name first - * var suite = new Benchmark.Suite('foo'); - * - * // or with options - * var suite = new Benchmark.Suite('foo', { - * - * // called when the suite starts running - * 'onStart': onStart, - * - * // called between running benchmarks - * 'onCycle': onCycle, - * - * // called when aborted - * 'onAbort': onAbort, - * - * // called when a test errors - * 'onError': onError, - * - * // called when reset - * 'onReset': onReset, - * - * // called when the suite completes running - * 'onComplete': onComplete - * }); - */ - function Suite(name, options) { - var me = this; - - // allow instance creation without the `new` operator - if (me == null || me.constructor != Suite) { - return new Suite(name, options); - } - // juggle arguments - if (isClassOf(name, 'Object')) { - // 1 argument (options) - options = name; - } else { - // 2 arguments (name [, options]) - me.name = name; - } - setOptions(me, options); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Note: Some array methods have been implemented in plain JavaScript to avoid - * bugs in IE, Opera, Rhino, and Mobile Safari. - * - * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()` - * functions that fail to remove the last element, `object[0]`, of - * array-like-objects even though the `length` property is set to `0`. - * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` - * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. - * - * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()` - * generically to augment the `arguments` object will pave the value at index 0 - * without incrimenting the other values's indexes. - * https://github.com/documentcloud/underscore/issues/9 - * - * Rhino and environments it powers, like Narwhal and RingoJS, may have - * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and - * `unshift()` functions that make sparse arrays non-sparse by assigning the - * undefined indexes a value of undefined. - * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd - */ - - /** - * Creates an array containing the elements of the host array followed by the - * elements of each argument in order. - * - * @memberOf Benchmark.Suite - * @returns {Array} The new array. - */ - function concat() { - var value, - j = -1, - length = arguments.length, - result = slice.call(this), - index = result.length; - - while (++j < length) { - value = arguments[j]; - if (isClassOf(value, 'Array')) { - for (var k = 0, l = value.length; k < l; k++, index++) { - if (k in value) { - result[index] = value[k]; - } - } - } else { - result[index++] = value; - } - } - return result; - } - - /** - * Utility function used by `shift()`, `splice()`, and `unshift()`. - * - * @private - * @param {Number} start The index to start inserting elements. - * @param {Number} deleteCount The number of elements to delete from the insert point. - * @param {Array} elements The elements to insert. - * @returns {Array} An array of deleted elements. - */ - function insert(start, deleteCount, elements) { - // `result` should have its length set to the `deleteCount` - // see https://bugs.ecmascript.org/show_bug.cgi?id=332 - var deleteEnd = start + deleteCount, - elementCount = elements ? elements.length : 0, - index = start - 1, - length = start + elementCount, - object = this, - result = Array(deleteCount), - tail = slice.call(object, deleteEnd); - - // delete elements from the array - while (++index < deleteEnd) { - if (index in object) { - result[index - start] = object[index]; - delete object[index]; - } - } - // insert elements - index = start - 1; - while (++index < length) { - object[index] = elements[index - start]; - } - // append tail elements - start = index--; - length = max(0, (object.length >>> 0) - deleteCount + elementCount); - while (++index < length) { - if ((index - start) in tail) { - object[index] = tail[index - start]; - } else if (index in object) { - delete object[index]; - } - } - // delete excess elements - deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0; - while (deleteCount--) { - index = length + deleteCount; - if (index in object) { - delete object[index]; - } - } - object.length = length; - return result; - } - - /** - * Rearrange the host array's elements in reverse order. - * - * @memberOf Benchmark.Suite - * @returns {Array} The reversed array. - */ - function reverse() { - var upperIndex, - value, - index = -1, - object = Object(this), - length = object.length >>> 0, - middle = floor(length / 2); - - if (length > 1) { - while (++index < middle) { - upperIndex = length - index - 1; - value = upperIndex in object ? object[upperIndex] : uid; - if (index in object) { - object[upperIndex] = object[index]; - } else { - delete object[upperIndex]; - } - if (value != uid) { - object[index] = value; - } else { - delete object[index]; - } - } - } - return object; - } - - /** - * Removes the first element of the host array and returns it. - * - * @memberOf Benchmark.Suite - * @returns {Mixed} The first element of the array. - */ - function shift() { - return insert.call(this, 0, 1)[0]; - } - - /** - * Creates an array of the host array's elements from the start index up to, - * but not including, the end index. - * - * @memberOf Benchmark.Suite - * @param {Number} start The starting index. - * @param {Number} end The end index. - * @returns {Array} The new array. - */ - function slice(start, end) { - var index = -1, - object = Object(this), - length = object.length >>> 0, - result = []; - - start = toInteger(start); - start = start < 0 ? max(length + start, 0) : min(start, length); - start--; - end = end == null ? length : toInteger(end); - end = end < 0 ? max(length + end, 0) : min(end, length); - - while ((++index, ++start) < end) { - if (start in object) { - result[index] = object[start]; - } - } - return result; - } - - /** - * Allows removing a range of elements and/or inserting elements into the - * host array. - * - * @memberOf Benchmark.Suite - * @param {Number} start The start index. - * @param {Number} deleteCount The number of elements to delete. - * @param {Mixed} [val1, val2, ...] values to insert at the `start` index. - * @returns {Array} An array of removed elements. - */ - function splice(start, deleteCount) { - var object = Object(this), - length = object.length >>> 0; - - start = toInteger(start); - start = start < 0 ? max(length + start, 0) : min(start, length); - - // support the de-facto SpiderMonkey extension - // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice#Parameters - // https://bugs.ecmascript.org/show_bug.cgi?id=429 - deleteCount = arguments.length == 1 - ? length - start - : min(max(toInteger(deleteCount), 0), length - start); - - return insert.call(object, start, deleteCount, slice.call(arguments, 2)); - } - - /** - * Converts the specified `value` to an integer. - * - * @private - * @param {Mixed} value The value to convert. - * @returns {Number} The resulting integer. - */ - function toInteger(value) { - value = +value; - return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1); - } - - /** - * Appends arguments to the host array. - * - * @memberOf Benchmark.Suite - * @returns {Number} The new length. - */ - function unshift() { - var object = Object(this); - insert.call(object, 0, 0, arguments); - return object.length; - } - - /*--------------------------------------------------------------------------*/ - - /** - * A generic `Function#bind` like method. - * - * @private - * @param {Function} fn The function to be bound to `thisArg`. - * @param {Mixed} thisArg The `this` binding for the given function. - * @returns {Function} The bound function. - */ - function bind(fn, thisArg) { - return function() { fn.apply(thisArg, arguments); }; - } - - /** - * Creates a function from the given arguments string and body. - * - * @private - * @param {String} args The comma separated function arguments. - * @param {String} body The function body. - * @returns {Function} The new function. - */ - function createFunction() { - // lazy define - createFunction = function(args, body) { - var result, - anchor = freeDefine ? define.amd : Benchmark, - prop = uid + 'createFunction'; - - runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}'); - result = anchor[prop]; - delete anchor[prop]; - return result; - }; - // fix JaegerMonkey bug - // http://bugzil.la/639720 - createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function; - return createFunction.apply(null, arguments); - } - - /** - * Delay the execution of a function based on the benchmark's `delay` property. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} fn The function to execute. - */ - function delay(bench, fn) { - bench._timerId = setTimeout(fn, bench.delay * 1e3); - } - - /** - * Destroys the given element. - * - * @private - * @param {Element} element The element to destroy. - */ - function destroyElement(element) { - trash.appendChild(element); - trash.innerHTML = ''; - } - - /** - * Iterates over an object's properties, executing the `callback` for each. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} callback The function executed per own property. - * @param {Object} options The options object. - * @returns {Object} Returns the object iterated over. - */ - function forProps() { - var forShadowed, - skipSeen, - forArgs = true, - shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']; - - (function(enumFlag, key) { - // must use a non-native constructor to catch the Safari 2 issue - function Klass() { this.valueOf = 0; }; - Klass.prototype.valueOf = 0; - // check various for-in bugs - for (key in new Klass) { - enumFlag += key == 'valueOf' ? 1 : 0; - } - // check if `arguments` objects have non-enumerable indexes - for (key in arguments) { - key == '0' && (forArgs = false); - } - // Safari 2 iterates over shadowed properties twice - // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/ - skipSeen = enumFlag == 2; - // IE < 9 incorrectly makes an object's properties non-enumerable if they have - // the same name as other non-enumerable properties in its prototype chain. - forShadowed = !enumFlag; - }(0)); - - // lazy define - forProps = function(object, callback, options) { - options || (options = {}); - - var result = object; - object = Object(object); - - var ctor, - key, - keys, - skipCtor, - done = !result, - which = options.which, - allFlag = which == 'all', - index = -1, - iteratee = object, - length = object.length, - ownFlag = allFlag || which == 'own', - seen = {}, - skipProto = isClassOf(object, 'Function'), - thisArg = options.bind; - - if (thisArg !== undefined) { - callback = bind(callback, thisArg); - } - // iterate all properties - if (allFlag && support.getAllKeys) { - for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) { - key = keys[index]; - if (callback(object[key], key, object) === false) { - break; - } - } - } - // else iterate only enumerable properties - else { - for (key in object) { - // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 - // (if the prototype or a property on the prototype has been set) - // incorrectly set a function's `prototype` property [[Enumerable]] value - // to `true`. Because of this we standardize on skipping the `prototype` - // property of functions regardless of their [[Enumerable]] value. - if ((done = - !(skipProto && key == 'prototype') && - !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) && - (!ownFlag || ownFlag && hasKey(object, key)) && - callback(object[key], key, object) === false)) { - break; - } - } - // in IE < 9 strings don't support accessing characters by index - if (!done && (forArgs && isArguments(object) || - ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') && - (iteratee = noCharByIndex ? object.split('') : object)))) { - while (++index < length) { - if ((done = - callback(iteratee[index], String(index), object) === false)) { - break; - } - } - } - if (!done && forShadowed) { - // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing - // property and the `constructor` property of a prototype defaults to - // non-enumerable, we manually skip the `constructor` property when we - // think we are iterating over a `prototype` object. - ctor = object.constructor; - skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor; - for (index = 0; index < 7; index++) { - key = shadowed[index]; - if (!(skipCtor && key == 'constructor') && - hasKey(object, key) && - callback(object[key], key, object) === false) { - break; - } - } - } - } - return result; - }; - return forProps.apply(null, arguments); - } - - /** - * Gets the name of the first argument from a function's source. - * - * @private - * @param {Function} fn The function. - * @returns {String} The argument name. - */ - function getFirstArgument(fn) { - return (!hasKey(fn, 'toString') && - (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || ''; - } - - /** - * Computes the arithmetic mean of a sample. - * - * @private - * @param {Array} sample The sample. - * @returns {Number} The mean. - */ - function getMean(sample) { - return reduce(sample, function(sum, x) { - return sum + x; - }) / sample.length || 0; - } - - /** - * Gets the source code of a function. - * - * @private - * @param {Function} fn The function. - * @param {String} altSource A string used when a function's source code is unretrievable. - * @returns {String} The function's source code. - */ - function getSource(fn, altSource) { - var result = altSource; - if (isStringable(fn)) { - result = String(fn); - } else if (support.decompilation) { - // escape the `{` for Firefox 1 - result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1]; - } - // trim string - result = (result || '').replace(/^\s+|\s+$/g, ''); - - // detect strings containing only the "use strict" directive - return /^(?:\/\*+[\w|\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result) - ? '' - : result; - } - - /** - * Checks if a value is an `arguments` object. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`. - */ - function isArguments() { - // lazy define - isArguments = function(value) { - return toString.call(value) == '[object Arguments]'; - }; - if (noArgumentsClass) { - isArguments = function(value) { - return hasKey(value, 'callee') && - !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee')); - }; - } - return isArguments(arguments[0]); - } - - /** - * Checks if an object is of the specified class. - * - * @private - * @param {Mixed} value The value to check. - * @param {String} name The name of the class. - * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`. - */ - function isClassOf(value, name) { - return value != null && toString.call(value) == '[object ' + name + ']'; - } - - /** - * Host objects can return type values that are different from their actual - * data type. The objects we are concerned with usually return non-primitive - * types of object, function, or unknown. - * - * @private - * @param {Mixed} object The owner of the property. - * @param {String} property The property to check. - * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. - */ - function isHostType(object, property) { - var type = object != null ? typeof object[property] : 'number'; - return !/^(?:boolean|number|string|undefined)$/.test(type) && - (type == 'object' ? !!object[property] : true); - } - - /** - * Checks if a given `value` is an object created by the `Object` constructor - * assuming objects created by the `Object` constructor have no inherited - * enumerable properties and that there are no `Object.prototype` extensions. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the `value` is a plain `Object` object, else `false`. - */ - function isPlainObject(value) { - // avoid non-objects and false positives for `arguments` objects in IE < 9 - var result = false; - if (!(value && typeof value == 'object') || isArguments(value)) { - return result; - } - // IE < 9 presents DOM nodes as `Object` objects except they have `toString` - // methods that are `typeof` "string" and still can coerce nodes to strings. - // Also check that the constructor is `Object` (i.e. `Object instanceof Object`) - var ctor = value.constructor; - if ((support.nodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) && - (!isClassOf(ctor, 'Function') || ctor instanceof ctor)) { - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - if (support.iteratesOwnFirst) { - forProps(value, function(subValue, subKey) { - result = subKey; - }); - return result === false || hasKey(value, result); - } - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - forProps(value, function(subValue, subKey) { - result = !hasKey(value, subKey); - return false; - }); - return result === false; - } - return result; - } - - /** - * Checks if a value can be safely coerced to a string. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the value can be coerced, else `false`. - */ - function isStringable(value) { - return hasKey(value, 'toString') || isClassOf(value, 'String'); - } - - /** - * Wraps a function and passes `this` to the original function as the - * first argument. - * - * @private - * @param {Function} fn The function to be wrapped. - * @returns {Function} The new function. - */ - function methodize(fn) { - return function() { - var args = [this]; - args.push.apply(args, arguments); - return fn.apply(null, args); - }; - } - - /** - * A no-operation function. - * - * @private - */ - function noop() { - // no operation performed - } - - /** - * A wrapper around require() to suppress `module missing` errors. - * - * @private - * @param {String} id The module id. - * @returns {Mixed} The exported module or `null`. - */ - function req(id) { - try { - var result = freeExports && freeRequire(id); - } catch(e) { } - return result || null; - } - - /** - * Runs a snippet of JavaScript via script injection. - * - * @private - * @param {String} code The code to run. - */ - function runScript(code) { - var anchor = freeDefine ? define.amd : Benchmark, - script = doc.createElement('script'), - sibling = doc.getElementsByTagName('script')[0], - parent = sibling.parentNode, - prop = uid + 'runScript', - prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();'; - - // Firefox 2.0.0.2 cannot use script injection as intended because it executes - // asynchronously, but that's OK because script injection is only used to avoid - // the previously commented JaegerMonkey bug. - try { - // remove the inserted script *before* running the code to avoid differences - // in the expected script element count/order of the document. - script.appendChild(doc.createTextNode(prefix + code)); - anchor[prop] = function() { destroyElement(script); }; - } catch(e) { - parent = parent.cloneNode(false); - sibling = null; - script.text = code; - } - parent.insertBefore(script, sibling); - delete anchor[prop]; - } - - /** - * A helper function for setting options/event handlers. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} [options={}] Options object. - */ - function setOptions(bench, options) { - options = extend({}, bench.constructor.options, options); - bench.options = forOwn(options, function(value, key) { - if (value != null) { - // add event listeners - if (/^on[A-Z]/.test(key)) { - forEach(key.split(' '), function(key) { - bench.on(key.slice(2).toLowerCase(), value); - }); - } else if (!hasKey(bench, key)) { - bench[key] = deepClone(value); - } - } - }); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Handles cycling/completing the deferred benchmark. - * - * @memberOf Benchmark.Deferred - */ - function resolve() { - var me = this, - clone = me.benchmark, - bench = clone._original; - - if (bench.aborted) { - // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete - me.teardown(); - clone.running = false; - cycle(me); - } - else if (++me.cycles < clone.count) { - // continue the test loop - if (support.timeout) { - // use setTimeout to avoid a call stack overflow if called recursively - setTimeout(function() { clone.compiled.call(me, timer); }, 0); - } else { - clone.compiled.call(me, timer); - } - } - else { - timer.stop(me); - me.teardown(); - delay(clone, function() { cycle(me); }); - } - } - - /*--------------------------------------------------------------------------*/ - - /** - * A deep clone utility. - * - * @static - * @memberOf Benchmark - * @param {Mixed} value The value to clone. - * @returns {Mixed} The cloned value. - */ - function deepClone(value) { - var accessor, - circular, - clone, - ctor, - descriptor, - extensible, - key, - length, - markerKey, - parent, - result, - source, - subIndex, - data = { 'value': value }, - index = 0, - marked = [], - queue = { 'length': 0 }, - unmarked = []; - - /** - * An easily detectable decorator for cloned values. - */ - function Marker(object) { - this.raw = object; - } - - /** - * The callback used by `forProps()`. - */ - function forPropsCallback(subValue, subKey) { - // exit early to avoid cloning the marker - if (subValue && subValue.constructor == Marker) { - return; - } - // add objects to the queue - if (subValue === Object(subValue)) { - queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value }; - } - // assign non-objects - else { - try { - // will throw an error in strict mode if the property is read-only - clone[subKey] = subValue; - } catch(e) { } - } - } - - /** - * Gets an available marker key for the given object. - */ - function getMarkerKey(object) { - // avoid collisions with existing keys - var result = uid; - while (object[result] && object[result].constructor != Marker) { - result += 1; - } - return result; - } - - do { - key = data.key; - parent = data.parent; - source = data.source; - clone = value = source ? source[key] : data.value; - accessor = circular = descriptor = false; - - // create a basic clone to filter out functions, DOM elements, and - // other non `Object` objects - if (value === Object(value)) { - // use custom deep clone function if available - if (isClassOf(value.deepClone, 'Function')) { - clone = value.deepClone(); - } else { - ctor = value.constructor; - switch (toString.call(value)) { - case '[object Array]': - clone = new ctor(value.length); - break; - - case '[object Boolean]': - clone = new ctor(value == true); - break; - - case '[object Date]': - clone = new ctor(+value); - break; - - case '[object Object]': - isPlainObject(value) && (clone = {}); - break; - - case '[object Number]': - case '[object String]': - clone = new ctor(value); - break; - - case '[object RegExp]': - clone = ctor(value.source, - (value.global ? 'g' : '') + - (value.ignoreCase ? 'i' : '') + - (value.multiline ? 'm' : '')); - } - } - // continue clone if `value` doesn't have an accessor descriptor - // http://es5.github.com/#x8.10.1 - if (clone && clone != value && - !(descriptor = source && support.descriptors && getDescriptor(source, key), - accessor = descriptor && (descriptor.get || descriptor.set))) { - // use an existing clone (circular reference) - if ((extensible = isExtensible(value))) { - markerKey = getMarkerKey(value); - if (value[markerKey]) { - circular = clone = value[markerKey].raw; - } - } else { - // for frozen/sealed objects - for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) { - data = unmarked[subIndex]; - if (data.object === value) { - circular = clone = data.clone; - break; - } - } - } - if (!circular) { - // mark object to allow quickly detecting circular references and tie it to its clone - if (extensible) { - value[markerKey] = new Marker(clone); - marked.push({ 'key': markerKey, 'object': value }); - } else { - // for frozen/sealed objects - unmarked.push({ 'clone': clone, 'object': value }); - } - // iterate over object properties - forProps(value, forPropsCallback, { 'which': 'all' }); - } - } - } - if (parent) { - // for custom property descriptors - if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) { - if ('value' in descriptor) { - descriptor.value = clone; - } - setDescriptor(parent, key, descriptor); - } - // for default property descriptors - else { - parent[key] = clone; - } - } else { - result = clone; - } - } while ((data = queue[index++])); - - // remove markers - for (index = 0, length = marked.length; index < length; index++) { - data = marked[index]; - delete data.object[data.key]; - } - return result; - } - - /** - * An iteration utility for arrays and objects. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Array|Object} object The object to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array|Object} Returns the object iterated over. - */ - function each(object, callback, thisArg) { - var result = object; - object = Object(object); - - var fn = callback, - index = -1, - length = object.length, - isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)), - isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'), - isConvertable = isSnapshot || isSplittable || 'item' in object, - origObject = object; - - // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists - if (length === length >>> 0) { - if (isConvertable) { - // the third argument of the callback is the original non-array object - callback = function(value, index) { - return fn.call(this, value, index, origObject); - }; - // in IE < 9 strings don't support accessing characters by index - if (isSplittable) { - object = object.split(''); - } else { - object = []; - while (++index < length) { - // in Safari 2 `index in object` is always `false` for NodeLists - object[index] = isSnapshot ? result.snapshotItem(index) : result[index]; - } - } - } - forEach(object, callback, thisArg); - } else { - forOwn(object, callback, thisArg); - } - return result; - } - - /** - * Copies enumerable properties from the source(s) object to the destination object. - * - * @static - * @memberOf Benchmark - * @param {Object} destination The destination object. - * @param {Object} [source={}] The source object. - * @returns {Object} The destination object. - */ - function extend(destination, source) { - // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]` - // http://code.google.com/p/v8/issues/detail?id=839 - var result = destination; - delete arguments[0]; - - forEach(arguments, function(source) { - forProps(source, function(value, key) { - result[key] = value; - }); - }); - return result; - } - - /** - * A generic `Array#filter` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function|String} callback The function/alias called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} A new array of values that passed callback filter. - * @example - * - * // get odd numbers - * Benchmark.filter([1, 2, 3, 4, 5], function(n) { - * return n % 2; - * }); // -> [1, 3, 5]; - * - * // get fastest benchmarks - * Benchmark.filter(benches, 'fastest'); - * - * // get slowest benchmarks - * Benchmark.filter(benches, 'slowest'); - * - * // get benchmarks that completed without erroring - * Benchmark.filter(benches, 'successful'); - */ - function filter(array, callback, thisArg) { - var result; - - if (callback == 'successful') { - // callback to exclude those that are errored, unrun, or have hz of Infinity - callback = function(bench) { return bench.cycles && isFinite(bench.hz); }; - } - else if (callback == 'fastest' || callback == 'slowest') { - // get successful, sort by period + margin of error, and filter fastest/slowest - result = filter(array, 'successful').sort(function(a, b) { - a = a.stats; b = b.stats; - return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1); - }); - result = filter(result, function(bench) { - return result[0].compare(bench) == 0; - }); - } - return result || reduce(array, function(result, value, index) { - return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result; - }, []); - } - - /** - * A generic `Array#forEach` like method. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} Returns the array iterated over. - */ - function forEach(array, callback, thisArg) { - var index = -1, - length = (array = Object(array)).length >>> 0; - - if (thisArg !== undefined) { - callback = bind(callback, thisArg); - } - while (++index < length) { - if (index in array && - callback(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * Iterates over an object's own properties, executing the `callback` for each. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Object} object The object to iterate over. - * @param {Function} callback The function executed per own property. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Object} Returns the object iterated over. - */ - function forOwn(object, callback, thisArg) { - return forProps(object, callback, { 'bind': thisArg, 'which': 'own' }); - } - - /** - * Converts a number to a more readable comma-separated string representation. - * - * @static - * @memberOf Benchmark - * @param {Number} number The number to convert. - * @returns {String} The more readable string representation. - */ - function formatNumber(number) { - number = String(number).split('.'); - return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + - (number[1] ? '.' + number[1] : ''); - } - - /** - * Checks if an object has the specified key as a direct property. - * - * @static - * @memberOf Benchmark - * @param {Object} object The object to check. - * @param {String} key The key to check for. - * @returns {Boolean} Returns `true` if key is a direct property, else `false`. - */ - function hasKey() { - // lazy define for worst case fallback (not as accurate) - hasKey = function(object, key) { - var parent = object != null && (object.constructor || Object).prototype; - return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); - }; - // for modern browsers - if (isClassOf(hasOwnProperty, 'Function')) { - hasKey = function(object, key) { - return object != null && hasOwnProperty.call(object, key); - }; - } - // for Safari 2 - else if ({}.__proto__ == Object.prototype) { - hasKey = function(object, key) { - var result = false; - if (object != null) { - object = Object(object); - object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0]; - } - return result; - }; - } - return hasKey.apply(this, arguments); - } - - /** - * A generic `Array#indexOf` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Mixed} value The value to search for. - * @param {Number} [fromIndex=0] The index to start searching from. - * @returns {Number} The index of the matched value or `-1`. - */ - function indexOf(array, value, fromIndex) { - var index = toInteger(fromIndex), - length = (array = Object(array)).length >>> 0; - - index = (index < 0 ? max(0, length + index) : index) - 1; - while (++index < length) { - if (index in array && value === array[index]) { - return index; - } - } - return -1; - } - - /** - * Modify a string by replacing named tokens with matching object property values. - * - * @static - * @memberOf Benchmark - * @param {String} string The string to modify. - * @param {Object} object The template object. - * @returns {String} The modified string. - */ - function interpolate(string, object) { - forOwn(object, function(value, key) { - // escape regexp special characters in `key` - string = string.replace(RegExp('#\\{' + key.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '\\}', 'g'), value); - }); - return string; - } - - /** - * Invokes a method on all items in an array. - * - * @static - * @memberOf Benchmark - * @param {Array} benches Array of benchmarks to iterate over. - * @param {String|Object} name The name of the method to invoke OR options object. - * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. - * @returns {Array} A new array of values returned from each method invoked. - * @example - * - * // invoke `reset` on all benchmarks - * Benchmark.invoke(benches, 'reset'); - * - * // invoke `emit` with arguments - * Benchmark.invoke(benches, 'emit', 'complete', listener); - * - * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks - * Benchmark.invoke(benches, { - * - * // invoke the `run` method - * 'name': 'run', - * - * // pass a single argument - * 'args': true, - * - * // treat as queue, removing benchmarks from front of `benches` until empty - * 'queued': true, - * - * // called before any benchmarks have been invoked. - * 'onStart': onStart, - * - * // called between invoking benchmarks - * 'onCycle': onCycle, - * - * // called after all benchmarks have been invoked. - * 'onComplete': onComplete - * }); - */ - function invoke(benches, name) { - var args, - bench, - queued, - index = -1, - eventProps = { 'currentTarget': benches }, - options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop }, - result = map(benches, function(bench) { return bench; }); - - /** - * Invokes the method of the current object and if synchronous, fetches the next. - */ - function execute() { - var listeners, - async = isAsync(bench); - - if (async) { - // use `getNext` as the first listener - bench.on('complete', getNext); - listeners = bench.events.complete; - listeners.splice(0, 0, listeners.pop()); - } - // execute method - result[index] = isClassOf(bench && bench[name], 'Function') ? bench[name].apply(bench, args) : undefined; - // if synchronous return true until finished - return !async && getNext(); - } - - /** - * Fetches the next bench or executes `onComplete` callback. - */ - function getNext(event) { - var cycleEvent, - last = bench, - async = isAsync(last); - - if (async) { - last.off('complete', getNext); - last.emit('complete'); - } - // emit "cycle" event - eventProps.type = 'cycle'; - eventProps.target = last; - cycleEvent = Event(eventProps); - options.onCycle.call(benches, cycleEvent); - - // choose next benchmark if not exiting early - if (!cycleEvent.aborted && raiseIndex() !== false) { - bench = queued ? benches[0] : result[index]; - if (isAsync(bench)) { - delay(bench, execute); - } - else if (async) { - // resume execution if previously asynchronous but now synchronous - while (execute()) { } - } - else { - // continue synchronous execution - return true; - } - } else { - // emit "complete" event - eventProps.type = 'complete'; - options.onComplete.call(benches, Event(eventProps)); - } - // When used as a listener `event.aborted = true` will cancel the rest of - // the "complete" listeners because they were already called above and when - // used as part of `getNext` the `return false` will exit the execution while-loop. - if (event) { - event.aborted = true; - } else { - return false; - } - } - - /** - * Checks if invoking `Benchmark#run` with asynchronous cycles. - */ - function isAsync(object) { - // avoid using `instanceof` here because of IE memory leak issues with host objects - var async = args[0] && args[0].async; - return Object(object).constructor == Benchmark && name == 'run' && - ((async == null ? object.options.async : async) && support.timeout || object.defer); - } - - /** - * Raises `index` to the next defined index or returns `false`. - */ - function raiseIndex() { - var length = result.length; - if (queued) { - // if queued remove the previous bench and subsequent skipped non-entries - do { - ++index > 0 && shift.call(benches); - } while ((length = benches.length) && !('0' in benches)); - } - else { - while (++index < length && !(index in result)) { } - } - // if we reached the last index then return `false` - return (queued ? length : index < length) ? index : (index = false); - } - - // juggle arguments - if (isClassOf(name, 'String')) { - // 2 arguments (array, name) - args = slice.call(arguments, 2); - } else { - // 2 arguments (array, options) - options = extend(options, name); - name = options.name; - args = isClassOf(args = 'args' in options ? options.args : [], 'Array') ? args : [args]; - queued = options.queued; - } - - // start iterating over the array - if (raiseIndex() !== false) { - // emit "start" event - bench = result[index]; - eventProps.type = 'start'; - eventProps.target = bench; - options.onStart.call(benches, Event(eventProps)); - - // end early if the suite was aborted in an "onStart" listener - if (benches.aborted && benches.constructor == Suite && name == 'run') { - // emit "cycle" event - eventProps.type = 'cycle'; - options.onCycle.call(benches, Event(eventProps)); - // emit "complete" event - eventProps.type = 'complete'; - options.onComplete.call(benches, Event(eventProps)); - } - // else start - else { - if (isAsync(bench)) { - delay(bench, execute); - } else { - while (execute()) { } - } - } - } - return result; - } - - /** - * Creates a string of joined array values or object key-value pairs. - * - * @static - * @memberOf Benchmark - * @param {Array|Object} object The object to operate on. - * @param {String} [separator1=','] The separator used between key-value pairs. - * @param {String} [separator2=': '] The separator used between keys and values. - * @returns {String} The joined result. - */ - function join(object, separator1, separator2) { - var result = [], - length = (object = Object(object)).length, - arrayLike = length === length >>> 0; - - separator2 || (separator2 = ': '); - each(object, function(value, key) { - result.push(arrayLike ? value : key + separator2 + value); - }); - return result.join(separator1 || ','); - } - - /** - * A generic `Array#map` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} A new array of values returned by the callback. - */ - function map(array, callback, thisArg) { - return reduce(array, function(result, value, index) { - result[index] = callback.call(thisArg, value, index, array); - return result; - }, Array(Object(array).length >>> 0)); - } - - /** - * Retrieves the value of a specified property from all items in an array. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {String} property The property to pluck. - * @returns {Array} A new array of property values. - */ - function pluck(array, property) { - return map(array, function(object) { - return object == null ? undefined : object[property]; - }); - } - - /** - * A generic `Array#reduce` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} accumulator Initial value of the accumulator. - * @returns {Mixed} The accumulator. - */ - function reduce(array, callback, accumulator) { - var noaccum = arguments.length < 3; - forEach(array, function(value, index) { - accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, array); - }); - return accumulator; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Aborts all benchmarks in the suite. - * - * @name abort - * @memberOf Benchmark.Suite - * @returns {Object} The suite instance. - */ - function abortSuite() { - var event, - me = this, - resetting = calledBy.resetSuite; - - if (me.running) { - event = Event('abort'); - me.emit(event); - if (!event.cancelled || resetting) { - // avoid infinite recursion - calledBy.abortSuite = true; - me.reset(); - delete calledBy.abortSuite; - - if (!resetting) { - me.aborted = true; - invoke(me, 'abort'); - } - } - } - return me; - } - - /** - * Adds a test to the benchmark suite. - * - * @memberOf Benchmark.Suite - * @param {String} name A name to identify the benchmark. - * @param {Function|String} fn The test to benchmark. - * @param {Object} [options={}] Options object. - * @returns {Object} The benchmark instance. - * @example - * - * // basic usage - * suite.add(fn); - * - * // or using a name first - * suite.add('foo', fn); - * - * // or with options - * suite.add('foo', fn, { - * 'onCycle': onCycle, - * 'onComplete': onComplete - * }); - * - * // or name and options - * suite.add('foo', { - * 'fn': fn, - * 'onCycle': onCycle, - * 'onComplete': onComplete - * }); - * - * // or options only - * suite.add({ - * 'name': 'foo', - * 'fn': fn, - * 'onCycle': onCycle, - * 'onComplete': onComplete - * }); - */ - function add(name, fn, options) { - var me = this, - bench = Benchmark(name, fn, options), - event = Event({ 'type': 'add', 'target': bench }); - - if (me.emit(event), !event.cancelled) { - me.push(bench); - } - return me; - } - - /** - * Creates a new suite with cloned benchmarks. - * - * @name clone - * @memberOf Benchmark.Suite - * @param {Object} options Options object to overwrite cloned options. - * @returns {Object} The new suite instance. - */ - function cloneSuite(options) { - var me = this, - result = new me.constructor(extend({}, me.options, options)); - - // copy own properties - forOwn(me, function(value, key) { - if (!hasKey(result, key)) { - result[key] = value && isClassOf(value.clone, 'Function') - ? value.clone() - : deepClone(value); - } - }); - return result; - } - - /** - * An `Array#filter` like method. - * - * @name filter - * @memberOf Benchmark.Suite - * @param {Function|String} callback The function/alias called per iteration. - * @returns {Object} A new suite of benchmarks that passed callback filter. - */ - function filterSuite(callback) { - var me = this, - result = new me.constructor; - - result.push.apply(result, filter(me, callback)); - return result; - } - - /** - * Resets all benchmarks in the suite. - * - * @name reset - * @memberOf Benchmark.Suite - * @returns {Object} The suite instance. - */ - function resetSuite() { - var event, - me = this, - aborting = calledBy.abortSuite; - - if (me.running && !aborting) { - // no worries, `resetSuite()` is called within `abortSuite()` - calledBy.resetSuite = true; - me.abort(); - delete calledBy.resetSuite; - } - // reset if the state has changed - else if ((me.aborted || me.running) && - (me.emit(event = Event('reset')), !event.cancelled)) { - me.running = false; - if (!aborting) { - invoke(me, 'reset'); - } - } - return me; - } - - /** - * Runs the suite. - * - * @name run - * @memberOf Benchmark.Suite - * @param {Object} [options={}] Options object. - * @returns {Object} The suite instance. - * @example - * - * // basic usage - * suite.run(); - * - * // or with options - * suite.run({ 'async': true, 'queued': true }); - */ - function runSuite(options) { - var me = this; - - me.reset(); - me.running = true; - options || (options = {}); - - invoke(me, { - 'name': 'run', - 'args': options, - 'queued': options.queued, - 'onStart': function(event) { - me.emit(event); - }, - 'onCycle': function(event) { - var bench = event.target; - if (bench.error) { - me.emit({ 'type': 'error', 'target': bench }); - } - me.emit(event); - event.aborted = me.aborted; - }, - 'onComplete': function(event) { - me.running = false; - me.emit(event); - } - }); - return me; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Executes all registered listeners of the specified event type. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String|Object} type The event type or object. - * @returns {Mixed} Returns the return value of the last listener executed. - */ - function emit(type) { - var listeners, - me = this, - event = Event(type), - events = me.events, - args = (arguments[0] = event, arguments); - - event.currentTarget || (event.currentTarget = me); - event.target || (event.target = me); - delete event.result; - - if (events && (listeners = hasKey(events, event.type) && events[event.type])) { - forEach(listeners.slice(), function(listener) { - if ((event.result = listener.apply(me, args)) === false) { - event.cancelled = true; - } - return !event.aborted; - }); - } - return event.result; - } - - /** - * Returns an array of event listeners for a given type that can be manipulated - * to add or remove listeners. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} type The event type. - * @returns {Array} The listeners array. - */ - function listeners(type) { - var me = this, - events = me.events || (me.events = {}); - - return hasKey(events, type) ? events[type] : (events[type] = []); - } - - /** - * Unregisters a listener for the specified event type(s), - * or unregisters all listeners for the specified event type(s), - * or unregisters all listeners for all event types. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} [type] The event type. - * @param {Function} [listener] The function to unregister. - * @returns {Object} The benchmark instance. - * @example - * - * // unregister a listener for an event type - * bench.off('cycle', listener); - * - * // unregister a listener for multiple event types - * bench.off('start cycle', listener); - * - * // unregister all listeners for an event type - * bench.off('cycle'); - * - * // unregister all listeners for multiple event types - * bench.off('start cycle complete'); - * - * // unregister all listeners for all event types - * bench.off(); - */ - function off(type, listener) { - var me = this, - events = me.events; - - events && each(type ? type.split(' ') : events, function(listeners, type) { - var index; - if (typeof listeners == 'string') { - type = listeners; - listeners = hasKey(events, type) && events[type]; - } - if (listeners) { - if (listener) { - index = indexOf(listeners, listener); - if (index > -1) { - listeners.splice(index, 1); - } - } else { - listeners.length = 0; - } - } - }); - return me; - } - - /** - * Registers a listener for the specified event type(s). - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} type The event type. - * @param {Function} listener The function to register. - * @returns {Object} The benchmark instance. - * @example - * - * // register a listener for an event type - * bench.on('cycle', listener); - * - * // register a listener for multiple event types - * bench.on('start cycle', listener); - */ - function on(type, listener) { - var me = this, - events = me.events || (me.events = {}); - - forEach(type.split(' '), function(type) { - (hasKey(events, type) - ? events[type] - : (events[type] = []) - ).push(listener); - }); - return me; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Aborts the benchmark without recording times. - * - * @memberOf Benchmark - * @returns {Object} The benchmark instance. - */ - function abort() { - var event, - me = this, - resetting = calledBy.reset; - - if (me.running) { - event = Event('abort'); - me.emit(event); - if (!event.cancelled || resetting) { - // avoid infinite recursion - calledBy.abort = true; - me.reset(); - delete calledBy.abort; - - if (support.timeout) { - clearTimeout(me._timerId); - delete me._timerId; - } - if (!resetting) { - me.aborted = true; - me.running = false; - } - } - } - return me; - } - - /** - * Creates a new benchmark using the same test and options. - * - * @memberOf Benchmark - * @param {Object} options Options object to overwrite cloned options. - * @returns {Object} The new benchmark instance. - * @example - * - * var bizarro = bench.clone({ - * 'name': 'doppelganger' - * }); - */ - function clone(options) { - var me = this, - result = new me.constructor(extend({}, me, options)); - - // correct the `options` object - result.options = extend({}, me.options, options); - - // copy own custom properties - forOwn(me, function(value, key) { - if (!hasKey(result, key)) { - result[key] = deepClone(value); - } - }); - return result; - } - - /** - * Determines if a benchmark is faster than another. - * - * @memberOf Benchmark - * @param {Object} other The benchmark to compare. - * @returns {Number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate. - */ - function compare(other) { - var critical, - zStat, - me = this, - sample1 = me.stats.sample, - sample2 = other.stats.sample, - size1 = sample1.length, - size2 = sample2.length, - maxSize = max(size1, size2), - minSize = min(size1, size2), - u1 = getU(sample1, sample2), - u2 = getU(sample2, sample1), - u = min(u1, u2); - - function getScore(xA, sampleB) { - return reduce(sampleB, function(total, xB) { - return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5); - }, 0); - } - - function getU(sampleA, sampleB) { - return reduce(sampleA, function(total, xA) { - return total + getScore(xA, sampleB); - }, 0); - } - - function getZ(u) { - return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12); - } - - // exit early if comparing the same benchmark - if (me == other) { - return 0; - } - // reject the null hyphothesis the two samples come from the - // same population (i.e. have the same median) if... - if (size1 + size2 > 30) { - // ...the z-stat is greater than 1.96 or less than -1.96 - // http://www.statisticslectures.com/topics/mannwhitneyu/ - zStat = getZ(u); - return abs(zStat) > 1.96 ? (zStat > 0 ? -1 : 1) : 0; - } - // ...the U value is less than or equal the critical U value - // http://www.geoib.com/mann-whitney-u-test.html - critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3]; - return u <= critical ? (u == u1 ? 1 : -1) : 0; - } - - /** - * Reset properties and abort if running. - * - * @memberOf Benchmark - * @returns {Object} The benchmark instance. - */ - function reset() { - var data, - event, - me = this, - index = 0, - changes = { 'length': 0 }, - queue = { 'length': 0 }; - - if (me.running && !calledBy.abort) { - // no worries, `reset()` is called within `abort()` - calledBy.reset = true; - me.abort(); - delete calledBy.reset; - } - else { - // a non-recursive solution to check if properties have changed - // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4 - data = { 'destination': me, 'source': extend({}, me.constructor.prototype, me.options) }; - do { - forOwn(data.source, function(value, key) { - var changed, - destination = data.destination, - currValue = destination[key]; - - if (value && typeof value == 'object') { - if (isClassOf(value, 'Array')) { - // check if an array value has changed to a non-array value - if (!isClassOf(currValue, 'Array')) { - changed = currValue = []; - } - // or has changed its length - if (currValue.length != value.length) { - changed = currValue = currValue.slice(0, value.length); - currValue.length = value.length; - } - } - // check if an object has changed to a non-object value - else if (!currValue || typeof currValue != 'object') { - changed = currValue = {}; - } - // register a changed object - if (changed) { - changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue }; - } - queue[queue.length++] = { 'destination': currValue, 'source': value }; - } - // register a changed primitive - else if (value !== currValue && !(value == null || isClassOf(value, 'Function'))) { - changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value }; - } - }); - } - while ((data = queue[index++])); - - // if changed emit the `reset` event and if it isn't cancelled reset the benchmark - if (changes.length && (me.emit(event = Event('reset')), !event.cancelled)) { - forEach(changes, function(data) { - data.destination[data.key] = data.value; - }); - } - } - return me; - } - - /** - * Displays relevant benchmark information when coerced to a string. - * - * @name toString - * @memberOf Benchmark - * @returns {String} A string representation of the benchmark instance. - */ - function toStringBench() { - var me = this, - error = me.error, - hz = me.hz, - id = me.id, - stats = me.stats, - size = stats.sample.length, - pm = support.java ? '+/-' : '\xb1', - result = me.name || (isNaN(id) ? id : ''); - - if (error) { - result += ': ' + join(error); - } else { - result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm + - stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)'; - } - return result; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Clocks the time taken to execute a test per cycle (secs). - * - * @private - * @param {Object} bench The benchmark instance. - * @returns {Number} The time taken. - */ - function clock() { - var applet, - options = Benchmark.options, - template = { 'begin': 's$=new n$', 'end': 'r$=(new n$-s$)/1e3', 'uid': uid }, - timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }]; - - // lazy define for hi-res timers - clock = function(clone) { - var deferred; - if (clone instanceof Deferred) { - deferred = clone; - clone = deferred.benchmark; - } - - var bench = clone._original, - fn = bench.fn, - fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '', - stringable = isStringable(fn); - - var source = { - 'setup': getSource(bench.setup, preprocess('m$.setup()')), - 'fn': getSource(fn, preprocess('m$.fn(' + fnArg + ')')), - 'fnArg': fnArg, - 'teardown': getSource(bench.teardown, preprocess('m$.teardown()')) - }; - - var count = bench.count = clone.count, - decompilable = support.decompilation || stringable, - id = bench.id, - isEmpty = !(source.fn || stringable), - name = bench.name || (typeof id == 'number' ? '' : id), - ns = timer.ns, - result = 0; - - // init `minTime` if needed - clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime); - - // repair nanosecond timer - // (some Chrome builds erase the `ns` variable after millions of executions) - if (applet) { - try { - ns.nanoTime(); - } catch(e) { - // use non-element to avoid issues with libs that augment them - ns = timer.ns = new applet.Packages.nano; - } - } - - // Compile in setup/teardown functions and the test loop. - // Create a new compiled test, instead of using the cached `bench.compiled`, - // to avoid potential engine optimizations enabled over the life of the test. - var compiled = bench.compiled = createFunction(preprocess('t$'), interpolate( - preprocess(deferred - ? 'var d$=this,#{fnArg}=d$,m$=d$.benchmark._original,f$=m$.fn,su$=m$.setup,td$=m$.teardown;' + - // when `deferred.cycles` is `0` then... - 'if(!d$.cycles){' + - // set `deferred.fn` - 'd$.fn=function(){var #{fnArg}=d$;if(typeof f$=="function"){try{#{fn}\n}catch(e$){f$(d$)}}else{#{fn}\n}};' + - // set `deferred.teardown` - 'd$.teardown=function(){d$.cycles=0;if(typeof td$=="function"){try{#{teardown}\n}catch(e$){td$()}}else{#{teardown}\n}};' + - // execute the benchmark's `setup` - 'if(typeof su$=="function"){try{#{setup}\n}catch(e$){su$()}}else{#{setup}\n};' + - // start timer - 't$.start(d$);' + - // execute `deferred.fn` and return a dummy object - '}d$.fn();return{}' - - : 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count,n$=t$.ns;#{setup}\n#{begin};' + - 'while(i$--){#{fn}\n}#{end};#{teardown}\nreturn{elapsed:r$,uid:"#{uid}"}'), - source - )); - - try { - if (isEmpty) { - // Firefox may remove dead code from Function#toString results - // http://bugzil.la/536085 - throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.'); - } - else if (!deferred) { - // pretest to determine if compiled code is exits early, usually by a - // rogue `return` statement, by checking for a return object with the uid - bench.count = 1; - compiled = (compiled.call(bench, timer) || {}).uid == uid && compiled; - bench.count = count; - } - } catch(e) { - compiled = null; - clone.error = e || new Error(String(e)); - bench.count = count; - } - // fallback when a test exits early or errors during pretest - if (decompilable && !compiled && !deferred && !isEmpty) { - compiled = createFunction(preprocess('t$'), interpolate( - preprocess( - (clone.error && !stringable - ? 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count' - : 'function f$(){#{fn}\n}var r$,s$,m$=this,i$=m$.count' - ) + - ',n$=t$.ns;#{setup}\n#{begin};m$.f$=f$;while(i$--){m$.f$()}#{end};' + - 'delete m$.f$;#{teardown}\nreturn{elapsed:r$}' - ), - source - )); - - try { - // pretest one more time to check for errors - bench.count = 1; - compiled.call(bench, timer); - bench.compiled = compiled; - bench.count = count; - delete clone.error; - } - catch(e) { - bench.count = count; - if (clone.error) { - compiled = null; - } else { - bench.compiled = compiled; - clone.error = e || new Error(String(e)); - } - } - } - // assign `compiled` to `clone` before calling in case a deferred benchmark - // immediately calls `deferred.resolve()` - clone.compiled = compiled; - // if no errors run the full test loop - if (!clone.error) { - result = compiled.call(deferred || bench, timer).elapsed; - } - return result; - }; - - /*------------------------------------------------------------------------*/ - - /** - * Gets the current timer's minimum resolution (secs). - */ - function getRes(unit) { - var measured, - begin, - count = 30, - divisor = 1e3, - ns = timer.ns, - sample = []; - - // get average smallest measurable time - while (count--) { - if (unit == 'us') { - divisor = 1e6; - if (ns.stop) { - ns.start(); - while (!(measured = ns.microseconds())) { } - } else if (ns[perfName]) { - divisor = 1e3; - measured = Function('n', 'var r,s=n.' + perfName + '();while(!(r=n.' + perfName + '()-s)){};return r')(ns); - } else { - begin = ns(); - while (!(measured = ns() - begin)) { } - } - } - else if (unit == 'ns') { - divisor = 1e9; - if (ns.nanoTime) { - begin = ns.nanoTime(); - while (!(measured = ns.nanoTime() - begin)) { } - } else { - begin = (begin = ns())[0] + (begin[1] / divisor); - while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) { } - divisor = 1; - } - } - else { - begin = new ns; - while (!(measured = new ns - begin)) { } - } - // check for broken timers (nanoTime may have issues) - // http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/ - if (measured > 0) { - sample.push(measured); - } else { - sample.push(Infinity); - break; - } - } - // convert to seconds - return getMean(sample) / divisor; - } - - /** - * Replaces all occurrences of `$` with a unique number and - * template tokens with content. - */ - function preprocess(code) { - return interpolate(code, template).replace(/\$/g, /\d+/.exec(uid)); - } - - /*------------------------------------------------------------------------*/ - - // detect nanosecond support from a Java applet - each(doc && doc.applets || [], function(element) { - return !(timer.ns = applet = 'nanoTime' in element && element); - }); - - // check type in case Safari returns an object instead of a number - try { - if (typeof timer.ns.nanoTime() == 'number') { - timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); - } - } catch(e) { } - - // detect Chrome's microsecond timer: - // enable benchmarking via the --enable-benchmarking command - // line switch in at least Chrome 7 to use chrome.Interval - try { - if ((timer.ns = new (window.chrome || window.chromium).Interval)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - } catch(e) { } - - // detect `performance.now` microsecond resolution timer - if ((timer.ns = perfName && perfObject)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - - // detect Node's nanosecond resolution timer available in Node >= 0.8 - if (processObject && typeof (timer.ns = processObject.hrtime) == 'function') { - timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); - } - - // detect Wade Simmons' Node microtime module - if (microtimeObject && typeof (timer.ns = microtimeObject.now) == 'function') { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - - // pick timer with highest resolution - timer = reduce(timers, function(timer, other) { - return other.res < timer.res ? other : timer; - }); - - // remove unused applet - if (timer.unit != 'ns' && applet) { - applet = destroyElement(applet); - } - // error if there are no working timers - if (timer.res == Infinity) { - throw new Error('Benchmark.js was unable to find a working timer.'); - } - // use API of chosen timer - if (timer.unit == 'ns') { - if (timer.ns.nanoTime) { - extend(template, { - 'begin': 's$=n$.nanoTime()', - 'end': 'r$=(n$.nanoTime()-s$)/1e9' - }); - } else { - extend(template, { - 'begin': 's$=n$()', - 'end': 'r$=n$(s$);r$=r$[0]+(r$[1]/1e9)' - }); - } - } - else if (timer.unit == 'us') { - if (timer.ns.stop) { - extend(template, { - 'begin': 's$=n$.start()', - 'end': 'r$=n$.microseconds()/1e6' - }); - } else if (perfName) { - extend(template, { - 'begin': 's$=n$.' + perfName + '()', - 'end': 'r$=(n$.' + perfName + '()-s$)/1e3' - }); - } else { - extend(template, { - 'begin': 's$=n$()', - 'end': 'r$=(n$()-s$)/1e6' - }); - } - } - - // define `timer` methods - timer.start = createFunction(preprocess('o$'), - preprocess('var n$=this.ns,#{begin};o$.elapsed=0;o$.timeStamp=s$')); - - timer.stop = createFunction(preprocess('o$'), - preprocess('var n$=this.ns,s$=o$.timeStamp,#{end};o$.elapsed=r$')); - - // resolve time span required to achieve a percent uncertainty of at most 1% - // http://spiff.rit.edu/classes/phys273/uncert/uncert.html - options.minTime || (options.minTime = max(timer.res / 2 / 0.01, 0.05)); - return clock.apply(null, arguments); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Computes stats on benchmark results. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} options The options object. - */ - function compute(bench, options) { - options || (options = {}); - - var async = options.async, - elapsed = 0, - initCount = bench.initCount, - minSamples = bench.minSamples, - queue = [], - sample = bench.stats.sample; - - /** - * Adds a clone to the queue. - */ - function enqueue() { - queue.push(bench.clone({ - '_original': bench, - 'events': { - 'abort': [update], - 'cycle': [update], - 'error': [update], - 'start': [update] - } - })); - } - - /** - * Updates the clone/original benchmarks to keep their data in sync. - */ - function update(event) { - var clone = this, - type = event.type; - - if (bench.running) { - if (type == 'start') { - // Note: `clone.minTime` prop is inited in `clock()` - clone.count = bench.initCount; - } - else { - if (type == 'error') { - bench.error = clone.error; - } - if (type == 'abort') { - bench.abort(); - bench.emit('cycle'); - } else { - event.currentTarget = event.target = bench; - bench.emit(event); - } - } - } else if (bench.aborted) { - // clear abort listeners to avoid triggering bench's abort/cycle again - clone.events.abort.length = 0; - clone.abort(); - } - } - - /** - * Determines if more clones should be queued or if cycling should stop. - */ - function evaluate(event) { - var critical, - df, - mean, - moe, - rme, - sd, - sem, - variance, - clone = event.target, - done = bench.aborted, - now = +new Date, - size = sample.push(clone.times.period), - maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime, - times = bench.times, - varOf = function(sum, x) { return sum + pow(x - mean, 2); }; - - // exit early for aborted or unclockable tests - if (done || clone.hz == Infinity) { - maxedOut = !(size = sample.length = queue.length = 0); - } - - if (!done) { - // sample mean (estimate of the population mean) - mean = getMean(sample); - // sample variance (estimate of the population variance) - variance = reduce(sample, varOf, 0) / (size - 1) || 0; - // sample standard deviation (estimate of the population standard deviation) - sd = sqrt(variance); - // standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean) - sem = sd / sqrt(size); - // degrees of freedom - df = size - 1; - // critical value - critical = tTable[Math.round(df) || 1] || tTable.infinity; - // margin of error - moe = sem * critical; - // relative margin of error - rme = (moe / mean) * 100 || 0; - - extend(bench.stats, { - 'deviation': sd, - 'mean': mean, - 'moe': moe, - 'rme': rme, - 'sem': sem, - 'variance': variance - }); - - // Abort the cycle loop when the minimum sample size has been collected - // and the elapsed time exceeds the maximum time allowed per benchmark. - // We don't count cycle delays toward the max time because delays may be - // increased by browsers that clamp timeouts for inactive tabs. - // https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs - if (maxedOut) { - // reset the `initCount` in case the benchmark is rerun - bench.initCount = initCount; - bench.running = false; - done = true; - times.elapsed = (now - times.timeStamp) / 1e3; - } - if (bench.hz != Infinity) { - bench.hz = 1 / mean; - times.cycle = mean * bench.count; - times.period = mean; - } - } - // if time permits, increase sample size to reduce the margin of error - if (queue.length < 2 && !maxedOut) { - enqueue(); - } - // abort the invoke cycle when done - event.aborted = done; - } - - // init queue and begin - enqueue(); - invoke(queue, { - 'name': 'run', - 'args': { 'async': async }, - 'queued': true, - 'onCycle': evaluate, - 'onComplete': function() { bench.emit('complete'); } - }); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Cycles a benchmark until a run `count` can be established. - * - * @private - * @param {Object} clone The cloned benchmark instance. - * @param {Object} options The options object. - */ - function cycle(clone, options) { - options || (options = {}); - - var deferred; - if (clone instanceof Deferred) { - deferred = clone; - clone = clone.benchmark; - } - - var clocked, - cycles, - divisor, - event, - minTime, - period, - async = options.async, - bench = clone._original, - count = clone.count, - times = clone.times; - - // continue, if not aborted between cycles - if (clone.running) { - // `minTime` is set to `Benchmark.options.minTime` in `clock()` - cycles = ++clone.cycles; - clocked = deferred ? deferred.elapsed : clock(clone); - minTime = clone.minTime; - - if (cycles > bench.cycles) { - bench.cycles = cycles; - } - if (clone.error) { - event = Event('error'); - event.message = clone.error; - clone.emit(event); - if (!event.cancelled) { - clone.abort(); - } - } - } - - // continue, if not errored - if (clone.running) { - // time taken to complete last test cycle - bench.times.cycle = times.cycle = clocked; - // seconds per operation - period = bench.times.period = times.period = clocked / count; - // ops per second - bench.hz = clone.hz = 1 / period; - // avoid working our way up to this next time - bench.initCount = clone.initCount = count; - // do we need to do another cycle? - clone.running = clocked < minTime; - - if (clone.running) { - // tests may clock at `0` when `initCount` is a small number, - // to avoid that we set its count to something a bit higher - if (!clocked && (divisor = divisors[clone.cycles]) != null) { - count = floor(4e6 / divisor); - } - // calculate how many more iterations it will take to achive the `minTime` - if (count <= clone.count) { - count += Math.ceil((minTime - clocked) / period); - } - clone.running = count != Infinity; - } - } - // should we exit early? - event = Event('cycle'); - clone.emit(event); - if (event.aborted) { - clone.abort(); - } - // figure out what to do next - if (clone.running) { - // start a new cycle - clone.count = count; - if (deferred) { - clone.compiled.call(deferred, timer); - } else if (async) { - delay(clone, function() { cycle(clone, options); }); - } else { - cycle(clone); - } - } - else { - // fix TraceMonkey bug associated with clock fallbacks - // http://bugzil.la/509069 - if (support.browser) { - runScript(uid + '=1;delete ' + uid); - } - // done - clone.emit('complete'); - } - } - - /*--------------------------------------------------------------------------*/ - - /** - * Runs the benchmark. - * - * @memberOf Benchmark - * @param {Object} [options={}] Options object. - * @returns {Object} The benchmark instance. - * @example - * - * // basic usage - * bench.run(); - * - * // or with options - * bench.run({ 'async': true }); - */ - function run(options) { - var me = this, - event = Event('start'); - - // set `running` to `false` so `reset()` won't call `abort()` - me.running = false; - me.reset(); - me.running = true; - - me.count = me.initCount; - me.times.timeStamp = +new Date; - me.emit(event); - - if (!event.cancelled) { - options = { 'async': ((options = options && options.async) == null ? me.async : options) && support.timeout }; - - // for clones created within `compute()` - if (me._original) { - if (me.defer) { - Deferred(me); - } else { - cycle(me, options); - } - } - // for original benchmarks - else { - compute(me, options); - } - } - return me; - } - - /*--------------------------------------------------------------------------*/ - - // Firefox 1 erroneously defines variable and argument names of functions on - // the function itself as non-configurable properties with `undefined` values. - // The bugginess continues as the `Benchmark` constructor has an argument - // named `options` and Firefox 1 will not assign a value to `Benchmark.options`, - // making it non-writable in the process, unless it is the first property - // assigned by for-in loop of `extend()`. - extend(Benchmark, { - - /** - * The default options copied by benchmark instances. - * - * @static - * @memberOf Benchmark - * @type Object - */ - 'options': { - - /** - * A flag to indicate that benchmark cycles will execute asynchronously - * by default. - * - * @memberOf Benchmark.options - * @type Boolean - */ - 'async': false, - - /** - * A flag to indicate that the benchmark clock is deferred. - * - * @memberOf Benchmark.options - * @type Boolean - */ - 'defer': false, - - /** - * The delay between test cycles (secs). - * @memberOf Benchmark.options - * @type Number - */ - 'delay': 0.005, - - /** - * Displayed by Benchmark#toString when a `name` is not available - * (auto-generated if absent). - * - * @memberOf Benchmark.options - * @type String - */ - 'id': undefined, - - /** - * The default number of times to execute a test on a benchmark's first cycle. - * - * @memberOf Benchmark.options - * @type Number - */ - 'initCount': 1, - - /** - * The maximum time a benchmark is allowed to run before finishing (secs). - * - * Note: Cycle delays aren't counted toward the maximum time. - * - * @memberOf Benchmark.options - * @type Number - */ - 'maxTime': 5, - - /** - * The minimum sample size required to perform statistical analysis. - * - * @memberOf Benchmark.options - * @type Number - */ - 'minSamples': 5, - - /** - * The time needed to reduce the percent uncertainty of measurement to 1% (secs). - * - * @memberOf Benchmark.options - * @type Number - */ - 'minTime': 0, - - /** - * The name of the benchmark. - * - * @memberOf Benchmark.options - * @type String - */ - 'name': undefined, - - /** - * An event listener called when the benchmark is aborted. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onAbort': undefined, - - /** - * An event listener called when the benchmark completes running. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onComplete': undefined, - - /** - * An event listener called after each run cycle. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onCycle': undefined, - - /** - * An event listener called when a test errors. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onError': undefined, - - /** - * An event listener called when the benchmark is reset. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onReset': undefined, - - /** - * An event listener called when the benchmark starts running. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onStart': undefined - }, - - /** - * Platform object with properties describing things like browser name, - * version, and operating system. - * - * @static - * @memberOf Benchmark - * @type Object - */ - 'platform': req('platform') || window.platform || { - - /** - * The platform description. - * - * @memberOf Benchmark.platform - * @type String - */ - 'description': window.navigator && navigator.userAgent || null, - - /** - * The name of the browser layout engine. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'layout': null, - - /** - * The name of the product hosting the browser. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'product': null, - - /** - * The name of the browser/environment. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'name': null, - - /** - * The name of the product's manufacturer. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'manufacturer': null, - - /** - * The name of the operating system. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'os': null, - - /** - * The alpha/beta release indicator. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'prerelease': null, - - /** - * The browser/environment version. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'version': null, - - /** - * Return platform description when the platform object is coerced to a string. - * - * @memberOf Benchmark.platform - * @type Function - * @returns {String} The platform description. - */ - 'toString': function() { - return this.description || ''; - } - }, - - /** - * The semantic version number. - * - * @static - * @memberOf Benchmark - * @type String - */ - 'version': '1.0.0', - - // an object of environment/feature detection flags - 'support': support, - - // clone objects - 'deepClone': deepClone, - - // iteration utility - 'each': each, - - // augment objects - 'extend': extend, - - // generic Array#filter - 'filter': filter, - - // generic Array#forEach - 'forEach': forEach, - - // generic own property iteration utility - 'forOwn': forOwn, - - // converts a number to a comma-separated string - 'formatNumber': formatNumber, - - // generic Object#hasOwnProperty - // (trigger hasKey's lazy define before assigning it to Benchmark) - 'hasKey': (hasKey(Benchmark, ''), hasKey), - - // generic Array#indexOf - 'indexOf': indexOf, - - // template utility - 'interpolate': interpolate, - - // invokes a method on each item in an array - 'invoke': invoke, - - // generic Array#join for arrays and objects - 'join': join, - - // generic Array#map - 'map': map, - - // retrieves a property value from each item in an array - 'pluck': pluck, - - // generic Array#reduce - 'reduce': reduce - }); - - /*--------------------------------------------------------------------------*/ - - extend(Benchmark.prototype, { - - /** - * The number of times a test was executed. - * - * @memberOf Benchmark - * @type Number - */ - 'count': 0, - - /** - * The number of cycles performed while benchmarking. - * - * @memberOf Benchmark - * @type Number - */ - 'cycles': 0, - - /** - * The number of executions per second. - * - * @memberOf Benchmark - * @type Number - */ - 'hz': 0, - - /** - * The compiled test function. - * - * @memberOf Benchmark - * @type Function|String - */ - 'compiled': undefined, - - /** - * The error object if the test failed. - * - * @memberOf Benchmark - * @type Object - */ - 'error': undefined, - - /** - * The test to benchmark. - * - * @memberOf Benchmark - * @type Function|String - */ - 'fn': undefined, - - /** - * A flag to indicate if the benchmark is aborted. - * - * @memberOf Benchmark - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the benchmark is running. - * - * @memberOf Benchmark - * @type Boolean - */ - 'running': false, - - /** - * Compiled into the test and executed immediately **before** the test loop. - * - * @memberOf Benchmark - * @type Function|String - * @example - * - * // basic usage - * var bench = Benchmark({ - * 'setup': function() { - * var c = this.count, - * element = document.getElementById('container'); - * while (c--) { - * element.appendChild(document.createElement('div')); - * } - * }, - * 'fn': function() { - * element.removeChild(element.lastChild); - * } - * }); - * - * // compiles to something like: - * var c = this.count, - * element = document.getElementById('container'); - * while (c--) { - * element.appendChild(document.createElement('div')); - * } - * var start = new Date; - * while (count--) { - * element.removeChild(element.lastChild); - * } - * var end = new Date - start; - * - * // or using strings - * var bench = Benchmark({ - * 'setup': '\ - * var a = 0;\n\ - * (function() {\n\ - * (function() {\n\ - * (function() {', - * 'fn': 'a += 1;', - * 'teardown': '\ - * }())\n\ - * }())\n\ - * }())' - * }); - * - * // compiles to something like: - * var a = 0; - * (function() { - * (function() { - * (function() { - * var start = new Date; - * while (count--) { - * a += 1; - * } - * var end = new Date - start; - * }()) - * }()) - * }()) - */ - 'setup': noop, - - /** - * Compiled into the test and executed immediately **after** the test loop. - * - * @memberOf Benchmark - * @type Function|String - */ - 'teardown': noop, - - /** - * An object of stats including mean, margin or error, and standard deviation. - * - * @memberOf Benchmark - * @type Object - */ - 'stats': { - - /** - * The margin of error. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'moe': 0, - - /** - * The relative margin of error (expressed as a percentage of the mean). - * - * @memberOf Benchmark#stats - * @type Number - */ - 'rme': 0, - - /** - * The standard error of the mean. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'sem': 0, - - /** - * The sample standard deviation. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'deviation': 0, - - /** - * The sample arithmetic mean. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'mean': 0, - - /** - * The array of sampled periods. - * - * @memberOf Benchmark#stats - * @type Array - */ - 'sample': [], - - /** - * The sample variance. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'variance': 0 - }, - - /** - * An object of timing data including cycle, elapsed, period, start, and stop. - * - * @memberOf Benchmark - * @type Object - */ - 'times': { - - /** - * The time taken to complete the last cycle (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'cycle': 0, - - /** - * The time taken to complete the benchmark (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'elapsed': 0, - - /** - * The time taken to execute the test once (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'period': 0, - - /** - * A timestamp of when the benchmark started (ms). - * - * @memberOf Benchmark#times - * @type Number - */ - 'timeStamp': 0 - }, - - // aborts benchmark (does not record times) - 'abort': abort, - - // creates a new benchmark using the same test and options - 'clone': clone, - - // compares benchmark's hertz with another - 'compare': compare, - - // executes listeners - 'emit': emit, - - // get listeners - 'listeners': listeners, - - // unregister listeners - 'off': off, - - // register listeners - 'on': on, - - // reset benchmark properties - 'reset': reset, - - // runs the benchmark - 'run': run, - - // pretty print benchmark info - 'toString': toStringBench - }); - - /*--------------------------------------------------------------------------*/ - - extend(Deferred.prototype, { - - /** - * The deferred benchmark instance. - * - * @memberOf Benchmark.Deferred - * @type Object - */ - 'benchmark': null, - - /** - * The number of deferred cycles performed while benchmarking. - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'cycles': 0, - - /** - * The time taken to complete the deferred benchmark (secs). - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'elapsed': 0, - - /** - * A timestamp of when the deferred benchmark started (ms). - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'timeStamp': 0, - - // cycles/completes the deferred benchmark - 'resolve': resolve - }); - - /*--------------------------------------------------------------------------*/ - - extend(Event.prototype, { - - /** - * A flag to indicate if the emitters listener iteration is aborted. - * - * @memberOf Benchmark.Event - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the default action is cancelled. - * - * @memberOf Benchmark.Event - * @type Boolean - */ - 'cancelled': false, - - /** - * The object whose listeners are currently being processed. - * - * @memberOf Benchmark.Event - * @type Object - */ - 'currentTarget': undefined, - - /** - * The return value of the last executed listener. - * - * @memberOf Benchmark.Event - * @type Mixed - */ - 'result': undefined, - - /** - * The object to which the event was originally emitted. - * - * @memberOf Benchmark.Event - * @type Object - */ - 'target': undefined, - - /** - * A timestamp of when the event was created (ms). - * - * @memberOf Benchmark.Event - * @type Number - */ - 'timeStamp': 0, - - /** - * The event type. - * - * @memberOf Benchmark.Event - * @type String - */ - 'type': '' - }); - - /*--------------------------------------------------------------------------*/ - - /** - * The default options copied by suite instances. - * - * @static - * @memberOf Benchmark.Suite - * @type Object - */ - Suite.options = { - - /** - * The name of the suite. - * - * @memberOf Benchmark.Suite.options - * @type String - */ - 'name': undefined - }; - - /*--------------------------------------------------------------------------*/ - - extend(Suite.prototype, { - - /** - * The number of benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @type Number - */ - 'length': 0, - - /** - * A flag to indicate if the suite is aborted. - * - * @memberOf Benchmark.Suite - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the suite is running. - * - * @memberOf Benchmark.Suite - * @type Boolean - */ - 'running': false, - - /** - * An `Array#forEach` like method. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @returns {Object} The suite iterated over. - */ - 'forEach': methodize(forEach), - - /** - * An `Array#indexOf` like method. - * - * @memberOf Benchmark.Suite - * @param {Mixed} value The value to search for. - * @returns {Number} The index of the matched value or `-1`. - */ - 'indexOf': methodize(indexOf), - - /** - * Invokes a method on all benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @param {String|Object} name The name of the method to invoke OR options object. - * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. - * @returns {Array} A new array of values returned from each method invoked. - */ - 'invoke': methodize(invoke), - - /** - * Converts the suite of benchmarks to a string. - * - * @memberOf Benchmark.Suite - * @param {String} [separator=','] A string to separate each element of the array. - * @returns {String} The string. - */ - 'join': [].join, - - /** - * An `Array#map` like method. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @returns {Array} A new array of values returned by the callback. - */ - 'map': methodize(map), - - /** - * Retrieves the value of a specified property from all benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @param {String} property The property to pluck. - * @returns {Array} A new array of property values. - */ - 'pluck': methodize(pluck), - - /** - * Removes the last benchmark from the suite and returns it. - * - * @memberOf Benchmark.Suite - * @returns {Mixed} The removed benchmark. - */ - 'pop': [].pop, - - /** - * Appends benchmarks to the suite. - * - * @memberOf Benchmark.Suite - * @returns {Number} The suite's new length. - */ - 'push': [].push, - - /** - * Sorts the benchmarks of the suite. - * - * @memberOf Benchmark.Suite - * @param {Function} [compareFn=null] A function that defines the sort order. - * @returns {Object} The sorted suite. - */ - 'sort': [].sort, - - /** - * An `Array#reduce` like method. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @param {Mixed} accumulator Initial value of the accumulator. - * @returns {Mixed} The accumulator. - */ - 'reduce': methodize(reduce), - - // aborts all benchmarks in the suite - 'abort': abortSuite, - - // adds a benchmark to the suite - 'add': add, - - // creates a new suite with cloned benchmarks - 'clone': cloneSuite, - - // executes listeners of a specified type - 'emit': emit, - - // creates a new suite of filtered benchmarks - 'filter': filterSuite, - - // get listeners - 'listeners': listeners, - - // unregister listeners - 'off': off, - - // register listeners - 'on': on, - - // resets all benchmarks in the suite - 'reset': resetSuite, - - // runs all benchmarks in the suite - 'run': runSuite, - - // array methods - 'concat': concat, - - 'reverse': reverse, - - 'shift': shift, - - 'slice': slice, - - 'splice': splice, - - 'unshift': unshift - }); - - /*--------------------------------------------------------------------------*/ - - // expose Deferred, Event and Suite - extend(Benchmark, { - 'Deferred': Deferred, - 'Event': Event, - 'Suite': Suite - }); - - // expose Benchmark - // some AMD build optimizers, like r.js, check for specific condition patterns like the following: - if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { - // define as an anonymous module so, through path mapping, it can be aliased - define(function() { - return Benchmark; - }); - } - // check for `exports` after `define` in case a build optimizer adds an `exports` object - else if (freeExports) { - // in Node.js or RingoJS v0.8.0+ - if (typeof module == 'object' && module && module.exports == freeExports) { - (module.exports = Benchmark).Benchmark = Benchmark; - } - // in Narwhal or RingoJS v0.7.0- - else { - freeExports.Benchmark = Benchmark; - } - } - // in a browser or Rhino - else { - // use square bracket notation so Closure Compiler won't munge `Benchmark` - // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export - window['Benchmark'] = Benchmark; - } - - // trigger clock's lazy define early to avoid a security error - if (support.air) { - clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } }); - } -}(this)); \ No newline at end of file diff --git a/library/cal.js b/library/cal.js index dbe3a06..3bcb76e 100644 --- a/library/cal.js +++ b/library/cal.js @@ -5,11 +5,9 @@ //Global Composite Operation //Linear Gradient //Radial Gradient -//Bezier Curve -//Circle -//Touch support "use strict"; + var CAL = { name: "Canvas Abstraction Layer", version: "1.0", @@ -18,27 +16,34 @@ var CAL = { }; CAL.Math = { - clamb: function (value, min, max) { - return (value > min) ? ((value < max) ? value : max) : min; + clamb: function clamb(value, min, max) { + "use strict"; + + return value > min ? value < max ? value : max : min; }, - randomInt: function (min, max) { - return Math.round(CAL.Math.random(min, max)); + randomInt: function randomInt(min, max) { + "use strict"; + + return Math.floor(CAL.Math.random(min, max + 1)); }, - random: function (min, max) { - min = min || 0; + random: function random(min, max) { + "use strict"; + + min = min === undefined ? 0 : min; max = max === undefined ? 1 : max; - return Math.random()*(max - min) + min; + return Math.random() * (max - min) + min; }, - sign: function (value) { - return (value > 0) ? 1 : ((value < 0) ? -1 : 0); + sign: function sign(value) { + "use strict"; + + return value > 0 ? 1 : value < 0 ? -1 : 0; }, - lineCollision: function (v1, v2, v3, v4) { + lineCollision: function lineCollision(v1, v2, v3, v4) { + "use strict"; + //bron: http://mathworld.wolfram.com/Line-LineIntersection.html - var intersection = new CAL.Vector( - ((v1.x*v2.y-v1.y*v2.x)*(v3.x-v4.x)-(v1.x-v2.x)*(v3.x*v4.y-v3.y*v4.x)) / ((v1.x-v2.x)*(v3.y-v4.y)-(v1.y-v2.y)*(v3.x-v4.x)), - ((v1.x*v2.y-v1.y*v2.x)*(v3.y-v4.y)-(v1.y-v2.y)*(v3.x*v4.y-v3.y*v4.x)) / ((v1.x-v2.x)*(v3.y-v4.y)-(v1.y-v2.y)*(v3.x-v4.x)) - ); + var intersection = new CAL.Vector(((v1.x * v2.y - v1.y * v2.x) * (v3.x - v4.x) - (v1.x - v2.x) * (v3.x * v4.y - v3.y * v4.x)) / ((v1.x - v2.x) * (v3.y - v4.y) - (v1.y - v2.y) * (v3.x - v4.x)), ((v1.x * v2.y - v1.y * v2.x) * (v3.y - v4.y) - (v1.y - v2.y) * (v3.x * v4.y - v3.y * v4.x)) / ((v1.x - v2.x) * (v3.y - v4.y) - (v1.y - v2.y) * (v3.x - v4.x))); var line1 = v1.subtract(v2).length(); var line2 = v3.subtract(v4).length(); @@ -48,2282 +53,2696 @@ CAL.Math = { var c = line2 >= v3.subtract(intersection).length(); var d = line2 >= v4.subtract(intersection).length(); - return (a && b && c && d) ? intersection : false; + return a && b && c && d ? intersection : false; } }; CAL.Easings = { - bounceEaseOut: function (dt, b, c, d) { - if ((dt /= d) < (1 / 2.75)) { + bounceEaseOut: function bounceEaseOut(dt, b, c, d) { + "use strict"; + + if ((dt /= d) < 1 / 2.75) { return c * (7.5625 * dt * dt) + b; - } - else if (dt < (2 / 2.75)) { - return c * (7.5625 * (dt -= (1.5 / 2.75)) * dt + 0.75) + b; - } - else if (dt < (2.5 / 2.75)) { - return c * (7.5625 * (dt -= (2.25 / 2.75)) * dt + 0.9375) + b; - } - else { - return c * (7.5625 * (dt -= (2.625 / 2.75)) * dt + 0.984375) + b; + } else if (dt < 2 / 2.75) { + return c * (7.5625 * (dt -= 1.5 / 2.75) * dt + 0.75) + b; + } else if (dt < 2.5 / 2.75) { + return c * (7.5625 * (dt -= 2.25 / 2.75) * dt + 0.9375) + b; + } else { + return c * (7.5625 * (dt -= 2.625 / 2.75) * dt + 0.984375) + b; } }, - easeIn: function (dt, b, c, d) { + easeIn: function easeIn(dt, b, c, d) { + "use strict"; + return c * (dt /= d) * dt + b; }, - easeOut: function (dt, b, c, d) { + easeOut: function easeOut(dt, b, c, d) { + "use strict"; + return -c * (dt /= d) * (dt - 2) + b; }, - easeInOut: function (dt, b, c, d) { + easeInOut: function easeInOut(dt, b, c, d) { + "use strict"; + if ((dt /= d / 2) < 1) { return c / 2 * dt * dt + b; } - return -c / 2 * ((--dt) * (dt - 2) - 1) + b; + return -c / 2 * (--dt * (dt - 2) - 1) + b; }, - strongEaseIn: function (dt, b, c, d) { + strongEaseIn: function strongEaseIn(dt, b, c, d) { + "use strict"; + return c * (dt /= d) * dt * dt * dt * dt + b; }, - strongEaseOut: function (dt, b, c, d) { - return c * (( dt = dt / d - 1) * dt * dt * dt * dt + 1) + b; + strongEaseOut: function strongEaseOut(dt, b, c, d) { + "use strict"; + + return c * ((dt = dt / d - 1) * dt * dt * dt * dt + 1) + b; }, - strongEaseInOut: function (dt, b, c, d) { + strongEaseInOut: function strongEaseInOut(dt, b, c, d) { + "use strict"; + if ((dt /= d / 2) < 1) { return c / 2 * dt * dt * dt * dt * dt + b; } return c / 2 * ((dt -= 2) * dt * dt * dt * dt + 2) + b; }, - linear: function (dt, b, c, d) { + linear: function linear(dt, b, c, d) { + "use strict"; + return c * dt / d + b; } }; - -//this doesn't work, everything is an instance of Object in JavaScript /*Object.prototype.clone = function () { + 'use strict'; + var object = {}; for (var i in this) { - var element = this[i]; + if (this[i] && this.hasOwnProperty(i)) { + var element = this[i]; - object[i] = element.clone ? element.clone() : element; + if (element.hasOwnProperty('clone')) { + console.log(element); + } + + object[i] = element.hasOwnProperty('clone') ? element.clone() : element; + } } return object; }; -Object.prototype.foreach = function (callback) { - for (var i in this) { - var element = this[i]; - callback(element, i); +String.prototype.clone = Boolean.prototype.clone = Number.prototype.clone = Function.prototype.clone = null; + +//doesn't clone it actualy +Uint16Array.prototype.clone = function () { + 'use strict'; + + var array = new Uint16Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; } + + return array; +}; +Uint32Array.prototype.clone = function () { + 'use strict'; + + var array = new Uint32Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; +}; +Uint8Array.prototype.clone = function () { + 'use strict'; + + var array = new Uint8Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; +}; +Uint8ClampedArray.prototype.clone = function () { + 'use strict'; + + var array = new Uint8ClampedArray(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; +}; +Int16Array.prototype.clone = function () { + 'use strict'; + + var array = new Int16Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; +}; +Int32Array.prototype.clone = function () { + 'use strict'; + + var array = new Int32Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; +}; +Int8Array.prototype.clone = function () { + 'use strict'; + + var array = new Int8Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; +}; +Float32Array.prototype.clone = function () { + 'use strict'; + + var array = new Float32Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; +}; +Float64Array.prototype.clone = function () { + 'use strict'; + + var array = new Float64Array(this.length); + for (var i = 0; i < this.length; i ++) { + array[i] = this[i]; + } + + return array; };*/ - -Array.prototype.foreach = function (callback, scope) { - for (var i = 0; i < this.length; i ++) { - var element = this[i]; - - if ((scope !== undefined) ? callback.call(scope, element, i) : callback(element, i)) { - break; - } - } -}; -Array.prototype.foreachReverse = function (callback, scope) { - for (var i = this.length-1; i >= 0; i --) { - var element = this[i]; - - if ((scope !== undefined) ? callback.call(scope, element, i) : callback(element, i)) { - break; - } - } -}; Array.prototype.max = function () { + "use strict"; + var max = -Infinity; - this.foreach(function (element) { + for (var i = 0; i < this.length; i++) { + var element = this[i]; + if (element > max) { max = element; } - }); + }; return max; }; Array.prototype.min = function () { + "use strict"; + var min = Infinity; - this.foreach(function (element) { + for (var i = 0; i < this.length; i++) { + var element = this[i]; + if (element < min) { min = element; } - }); + }; return min; }; Array.prototype.clone = function () { + "use strict"; + var array = []; - this.foreach(function (element) { - array.push((element.clone !== undefined) ? element.clone() : element); - }); + for (var i = 0; i < this.length; i++) { + var element = this[i]; + + array.push(element.clone !== undefined ? element.clone() : element); + }; return array; }; -Array.prototype.remove = function () { - for (var i = 0; i < arguments.length; i ++) { - var element = arguments[i]; - var index = this.indexOf(element); - if (index !== -1) { - this.splice(index, 1); - } +Array.prototype.remove = function (element) { + "use strict"; + + var index = this.indexOf(element); + if (index !== -1) { + this.splice(index, 1); } + + return index; }; var requestAnimFrame = (function () { + "use strict"; + return requestAnimationFrame || webkitRequestAnimationFrame || mozRequestAnimationFrame || function (callback) { - setTimeout(callback, 1000/60); + setTimeout(callback, 1000 / 60); }; })(); +"use strict"; -CAL.Vector = function (x, y) { - this.x = x || 0; - this.y = y || 0; -}; -CAL.Vector.prototype.add = function (vector) { - var x = this.x + vector.x; - var y = this.y + vector.y; +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; }; })(); - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.subtract = function (vector) { - var x = this.x - vector.x; - var y = this.y - vector.y; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.scale = function (scalar) { - var x = this.x * scalar; - var y = this.y * scalar; +CAL.Vector = (function () { + var _class = function _class(x, y) { + _classCallCheck(this, _class); - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.rotate = function (angle) { - var cos = Math.cos(angle); - var sin = Math.sin(angle); + this.x = x || 0; + this.y = y || 0; + }; - var x = cos*this.x - sin*this.y; - var y = sin*this.x + cos*this.y; + _createClass(_class, [{ + key: "identity", + value: function identity(x, y) { + this.x = 0; + this.y = 0; - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.multiply = function (vector) { - var x = this.x * vector.x; - var y = this.y * vector.y; + return this; + } + }, { + key: "set", + value: function set(x, y) { + this.x = x; + this.y = y; - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.length = function () { - return Math.sqrt(this.x*this.x + this.y*this.y); -}; -CAL.Vector.prototype.normal = function () { - return new CAL.Vector(this.y, -this.x); -}; -CAL.Vector.prototype.normalize = function () { - var length = this.length(); + return this; + } + }, { + key: "copy", + value: function copy(vector) { + this.x = vector.x; + this.y = vector.y; - var x = this.x/length; - var y = this.y/length; + return this; + } + }, { + key: "add", + value: function add(vector) { + var x = this.x + vector.x; + var y = this.y + vector.y; - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.angle = function () { - return Math.atan2(this.y, this.x); -}; -CAL.Vector.prototype.dot = function (vector) { - return this.x * vector.x + this.y * vector.y; -}; -CAL.Vector.prototype.cross = function (vector) { - return this.x * vector.y - this.y * vector.x; -}; -CAL.Vector.prototype.round = function () { - var x = Math.round(this.x); - var y = Math.round(this.y); + return new CAL.Vector(x, y); + } + }, { + key: "subtract", + value: function subtract(vector) { + var x = this.x - vector.x; + var y = this.y - vector.y; - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.applyMatrix = function (matrix) { - var m = matrix.matrix; + return new CAL.Vector(x, y); + } + }, { + key: "scale", + value: function scale(scalar) { + var x = this.x * scalar; + var y = this.y * scalar; - var x = m[0]*this.x + m[1]*this.y + m[2]; - var y = m[3]*this.x + m[4]*this.y + m[5]; + return new CAL.Vector(x, y); + } + }, { + key: "rotate", + value: function rotate(angle) { + var cos = Math.cos(angle); + var sin = Math.sin(angle); - return new CAL.Vector(x, y); -}; -CAL.Vector.prototype.clone = function () { - return new CAL.Vector(this.x, this.y); -}; -CAL.Vector.prototype.draw = function (context, x, y) { - var end = new CAL.Vector(this.x + x, this.y + y); - var arrowOrigin = new CAL.Vector(x, y).add(this.subtract(this.normalize().scale(10))); - var left = this.normal().normalize().scale(10).add(arrowOrigin); - var right = this.normal().normalize().scale(-10).add(arrowOrigin); + var x = cos * this.x - sin * this.y; + var y = sin * this.x + cos * this.y; - context.beginPath(); - context.moveTo(x, y); - context.lineTo(end.x, end.y); - context.moveTo(left.x, left.y); - context.lineTo(end.x, end.y); - context.lineTo(right.x, right.y); + return new CAL.Vector(x, y); + } + }, { + key: "multiply", + value: function multiply(vector) { + var x = this.x * vector.x; + var y = this.y * vector.y; - context.stroke(); -}; + return new CAL.Vector(x, y); + } + }, { + key: "setLength", + value: function setLength(length) { + return new CAL.Vector(this.x, this.y).normalize().scale(length); + } + }, { + key: "length", + value: function length() { + return Math.sqrt(this.x * this.x + this.y * this.y); + } + }, { + key: "normal", + value: function normal() { + return new CAL.Vector(this.y, -this.x); + } + }, { + key: "normalize", + value: function normalize() { + var length = this.length(); -CAL.Matrix = function (options) { - options = options || {}; + var x = this.x / length; + var y = this.y / length; - if (options.matrix !== undefined && options.sx !== undefined && options.sy !== undefined && options.rotation !== undefined && options.x !== undefined && options.y !== undefined) { - this.matrix = options.matrix; - this._sx = options.sx; - this._sy = options.sy; - this._rotation = options.rotation; - this._x = options.x; - this._y = options.y; - } - else if (options instanceof Array || options.matrix) { - this.matrix = options.matrix || options; + return new CAL.Vector(x, y); + } + }, { + key: "angle", + value: function angle() { + return Math.atan2(this.y, this.x); + } + }, { + key: "dot", + value: function dot(vector) { + return this.x * vector.x + this.y * vector.y; + } + }, { + key: "cross", + value: function cross(vector) { + return this.x * vector.y - this.y * vector.x; + } + }, { + key: "round", + value: function round() { + var x = Math.round(this.x); + var y = Math.round(this.y); - this._sx = CAL.Math.sign(this.matrix[0])*Math.sqrt(Math.pow(this.matrix[0], 2) + Math.pow(this.matrix[1], 2)); - this._sy = CAL.Math.sign(this.matrix[4])*Math.sqrt(Math.pow(this.matrix[3], 2) + Math.pow(this.matrix[4], 2)); - this._rotation = Math.atan2(-this.matrix[1], this.matrix[0]); - this._x = this.matrix[2]; - this._y = this.matrix[5]; - //source: http://math.stackexchange.com/questions/13150/extracting-rotation-scale-values-from-2d-transformation-matrix - //BUG doesn't convert right when both sx and sy aren't 1 - } - else { - this._sx = options.sx !== undefined ? options.sx : 1; - this._sy = options.sy !== undefined ? options.sy : 1; - this._x = options.x || 0; - this._y = options.y || 0; + return new CAL.Vector(x, y); + } + }, { + key: "applyMatrix", + value: function applyMatrix(matrix) { + var m = matrix.matrix; - if (options.rotation === undefined) { + var x = m[0] * this.x + m[1] * this.y + m[2]; + var y = m[3] * this.x + m[4] * this.y + m[5]; + + return new CAL.Vector(x, y); + } + }, { + key: "distanceTo", + value: function distanceTo(vector) { + return this.subtract(vector).length(); + } + }, { + key: "clone", + value: function clone() { + return new CAL.Vector(this.x, this.y); + } + }, { + key: "equals", + value: function equals(vector) { + return this.x === vector.x && this.y === vector.y; + } + }, { + key: "draw", + value: function draw(context, x, y) { + var end = new CAL.Vector(this.x + x, this.y + y); + var arrowOrigin = new CAL.Vector(x, y).add(this.subtract(this.normalize().scale(10))); + var left = this.normal().normalize().scale(10).add(arrowOrigin); + var right = this.normal().normalize().scale(-10).add(arrowOrigin); + + context.beginPath(); + context.moveTo(x, y); + context.lineTo(end.x, end.y); + context.moveTo(left.x, left.y); + context.lineTo(end.x, end.y); + context.lineTo(right.x, right.y); + + context.stroke(); + } + }]); + + return _class; +})(); +"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"); } } + +CAL.Matrix = (function () { + var _class = function _class(options) { + _classCallCheck(this, _class); + + if (options === undefined) { + this.identity(); + } else if (options instanceof Array) { + this.matrix = options; + } else { + if (options.matrix !== undefined) { + this.matrix = options.matrix; + } + if (options.x !== undefined) { + this._x = options.x; + } + if (options.y !== undefined) { + this._y = options.y; + } + if (options.sx !== undefined) { + this._sx = options.sx; + } + if (options.sy !== undefined) { + this._sy = options.sy; + } + if (options.rotation !== undefined) { + this._rotation = options.rotation; + } + + if (this._matrix === undefined) { + this._x = this._x || 0; + this._y = this._y || 0; + this._sx = this._sx !== undefined ? this._sx : 1; + this._sy = this._sy !== undefined ? this._sy : 1; + this._rotation = this._rotation || 0; + } + } + }; + + _createClass(_class, [{ + key: "identity", + value: function identity() { + this._matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1]; + + this._x = 0; + this._y = 0; + this._sx = 1; + this._sy = 1; this._rotation = 0; - this.matrix = [ - this._sx, 0, this._x, - 0, this._sy, this._y - ]; + return this; } - else { - this._rotation = options.rotation; - this.updateMatrix(); + }, { + key: "_updateMatrix", + value: function _updateMatrix() { + var sin = Math.sin(this._rotation); + var cos = Math.cos(this._rotation); + + this._matrix = [this._sx * cos, this._sy * -sin, this._x, this._sx * sin, this._sy * cos, this._y, 0, 0, 1]; + + this._x = this._matrix[2]; + this._y = this._matrix[5]; } - } -}; -CAL.Matrix.prototype = { - get sx () { - return this._sx; - }, - set sx (sx) { - this._sx = sx; - this.updateMatrix(); - }, - get sy () { - return this._sy; - }, - set sy (sy) { - this._sy = sy; - this.updateMatrix(); - }, - get rotation () { - return this._rotation; - }, - set rotation (rotation) { - this._rotation = rotation; - this.updateMatrix(); - }, - get x () { - return this._x; - }, - set x (x) { - this._x = this.matrix[2] = x; - }, - get y () { - return this._y; - }, - set y (y) { - this._y = this.matrix[5] = y; - } -}; -CAL.Matrix.prototype.updateMatrix = function () { - this.matrix = [ - this._sx * Math.cos(this._rotation), this._sy * -Math.sin(this._rotation), this._x, - this._sx * Math.sin(this._rotation), this._sy * Math.cos(this._rotation), this._y - ]; -}; -CAL.Matrix.prototype.multiplyMatrix = function (matrix) { - var a = this.matrix; - var b = matrix.matrix; - var translation = new CAL.Vector(b[2], b[5]).applyMatrix(this); + }, { + key: "multiplyMatrix", + value: function multiplyMatrix(m) { + var a = this.matrix; + var b = m.matrix; + var translation = new CAL.Vector(b[2], b[5]).applyMatrix(this); - return new CAL.Matrix([ - a[0]*b[0] + a[3]*b[1], a[1]*b[0] + a[4]*b[1], translation.x, - a[0]*b[3] + a[3]*b[4], a[1]*b[3] + a[4]*b[4], translation.y, - ]); -}; -CAL.Matrix.prototype.inverse = function () { - var m = this.matrix; - return new CAL.Matrix([ - m[4], -m[1], -m[2], - -m[3], m[0], -m[5] - ]); -}; -CAL.Matrix.prototype.translate = function (x, y) { - this.x += x; - this.y += y; + return new CAL.Matrix([a[0] * b[0] + a[3] * b[1] + a[6] * b[2], a[1] * b[0] + a[4] * b[1] + a[7] * b[2], a[2] * b[0] + a[5] * b[1] + a[8] * b[2], a[0] * b[3] + a[3] * b[4] + a[6] * b[5], a[1] * b[3] + a[4] * b[4] + a[7] * b[5], a[2] * b[3] + a[5] * b[4] + a[8] * b[5], a[0] * b[6] + a[3] * b[7] + a[6] * b[8], a[1] * b[6] + a[4] * b[7] + a[7] * b[8], a[2] * b[6] + a[5] * b[7] + a[8] * b[8]]); + } + }, { + key: "inverseMatrix", + value: function inverseMatrix() { + var m = this.matrix; - this.matrix[2] = this.x; - this.matrix[5] = this.y; + var det = 1 / (m[0] * m[4] * m[8] + m[1] * m[5] * m[6] + m[2] * m[3] * m[7] - m[1] * m[3] * m[8] - m[0] * m[5] * m[7] - m[2] * m[4] * m[6]); - return this; -}; -CAL.Matrix.prototype.setMatrix = function (matrix) { - this.matrix = matrix.matrix.clone(); - this._x = matrix._x; - this._y = matrix._y; - this._sx = matrix._sx; - this._sy = matrix._sy; - this._rotation = matrix._rotation; -}; -CAL.Matrix.prototype.setContext = function (context) { - var m = this.matrix; - context.transform(m[0], m[3], m[1], m[4], m[2], m[5]); -}; -CAL.Matrix.prototype.rotateAroundAbsolute = function (angle, center) { - if (angle !== 0) { - var center = center - .subtract(new CAL.Vector(this.x, this.y)) - .rotate(-this.rotation) - .multiply(new CAL.Vector(1/this.sx, 1/this.sy)); + return new CAL.Matrix([det * (m[4] * m[8] - m[5] * m[7]), -det * (m[1] * m[8] - m[2] * m[7]), det * (m[1] * m[5] - m[2] * m[4]), -det * (m[3] * m[8] - m[5] * m[6]), det * (m[0] * m[8] - m[2] * m[6]), -det * (m[0] * m[5] - m[2] * m[3]), det * (m[3] * m[7] - m[4] * m[6]), -det * (m[0] * m[7] - m[1] * m[6]), det * (m[0] * m[4] - m[1] * m[3])]); - this.rotateAroundRelative(angle, center); - } -}; -CAL.Matrix.prototype.rotateAroundRelative = function (angle, center) { - if (angle !== 0) { - var before = center.applyMatrix(this); + /*var m = this._matrix; + var det = 1 / (m[0]*m[4]*m[8] + m[1]*m[5]*m[6] + m[2]*m[3]*m[7] - m[2]*m[4]*m[6] - m[0]*m[5]*m[7] - m[1]*m[3]*m[8]); + return new CAL.Matrix([ + det * (m[4]*m[8] - m[5]*m[7]), + det * (m[3]*m[8] - m[5]*m[6]), + det * (m[3]*m[7] - m[4]*m[6]), + det * (m[1]*m[8] - m[2]*m[7]), + det * (m[0]*m[8] - m[2]*m[6]), + det * (m[0]*m[7] - m[1]*m[6]), + det * (m[1]*m[5] - m[2]*m[4]), + det * (m[0]*m[5] - m[2]*m[3]), + det * (m[0]*m[4] - m[1]*m[3]) + ]);*/ + } + }, { + key: "translate", + value: function translate(x, y) { + this.x += x; + this.y += y; - this.rotation += angle; - var after = center.applyMatrix(this); + return this; + } + }, { + key: "setMatrix", + value: function setMatrix(matrix) { + this._matrix = matrix.matrix; + this._x = matrix.x; + this._y = matrix.y; + this._sx = matrix.sx; + this._sy = matrix.sy; + this._rotation = matrix.rotation; - var offset = before.subtract(after); - - this._x += offset.x; - this._y += offset.y; - this.updateMatrix(); - } -}; -CAL.Matrix.prototype.clone = function () { - return new CAL.Matrix({ - matrix: this.matrix.clone(), - sx: this._sx, - sy: this._sy, - rotation: this._rotation, - x: this._x, - y: this._y - }); -}; + if (this.onchangetransfrom !== undefined) { + this.onchangetransfrom(); + } -CAL.Draw = function (centerX, centerY, numberWidth, numberHeight, options) { - CAL.Matrix.call(this, options); + return this; + } + }, { + key: "setMatrixContext", + value: function setMatrixContext(context) { + var m = this.matrix; + context.transform(m[0], m[3], m[1], m[4], m[2], m[5]); + } + }, { + key: "rotateAroundAbsolute", + value: function rotateAroundAbsolute(angle, center) { + this.rotateAroundRelative(angle, center.applyMatrix(this.inverseMatrix())); - this.visible = options.visible !== undefined ? options.visible : true; - this.active = options.active || false; - this.depth = options.depth || 0; + return this; + } + }, { + key: "rotateAroundRelative", + value: function rotateAroundRelative(angle, center) { + if (angle !== 0) { + var before = center.applyMatrix(this); - this.alpha = (typeof options.alpha === "number") ? options.alpha : 1; + this.rotation = angle; - this.centerX = centerX || 0; - this.centerY = centerY || 0; - this.index = 0; + var after = center.applyMatrix(this); - this.numberWidth = numberWidth || 1; - this.numberHeight = numberHeight || 1; - this.length = this.numberWidth*this.numberHeight; -}; -CAL.Draw.prototype = Object.create(CAL.Matrix.prototype); -CAL.Draw.prototype.draw = function (context, matrix) { - context.save(); - (matrix || this).setContext(context); - context.globalAlpha = this.alpha; - this.drawSimple(context, this.index, 0, 0); - context.restore(); -}; -CAL.Draw.prototype.drawSimple = function (context, number, x, y) { - var sx = (number % this.numberWidth)*this.width; - var sy = Math.floor(number/this.numberWidth)*this.height; + var offset = before.subtract(after); - context.drawImage(this.image, sx, sy, this.width, this.height, x-this.centerX, y-this.centerY, this.width, this.height); -}; -CAL.Draw.prototype.drawAlpha = function (context, number, x, y, alpha) { - context.globalAlpha = alpha; - this.drawSimple(context, number, x, y); - context.globalAlpha = 1; -}; -CAL.Draw.prototype.drawAngle = function (context, number, x, y, angle) { - context.save(); - context.translate(x, y); - context.rotate(angle); - this.drawSimple(context, number, 0, 0); - context.restore(); -}; -CAL.Draw.prototype.drawScale = function (context, number, x, y, width, height) { - var sx = (number % this.numberWidth)*this.width; - var sy = Math.floor(number/this.numberWidth)*this.height; + this.x += offset.x; + this.y += offset.y; + } - context.drawImage(this.image, sx, sy, this.width, this.height, x-this.centerX, y-this.centerY, width, height); -}; -CAL.Draw.prototype.drawContain = function (context, number, x, y, width, height) { - if (width/height > this.width/this.height) { - x = x + (width-height/this.height*this.width)/2; - width = height/this.height*this.width; - this.drawScale(context, number, x, y, width, height); - } - else { - y = y + (height-width/this.width*this.height)/2; - height = width/this.width*this.height; - this.drawScale(context, number, x, y, width, height); - } -}; + return this; + } + }, { + key: "scaleAroundAbsolute", + value: function scaleAroundAbsolute(sx, sy, center) { + this.scaleAroundRelative(sx, sy, center.applyMatrix(this.inverseMatrix())); -CAL.Surface = function (options) { - options = options || {}; - CAL.Draw.call(this, options.centerX, options.centerY, options.numberWidth, options.numberHeight, options); + return this; + } + }, { + key: "scaleAroundRelative", + value: function scaleAroundRelative(sx, sy, center) { + var before = center.applyMatrix(this); - this.clearColor = options.clearColor || false; + this.sx = sx; + this.sy = sy; - this.setCanvas(options.canvas || document.createElement("canvas")); + var after = center.applyMatrix(this); - this.setSize(options.width, options.height); -}; -CAL.Surface.prototype = Object.create(CAL.Draw.prototype); -CAL.Surface.prototype.setSize = function (width, height) { - this.image.width = width || this.image.width; - this.image.height = height || this.image.height; + var offset = before.subtract(after); - this.width = this.image.width/this.numberWidth; - this.height = this.image.height/this.numberHeight; -}; -CAL.Surface.prototype.setCanvas = function (canvas) { - this.image = canvas; - this.context = canvas.getContext("2d"); -}; -CAL.Surface.prototype.clear = function () { - if (this.clearColor) { - this.clearColor.setColor(this.context); - this.context.fillRect(0, 0, this.image.width, this.image.height); - } - else { - this.context.clearRect(0, 0, this.image.width, this.image.height); - } -}; -CAL.Surface.prototype.getImageData = function (x, y, width, height) { - var x = x || 0; - var y = y || 0; - var width = width || this.image.width; - var height = height || this.image.height; + this.x += offset.x; + this.y += offset.y; - return this.context.getImageData(x, y, width, height); -}; -CAL.Surface.prototype.getDataURL = function () { - return this.image.toDataURL(); -}; -CAL.Surface.prototype.blur = (function () { - //source: http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html - //author: Mario Klingemann + return this; + } + }, { + key: "clone", + value: function clone() { + var m = {}; - var mul_table = [512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,289,287,285,282,280,278,275,273,271,269,267,265,263,261,259]; - var shg_table = [9,11,12,13,13,14,14,15,15,15,15,16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24 ]; + if (this._matrix !== undefined) { + m.matrix = this._matrix; + } + if (this._x !== undefined) { + m.x = this._x; + } + if (this._y !== undefined) { + m.y = this._y; + } + if (this._rotation !== undefined) { + m.rotation = this._rotation; + } + if (this._sx !== undefined) { + m.sx = this._sx; + } + if (this._sy !== undefined) { + m.sy = this._sy; + } - return function (radius, x, y, width, height) { - x = x || 0; - y = y || 0; - width = this.image.width || 0; - height = this.image.height || 0; - var imageData = this.getImageData(x, y, width, height); + return new CAL.Matrix(m); + } + }, { + key: "sx", + get: function get() { + if (this._sx === undefined) { + this._sx = /*CAL.Math.sign(this._matrix[0]) * */Math.sqrt(Math.pow(this._matrix[0], 2) + Math.pow(this._matrix[1], 2)); + } - var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum, - r_out_sum, g_out_sum, b_out_sum, a_out_sum, - r_in_sum, g_in_sum, b_in_sum, a_in_sum, - pr, pg, pb, pa, rbs; + return this._sx; + }, + set: function set(sx) { + this._sx = sx; - var div = radius + radius + 1; - var w4 = width << 2; - var widthMinus1 = width - 1; - var heightMinus1 = height - 1; - var radiusPlus1 = radius + 1; - var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; - var pixels = imageData.data; + delete this._matrix; - var stackStart = {r: 0, g: 0, b: 0, next: null}; - var stack = stackStart; - for (i = 1; i < div; i ++) { - stack = stack.next = {r: 0, g: 0, b: 0, next: null}; - if (i == radiusPlus1) { - var stackEnd = stack; + if (this.onchangetransfrom !== undefined) { + this.onchangetransfrom(); } } - stack.next = stackStart; - var stackIn = null; - var stackOut = null; - - yw = yi = 0; - - var mul_sum = mul_table[radius]; - var shg_sum = shg_table[radius]; - - for (y = 0; y < height; y ++) { - r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0; - - r_out_sum = radiusPlus1 * (pr = pixels[yi]); - g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); - b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); - a_out_sum = radiusPlus1 * (pa = pixels[yi+3]); - - r_sum += sumFactor * pr; - g_sum += sumFactor * pg; - b_sum += sumFactor * pb; - a_sum += sumFactor * pa; - - stack = stackStart; - - for (i = 0; i < radiusPlus1; i ++) { - stack.r = pr; - stack.g = pg; - stack.b = pb; - stack.a = pa; - stack = stack.next; + }, { + key: "sy", + get: function get() { + if (this._sy === undefined) { + this._sy = /*CAL.Math.sign(this._matrix[4]) * */Math.sqrt(Math.pow(this._matrix[3], 2) + Math.pow(this._matrix[4], 2)); } - - for (i = 1; i < radiusPlus1; i ++) { - p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2); - r_sum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i); - g_sum += (stack.g = (pg = pixels[p+1])) * rbs; - b_sum += (stack.b = (pb = pixels[p+2])) * rbs; - a_sum += (stack.a = (pa = pixels[p+3])) * rbs; - - r_in_sum += pr; - g_in_sum += pg; - b_in_sum += pb; - a_in_sum += pa; - - stack = stack.next; - } - - stackIn = stackStart; - stackOut = stackEnd; - for (x = 0; x < width; x ++) { - pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum; - if (pa === 0) { - pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0; - } - else { - pa = 255 / pa; - pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa; - pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa; - pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa; - } - - - r_sum -= r_out_sum; - g_sum -= g_out_sum; - b_sum -= b_out_sum; - a_sum -= a_out_sum; - - r_out_sum -= stackIn.r; - g_out_sum -= stackIn.g; - b_out_sum -= stackIn.b; - a_out_sum -= stackIn.a; - - p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; - - r_in_sum += (stackIn.r = pixels[p]); - g_in_sum += (stackIn.g = pixels[p+1]); - b_in_sum += (stackIn.b = pixels[p+2]); - a_in_sum += (stackIn.a = pixels[p+3]); - - r_sum += r_in_sum; - g_sum += g_in_sum; - b_sum += b_in_sum; - a_sum += a_in_sum; - - stackIn = stackIn.next; - - r_out_sum += (pr = stackOut.r); - g_out_sum += (pg = stackOut.g); - b_out_sum += (pb = stackOut.b); - a_out_sum += (pa = stackOut.a); - - r_in_sum -= pr; - g_in_sum -= pg; - b_in_sum -= pb; - a_in_sum -= pa; - - stackOut = stackOut.next; - yi += 4; - } - yw += width; - } + return this._sy; + }, + set: function set(sy) { + this._sy = sy; + delete this._matrix; - for (x = 0; x < width; x ++) { - g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0; - - yi = x << 2; - r_out_sum = radiusPlus1 * (pr = pixels[yi]); - g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); - b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); - a_out_sum = radiusPlus1 * (pa = pixels[yi+3]); - - r_sum += sumFactor * pr; - g_sum += sumFactor * pg; - b_sum += sumFactor * pb; - a_sum += sumFactor * pa; - - stack = stackStart; - - for (i = 0; i < radiusPlus1; i ++) { - stack.r = pr; - stack.g = pg; - stack.b = pb; - stack.a = pa; - stack = stack.next; - } - - yp = width; - - for (i = 1; i <= radius; i ++) { - yi = (yp + x) << 2; - - r_sum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); - g_sum += (stack.g = (pg = pixels[yi+1])) * rbs; - b_sum += (stack.b = (pb = pixels[yi+2])) * rbs; - a_sum += (stack.a = (pa = pixels[yi+3])) * rbs; - - r_in_sum += pr; - g_in_sum += pg; - b_in_sum += pb; - a_in_sum += pa; - - stack = stack.next; - - if (i < heightMinus1) { - yp += width; - } - } - - yi = x; - stackIn = stackStart; - stackOut = stackEnd; - for (y = 0; y < height; y ++) { - p = yi << 2; - pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum; - if (pa > 0) { - pa = 255 / pa; - pixels[p] = ((r_sum * mul_sum) >> shg_sum) * pa; - pixels[p+1] = ((g_sum * mul_sum) >> shg_sum) * pa; - pixels[p+2] = ((b_sum * mul_sum) >> shg_sum) * pa; - } - else { - pixels[p] = pixels[p+1] = pixels[p+2] = 0; - } - - r_sum -= r_out_sum; - g_sum -= g_out_sum; - b_sum -= b_out_sum; - a_sum -= a_out_sum; - - r_out_sum -= stackIn.r; - g_out_sum -= stackIn.g; - b_out_sum -= stackIn.b; - a_out_sum -= stackIn.a; - - p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2; - - r_sum += (r_in_sum += (stackIn.r = pixels[p])); - g_sum += (g_in_sum += (stackIn.g = pixels[p+1])); - b_sum += (b_in_sum += (stackIn.b = pixels[p+2])); - a_sum += (a_in_sum += (stackIn.a = pixels[p+3])); - - stackIn = stackIn.next; - - r_out_sum += (pr = stackOut.r); - g_out_sum += (pg = stackOut.g); - b_out_sum += (pb = stackOut.b); - a_out_sum += (pa = stackOut.a); - - r_in_sum -= pr; - g_in_sum -= pg; - b_in_sum -= pb; - a_in_sum -= pa; - - stackOut = stackOut.next; - - yi += width; + if (this.onchangetransfrom !== undefined) { + this.onchangetransfrom(); } } - return imageData; - }; + }, { + key: "rotation", + get: function get() { + if (this._rotation === undefined) { + var p = new CAL.Vector(1, 0).applyMatrix(this).subtract(new CAL.Vector(this.x, this.y)); + this._rotation = Math.atan2(p.y, p.x); + + //this._rotation = Math.atan(-this._matrix[1], this._matrix[0]); + } + + return this._rotation; + }, + set: function set(rotation) { + this._rotation = rotation; + + delete this._matrix; + + if (this.onchangetransfrom !== undefined) { + this.onchangetransfrom(); + } + } + }, { + key: "x", + get: function get() { + if (this._x === undefined) { + this._x = this._matrix[2]; + } + + return this._x; + }, + set: function set(x) { + this._x = x; + + if (this._matrix !== undefined) { + this._matrix[2] = x; + } + + if (this.onchangetransfrom !== undefined) { + this.onchangetransfrom(); + } + } + }, { + key: "y", + get: function get() { + if (this._y === undefined) { + this._y = this._matrix[5]; + } + + return this._y; + }, + set: function set(y) { + this._y = y; + + if (this._matrix !== undefined) { + this._matrix[5] = y; + } + } + }, { + key: "matrix", + get: function get() { + if (this._matrix === undefined) { + this._updateMatrix(); + } + + return this._matrix; + }, + set: function set(m) { + if (m instanceof Array) { + this._matrix = m; + + delete this._sx; + delete this._sy; + delete this._rotation; + } else { + this.set(m); + } + + if (this.onchangetransfrom !== undefined) { + this.onchangetransfrom(); + } + } + }]); + + return _class; })(); +"use strict"; -CAL.Draw.prototype.drawBlur = (function () { - var surface = new CAL.Surface(); +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; }; })(); - return function (context, number, x, y, radius) { - if (radius > 0) { - surface.setSize(this.width + 2*radius, this.height + 2*radius); - this.drawSimple(surface.context, number, this.centerX+radius, this.centerY+radius); - var imageData = surface.blur(radius); - - context.putImageData(imageData, x-this.centerX - radius, y-this.centerY - radius); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - /*surface.setSize(this.width, this.height); - this.drawSimple(surface.context, number, this.centerX, this.centerY); - var imageData = surface.blur(radius); - - context.putImageData(imageData, x-this.centerX, y-this.centerY);*/ - } - else { - this.drawSimple(context, number, x, y); +CAL.Color = (function () { + var _class = function _class() { + _classCallCheck(this, _class); + + if (typeof arguments[0] === "number" && typeof arguments[1] === "number" && typeof arguments[2] === "number") { + this.r = arguments[0]; + this.g = arguments[1]; + this.b = arguments[2]; + this.a = typeof arguments[3] === "number" ? arguments[3] : 1; + } else if (typeof arguments[0] === "number") { + var hex = Math.floor(arguments[0]); + + this.r = hex >> 16 & 255; + this.g = hex >> 8 & 255; + this.b = hex & 255; + this.a = typeof arguments[1] === "number" ? arguments[1] : 1; + } else { + this.r = 0; + this.g = 0; + this.b = 0; + this.a = 1; } }; + + _createClass(_class, [{ + key: "setStroke", + value: function setStroke(context) { + context.strokeStyle = "rgba(" + this.r + ", " + this.g + ", " + this.b + ", " + this.a + ")"; + + return this; + } + }, { + key: "setFill", + value: function setFill(context) { + context.fillStyle = "rgba(" + this.r + ", " + this.g + ", " + this.b + ", " + this.a + ")"; + + return this; + } + }, { + key: "setColor", + value: function setColor(context) { + this.setStroke(context); + this.setFill(context); + + return this; + } + }]); + + return _class; })(); +"use strict"; -CAL.Group = function (options) { - options = options || {}; - CAL.Surface.call(this, options); +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; }; })(); - this.active = true; - this.visible = true; +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; - this.objects = []; - this.useCanvas = options.useCanvas || false; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - this.clearCanvas = true; - this.drawCanvas = true; +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) subClass.__proto__ = superClass; } - this.mouse = { - x: null, - y: null, - startX: null, - startY: null, - deltaX: null, - deltaY: null, - down: false, - moved: false +CAL.Draw = (function (_CAL$Matrix) { + var _class = function _class(centerX, centerY, numberWidth, numberHeight, options) { + _classCallCheck(this, _class); + + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options); + + this.visible = options.visible !== undefined ? options.visible : true; + this.active = false; + this.depth = options.depth || 0; + + this.alpha = typeof options.alpha === "number" ? options.alpha : 1; + + this.centerX = centerX || 0; + this.centerY = centerY || 0; + this.index = 0; + + this.numberWidth = numberWidth || 1; + this.numberHeight = numberHeight || 1; + this.length = this.numberWidth * this.numberHeight; }; -}; -CAL.Group.prototype = Object.create(CAL.Surface.prototype); -CAL.Group.prototype.updateEvents = function () { - var scope = this; - this.image.onmousedown = function (event) { - if (scope.useCanvas) { - scope.mouse.x = scope.mouse.startX = Math.round(scope.image.width / scope.image.clientWidth * event.offsetX); - scope.mouse.y = scope.mouse.startY = Math.round(scope.image.height / scope.image.clientHeight * event.offsetY); - scope.mouse.deltaX = 0; - scope.mouse.deltaY = 0; - scope.mouse.down = true; - scope.mouse.moved = false; - scope.mouseDown(scope.mouse, this); + _inherits(_class, _CAL$Matrix); + + _createClass(_class, [{ + key: "getBoundingBox", + value: function getBoundingBox() { + return { + top: -this.centerX, + left: -this.centerY, + right: this.width - this.centerX, + bottom: this.height - this.centerY, + width: this.width, + height: this.height + }; } + }, { + key: "draw", + value: function draw(context, matrix) { + console.log("Test"); + context.save(); + (matrix || this).setMatrixContext(context); + context.globalAlpha = this.alpha; + this.drawSimple(context, this.index, 0, 0); + context.restore(); + + return this; + } + }, { + key: "drawSimple", + value: function drawSimple(context, index, x, y) { + var sx = index % this.numberWidth * this.width; + var sy = Math.floor(index / this.numberWidth) * this.height; + + var offsetX = x - this.centerX; + var offsetY = y - this.centerY; + + context.drawImage(this.image, sx, sy, this.width, this.height, offsetX, offsetY, this.width, this.height); + + return this; + } + }, { + key: "drawAlpha", + value: function drawAlpha(context, index, x, y, alpha) { + context.globalAlpha = alpha; + this.drawSimple(context, index, x, y); + context.globalAlpha = 1; + + return this; + } + }, { + key: "drawAngle", + value: function drawAngle(context, index, x, y, angle) { + context.save(); + context.translate(x, y); + context.rotate(angle); + this.drawSimple(context, index, 0, 0); + context.restore(); + + return this; + } + }, { + key: "drawScale", + value: function drawScale(context, index, x, y, width, height) { + var sx = index % this.length * this.width; + var sy = Math.floor(index / this.length) * this.height; + + var offsetX = x - this.centerX; + var offsetY = y - this.centerY; + + context.drawImage(this.image, sx, sy, this.width, this.height, offsetX, offsetY, width, height); + + return this; + } + }, { + key: "drawContain", + value: function drawContain(context, index, x, y, width, height) { + if (width / height > this.width / this.height) { + x = x + (width - height / this.height * this.width) / 2; + width = height / this.height * this.width; + } else { + y = y + (height - width / this.width * this.height) / 2; + height = width / this.width * this.height; + } + + this.drawScale(context, index, x, y, width, height); + + return this; + } + }]); + + return _class; +})(CAL.Matrix); +"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(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } 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 _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) subClass.__proto__ = superClass; } + +CAL.Surface = (function (_CAL$Draw) { + var _class = function _class(options) { + _classCallCheck(this, _class); + + options = options || {}; + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options.centerX, options.centerY, options.numberWidth, options.numberHeight, options); + + this.clearColor = options.clearColor || false; + + this.setCanvas(options.canvas || document.createElement("canvas")); + + this.setSize(options.width, options.height, options.pixelRatio); }; - this.image.onmouseup = function (event) { - if (scope.useCanvas) { - scope.mouse.x = Math.round(scope.image.width / scope.image.clientWidth * event.offsetX); - scope.mouse.y = Math.round(scope.image.height / scope.image.clientHeight * event.offsetY); - scope.mouse.down = false; - scope.mouseUp(scope.mouse, this); + _inherits(_class, _CAL$Draw); - scope.mouse.startX = null; - scope.mouse.startY = null; - scope.mouse.deltaX = null; - scope.mouse.deltaY = null; - scope.mouse.moved = false; + _createClass(_class, [{ + key: "setSize", + value: function setSize(width, height, pixelRatio) { + var width = width || this.image.width; + var height = height || this.image.height; + var pixelRatio = pixelRatio ? pixelRatio : 1; + + this.image.width = width * pixelRatio; + this.image.height = height * pixelRatio; + + this.image.style.width = width + "px"; + this.image.style.height = height + "px"; + + this.width = this.image.width / this.numberWidth; + this.height = this.image.height / this.numberHeight; + + return this; } - }; - this.image.onmousemove = function (event) { - if (scope.useCanvas) { - scope.mouse.x = Math.round(scope.image.width / scope.image.clientWidth * event.offsetX); - scope.mouse.y = Math.round(scope.image.height / scope.image.clientHeight * event.offsetY); - if (scope.mouse.down) { - scope.mouse.moved = true; - scope.mouse.deltaX = scope.mouse.x - scope.mouse.startX; - scope.mouse.deltaY = scope.mouse.y - scope.mouse.startY; + }, { + key: "setCanvas", + value: function setCanvas(canvas) { + this.image = canvas; + this.context = canvas.getContext("2d"); + + return this; + } + }, { + key: "clear", + value: function clear() { + if (this.clearColor) { + this.clearColor.setColor(this.context); + this.context.fillRect(0, 0, this.image.width, this.image.height); + } else { + this.context.clearRect(0, 0, this.image.width, this.image.height); } + + return this; } - }; - //this.image.ontouchstart = function (event) {scope.touchStart(event);}; - //this.image.ontouchmove = function (event) {scope.touchMove(event);}; - //this.image.ontouchend = function (event) {scope.touchEnd(event);}; -}; -CAL.Group.prototype.setCanvas = function (canvas) { - /*this.image.onmousedown = null; - this.image.onmouseup = null; - this.image.onmousemove = null; - this.image.ontouchstart = null; - this.image.ontouchmove = null; - this.image.ontouchend = null;*/ + }, { + key: "getImageData", + value: function getImageData(x, y, width, height) { + var x = x || 0; + var y = y || 0; + var width = width || this.image.width; + var height = height || this.image.height; - this.image = canvas; - this.context = canvas.getContext("2d"); - - this.drawCanvas = true; - this.updateEvents(); -}; -CAL.Group.prototype.add = function () { - for (var i = 0; i < arguments.length; i ++) { - var object = arguments[i]; - if (this.objects.indexOf(object) === -1) { - this.objects.push(object); - if (object.init) { - object.init(this); - } + return this.context.getImageData(x, y, width, height); } - } - this.sort(); - this.drawCanvas = true; -}; -CAL.Group.prototype.remove = function () { - for (var i = 0; i < arguments.length; i ++) { - var object = arguments[i]; - this.objects.remove(object); - if (object.active && object.remove !== undefined) { - object.remove(this); + }, { + key: "getDataURL", + value: function getDataURL() { + return this.image.toDataURL(); } - } - this.drawCanvas = true; -}; -CAL.Group.prototype.sort = function () { - this.objects.sort(function (a, b) { - return (a.depth || 0) - (b.depth || 0); - }); -}; -CAL.Group.prototype.keyDown = function (keyCode) { - for (var i = this.objects.length-1; i >= 0; i --) { - var object = this.objects[i]; - if (object.active && object.keyDown !== undefined) { - if (object.keyDown(keyCode, this)) { - break; - } - } - } -}; -CAL.Group.prototype.keyUp = function (keyCode) { - for (var i = this.objects.length-1; i >= 0; i --) { - var object = this.objects[i]; - if (object.active && object.keyUp !== undefined) { - if (object.keyUp(keyCode, this)) { - break; - } - } - } -}; -CAL.Group.prototype.mouseDown = function (mouse) { - for (var i = this.objects.length-1; i >= 0; i --) { - var object = this.objects[i]; - if (object.useCanvas !== true && object.active && object.mouseDown !== undefined) { - if (object.mouseDown(mouse, this)) { - break; - } - } - } -}; -CAL.Group.prototype.mouseUp = function (mouse) { - for (var i = this.objects.length-1; i >= 0; i --) { - var object = this.objects[i]; - if (object.useCanvas !== true && object.active && object.mouseUp !== undefined) { - if (object.mouseUp(mouse, this)) { - break; - } - } - } -}; -CAL.Group.prototype.step = function (deltaTime) { - for (var i = 0; i < this.objects.length; i ++) { - var object = this.objects[i]; - if (object.active && object.step !== undefined) { - object.step(deltaTime, this); - } - } - if (this.clearCanvas && this.useCanvas) { - this.clear(); - } + /* + blur = (function () { + //source: http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html + //author: Mario Klingemann + var mul_table = [512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,289,287,285,282,280,278,275,273,271,269,267,265,263,261,259]; + var shg_table = [9,11,12,13,13,14,14,15,15,15,15,16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24 ]; + return function (radius, x, y, width, height) { + x = x || 0; + y = y || 0; + width = this.image.width || 0; + height = this.image.height || 0; + var imageData = this.getImageData(x, y, width, height); + var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum, + r_out_sum, g_out_sum, b_out_sum, a_out_sum, + r_in_sum, g_in_sum, b_in_sum, a_in_sum, + pr, pg, pb, pa, rbs; + var div = radius + radius + 1; + var w4 = width << 2; + var widthMinus1 = width - 1; + var heightMinus1 = height - 1; + var radiusPlus1 = radius + 1; + var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; + var pixels = imageData.data; + var stackStart = {r: 0, g: 0, b: 0, next: null}; + var stack = stackStart; + for (i = 1; i < div; i ++) { + stack = stack.next = {r: 0, g: 0, b: 0, next: null}; + if (i == radiusPlus1) { + var stackEnd = stack; + } + } + stack.next = stackStart; + var stackIn = null; + var stackOut = null; + yw = yi = 0; + var mul_sum = mul_table[radius]; + var shg_sum = shg_table[radius]; + for (y = 0; y < height; y ++) { + r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0; + + r_out_sum = radiusPlus1 * (pr = pixels[yi]); + g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); + b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); + a_out_sum = radiusPlus1 * (pa = pixels[yi+3]); + + r_sum += sumFactor * pr; + g_sum += sumFactor * pg; + b_sum += sumFactor * pb; + a_sum += sumFactor * pa; + + stack = stackStart; + + for (i = 0; i < radiusPlus1; i ++) { + stack.r = pr; + stack.g = pg; + stack.b = pb; + stack.a = pa; + stack = stack.next; + } + + for (i = 1; i < radiusPlus1; i ++) { + p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2); + r_sum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i); + g_sum += (stack.g = (pg = pixels[p+1])) * rbs; + b_sum += (stack.b = (pb = pixels[p+2])) * rbs; + a_sum += (stack.a = (pa = pixels[p+3])) * rbs; + + r_in_sum += pr; + g_in_sum += pg; + b_in_sum += pb; + a_in_sum += pa; + + stack = stack.next; + } + + stackIn = stackStart; + stackOut = stackEnd; + for (x = 0; x < width; x ++) { + pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum; + if (pa === 0) { + pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0; + } + else { + pa = 255 / pa; + pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa; + pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa; + pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa; + } + + + r_sum -= r_out_sum; + g_sum -= g_out_sum; + b_sum -= b_out_sum; + a_sum -= a_out_sum; + + r_out_sum -= stackIn.r; + g_out_sum -= stackIn.g; + b_out_sum -= stackIn.b; + a_out_sum -= stackIn.a; + + p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; + + r_in_sum += (stackIn.r = pixels[p]); + g_in_sum += (stackIn.g = pixels[p+1]); + b_in_sum += (stackIn.b = pixels[p+2]); + a_in_sum += (stackIn.a = pixels[p+3]); + + r_sum += r_in_sum; + g_sum += g_in_sum; + b_sum += b_in_sum; + a_sum += a_in_sum; + + stackIn = stackIn.next; + + r_out_sum += (pr = stackOut.r); + g_out_sum += (pg = stackOut.g); + b_out_sum += (pb = stackOut.b); + a_out_sum += (pa = stackOut.a); + + r_in_sum -= pr; + g_in_sum -= pg; + b_in_sum -= pb; + a_in_sum -= pa; + + stackOut = stackOut.next; + yi += 4; + } + yw += width; + } + + for (x = 0; x < width; x ++) { + g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0; + + yi = x << 2; + r_out_sum = radiusPlus1 * (pr = pixels[yi]); + g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); + b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); + a_out_sum = radiusPlus1 * (pa = pixels[yi+3]); + + r_sum += sumFactor * pr; + g_sum += sumFactor * pg; + b_sum += sumFactor * pb; + a_sum += sumFactor * pa; + + stack = stackStart; + + for (i = 0; i < radiusPlus1; i ++) { + stack.r = pr; + stack.g = pg; + stack.b = pb; + stack.a = pa; + stack = stack.next; + } + + yp = width; + + for (i = 1; i <= radius; i ++) { + yi = (yp + x) << 2; + + r_sum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); + g_sum += (stack.g = (pg = pixels[yi+1])) * rbs; + b_sum += (stack.b = (pb = pixels[yi+2])) * rbs; + a_sum += (stack.a = (pa = pixels[yi+3])) * rbs; + + r_in_sum += pr; + g_in_sum += pg; + b_in_sum += pb; + a_in_sum += pa; + + stack = stack.next; + + if (i < heightMinus1) { + yp += width; + } + } + + yi = x; + stackIn = stackStart; + stackOut = stackEnd; + for (y = 0; y < height; y ++) { + p = yi << 2; + pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum; + if (pa > 0) { + pa = 255 / pa; + pixels[p] = ((r_sum * mul_sum) >> shg_sum) * pa; + pixels[p+1] = ((g_sum * mul_sum) >> shg_sum) * pa; + pixels[p+2] = ((b_sum * mul_sum) >> shg_sum) * pa; + } + else { + pixels[p] = pixels[p+1] = pixels[p+2] = 0; + } + + r_sum -= r_out_sum; + g_sum -= g_out_sum; + b_sum -= b_out_sum; + a_sum -= a_out_sum; + + r_out_sum -= stackIn.r; + g_out_sum -= stackIn.g; + b_out_sum -= stackIn.b; + a_out_sum -= stackIn.a; + + p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2; + + r_sum += (r_in_sum += (stackIn.r = pixels[p])); + g_sum += (g_in_sum += (stackIn.g = pixels[p+1])); + b_sum += (b_in_sum += (stackIn.b = pixels[p+2])); + a_sum += (a_in_sum += (stackIn.a = pixels[p+3])); + + stackIn = stackIn.next; + + r_out_sum += (pr = stackOut.r); + g_out_sum += (pg = stackOut.g); + b_out_sum += (pb = stackOut.b); + a_out_sum += (pa = stackOut.a); + + r_in_sum -= pr; + g_in_sum -= pg; + b_in_sum -= pb; + a_in_sum -= pa; + + stackOut = stackOut.next; + + yi += width; + } + } + return imageData; + }; + })(); + CAL.Draw.prototype.drawBlur = (function () { + + var surface = new CAL.Surface(); + return function (context, number, x, y, radius) { + if (radius > 0) { + surface.setSize(this.width + 2*radius, this.height + 2*radius); + this.drawSimple(surface.context, number, this.centerX+radius, this.centerY+radius); + var imageData = surface.blur(radius); + + context.putImageData(imageData, x-this.centerX - radius, y-this.centerY - radius); + /* + surface.setSize(this.width, this.height); + this.drawSimple(surface.context, number, this.centerX, this.centerY); + var imageData = surface.blur(radius); + + context.putImageData(imageData, x-this.centerX, y-this.centerY); + */ + /* + } + else { + this.drawSimple(context, number, x, y); + } + }; + })(); + */ - if (this.drawCanvas && this.useCanvas) { - this.draw(); - } + }]); - this.clearCanvas = false; - this.drawCanvas = false; -}; -CAL.Group.prototype.draw = function (context, matrix) { - context = this.useCanvas ? this.context : context; - matrix = this.useCanvas ? this : matrix; + return _class; +})(CAL.Draw); +'use strict'; - for (var i = 0; i < this.objects.length; i ++) { - var object = this.objects[i]; - if (object.useCanvas !== true && object.visible && object.draw !== undefined) { - if (object instanceof CAL.Matrix) { - object.draw(context, matrix.multiplyMatrix(object)); - } - else { - object.draw(context, matrix); - } - } - } -}; +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; }; })(); -CAL.Scene = function () { - CAL.Group.call(this, {useCanvas: true}); +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; - this.lastTime = new Date().getTime(); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - this.keysDown = []; - this.focus = true; +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) subClass.__proto__ = superClass; } - var scope = this; - window.onkeydown = function (event) { - if (!scope.keysDown[event.keyCode]) { - scope.keysDown[event.keyCode] = true; - scope.keyDown(event.keyCode); - } - }; - window.onkeyup = function (event) { - scope.keysDown[event.keyCode] = false; +CAL.Group = (function (_CAL$Surface) { + var _class = function _class(options) { + _classCallCheck(this, _class); - scope.keyUp(event.keyCode); - }; - window.onblur = function (event) { - this.focus = false; - }; - window.onfocus = function (event) { - scope.lastTime = new Date().getTime(); + options = options || {}; + _get(Object.getPrototypeOf(_class.prototype), 'constructor', this).call(this, options); + + this.active = true; + this.visible = true; + + this.objects = []; + this.useCanvas = options.useCanvas !== undefined ? options.useCanvas : true; + + this.clearCanvas = true; + this.drawCanvas = true; + this.autoClearCanvas = options.autoClearCanvas || false; + this.autoDrawCanvas = options.autoDrawCanvas || false; + + this.loop = false; + this.itemsToAdd = []; + this.itemsToRemove = []; + + this.mouse = { + position: new CAL.Vector(), + start: new CAL.Vector(), + delta: new CAL.Vector(), + length: 0, + down: false + }; + + this.lastTime = new Date().getTime(); + + this.keysDown = []; this.focus = true; + + window.addEventListener('keydown', this); + window.addEventListener('keyup', this); + window.addEventListener('blur', this); + window.addEventListener('focus', this); }; -}; -CAL.Scene.prototype = Object.create(CAL.Group.prototype); -CAL.Scene.prototype.cycle = function () { - if (this.focus) { - var currentTime = new Date().getTime(); - var deltaTime = currentTime-this.lastTime; - this.lastTime = currentTime; - this.step(deltaTime); - } -}; -CAL.Scene = new CAL.Scene(); + _inherits(_class, _CAL$Surface); -CAL.Image = function (source, centerX, centerY, numberWidth, numberHeight, options) { - options = options || {}; - CAL.Draw.call(this, centerX, centerY, numberWidth, numberHeight, options); - - this.image = new Image(); - this.source = source; -}; -CAL.Image.prototype = Object.create(CAL.Draw.prototype); -CAL.Image.prototype.load = function (callback) { - var scope = this; - this.image.onload = function () { - scope.loaded = true; - - scope.width = scope.image.width/scope.numberWidth; - scope.height = scope.image.height/scope.numberHeight; - - if (callback !== undefined) { - callback(); + _createClass(_class, [{ + key: 'init', + value: function init() { + this.useCanvas = false; } - }; - this.image.src = this.source; -}; + }, { + key: 'handleEvent', + value: function handleEvent(event) { + if (this.useCanvas) { + switch (event.type) { + case 'mousedown': + var offsetX = event.pageX - this.image.offsetLeft; + var offsetY = event.pageY - this.image.offsetTop; -CAL.ImageLoader = function () { - this.images = []; + var x = this.mouse.startX = Math.round(this.image.width / this.image.clientWidth * offsetX); + var y = this.mouse.startY = Math.round(this.image.height / this.image.clientHeight * offsetY); - for (var i = 0; i < arguments.length; i ++) { - var image = arguments[i]; - this.images.push(image); - } -}; -CAL.ImageLoader.prototype.add = function () { - for (var i = 0; i < arguments.length; i ++) { - var image = arguments[i]; - if (this.images.indexOf(image) === -1) { - this.images.push(image); - } - } -}; -CAL.ImageLoader.prototype.remove = function () { - for (var i = 0; i < arguments.length; i ++) { - var image = arguments[i]; - this.images.remove(image); - } -}; -CAL.ImageLoader.prototype.load = function (callback) { - var imagesToLoad = this.images.length; - for (var i = 0; i < this.images.length; i ++) { - var image = this.images[i]; - image.load(function () { - imagesToLoad --; - if (imagesToLoad === 0 && callback !== undefined) { - callback(); - } - }, this); - }; -}; + this.mouse.position.copy(new CAL.Vector(x, y)); + this.mouse.start.copy(this.mouse.position); + this.mouse.delta.identity(); + this.mouse.length = 0; + this.mouse.down = true; -CAL.Color = function () { - if (typeof arguments[0] === "number" && typeof arguments[1] === "number" && typeof arguments[2] === "number") { - this.r = arguments[0]; - this.g = arguments[1]; - this.b = arguments[2]; - this.a = typeof arguments[3] === "number" ? arguments[3] : 1; - } - else if (typeof arguments[0] === "number") { - var hex = Math.floor(arguments[0]); + this.mouseDown(this.mouse); + break; - this.r = hex >> 16 & 255; - this.g = hex >> 8 & 255; - this.b = hex & 255; - this.a = 1; - } - else { - this.r = 0; - this.g = 0; - this.b = 0; - this.a = 1; - } -}; -CAL.Color.prototype.setStroke = function (context) { - context.strokeStyle = "rgba("+this.r+", "+this.g+", "+this.b+", "+this.a+")"; -}; -CAL.Color.prototype.setFill = function (context) { - context.fillStyle = "rgba("+this.r+", "+this.g+", "+this.b+", "+this.a+")"; -}; -CAL.Color.prototype.setColor = function (context) { - this.setStroke(context); - this.setFill(context); -}; + case 'mouseup': + var offsetX = event.pageX - this.image.offsetLeft; + var offsetY = event.pageY - this.image.offsetTop; -CAL.Tween = function (object, attributes, duration, options) { - options = options || {}; - this.visible = false; - this.active = true; - this.depth = -10000; + var x = Math.round(this.image.width / this.image.clientWidth * offsetX); + var y = Math.round(this.image.height / this.image.clientHeight * offsetY); - this.object = object; - this.attributes = attributes; - this.timer = 0; - this.duration = duration; - this.easing = options.easing || CAL.Easings.linear; - this.callback = options.callback; + this.mouse.position.copy(new CAL.Vector(x, y)); + this.mouse.down = false; - this.begin = {}; - for (var i in attributes) { - this.begin[i] = this.object[i]; - } + this.mouseUp(this.mouse); - this.change = {}; - for (var i in attributes) { - this.change[i] = attributes[i] - this.begin[i]; - } + this.mouse.start.identity(); + this.mouse.delta.identity(); + this.mouse.length = 0; + break; - this.drawCanvas = options.drawCanvas !== undefined ? options.drawCanvas : true; - this.clearCanvas = options.clearCanvas !== undefined ? options.clearCanvas : false; -}; -CAL.Tween.prototype.start = function () { - this.t = 0; - this.active = true; -}; -CAL.Tween.prototype.stop = function () { - this.t = 0; - this.active = false; -}; -CAL.Tween.prototype.pause = function () { - this.active = false; -}; -CAL.Tween.prototype.resume = function () { - this.active = true; -}; -CAL.Tween.prototype.step = function (deltaTime, group) { - this.timer += deltaTime; + case 'mousemove': + var offsetX = event.pageX - this.image.offsetLeft; + var offsetY = event.pageY - this.image.offsetTop; - if (this.timer < this.duration) { + var x = Math.round(this.image.width / this.image.clientWidth * offsetX); + var y = Math.round(this.image.height / this.image.clientHeight * offsetY); - for (var i in this.attributes) { - var dt = this.timer; - var d = this.duration; - var b = this.begin[i]; - var c = this.change[i]; - - this.object[i] = this.easing(dt, b, c, d); - } - } - else { - for (var i in this.attributes) { - this.object[i] = this.attributes[i]; - } - if (this.callback !== undefined) { - this.callback(); - } - group.remove(this); - } + var position = new CAL.Vector(x, y); - if (this.clearCanvas) { - group.clearCanvas = true; - } - if (this.drawCanvas) { - group.drawCanvas = true; - } -}; + this.mouse.length += this.mouse.position.distanceTo(position); -CAL.TimeLine = function (options) { - options = options || {}; - - this.visible = false; - this.active = true; - this.depth = -10000; + this.mouse.position.copy(position); - this.moments = []; - this.autoRemove = (options.autoRemove !== undefined) ? options.autoremove : true; - this.loop = (options.loop !== undefined) ? options.loop : false; - this.t = 0; + if (this.mouse.down) { + this.mouse.delta.copy(this.mouse.position.subtract(this.mouse.start)); + } - CAL.Scene.add(this); -}; -CAL.TimeLine.prototype = { - addMoment: function (time, callback) { - this.moments.push({ - time: time, - callback: callback - }); - }, - removeMoment: function (remove) { - for (var i = 0; i < this.moments.length; i ++) { - var moment = this.moments[i]; + this.mouseMove(this.mouse); + break; - if (moment === remove || moment.time === remove || moment.callback === remove) { - this.moments.remove(moment); - } - } - }, - start: function () { - this.t = 0; - this.active = true; - }, - stop: function () { - this.t = 0; - this.active = false; - }, - pause: function () { - this.active = false; - }, - resume: function () { - this.active = true; - }, - step: function (dt) { - var newTime = this.t + dt; - var remove = true; + case 'touchstart': + event.preventDefault(); - for (var i = 0; i < this.moments.length; i ++) { - var moment = this.moments[i]; - if (moment.time >= this.t) { - if (moment.time < newTime) { - moment.callback(); - } - else { - remove = false; + if (event.touches.length === 1) { + var touch = event.touches[0]; + + var offsetX = touch.pageX - this.image.offsetLeft; + var offsetY = touch.pageY - this.image.offsetTop; + + var x = this.mouse.startX = Math.round(this.image.width / this.image.clientWidth * offsetX); + var y = this.mouse.startY = Math.round(this.image.height / this.image.clientHeight * offsetY); + + this.mouse.position.copy(new CAL.Vector(x, y)); + this.mouse.start.copy(this.mouse.position); + this.mouse.delta.identity(); + this.mouse.length = 0; + this.mouse.down = true; + + this.mouseDown(this.mouse); + } + break; + + case 'touchmove': + event.preventDefault(); + + var touch = event.touches[0]; + + var offsetX = touch.pageX - this.image.offsetLeft; + var offsetY = touch.pageY - this.image.offsetTop; + + var x = Math.round(this.image.width / this.image.clientWidth * offsetX); + var y = Math.round(this.image.height / this.image.clientHeight * offsetY); + + var position = new CAL.Vector(x, y); + + this.mouse.length += this.mouse.position.distanceTo(position); + + this.mouse.position.copy(position); + + if (this.mouse.down) { + this.mouse.delta.copy(this.mouse.position.subtract(this.mouse.start)); + } + + this.mouseMove(this.mouse); + break; + + case 'touchend': + event.preventDefault(); + + if (this.useCanvas && event.touches.length === 0) { + this.mouse.down = false; + + this.mouseUp(this.mouse); + + this.mouse.start.identity(); + this.mouse.delta.identity(); + this.mouse.length = 0; + } + break; + + case 'keydown': + if (!this.keysDown[event.keyCode]) { + this.keysDown[event.keyCode] = true; + this.keyDown(event.keyCode); + } + break; + + case 'keyup': + this.keysDown[event.keyCode] = false; + + this.keyUp(event.keyCode); + break; + + case 'blur': + this.focus = false; + break; + + case 'focus': + this.lastTime = new Date().getTime(); + this.focus = true; + break; } } } + }, { + key: '_addEventsListeners', + value: function _addEventsListeners() { + this.image.addEventListener('mousedown', this); + this.image.addEventListener('mouseup', this); + this.image.addEventListener('mousemove', this); + this.image.addEventListener('touchstart', this); + this.image.addEventListener('touchmove', this); + this.image.addEventListener('touchend', this); + } + }, { + key: '_removeEventListeners', + value: function _removeEventListeners() { + this.image.removeEventListener('mousedown', this); + this.image.removeEventListener('mouseup', this); + this.image.removeEventListener('mousemove', this); + this.image.removeEventListener('touchstart', this); + this.image.removeEventListener('touchmove', this); + this.image.removeEventListener('touchend', this); + } + }, { + key: 'setCanvas', + value: function setCanvas(canvas) { + if (this.image instanceof Node) { + this._removeEventListeners(); + var imageData = this.context.getImageData(0, 0, this.width, this.height); + this.clear(); + } - if (remove && this.loop) { + this.image = canvas; + this.context = canvas.getContext('2d'); + this.clear(); + + this._addEventsListeners(); + + if (imageData !== undefined) { + this.context.putImageData(imageData, 0, 0); + } + + return this; + } + }, { + key: 'add', + value: function add() { + if (this.loop) { + for (var i = 0; i < arguments.length; i++) { + var object = arguments[i]; + this.itemsToAdd.push(object); + } + } else { + for (var i = 0; i < arguments.length; i++) { + var object = arguments[i]; + if (this.objects.indexOf(object) === -1) { + object.parent = this; + this.objects.push(object); + if (object.init) { + object.init(this); + } + } + } + this.sort(); + } + + return this; + } + }, { + key: 'remove', + value: function remove() { + if (this.loop) { + for (var i = 0; i < arguments.length; i++) { + var object = arguments[i]; + this.itemsToRemove.push(object); + } + } else { + for (var i = 0; i < arguments.length; i++) { + var object = arguments[i]; + this.objects.remove(object); + if (object.active && object.remove !== undefined) { + object.parent = false; + object.remove(this); + } + } + } + } + }, { + key: 'handleAdded', + value: function handleAdded() { + for (var i = 0; i < this.itemsToAdd.length; i++) { + var object = this.itemsToAdd[i]; + this.add(object); + } + + for (var i = 0; i < this.itemsToRemove.length; i++) { + var object = this.itemsToRemove[i]; + this.remove(object); + } + } + }, { + key: 'sort', + value: function sort() { + this.objects.sort(function (a, b) { + return (a.depth || 0) - (b.depth || 0); + }); + } + }, { + key: 'keyDown', + value: function keyDown(keyCode) { + this.loop = true; + for (var i = this.objects.length - 1; i >= 0; i--) { + var object = this.objects[i]; + if (object.active && object.keyDown !== undefined) { + if (object.keyDown(keyCode, this)) { + break; + } + } + } + this.loop = false; + this.handleAdded(); + } + }, { + key: 'keyUp', + value: function keyUp(keyCode) { + this.loop = true; + for (var i = this.objects.length - 1; i >= 0; i--) { + var object = this.objects[i]; + if (object.active && object.keyUp !== undefined) { + if (object.keyUp(keyCode, this)) { + break; + } + } + } + this.loop = false; + this.handleAdded(); + } + }, { + key: 'mouseDown', + value: function mouseDown(mouse) { + var position = mouse.position.applyMatrix(this.inverseMatrix()); + var start = mouse.start.applyMatrix(this.inverseMatrix()); + + var mouse = { + position: position, + start: start, + delta: position.subtract(start), + length: mouse.length * this.sx * this.sy, + down: mouse.down + }; + + this.loop = true; + for (var i = this.objects.length - 1; i >= 0; i--) { + var object = this.objects[i]; + if (object.useCanvas !== true && object.active && object.mouseDown !== undefined) { + if (object.mouseDown(mouse, this)) { + break; + } + } + } + this.loop = false; + this.handleAdded(); + } + }, { + key: 'mouseUp', + value: function mouseUp(mouse) { + var position = mouse.position.applyMatrix(this.inverseMatrix()); + var start = mouse.start.applyMatrix(this.inverseMatrix()); + + var mouse = { + position: position, + start: start, + delta: position.subtract(start), + length: mouse.length * this.sx * this.sy, + down: mouse.down + }; + + this.loop = true; + for (var i = this.objects.length - 1; i >= 0; i--) { + var object = this.objects[i]; + if (object.useCanvas !== true && object.active && object.mouseUp !== undefined) { + if (object.mouseUp(mouse, this)) { + break; + } + } + } + this.loop = false; + this.handleAdded(); + } + }, { + key: 'mouseMove', + value: function mouseMove(mouse) { + var position = mouse.position.applyMatrix(this.inverseMatrix()); + var start = mouse.start.applyMatrix(this.inverseMatrix()); + + var mouse = { + position: position, + start: start, + delta: position.subtract(start), + length: mouse.length * this.sx * this.sy, + down: mouse.down + }; + + this.loop = true; + for (var i = this.objects.length - 1; i >= 0; i--) { + var object = this.objects[i]; + if (object.useCanvas !== true && object.active && object.mouseMove !== undefined) { + if (object.mouseMove(mouse, this)) { + break; + } + } + } + this.loop = false; + this.handleAdded(); + } + }, { + key: 'step', + value: function step(deltaTime) { + + this.loop = true; + for (var i = 0; i < this.objects.length; i++) { + var object = this.objects[i]; + if (object.active && object.step !== undefined) { + if (object instanceof CAL.Group && !object.useCanvas) { + if (object.clearCanvas || object.autoClearCanvas) { + this.clearCanvas = true; + } + if (object.drawCanvas || object.autoDrawCanvas) { + this.drawCanvas = true; + } + } + + object.step(deltaTime, this); + } + } + this.loop = true; + + if ((this.clearCanvas || this.autoClearCanvas) && this.useCanvas) { + this.clear(); + } + if ((this.drawCanvas || this.autoDrawCanvas) && this.useCanvas) { + this.draw(); + } + + this.clearCanvas = false; + this.drawCanvas = false; + } + }, { + key: 'cycle', + value: function cycle() { + if (this.focus) { + var currentTime = new Date().getTime(); + var deltaTime = currentTime - this.lastTime; + this.lastTime = currentTime; + + this.step(deltaTime); + } + } + }, { + key: 'draw', + value: function draw(context, matrix) { + context = this.useCanvas ? this.context : context; + matrix = this.useCanvas ? this : matrix; + + this.loop = true; + for (var i = 0; i < this.objects.length; i++) { + var object = this.objects[i]; + if (object.useCanvas !== true && object.visible && object.draw !== undefined) { + if (object instanceof CAL.Matrix) { + object.draw(context, object.multiplyMatrix(matrix)); + } else { + object.draw(context, matrix); + } + } + } + this.loop = false; + this.handleAdded(); + } + }]); + + return _class; +})(CAL.Surface); +"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(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } 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 _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) subClass.__proto__ = superClass; } + +CAL.Image = (function (_CAL$Draw) { + var _class = function _class(source, centerX, centerY, numberWidth, numberHeight, options) { + _classCallCheck(this, _class); + + options = options || {}; + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, centerX, centerY, numberWidth, numberHeight, options); + + this.image = new Image(); + this.source = source; + }; + + _inherits(_class, _CAL$Draw); + + _createClass(_class, [{ + key: "load", + value: function load(callback) { + var scope = this; + this.image.onload = function () { + scope.loaded = true; + + scope.width = scope.image.width / scope.numberWidth; + scope.height = scope.image.height / scope.numberHeight; + + if (callback !== undefined) { + callback(); + } + }; + this.image.src = this.source; + + return this; + } + }]); + + return _class; +})(CAL.Draw); +"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"); } } + +CAL.Loader = (function () { + var _class = function _class(objects) { + _classCallCheck(this, _class); + + this.objects = objects || []; + }; + + _createClass(_class, [{ + key: "add", + value: function add() { + for (var i = 0; i < arguments.length; i++) { + var object = arguments[i]; + if (this.objects.indexOf(object) === -1) { + this.objects.push(object); + } + } + + return this; + } + }, { + key: "remove", + value: function remove() { + for (var i = 0; i < arguments.length; i++) { + var object = arguments[i]; + this.objects.remove(object); + } + + return this; + } + }, { + key: "load", + value: function load(callback) { + var objectsToLoad = this.objects.length; + for (var i = 0; i < this.objects.length; i++) { + var object = this.objects[i]; + object.load(function () { + objectsToLoad -= 1; + if (objectsToLoad === 0 && callback !== undefined) { + callback(); + } + }, this); + }; + + return this; + } + }]); + + return _class; +})(); +"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"); } } + +CAL.Tween = (function () { + var _class = function _class(object, attributes, duration, options) { + _classCallCheck(this, _class); + + options = options || {}; + + this.visible = false; + this.active = true; + this.depth = -10000; + + this.object = object; + this.attributes = attributes; + this.timer = 0; + this.duration = duration; + this.easing = options.easing || CAL.Easings.linear; + this.callback = options.callback; + + this.begin = {}; + for (var i in attributes) { + this.begin[i] = this.object[i]; + } + + this.change = {}; + for (var i in attributes) { + this.change[i] = attributes[i] - this.begin[i]; + } + + this.drawCanvas = options.drawCanvas !== undefined ? options.drawCanvas : true; + this.clearCanvas = options.clearCanvas !== undefined ? options.clearCanvas : false; + }; + + _createClass(_class, [{ + key: "start", + value: function start() { this.t = 0; + this.active = true; + + return this; } - else if (remove && this.autoRemove) { - CAL.Scene.remove(this); + }, { + key: "stop", + value: function stop() { + this.t = 0; + this.active = false; + + return this; } - this.t = newTime; - } -}; + }, { + key: "pause", + value: function pause() { + this.active = false; -CAL.Shape = function (options) { - options = options || {}; - CAL.Matrix.call(this, options); - - this.visible = options.visible !== undefined ? options.visible : true; - this.active = false; - this.depth = options.depth || 0; - this.lines = []; - - this.closePath = options.closePath !== undefined ? options.closePath : true; - this.lineColor = options.lineColor !== undefined ? options.lineColor : new CAL.Color(); - this.shapeColor = options.shapeColor !== undefined ? options.shapeColor : new CAL.Color(); - this.lineWidth = options.lineWidth || 1; - this.lineJoin = options.lineJoin || "miter"; - this.lineCap = options.lineCap || "square"; - - this.points = options.points || []; -}; -CAL.Shape.prototype = Object.create(CAL.Matrix.prototype); -CAL.Shape.prototype.addPoint = function () { - for (var i = 0; i < arguments.length; i ++) { - var point = arguments[i]; - this.points.push(point); - } - //this.update(); -}; -CAL.Shape.prototype.hit = function (x, y) { - - for (var i = 0; i < this.points.length; i ++) { - if (new CAL.Vector(x, y).subtract(this.points[i].applyMatrix(this)).dot(this.getNormal(i)) > 0) { - return false; + return this; } - } + }, { + key: "resume", + value: function resume() { + this.active = true; - return true; -}; -CAL.Shape.prototype.setContext = function (context, matrix) { - var matrix = matrix || this; - context.beginPath(); - for (var i = 0; i < this.points.length; i ++) { - var point = this.points[i].applyMatrix(matrix); - context.lineTo(point.x, point.y); - } - if (this.closePath) { - context.closePath(); - } -}; -CAL.Shape.prototype.getBoundingBox = function () { - var minX = Infinity; - var minY = Infinity; - var maxX = -Infinity; - var maxY = -Infinity; + return this; + } + }, { + key: "step", + value: function step(deltaTime, group) { + this.timer += deltaTime; - for (var i = 0; i < this.points.length; i ++) { - var point = this.points[i]; - minX = point.x < minX ? point.x : minX; - minY = point.y < minY ? point.y : minY; - maxX = point.x > maxX ? point.x : maxX; - maxY = point.y > maxY ? point.y : maxY; + if (this.timer < this.duration) { + for (var i in this.attributes) { + var dt = this.timer; + var d = this.duration; + var b = this.begin[i]; + var c = this.change[i]; + + this.object[i] = this.easing(dt, b, c, d); + } + } else { + for (var i in this.attributes) { + this.object[i] = this.attributes[i]; + } + + if (this.callback !== undefined) { + this.callback(); + } + group.remove(this); + } + + if (this.clearCanvas) { + group.clearCanvas = true; + } + if (this.drawCanvas) { + group.drawCanvas = true; + } + } + }]); + + return _class; +})(); +"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"); } } + +CAL.TimeLine = (function () { + var _class = function _class(options) { + _classCallCheck(this, _class); + + options = options || {}; + + this.visible = false; + this.active = true; + this.depth = -10000; + + this.moments = []; + this.autoRemove = options.autoRemove !== undefined ? options.autoremove : true; + this.loop = options.loop !== undefined ? options.loop : false; + this.t = 0; }; - return {x: minX, y: minY, width: maxX-minX, height: maxY-minY}; -}; -CAL.Shape.prototype.getNormal = function (i) { - var pointA = this.points[(i+1)%this.points.length].applyMatrix(this); - var pointB = this.points[i].applyMatrix(this); - return pointA.subtract(pointB).normal().normalize(); -}; -CAL.Shape.prototype.clip = function (context, matrix) { - this.setContext(context, matrix); - context.clip(); -}; -CAL.Shape.prototype.fill = function (context, matrix) { - this.setContext(context, matrix); + _createClass(_class, [{ + key: "addMoment", + value: function addMoment(time, callback) { + this.moments.push({ + time: time, + callback: callback + }); - this.shapeColor.setFill(context); - - context.fill(); -}; -CAL.Shape.prototype.stroke = function (context, matrix) { - this.setContext(context, matrix); - - context.lineColor = this.lineColor; - context.lineWidth = this.lineWidth; - context.lineJoin = this.lineJoin; - context.lineCap = this.lineCap; - - this.lineColor.setStroke(context); - - context.stroke(); -}; -CAL.Shape.prototype.draw = function (context, matrix) { - this.setContext(context, matrix); - - if (this.shapeColor) { - this.shapeColor.setFill(context); - context.fill(); - } - - if (this.lineColor) { - context.lineColor = this.lineColor; - context.lineWidth = this.lineWidth; - context.lineJoin = this.lineJoin; - context.lineCap = this.lineCap; - this.lineColor.setStroke(context); - context.stroke(); - } -}; - -CAL.BezierPoint = function (position, controlPointA, controlPointB) { - this.position = position || new CAL.Vector(0, 0); - this.controlPointA = controlPointA || new CAL.Vector(0, 0); - this.controlPointB = controlPointB || new CAL.Vector(0, 0); -} -CAL.BezierPoint.prototype.applyMatrix = function (matrix) { - var position = this.position.applyMatrix(matrix); - var controlPointA = this.controlPointA.applyMatrix(matrix); - var controlPointB = this.controlPointB.applyMatrix(matrix); - - return new CAL.BezierPoint(position, controlPointA, controlPointB); -}; -CAL.BezierPoint.prototype.draw = function (context) { - var leftHandle = this.controlPointA.add(this.position); - var rightHandle = this.controlPointB.add(this.position); - - context.strokeStyle = "#09F"; - - context.beginPath(); - context.moveTo(leftHandle.x, leftHandle.y); - context.lineTo(this.position.x, this.position.y); - context.lineTo(rightHandle.x, rightHandle.y); - context.stroke(); - - context.beginPath(); - context.arc(this.position.x, this.position.y, 10, 0, Math.PI*2, true); - context.stroke(); - - context.beginPath(); - context.arc(leftHandle.x, leftHandle.y, 5, 0, Math.PI*2, true); - context.stroke(); - - context.beginPath(); - context.arc(rightHandle.x, rightHandle.y, 5, 0, Math.PI*2, true); - context.stroke(); -}; -/*CAL.Shape = function (options) { - options = options || {}; - CAL.Matrix.call(this, options); - - this.visible = options.visible !== undefined ? options.visible : true; - this.active = false; - this.depth = options.depth || 0; - - this.closePath = options.closePath !== undefined ? options.closePath : true; - this.lineColor = options.lineColor !== undefined ? options.lineColor : new CAL.Color(); - this.shapeColor = options.shapeColor !== undefined ? options.shapeColor : new CAL.Color(); - this.lineWidth = options.lineWidth || 1; - this.lineJoin = options.lineJoin || "miter"; - this.lineCap = options.lineCap || "square"; - - this.points = options.points || []; - this.precision = options.precision || 3; - - this.lines = []; - this.length = 0; - this.closed = false; -} -CAL.Shape.prototype.init = function (group) { - for (var i = 0; i < this.points.length; i ++) { - var point = this.points[i]; - if (point instanceof CAL.Vector) { - point = new CAL.BezierPoint(point); + return this; } - this.points[i] = point; - } + }, { + key: "removeMoment", + value: function removeMoment(remove) { + for (var i = 0; i < this.moments.length; i++) { + var moment = this.moments[i]; - this.update(); -}; -CAL.Shape.prototype.addPoint = function () { - for (var i = 0; i < arguments.length; i ++) { - var point = arguments[i]; + if (moment === remove || moment.time === remove || moment.callback === remove) { + this.moments.remove(moment); + } + } - if (point instanceof CAL.Vector) { - point = new CAL.BezierPoint(point); + return this; } - if (point instanceof CAL.BezierPoint) { - this.points.push(point); + }, { + key: "start", + value: function start() { + this.t = 0; + this.active = true; + + return this; } - } + }, { + key: "stop", + value: function stop() { + this.t = 0; + this.active = false; - this.update(); -}; -CAL.Shape.prototype.collisionBox = function (vec1, vec2) { - for (var i = 0; i < this.lines.length; i ++) { - var point = this.lines[i]; + return this; + } + }, { + key: "pause", + value: function pause() { + this.active = false; + + return this; + } + }, { + key: "resume", + value: function resume() { + this.active = true; + + return this; + } + }, { + key: "step", + value: function step(dt) { + var newTime = this.t + dt; + var remove = true; + + for (var i = 0; i < this.moments.length; i++) { + var moment = this.moments[i]; + if (moment.time >= this.t) { + if (moment.time < newTime) { + moment.callback(); + } else { + remove = false; + } + } + } + + if (remove && this.loop) { + this.t = 0; + } else if (remove && this.autoRemove) { + this.parent.remove(this); + } + + this.t = newTime; + } + }]); + + return _class; +})(); +"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"); } } + +CAL.BezierPoint = (function () { + var _class = function _class(position, handleIn, handleOut) { + _classCallCheck(this, _class); + + this.position = position || new CAL.Vector(); + this.handleIn = handleIn || new CAL.Vector().copy(position); + this.handleOut = handleOut || new CAL.Vector().copy(position); + }; + + _createClass(_class, [{ + key: "copy", + value: function copy(bezierPoint) { + this.position.copy(bezierPoint.position); + this.handleIn.copy(bezierPoint.handleIn); + this.handleOut.copy(bezierPoint.handleOut); + } + }, { + key: "applyMatrix", + value: function applyMatrix(matrix) { + var position = this.position.applyMatrix(matrix); + var handleIn = this.handleIn.applyMatrix(matrix); + var handleOut = this.handleOut.applyMatrix(matrix); + + return new CAL.BezierPoint(position, handleIn, handleOut); + } + }, { + key: "draw", + value: function draw(context) { + var handleIn = this.handleIn.add(this.position); + var handleOut = this.handleOut.add(this.position); + + context.strokeStyle = "#09F"; + + context.beginPath(); + context.moveTo(handleIn.x, handleIn.y); + context.lineTo(this.position.x, this.position.y); + context.lineTo(handleOut.x, handleOut.y); + context.stroke(); + + context.beginPath(); + context.arc(this.position.x, this.position.y, 10, 0, Math.PI * 2, true); + context.stroke(); + + context.beginPath(); + context.arc(handleIn.x, handleIn.y, 5, 0, Math.PI * 2, true); + context.stroke(); + + context.beginPath(); + context.arc(handleOut.x, handleOut.y, 5, 0, Math.PI * 2, true); + context.stroke(); + } + }]); + + return _class; +})(); +"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(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } 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 _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) subClass.__proto__ = superClass; } + +CAL.Shape = (function (_CAL$Matrix) { + var _class = function _class(options) { + _classCallCheck(this, _class); + + options = options || {}; + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options); + + this.visible = options.visible !== undefined ? options.visible : true; + this.active = false; + this.depth = options.depth || 0; + this.lines = []; + + this.closePath = options.closePath !== undefined ? options.closePath : true; + this.lineColor = options.lineColor !== undefined ? options.lineColor : new CAL.Color(); + this.shapeColor = options.shapeColor !== undefined ? options.shapeColor : new CAL.Color(); + this.lineWidth = options.lineWidth || 1; + this.lineJoin = options.lineJoin || "round"; + this.lineCap = options.lineCap || "round"; + + this.points = []; + if (options.points) { + for (var i = 0; i < options.points.length; i++) { + var point = options.points[i]; + this.addPoint(point); + } + } + }; + + _inherits(_class, _CAL$Matrix); + + _createClass(_class, [{ + key: "addPoint", + value: function addPoint() { + for (var i = 0; i < arguments.length; i++) { + var point = arguments[i]; + + if (point instanceof CAL.Vector) { + point = new CAL.BezierPoint(point); + } + + this.points.push(point); + } + + return this; + } + }, { + key: "applyMatrix", + value: function applyMatrix(matrix) { + for (var i = 0; i < this.points.length; i++) { + var point = this.points[i]; + point.copy(point.applyMatrix(matrix)); + } + + return this; + } + }, { + key: "hit", + value: function hit(vector, matrix) { + if (matrix instanceof CAL.Matrix) { + vector = vector.applyMatrix(matrix.multiplyMatrix(this.inverseMatrix())); + } else { + vector = vector.applyMatrix(this.inverseMatrix()); + } + + if (this.points.length <= 3) { + return false; + } + + for (var i = 0; i < this.points.length; i++) { + if (vector.subtract(this.points[i].position).dot(this.getNormal(i)) > 0) { + return false; + } + } - if (point.x > vec1.x && point.y > vec1.y && point.x < vec2.x && point.y < vec2.y) { return true; } - } - return false; -}; -CAL.Shape.prototype.getNormal = function (i) { - var pointA = this.lines[(i+1)%this.lines.length].applyMatrix(this); - var pointB = this.lines[i].applyMatrix(this); - return pointA.subtract(pointB).normal().normalize(); -}; -CAL.Shape.prototype.collisionPoint = function (x, y) { - for (var i = 0; i < this.lines.length; i ++) { - if (new CAL.Vector(x, y).subtract(this.lines[i].applyMatrix(this)).dot(this.getNormal(i)) > 0) { - return false; - } - } + }, { + key: "getBoundingBox", + value: function getBoundingBox() { + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; - return true; -}; -CAL.Shape.prototype.removePoint = function () { - for (var i = 0; i < arguments.length; i ++) { + for (var i = 0; i < this.points.length; i++) { + var point = this.points[i].position; - var argument = arguments[i]; - - if (typeof argument === "number") { - var index = argument; - } - else if (argument instanceof CAL.BezierPoint || argument instanceof CAL.Vector) { - var index = this.getPointIndex(argument); - } - - if (index !== -1) { - this.points.splice(index, 1); - } - } - - this.update(); -}; - -CAL.Shape.prototype.getPointIndex = function (point) { - if (point instanceof CAL.BezierPoint) { - return this.points.indexOf(argument); - } - else if (point instanceof CAL.Vector) { - for (i = 0; i < this.points.length; i ++) { - var length = this.points[i].position.subtract(point).length(); - - if (length === 0) { - return i; + minX = point.x < minX ? point.x : minX; + minY = point.y < minY ? point.y : minY; + maxX = point.x > maxX ? point.x : maxX; + maxY = point.y > maxY ? point.y : maxY; } - } - return -1; - } -}; - -CAL.Shape.prototype.numberPoints = function () { - return this.points.length; -}; - -CAL.Shape.prototype.insertPoint = function (point, index) { - if (point instanceof CAL.Vector) { - point = new CAL.BezierPoint(point); - } - if (point instanceof CAL.BezierPoint) { - this.points.splice(index, 0, point); - - this.update(); - } -}; -CAL.Shape.prototype.setClosed = function (closed) { - this.closed = closed; - this.update(); -}; - -CAL.Shape.prototype.setPrecision = function (precision) { - this.precision = precision; - this.update(); -}; - -CAL.Shape.prototype.makeSmooth = function (strength, start, end) { - start = start || 0; - end = end || this.points.length; - - if (this.closed === false) { - start = Math.max(start, 1); - end = Math.min(end, this.points.length-1); - } - else { - start = Math.max(start, 0); - end = Math.min(end, this.points.length); - } - - for (var i = start; i < end; i ++) { - var p0 = this.points[i-1]; - var p1 = this.points[i]; - var p2 = this.points[i+1]; - - if (typeof(p0) === "undefined") { - p0 = this.points[this.points.length-1]; - } - else if (typeof(p2) === "undefined") { - p2 = this.points[0]; - } - - var a = p0.position.subtract(p1.position); - var b = p2.position.subtract(p1.position); - - var length = (a.length()+b.length())/4; - - var direction = a.normalize().add(b.scale(-1).normalize()).normalize(); - - p1.controlPointA = direction.scale(length*strength); - p1.controlPointB = direction.scale(-length*strength); - } - - this.update(); -}; - -CAL.Shape.prototype.calculateBezierPoints = function (p0, p1) { - var array = []; - - if (p0.controlPointB.length() === 0 && p1.controlPointA.length() === 0) { - var angle = p1.position.subtract(p0.position).angle(); - - array.push({ - x: p0.position.x, - y: p0.position.y, - angle: angle - }, { - x: p1.position.x, - y: p1.position.y, - angle: angle - }); - } - else { - var point = { - x: p1.position.x, - y: p1.position.y, - angle: p1.controlPointB.direction() - } - - array = array.concat( - recursiveBezier( - p0.position, - p0.position.add(p0.controlPointB), - p1.position.add(p1.controlPointA), - p1.position, - this.precision - ), - [point] - ); - } - - return array; -}; - -CAL.Shape.prototype.update = function () { - if (this.points.length >= 2) { - if (this.points[0].controlPointB.length() !== 0) { - var point = { - x: this.points[0].position.x, - y: this.points[0].position.y, - angle: this.points[0].controlPointB.direction() - }; - this.lines = [point]; - } - - for (var i = 0; i < this.points.length-1; i ++) { - var p0 = this.points[i]; - var p1 = this.points[i+1]; - - this.lines = this.lines.concat(this.calculateBezierPoints(p0, p1)); - } - - if (this.closed === true) { - - var p0 = this.points[this.points.length-1]; - var p1 = this.points[0]; - - this.lines = this.lines.concat(this.calculateBezierPoints(p0, p1)); - } - - var pathLength = 0; - this.lines[0].position = 0; - - for (var i = 0; i < this.lines.length-1; i ++) { - - var p0 = this.lines[i]; - var p1 = this.lines[i+1]; - var line = new CAL.Vector(p1.x, p1.y).subtract(p0); - pathLength += line.length(); - - p1.position = pathLength; - } - - this.length = pathLength; - } -}; - -CAL.Shape.prototype.getPosition = function (t) { - var t = Math.max(Math.min(t, this.length), 0); - - for (var i = 1; true; i ++) { - var p0 = this.lines[i-1]; - var p1 = this.lines[i]; - - if (p1.position >= t) { - t = (t-p0.position) / (p1.position-p0.position); - - var position = new CAL.Vector(p0.x, p0.y).scale(1-t).add(new CAL.Vector(p1.x, p1.y).scale(t)); - var angle = p0.angle + ((((p1.angle-p0.angle)%360)+540)%360-180)*t; return { - x: position.x, - y: position.y, - angle: angle + top: minY, + left: minX, + bottom: maxY, + right: maxX, + width: maxX - minX, + height: maxY - minY }; } - } -}; + }, { + key: "getNormal", + value: function getNormal(i) { + var pointA = this.points[(i + 1) % this.points.length].position; + var pointB = this.points[i].position; -CAL.Shape.prototype.setContextPart = function (context, begin, end) { - var beginPos = this.getPosition(begin); - var endPos = this.getPosition(end); + return pointA.subtract(pointB).normal().normalize(); + } + }, { + key: "setContext", + value: function setContext(context, matrix) { + var matrix = matrix || this; - context.beginPath(); - context.moveTo(beginPos.x, beginPos.y); + context.beginPath(); - for (var i = 0; i < this.lines.length; i ++) { - var line = this.lines[i]; + var currentPoint = this.points[0].applyMatrix(matrix); - if (line.position > begin) { + context.moveTo(currentPoint.position.x, currentPoint.position.y); - context.lineTo(line.x, line.y); - if (line.position > end) { - break; + var length = this.closePath ? this.points.length + 1 : this.points.length; + for (var i = 1; i < length; i++) { + var prevPoint = currentPoint; + var currentPoint = this.points[i % this.points.length].applyMatrix(matrix); + + var handleOut = prevPoint.handleOut; + var handleIn = currentPoint.handleIn; + var position = currentPoint.position; + + context.bezierCurveTo(handleOut.x, handleOut.y, handleIn.x, handleIn.y, position.x, position.y); + } + + return this; + } + }, { + key: "clip", + value: function clip(context, matrix) { + this.setContext(context, matrix); + context.clip(); + + return this; + } + }, { + key: "fill", + value: function fill(context, matrix) { + this.setContext(context, matrix); + + this.shapeColor.setFill(context); + + context.fill(); + + return this; + } + }, { + key: "stroke", + value: function stroke(context, matrix) { + this.setContext(context, matrix); + + context.lineColor = this.lineColor; + context.lineWidth = this.lineWidth; + context.lineJoin = this.lineJoin; + context.lineCap = this.lineCap; + + this.lineColor.setStroke(context); + + context.stroke(); + + return this; + } + }, { + key: "draw", + value: function draw(context, matrix) { + this.setContext(context, matrix); + + if (this.shapeColor) { + this.shapeColor.setFill(context); + context.fill(); + } + + if (this.lineColor) { + context.lineColor = this.lineColor; + context.lineWidth = this.lineWidth; + context.lineJoin = this.lineJoin; + context.lineCap = this.lineCap; + this.lineColor.setStroke(context); + context.stroke(); } } - } - context.lineTo(endPos.x, endPos.y); -}; + }]); -CAL.Shape.prototype.setContext = function (context) { - this.setContextPart(context, 0, this.length); -}; + return _class; +})(CAL.Matrix); +"use strict"; -CAL.Shape.prototype.setClippingPart = function (context, begin, end) { - context.save(); - this.setContextPart(begin, end); - context.clip(); -}; +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; }; })(); -CAL.Shape.prototype.setClipping = function (context) { - this.setClippingPart(context, 0, this.length); -}; +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; -CAL.Shape.prototype.drawPart = function (context, begin, end, color, width, cap) { - this.setContextPart(context, begin, end); - - context.strokeStyle = color || "black"; - context.lineWidth = width || 1; - context.lineCap = cap || 'butt'; - context.stroke(); -}; -CAL.Shape.prototype.setContext = function (context, matrix) { - var matrix = matrix || this; - context.beginPath(); - for (var i = 0; i < this.lines.length; i ++) { - var point = this.lines[i]//.applyMatrix(matrix); - context.lineTo(point.x, point.y); - } - if (this.closePath) { - context.closePath(); - } -}; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -CAL.Shape.prototype.fill = function (context, matrix) { - this.setContext(context, matrix); +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) subClass.__proto__ = superClass; } - this.shapeColor.setFill(context); +CAL.Text = (function (_CAL$Matrix) { + var _class = function _class(options) { + _classCallCheck(this, _class); - context.fill(); -}; -CAL.Shape.prototype.stroke = function (context, matrix) { - this.setContext(context, matrix); - context.lineColor = this.lineColor; - context.lineWidth = this.lineWidth; - context.lineJoin = this.lineJoin; - context.lineCap = this.lineCap; + options = options || {}; + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options); - this.lineColor.setStroke(context); + this.visible = options.visible !== undefined ? options.visible : true; + this.active = options.active !== undefined ? options.active : true; + this.depth = options.depth || 0; + this.text = options.text || ""; + this.style = options.style || "normal"; + this.variant = options.variant || "normal"; + this.weight = options.weight || "normal"; + this.size = options.size || 12; + this.font = options.font || "Arial"; + this.align = options.align || "left"; + this.baseline = options.baseline || "bottom"; - context.stroke(); -}; + this.textAlign = options.textAlign || "left"; -CAL.Shape.prototype.draw = function (context, matrix) { - if (this.shapeColor) { - this.shapeColor.setFill(context); - context.fill(); - } - - if (this.lineColor) { - this.stroke(context, matrix); - } - this.debugDraw(context); -}; -CAL.Shape.prototype.debugDraw = function (context) { - context.beginPath(); - context.lineWidth = 1; - - for (var i = 0; i < this.points.length; i ++) { - var point = this.points[i]; - - point.draw(context); - } - - context.beginPath(); - - for (var i = 0; i < this.lines.length; i ++) { - var point = this.lines[i]; - - context.lineTo(point.x, point.y); - context.arc(point.x, point.y, 2, 0, Math.PI*2, true); - context.lineTo(point.x, point.y); - } - - context.strokeStyle = "black"; - context.stroke(); -}; - -CAL.Shape.prototype.getSize = function () { - var width = 0; - var height = 0; - - for (var i = 0; i < this.lines.length; i ++) { - var line = this.lines[i]; - - width = Math.max(width, Math.ceil(line.x)); - height = Math.max(width, Math.ceil(line.y)); - } - - return { - width: width, - height: height + this.color = options.color || new CAL.Color(); + this.alpha = typeof options.alpha === "number" ? options.alpha : 1; }; -}; + _inherits(_class, _CAL$Matrix); -CAL.BezierPoint = function (position, controlPointA, controlPointB) { - this.position = position || new CAL.Vector(0, 0); - this.controlPointA = controlPointA || new CAL.Vector(0, 0); - this.controlPointB = controlPointB || new CAL.Vector(0, 0); -} -CAL.BezierPoint.prototype.applyMatrix = function (matrix) { - var position = this.position.applyMatrix(matrix); - var controlPointA = this.controlPointA.applyMatrix(matrix); - var controlPointB = this.controlPointB.applyMatrix(matrix); + _createClass(_class, [{ + key: "measure", + value: function measure(text) { + text = text || this.text; - return new CAL.BezierPoint(position, controlPointA, controlPointB); -}; -CAL.BezierPoint.prototype.draw = function (context) { - var leftHandle = this.controlPointA.add(this.position); - var rightHandle = this.controlPointB.add(this.position); + context.font = [this.style, this.variant, this.weight, this.size + "px", this.font].join(" "); - context.strokeStyle = "#09F"; - - context.beginPath(); - context.moveTo(leftHandle.x, leftHandle.y); - context.lineTo(this.position.x, this.position.y); - context.lineTo(rightHandle.x, rightHandle.y); - context.stroke(); - - context.beginPath(); - context.arc(this.position.x, this.position.y, 10, 0, Math.PI*2, true); - context.stroke(); - - context.beginPath(); - context.arc(leftHandle.x, leftHandle.y, 5, 0, Math.PI*2, true); - context.stroke(); - - context.beginPath(); - context.arc(rightHandle.x, rightHandle.y, 5, 0, Math.PI*2, true); - context.stroke(); -}; - -function recursiveBezier (p1, p2, p3, p4, precision) { - //source: http://antigrain.com/research/adaptive_bezier/ - //source: http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Derivative - - var p12 = p1.add(p2).scale(0.5); - var p23 = p2.add(p3).scale(0.5); - var p34 = p3.add(p4).scale(0.5); - var p123 = p12.add(p23).scale(0.5); - var p234 = p23.add(p34).scale(0.5); - var p1234 = p123.add(p234).scale(0.5); - - var d = p4.subtract(p1); - - var d2 = Math.abs((p2.x - p4.x) * d.y - (p2.y - p4.y) * d.x); - var d3 = Math.abs((p3.x - p4.x) * d.y - (p3.y - p4.y) * d.x); - - //if (Math.abs(p1.x + p3.x - p2.x - p2.x) + Math.abs(p1.y + p3.y - p2.y - p2.y) + Math.abs(p2.x + p4.x - p3.x - p3.x) + Math.abs(p2.y + p4.y - p3.y - p3.y) <= precision) { - if (Math.pow((d2 + d3), 2) < precision * d.dot(d)) { - - //var t = 0.5; - //var derivative = (p2.subtract(p1)).scale(Math.pow(3*(1-t), 2)).add((p3.subtract(p2)).scale(6*(1-t)*t)).add((p4.subtract(p3)).scale(Math.pow(3*t, 2))); - var derivative = (p2.subtract(p1)).scale(2.25).add((p3.subtract(p2)).scale(1.5)).add((p4.subtract(p3)).scale(2.25)); - - var point = { - x: p1234.x, - y: p1234.y, - angle: derivative.direction() + return context.measureText(text).width; } + }, { + key: "drawText", + value: function drawText(context, text, x, y) { + context.font = [this.style, this.variant, this.weight, this.size + "px", this.font].join(" "); - return [point]; - } - else { + context.textAlign = this.align; + context.textBaseline = this.baseline; - return [].concat( - recursiveBezier(p1, p12, p123, p1234, precision), - recursiveBezier(p1234, p234, p34, p4, precision) - ); - } -}*/ + this.color.setColor(context); -CAL.Text = function (options) { - options = options || {}; - CAL.Matrix.call(this, options); - - this.visible = options.visible !== undefined ? options.visible : true; - this.active = options.active !== undefined ? options.active : true; - this.depth = options.depth || 0; - this.text = options.text || ""; - this.style = options.style || "normal"; - this.variant = options.variant || "normal"; - this.weight = options.weight || "normal"; - this.size = options.size || 12; - this.font = options.font || "Arial"; - - this.textAlign = options.textAlign || "left"; - - this.color = options.color || new CAL.Color(); - this.alpha = typeof options.alpha === "number" ? options.alpha : 1; -}; -CAL.Text.prototype = Object.create(CAL.Matrix.prototype); -CAL.Text.prototype.drawText = function (context, text, x, y) { - context.font = [this.style, this.variant, this.weight, this.size+"px", this.font].join(" "); - context.textAlign = this.textAlign; - this.color.setColor(context); - context.fillText(text, x, y); -}; -CAL.Text.prototype.drawTextAlpha = function (context, text, x, y, apha) { - context.font = [this.style, this.variant, this.weight, this.size+"px", this.font].join(" "); - context.globalAlpha = apha; - this.color.setColor(context); - context.fillText(text, x, y); - context.globalAlpha = 1; -}; -CAL.Text.prototype.draw = function (context, matrix) { - context.save(); - matrix.setContext(context); - context.globalAlpha = this.alpha; - this.drawText(context, this.text, 0, 0); - context.restore(); -}; -CAL.Text.prototype.clone = function () { - return new CAL.text({ - style : this.style, - variant : this.variant, - weight : this.weight, - size : this.size, - font : this.font, - color : this.color.clone() - }); -}; - -CAL.KeyListener = function (options) { - options = options || {}; - - this.visible = false; - this.active = options.active !== undefined ? option.active : true; - this.depth = -10000; - - this.actions = options.actions || {}; - - CAL.Scene.add(this); -}; -CAL.KeyListener.prototype.add = function (key, callback) { - this.actions[key] = callback; -}; -CAL.KeyListener.prototype.keyDown = function (key) { - if (this.actions[key]) { - this.actions[key](); - } -}; - -CAL.Physics = function () { - CAL.Scene.add(this); - this.depth = -1000; - this.active = true; - this.visible = false; - - this.objects = []; - this.manifolds = []; - this.forces = []; -} -CAL.Physics.prototype.keyDown = function () { - //DEBUG REASONS - //EASIER TO DEBUG ON KEYDOWN - - CAL.Scene.clear(); - - this.test(120); - - polygon.debugDraw(CAL.Scene.context); - box.debugDraw(CAL.Scene.context); - -}; -CAL.Physics.prototype.add = function () { - for (var i = 0; i < arguments.length; i ++) { - var object = arguments[i]; - - if (object instanceof CAL.PhysicsObject && this.objects.indexOf(object) === -1) { - for (var j = 0; j < this.objects.length; j ++) { - this.manifolds.push(new CAL.Manifold(object, this.objects[j])); - this.manifolds.push(new CAL.Manifold(this.objects[j], object)); - } - - this.objects.push(object); + context.fillText(text, x, y); } - else if (object instanceof CAL.Force && this.forces.indexOf(object) === -1) { - this.forces.push(object); + }, { + key: "drawTextAlpha", + value: function drawTextAlpha(context, text, x, y, apha) { + context.globalAlpha = apha; + + this.drawText(context, text, x, y); + + context.globalAlpha = 1; } - } -}; -CAL.Physics.prototype.test = function (dt) { - //var dt = 120; + }, { + key: "draw", + value: function draw(context, matrix) { + context.save(); - this.objects.foreach(function (object) { - object.step(dt); - }, this); + context.globalAlpha = this.alpha; + matrix.setMatrixContext(context); - this.forces.foreach(function (force) { - force.step(dt); - }, this); + this.drawText(context, this.text, 0, 0); - this.manifolds.foreach(function (manifold) { - manifold.step(dt); - }, this); - -}; - -CAL.Manifold = function (a, b) { - this.a = a; - this.b = b; - - this.normal; -}; -CAL.Manifold.prototype.checkCollision = function (dt) { - var collisionData = {collision: false}; - - this.b.shape.points.foreach(function (pointA, i) { - var pointA = pointA.applyMatrix(this.b.shape); - var collision = true; - var bestDistance = -Infinity; - var bestNormal; - - this.a.shape.points.foreach(function (pointB, j) { - var pointB = pointB.applyMatrix(this.a.shape); - var normal = this.a.shape.getNormal(j); - var distance = normal.dot(pointA.subtract(pointB)); - - if (distance > 0) { - collision = false; - return true; - } - else if (distance > bestDistance) { - bestDistance = distance; - bestNormal = normal; - } - }, this); - - if (collision) { - collisionData = {collision: true, penetrationDepth: -bestDistance, normal: bestNormal, impactPoint: pointA}; - - return true; + context.restore(); } - - }, this); - - return collisionData; - - /*this.a.shape.points.foreach(function (point, i) { - var normal = this.a.shape.getNormal(i); - var support = this.b.getSupport(normal.scale(-1)); - - var point = point.applyMatrix(this.a.shape); - var distance = normal.dot(support.subtract(point)); - - //if (distance > 0) { - // console.log("test"); - // bestDistance = 1; - // return true; - //} - if (distance > bestDistance || bestDistance === false) { - - //var velocity = this.b.velocity.add(this.b.getPointVelocity(support)); - //if (velocity.dot(normal) < 0 || velocity.length === 0) { - - bestDistance = distance; - bestNormal = normal; - bestImpactPoint = support; - //bestVelocity = velocity; - //} + }, { + key: "clone", + value: function clone() { + return new CAL.text({ + style: this.style, + variant: this.variant, + weight: this.weight, + size: this.size, + font: this.font, + color: this.color.clone() + }); } - }, this); + }]); - var i = 2; - var normal = this.a.shape.getNormal(i); - normal.scale(100).draw(CAL.Scene.context, 200, 200); - var support = this.b.getSupport(normal.scale(-1)); + return _class; +})(CAL.Matrix); +"use strict"; - var point = this.a.shape.points[i].applyMatrix(this.a.shape); - var distance = normal.dot(support.subtract(point)); +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; }; })(); - console.log(distance); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - CAL.Scene.context.beginPath(); - CAL.Scene.context.arc(support.x, support.y, 10, 0, Math.PI*2); - CAL.Scene.context.stroke(); +CAL.KeyListener = (function () { + var _class = function _class(options) { + _classCallCheck(this, _class); - return {collision: bestDistance < 0, penetrationDepth: bestDistance, normal: bestNormal, impactPoint: bestImpactPoint};*/ -}; -CAL.Manifold.prototype.positionalCorrection = function (collisionData) { - var percent = 0.2; // usually 20% to 80% - var slop = 0.1; // usually 0.01 to 0.1 + options = options || {}; - var correction = collisionData.normal.scale(Math.max(collisionData.penetrationDepth - slop, 0) / (1/this.a.mass + 1/this.b.mass) * percent); + this.visible = false; + this.active = options.active !== undefined ? options.active : true; + this.depth = -10000; - var aPos = correction.scale(1/this.a.mass); - this.a.shape._x += aPos.x; - this.a.shape._y += aPos.y; - this.a.shape.updateMatrix(); - - var bPos = correction.scale(1/this.b.mass); - this.b.shape._x -= bPos.x; - this.b.shape._y -= bPos.y; - this.b.shape.updateMatrix(); -}; -CAL.Manifold.prototype.resolveCollision = function (collisionData) { - var restVelocity = this.b.velocity.subtract(this.a.velocity); - - var velAlongNormal = restVelocity.dot(collisionData.normal); - if (velAlongNormal > 0) { - return; - } - var restitution = Math.min(this.a.restitution, this.b.restitution); - - var force = -(1 + restitution) * velAlongNormal / (1/this.a.mass + 1/this.b.mass); - - var impulse = collisionData.normal.scale(force); - - this.a.addForce(impulse.scale(-1), collisionData.impactPoint); - this.b.addForce(impulse, collisionData.impactPoint); -}; -CAL.Manifold.prototype.step = function (dt) { - var collisionData = this.checkCollision(); - - if (collisionData.collision) { - this.resolveCollision(collisionData); - this.positionalCorrection(collisionData); - } -}; - -CAL.PhysicsObject = function (options) { - options = options || {}; - - this.shape = options.shape || new CAL.Shape(); - this.velocity = options.velocity || new CAL.Vector(); - this.angularVelocity = options.angularVelocity !== undefined ? options.angularVelocity : 0; - this.restitution = options.restitution !== undefined ? options.restitution : 0.5; - this.density = options.density || 1; - this.updateMass(); -}; -CAL.PhysicsObject.prototype.calculateBoundingBox = function (matrix) { - matrix = matrix || this.shape; - - var minX = Infinity; - var minY = Infinity; - var maxX = -Infinity; - var maxY = -Infinity; - this.shape.points.foreach(function (point) { - var point = point.applyMatrix(matrix); - - minX = (point.x < minX) ? point.x : minX; - minY = (point.y < minY) ? point.y : minY; - maxX = (point.x > maxX) ? point.x : maxX; - maxY = (point.y > maxY) ? point.y : maxY; - }, this); - - return {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; -}; -CAL.PhysicsObject.prototype.addForce = function (impulse, contactVector) { - this.velocity = this.velocity.add(impulse.scale(1.0/this.mass)); - - /*if (contactVector !== undefined) { - this.angularVelocity += contactVector.subtract(this.centerOfMass.applyMatrix(this.shape)).cross(impulse)*(1.0/this.inertia); - //this.angularVelocity = contactVector.subtract(this.centerOfMass.applyMatrix(this.shape)).cross(impulse)*(1.0/this.inertia); - }*/ -}; -CAL.PhysicsObject.prototype.pointCollision = function (point) { - var point = point - .subtract(new CAL.Vector(this.shape.x, this.shape.y)) - .rotate(-this.shape.rotation) - .multiply(new CAL.Vector(1/this.shape.sx, 1/this.shape.sy)) - .subtract(new CAL.Vector(this.collisionMask.offsetX, this.collisionMask.offsetY)); - - if (point.x < 0) return false; - if (point.y < 0) return false; - if (point.x > this.collisionMask.width) return false; - if (point.y > this.collisionMask.height) return false; - - var i = Math.round(point.y)*this.collisionMask.width + Math.round(point.x); - return this.collisionMask.data[i]; -}; -CAL.PhysicsObject.prototype.setDensity = function (density) { - this.density = density; - this.mass = this.area*density; - this.inertia = this.mass*this.area; -}; -CAL.PhysicsObject.prototype.updateMass = function () { - var boundingBox = this.calculateBoundingBox(new CAL.Matrix()); - var surface = new CAL.Surface({x: boundingBox.maxX - boundingBox.minX, y: boundingBox.maxY - boundingBox.minY}); - this.shape.clip(surface.context, new CAL.Matrix({x: -boundingBox.minX, y: -boundingBox.minY})); - surface.context.fillStyle = "black"; - surface.context.fillRect(0, 0, surface.width, surface.height); - - var imageData = surface.getImageData(); - - var point = new CAL.Vector(); - var area = 0; - this.collisionMask = { - data: [], - width: imageData.width, - height: imageData.height, - offsetX: boundingBox.minX, - offsetY: boundingBox.minY + this.actions = options.actions || {}; }; - for (var i = 0; i < imageData.data.length; i += 4) { - var alpha = imageData.data[i + 3]; - if (alpha > 0) { - point = point.add(new CAL.Vector(i/4 % imageData.width, Math.floor(i/4/imageData.width))); - area ++; - this.collisionMask.data.push(true); + + _createClass(_class, [{ + key: "add", + value: function add(key, callback) { + this.actions[key] = callback; + + return this; } - else { - this.collisionMask.data.push(false); + }, { + key: "keyDown", + value: function keyDown(key) { + if (this.actions[key]) { + this.actions[key](); + } } - } - this.area = area/**this.sx*this.sy*/; - this.mass = area*this.density; - this.inertia = this.mass*area; - this.centerOfMass = point.scale(1/area).add(new CAL.Vector(boundingBox.minX, boundingBox.minY)); -}; -CAL.PhysicsObject.prototype.getSupport = function (n) { - var bestProjection = -Infinity; - var bestPoint; + }]); - for (var i = 0; i < this.shape.points.length; i ++) { - var point = this.shape.points[i].applyMatrix(this.shape); - var projection = point.dot(n); + return _class; +})(); +"use strict"; - if (projection > bestProjection) { - bestPoint = point; - bestProjection = projection; +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(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } 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 _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) subClass.__proto__ = superClass; } + +CAL.Star = (function (_CAL$Shape) { + var _class = function _class(rays, outerRadius, innerRadius, options) { + _classCallCheck(this, _class); + + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options); + + this.set(rays, outerRadius, innerRadius); + }; + + _inherits(_class, _CAL$Shape); + + _createClass(_class, [{ + key: "set", + value: function set(rays, outerRadius, innerRadius) { + this.rays = rays || 5; + this.outerRadius = outerRadius || 100; + this.innerRadius = innerRadius || 50; + + this.points = []; + + var even = true; + for (var rad = 0; rad < Math.PI * 2; rad += Math.PI / this.rays) { + var radius = even ? this.outerRadius : this.innerRadius; + + var x = Math.cos(rad) * radius; + var y = Math.sin(rad) * radius; + + this.addPoint(new CAL.BezierPoint(new CAL.Vector(x, y), null, null)); + + even = !even; + } } - } + }, { + key: "toShape", + value: function toShape() { + return new CAL.Shape({ + points: this.points, + closedPath: true, + lineColor: this.lineColor, + shapeColor: this.shapeColor, + lineWidth: this.lineWidth, + lineJoin: this.lineJoin, + lineCap: this.lineCap, + matrix: this.matrix + }); + } + }]); - return bestPoint; -}; -CAL.PhysicsObject.prototype.getPointVelocity = function (point) { + return _class; +})(CAL.Shape); +"use strict"; - var relativePoint = point.subtract(this.centerOfMass.applyMatrix(this.shape)); - var rotatedPoint = relativePoint.rotate(this.angularVelocity); +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; }; })(); - return rotatedPoint.subtract(relativePoint); -}; -CAL.PhysicsObject.prototype.findCollisionFace = function (point) { +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; -}; -CAL.PhysicsObject.prototype.step = function (dt) { - //this.rotateAroundRelative(this.torque*dt, this.centerOfMass); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - //this.angularVelocity += torque * (1.0 / this.inertia) * dt +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) subClass.__proto__ = superClass; } - /*if (this.velocity.length < 0.0001) { - this.velocity = new CAL.Vector(); - } - if (Math.abs(this.angularVelocity) < 0.00001) { - this.angularVelocity = 0; - }*/ +CAL.Circle = (function (_CAL$Shape) { + var _class = function _class(radius, options) { + _classCallCheck(this, _class); - this.shape._x += this.velocity.x*dt; - this.shape._y += this.velocity.y*dt; - this.shape.updateMatrix(); + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options); - //this.shape.rotateAroundRelative(this.angularVelocity*dt, this.centerOfMass); -}; + this.set(radius); + }; -CAL.PhysicsObject.prototype.debugDraw = function (context) { - context.lineWidth = 1; - context.strokeStyle = "black"; + _inherits(_class, _CAL$Shape); - var minX = Infinity; - var minY = Infinity; - var maxX = -Infinity; - var maxY = -Infinity; - context.beginPath(); - this.shape.points.foreach(function (point) { - var point = point.applyMatrix(this.shape); + _createClass(_class, [{ + key: "set", + value: function set(radius) { + this.points = []; - context.lineTo(point.x, point.y); - context.arc(point.x, point.y, 3, 0, 2*Math.PI*2); - context.lineTo(point.x, point.y); + this.radius = typeof radius === "number" ? radius : 100; + var offset = 4 * (Math.sqrt(2) - 1) / 3 * radius; - minX = (point.x < minX) ? point.x : minX - minY = (point.y < minY) ? point.y : minY - maxX = (point.x > maxX) ? point.x : maxX - maxY = (point.y > maxY) ? point.y : maxY - }, this); - context.closePath(); - context.stroke(); + this.addPoint(new CAL.BezierPoint(new CAL.Vector(0, radius), new CAL.Vector(-offset, radius), new CAL.Vector(offset, radius)), new CAL.BezierPoint(new CAL.Vector(radius, 0), new CAL.Vector(radius, offset), new CAL.Vector(radius, -offset)), new CAL.BezierPoint(new CAL.Vector(0, -radius), new CAL.Vector(offset, -radius), new CAL.Vector(-offset, -radius)), new CAL.BezierPoint(new CAL.Vector(-radius, 0), new CAL.Vector(-radius, -offset), new CAL.Vector(-radius, offset))); + } + }, { + key: "toShape", + value: function toShape() { + return new CAL.Shape({ + points: this.points, + closedPath: true, + lineColor: this.lineColor, + shapeColor: this.shapeColor, + lineWidth: this.lineWidth, + lineJoin: this.lineJoin, + lineCap: this.lineCap, + matrix: this.matrix + }); + } + }]); - this.shape.points.foreach(function (point, i) { - var point = point.applyMatrix(this.shape); - var text = new CAL.Text(); - text.drawText(context, i, point.x + 10, point.y - 10); - //this.getPointVelocity(point).scale(1000).draw(context, point.x, point.y); - }, this); + return _class; +})(CAL.Shape); +"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; }; })(); - context.beginPath(); - context.moveTo(minX, minY); - context.lineTo(minX, maxY); - context.lineTo(maxX, maxY); - context.lineTo(maxX, minY); - context.closePath(); +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; - var centerOfMass = this.centerOfMass.applyMatrix(this.shape); - context.moveTo(centerOfMass.x-5, centerOfMass.y-5); - context.lineTo(centerOfMass.x+5, centerOfMass.y+5); - context.moveTo(centerOfMass.x+5, centerOfMass.y-5); - context.lineTo(centerOfMass.x-5, centerOfMass.y+5); - context.strokeStyle = "red"; - context.stroke(); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var center = this.centerOfMass.applyMatrix(this.shape); - this.velocity.scale(1000).draw(context, center.x, center.y); -}; +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) subClass.__proto__ = superClass; } -CAL.Force = function (options) { +CAL.Polygon = (function (_CAL$Shape) { + var _class = function _class(angles, radius, options) { + _classCallCheck(this, _class); - this.objects = options.objects || []; - this.velocity = options.velocity || new CAL.Vector(); -} -CAL.Force.prototype.add = function () { - for (var i = 0; i < arguments.length; i ++) { - var argument = arguments[i]; + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options); - this.objects.push(argument); - } -}; -CAL.Force.prototype.step = function (dt) { - - for (var i = 0; i < this.objects.length; i ++) { - var object = this.objects[i]; + this.set(angles); + }; - object.velocity = object.velocity.add(this.velocity.scale(dt)); - } -}; + _inherits(_class, _CAL$Shape); + + _createClass(_class, [{ + key: "set", + value: function set(angles, radius) { + this.points = []; + + this.angles = angles || 8; + this.radius = radius || 100; + + for (var rad = 0; rad < Math.PI * 2; rad += Math.PI * 2 / this.angles) { + var x = Math.cos(rad) * this.radius; + var y = Math.sin(rad) * this.radius; + + this.addPoint(new CAL.BezierPoint(new CAL.Vector(x, y), null, null)); + } + } + }, { + key: "toShape", + value: function toShape() { + return new CAL.Shape({ + points: this.points, + closedPath: true, + lineColor: this.lineColor, + shapeColor: this.shapeColor, + lineWidth: this.lineWidth, + lineJoin: this.lineJoin, + lineCap: this.lineCap, + matrix: this.matrix + }); + } + }]); + + return _class; +})(CAL.Shape); +"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(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } 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 _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) subClass.__proto__ = superClass; } + +CAL.RoundRect = (function (_CAL$Shape) { + var _class = function _class(radius, width, height, options) { + _classCallCheck(this, _class); + + _get(Object.getPrototypeOf(_class.prototype), "constructor", this).call(this, options); + + this.set(radius, width, height); + }; + + _inherits(_class, _CAL$Shape); + + _createClass(_class, [{ + key: "set", + value: function set(radius, width, height) { + this.points = []; + + this.radius = typeof radius === "number" ? radius : 50; + this.width = typeof width === "number" ? width : 200; + this.height = typeof height === "number" ? height : 200; + + this.addPoint(new CAL.Vector(-this.width / 2, -this.height / 2), new CAL.Vector(-this.width / 2, this.height / 2), new CAL.Vector(this.width / 2, this.height / 2), new CAL.Vector(this.width / 2, -this.height / 2)); + } + }, { + key: "toShape", + value: function toShape() { + var points = []; + + var prevPoint; + var currentPoint = this.points[this.points.length - 1].position.applyMatrix(this); + var nextPoint = this.points[0].position.applyMatrix(this); + + for (var i = 0; i < this.points.length; i++) { + prevPoint = currentPoint; + currentPoint = nextPoint; + var nextPoint = this.points[(i + 1) % this.points.length].position.applyMatrix(this); + + var maxRadius = Math.min(prevPoint.subtract(currentPoint).length(), nextPoint.subtract(currentPoint).length()) / 2; + var radius = Math.min(this.radius, maxRadius); + + var start = currentPoint.add(prevPoint.subtract(currentPoint).setLength(radius)); + var end = currentPoint.add(nextPoint.subtract(currentPoint).setLength(radius)); + + var handleIn = currentPoint.add(prevPoint.subtract(currentPoint).setLength(radius / 3)); + var handleOut = currentPoint.add(nextPoint.subtract(currentPoint).setLength(radius / 3)); + + var inverseMatrix = this.inverseMatrix(); + + points.push(new CAL.BezierPoint(new CAL.Vector().copy(start).applyMatrix(inverseMatrix), null, new CAL.Vector().copy(handleIn).applyMatrix(inverseMatrix))); + points.push(new CAL.BezierPoint(new CAL.Vector().copy(end).applyMatrix(inverseMatrix), new CAL.Vector().copy(handleOut).applyMatrix(inverseMatrix), null)); + } + + return new CAL.Shape({ + points: points, + closedPath: true, + lineColor: this.lineColor, + shapeColor: this.shapeColor, + lineWidth: this.lineWidth, + lineJoin: this.lineJoin, + lineCap: this.lineCap, + matrix: this.matrix + }); + } + }, { + key: "setContext", + value: function setContext(context, matrix) { + var matrix = matrix || this; + context.beginPath(); + + var prevPoint; + var currentPoint = this.points[this.points.length - 1].position.applyMatrix(matrix); + var nextPoint = this.points[0].position.applyMatrix(matrix); + + for (var i = 0; i < this.points.length; i++) { + prevPoint = currentPoint; + currentPoint = nextPoint; + var nextPoint = this.points[(i + 1) % this.points.length].position.applyMatrix(matrix); + + var maxRadius = Math.min(prevPoint.subtract(currentPoint).length(), nextPoint.subtract(currentPoint).length()) / 2; + var radius = Math.min(this.radius, maxRadius); + + var start = currentPoint.add(prevPoint.subtract(currentPoint).setLength(radius)); + var end = currentPoint.add(nextPoint.subtract(currentPoint).setLength(radius)); + + context.lineTo(start.x, start.y); + context.quadraticCurveTo(currentPoint.x, currentPoint.y, end.x, end.y); + } + context.closePath(); + } + }]); + + return _class; +})(CAL.Shape); \ No newline at end of file diff --git a/settings/user_settings.json b/settings/user_settings.json index 7dc1cd8..612cec5 100644 --- a/settings/user_settings.json +++ b/settings/user_settings.json @@ -5,7 +5,7 @@ "shellThickness": 0.4, "brimOffset": 4.0, "fillGridSize": 5.0, - "infillOverlap": 0.5, + "infillOverlap": 0.0, "travelSpeed": 200.0, "retractionAmount": 3.0, "retractionEnabled": true, @@ -13,32 +13,32 @@ "retractionMinDistance": 0.0, "supportAcceptanceMargin": 1.5, "supportDistanceY": 0.4, - "supportUse": true, + "supportUse": false, "supportGridSize": 6.0, "supportMargin": 2.0, "supportPlateSize": 4.0, "outerLine": { "flowRate": 1.0, - "speed": 50.0 + "speed": 40.0 }, "innerLine": { "flowRate": 1.0, - "speed": 80.0 + "speed": 50.0 }, "fill": { "flowRate": 1.0, - "speed": 80.0 + "speed": 50.0 }, "brim": { "flowRate": 1.0, - "speed": 50.0 + "speed": 40.0 }, "support": { "flowRate": 0.8, - "speed": 100.0 + "speed": 40.0 }, "bottom": { - "flowRate": 2.0, - "speed": 30.0 + "flowRate": 1.2, + "speed": 40.0 } } \ No newline at end of file diff --git a/src/paths.js b/src/paths.js index 27babea..28507ff 100644 --- a/src/paths.js +++ b/src/paths.js @@ -241,7 +241,7 @@ D3D.Paths.prototype.draw = function (context, color) { for (var j = 0; j < shape.length; j ++) { var point = shape[j % shape.length]; - context.lineTo(point.X*2, point.Y*2); + context.lineTo(point.X * 2, point.Y * 2); } if (this.closed) { context.closePath(); diff --git a/src/slicer.js b/src/slicer.js index 537031c..370dcfc 100644 --- a/src/slicer.js +++ b/src/slicer.js @@ -42,9 +42,6 @@ D3D.Slicer.prototype.setMesh = function (geometry, matrix) { this.geometry = geometry; - //get unique lines from geometry; - this._createLines(); - return this; }; D3D.Slicer.prototype.getGCode = function (printer) { @@ -54,12 +51,10 @@ D3D.Slicer.prototype.getGCode = function (printer) { var dimensionsZ = printer.config["dimensionsZ"]; var useSupport = printer.config["supportUse"]; - this.progress.totalLayers = Math.floor(Math.min(this.geometry.boundingBox.max.y, dimensionsZ) / layerHeight); - this.progress.sliceLayer = 0; - this.progress.dataLayer = 0; - this.progress.gcodeLayer = 0; + //get unique lines from geometry; + this._createLines(printer); - var slices = this._slice(layerHeight, dimensionsZ); + var slices = this._slice(printer); this._generateInnerLines(slices, printer); @@ -78,17 +73,22 @@ D3D.Slicer.prototype.getGCode = function (printer) { D3D.Slicer.prototype._updateProgress = function () { 'use strict'; + var useSupport = printer.config["supportUse"]; + var progress = {}; var procent = 0; var length = 0; for (var i in this.progress) { - progress[i] = this.progress[i]; - procent += this.progress[i] ? 1 : 0; - length ++; + if (!(!useSupport && i === "generatedSupport")) { + progress[i] = this.progress[i]; + if (this.progress[i]) { + procent ++; + } + length ++; + } } - console.log(procent, length); progress.procent = procent / length; if (this.onProgress !== undefined) { @@ -96,7 +96,7 @@ D3D.Slicer.prototype._updateProgress = function () { this.onProgress(progress); } }; -D3D.Slicer.prototype._createLines = function () { +D3D.Slicer.prototype._createLines = function (printer) { "use strict"; this._lines = []; @@ -144,12 +144,15 @@ D3D.Slicer.prototype._createLines = function () { } this.progress.createdLines = true; - this._updateProgress(); + this._updateProgress(printer); }; -D3D.Slicer.prototype._slice = function (layerHeight, height) { +D3D.Slicer.prototype._slice = function (printer) { "use strict"; - var testData = []; + var layerHeight = printer.config["layerHeight"]; + var height = printer.config["dimensionsZ"]; + + //var testData = []; var numLayers = height / layerHeight; @@ -172,7 +175,7 @@ D3D.Slicer.prototype._slice = function (layerHeight, height) { } var slices = []; - var testPoints = []; + //var testPoints = []; for (var layer = 1; layer < layersIntersections.length; layer ++) { var layerIntersections = layersIntersections[layer]; @@ -197,13 +200,13 @@ D3D.Slicer.prototype._slice = function (layerHeight, height) { } intersections[index] = new THREE.Vector2(z, x); - testPoints.push({ + /*testPoints.push({ x: z, y: x, connects: this._lines[index].connects, index: index, normals: this._lines[index].normals - }); + });*/ } var done = []; @@ -286,19 +289,19 @@ D3D.Slicer.prototype._slice = function (layerHeight, height) { slices.push(slice); - if (layer === 218) { + /*if (layer === 218) { testData.push({ testPoints: testPoints, pathData: slice.parts }); - } + }*/ } } //console.log(JSON.stringify(testData)); this.progress.sliced = true; - this._updateProgress(); + this._updateProgress(printer); return slices; }; @@ -321,7 +324,7 @@ D3D.Slicer.prototype._generateInnerLines = function (slices, printer) { for (var i = 0; i < slice.parts.length; i ++) { var part = slice.parts[i]; - var outerLine = part.intersect.clone().scaleUp(scale); + var outerLine = part.intersect.clone().scaleUp(scale).offset(-nozzleRadius); if (outerLine.length > 0) { part.outerLine = outerLine; @@ -341,7 +344,7 @@ D3D.Slicer.prototype._generateInnerLines = function (slices, printer) { } this.progress.generatedInnerLines = true; - this._updateProgress(); + this._updateProgress(printer); }; D3D.Slicer.prototype._generateInfills = function (slices, printer) { "use strict"; @@ -412,7 +415,7 @@ D3D.Slicer.prototype._generateInfills = function (slices, printer) { } this.progress.generatedInfills = true; - this._updateProgress(); + this._updateProgress(printer); }; D3D.Slicer.prototype._generateSupport = function (slices, printer) { "use strict"; @@ -476,7 +479,7 @@ D3D.Slicer.prototype._generateSupport = function (slices, printer) { } this.progress.generatedSupport = true; - this._updateProgress(); + this._updateProgress(printer); }; D3D.Slicer.prototype._optimizePaths = function (slices, printer) { @@ -520,7 +523,7 @@ D3D.Slicer.prototype._optimizePaths = function (slices, printer) { } this.progress.optimizedPaths = true; - this._updateProgress(); + this._updateProgress(printer); } D3D.Slicer.prototype._getFillTemplate = function (bounds, size, even, uneven) {