Advertisement
Guest User

two.js

a guest
Aug 29th, 2019
410
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2. * two.js
  3. * a two-dimensional drawing api meant for modern browsers. It is renderer
  4. * agnostic enabling the same api for rendering in multiple contexts: webgl,
  5. * canvas2d, and svg.
  6. *
  7. * Copyright (c) 2012 - 2017 jonobr1 / http://jonobr1.com
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28.  
  29. this.Two = (function (previousTwo) {
  30.  
  31.     var root = typeof window != 'undefined' ? window : typeof global != 'undefined' ? global : null;
  32.     var toString = Object.prototype.toString;
  33.     var _ = {
  34.         // http://underscorejs.org/ • 1.8.3
  35.         _indexAmount: 0,
  36.         natural: {
  37.             slice: Array.prototype.slice,
  38.             indexOf: Array.prototype.indexOf,
  39.             keys: Object.keys,
  40.             bind: Function.prototype.bind,
  41.             create: Object.create
  42.         },
  43.         identity: function (value) {
  44.             return value;
  45.         },
  46.         isArguments: function (obj) {
  47.             return toString.call(obj) === '[object Arguments]';
  48.         },
  49.         isFunction: function (obj) {
  50.             return toString.call(obj) === '[object Function]';
  51.         },
  52.         isString: function (obj) {
  53.             return toString.call(obj) === '[object String]';
  54.         },
  55.         isNumber: function (obj) {
  56.             return toString.call(obj) === '[object Number]';
  57.         },
  58.         isDate: function (obj) {
  59.             return toString.call(obj) === '[object Date]';
  60.         },
  61.         isRegExp: function (obj) {
  62.             return toString.call(obj) === '[object RegExp]';
  63.         },
  64.         isError: function (obj) {
  65.             return toString.call(obj) === '[object Error]';
  66.         },
  67.         isFinite: function (obj) {
  68.             return isFinite(obj) && !isNaN(parseFloat(obj));
  69.         },
  70.         isNaN: function (obj) {
  71.             return _.isNumber(obj) && obj !== +obj;
  72.         },
  73.         isBoolean: function (obj) {
  74.             return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
  75.         },
  76.         isNull: function (obj) {
  77.             return obj === null;
  78.         },
  79.         isUndefined: function (obj) {
  80.             return obj === void 0;
  81.         },
  82.         isEmpty: function (obj) {
  83.             if (obj == null) return true;
  84.             if (isArrayLike && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
  85.             return _.keys(obj).length === 0;
  86.         },
  87.         isElement: function (obj) {
  88.             return !!(obj && obj.nodeType === 1);
  89.         },
  90.         isArray: Array.isArray || function (obj) {
  91.             return toString.call(obj) === '[object Array]';
  92.         },
  93.         isObject: function (obj) {
  94.             var type = typeof obj;
  95.             return type === 'function' || type === 'object' && !!obj;
  96.         },
  97.         toArray: function (obj) {
  98.             if (!obj) {
  99.                 return [];
  100.             }
  101.             if (_.isArray(obj)) {
  102.                 return slice.call(obj);
  103.             }
  104.             if (isArrayLike(obj)) {
  105.                 return _.map(obj, _.identity);
  106.             }
  107.             return _.values(obj);
  108.         },
  109.         range: function (start, stop, step) {
  110.             if (stop == null) {
  111.                 stop = start || 0;
  112.                 start = 0;
  113.             }
  114.             step = step || 1;
  115.  
  116.             var length = Math.max(Math.ceil((stop - start) / step), 0);
  117.             var range = Array(length);
  118.  
  119.             for (var idx = 0; idx < length; idx++ , start += step) {
  120.                 range[idx] = start;
  121.             }
  122.  
  123.             return range;
  124.         },
  125.         indexOf: function (list, item) {
  126.             if (!!_.natural.indexOf) {
  127.                 return _.natural.indexOf.call(list, item);
  128.             }
  129.             for (var i = 0; i < list.length; i++) {
  130.                 if (list[i] === item) {
  131.                     return i;
  132.                 }
  133.             }
  134.             return -1;
  135.         },
  136.         has: function (obj, key) {
  137.             return obj != null && hasOwnProperty.call(obj, key);
  138.         },
  139.         bind: function (func, ctx) {
  140.             var natural = _.natural.bind;
  141.             if (natural && func.bind === natural) {
  142.                 return natural.apply(func, slice.call(arguments, 1));
  143.             }
  144.             var args = slice.call(arguments, 2);
  145.             return function () {
  146.                 func.apply(ctx, args);
  147.             };
  148.         },
  149.         extend: function (base) {
  150.             var sources = slice.call(arguments, 1);
  151.             for (var i = 0; i < sources.length; i++) {
  152.                 var obj = sources[i];
  153.                 for (var k in obj) {
  154.                     base[k] = obj[k];
  155.                 }
  156.             }
  157.             return base;
  158.         },
  159.         defaults: function (base) {
  160.             var sources = slice.call(arguments, 1);
  161.             for (var i = 0; i < sources.length; i++) {
  162.                 var obj = sources[i];
  163.                 for (var k in obj) {
  164.                     if (base[k] === void 0) {
  165.                         base[k] = obj[k];
  166.                     }
  167.                 }
  168.             }
  169.             return base;
  170.         },
  171.         keys: function (obj) {
  172.             if (!_.isObject(obj)) {
  173.                 return [];
  174.             }
  175.             if (_.natural.keys) {
  176.                 return _.natural.keys(obj);
  177.             }
  178.             var keys = [];
  179.             for (var k in obj) {
  180.                 if (_.has(obj, k)) {
  181.                     keys.push(k);
  182.                 }
  183.             }
  184.             return keys;
  185.         },
  186.         values: function (obj) {
  187.             var keys = _.keys(obj);
  188.             var values = [];
  189.             for (var i = 0; i < keys.length; i++) {
  190.                 var k = keys[i];
  191.                 values.push(obj[k]);
  192.             }
  193.             return values;
  194.         },
  195.         each: function (obj, iteratee, context) {
  196.             var ctx = context || this;
  197.             var keys = !isArrayLike(obj) && _.keys(obj);
  198.             var length = (keys || obj).length;
  199.             for (var i = 0; i < length; i++) {
  200.                 var k = keys ? keys[i] : i;
  201.                 iteratee.call(ctx, obj[k], k, obj);
  202.             }
  203.             return obj;
  204.         },
  205.         map: function (obj, iteratee, context) {
  206.             var ctx = context || this;
  207.             var keys = !isArrayLike(obj) && _.keys(obj);
  208.             var length = (keys || obj).length;
  209.             var result = [];
  210.             for (var i = 0; i < length; i++) {
  211.                 var k = keys ? keys[i] : i;
  212.                 result[i] = iteratee.call(ctx, obj[k], k, obj);
  213.             }
  214.             return result;
  215.         },
  216.         once: function (func) {
  217.             var init = false;
  218.             return function () {
  219.                 if (!!init) {
  220.                     return func;
  221.                 }
  222.                 init = true;
  223.                 return func.apply(this, arguments);
  224.             }
  225.         },
  226.         after: function (times, func) {
  227.             return function () {
  228.                 while (--times < 1) {
  229.                     return func.apply(this, arguments);
  230.                 }
  231.             }
  232.         },
  233.         uniqueId: function (prefix) {
  234.             var id = ++_._indexAmount + '';
  235.             return prefix ? prefix + id : id;
  236.         }
  237.     };
  238.  
  239.     /**
  240.         * Constants
  241.         */
  242.  
  243.     var sin = Math.sin,
  244.         cos = Math.cos,
  245.         atan2 = Math.atan2,
  246.         sqrt = Math.sqrt,
  247.         round = Math.round,
  248.         abs = Math.abs,
  249.         PI = Math.PI,
  250.         TWO_PI = PI * 2,
  251.         HALF_PI = PI / 2,
  252.         pow = Math.pow,
  253.         min = Math.min,
  254.         max = Math.max;
  255.  
  256.     /**
  257.         * Localized variables
  258.         */
  259.  
  260.     var count = 0;
  261.     var slice = _.natural.slice;
  262.     var perf = ((root.performance && root.performance.now) ? root.performance : Date);
  263.     var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
  264.     var getLength = function (obj) {
  265.         return obj == null ? void 0 : obj['length'];
  266.     };
  267.     var isArrayLike = function (collection) {
  268.         var length = getLength(collection);
  269.         return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
  270.     };
  271.  
  272.     /**
  273.         * Cross browser dom events.
  274.         */
  275.     var dom = {
  276.  
  277.         temp: (root.document ? root.document.createElement('div') : {}),
  278.  
  279.         hasEventListeners: _.isFunction(root.addEventListener),
  280.  
  281.         bind: function (elem, event, func, bool) {
  282.             if (this.hasEventListeners) {
  283.                 elem.addEventListener(event, func, !!bool);
  284.             } else {
  285.                 elem.attachEvent('on' + event, func);
  286.             }
  287.             return dom;
  288.         },
  289.  
  290.         unbind: function (elem, event, func, bool) {
  291.             if (dom.hasEventListeners) {
  292.                 elem.removeEventListeners(event, func, !!bool);
  293.             } else {
  294.                 elem.detachEvent('on' + event, func);
  295.             }
  296.             return dom;
  297.         },
  298.  
  299.         getRequestAnimationFrame: function () {
  300.  
  301.             var lastTime = 0;
  302.             var vendors = ['ms', 'moz', 'webkit', 'o'];
  303.             var request = root.requestAnimationFrame, cancel;
  304.  
  305.             if (!request) {
  306.                 for (var i = 0; i < vendors.length; i++) {
  307.                     request = root[vendors[i] + 'RequestAnimationFrame'] || request;
  308.                     cancel = root[vendors[i] + 'CancelAnimationFrame']
  309.                         || root[vendors[i] + 'CancelRequestAnimationFrame'] || cancel;
  310.                 }
  311.  
  312.                 request = request || function (callback, element) {
  313.                     var currTime = new Date().getTime();
  314.                     var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  315.                     var id = root.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
  316.                     lastTime = currTime + timeToCall;
  317.                     return id;
  318.                 };
  319.                 // cancel = cancel || function(id) {
  320.                 //   clearTimeout(id);
  321.                 // };
  322.             }
  323.  
  324.             request.init = _.once(loop);
  325.  
  326.             return request;
  327.  
  328.         }
  329.  
  330.     };
  331.  
  332.     /**
  333.         * @class
  334.         */
  335.     var Two = root.Two = function (options) {
  336.  
  337.         // Determine what Renderer to use and setup a scene.
  338.  
  339.         var params = _.defaults(options || {}, {
  340.             fullscreen: false,
  341.             width: 640,
  342.             height: 480,
  343.             type: Two.Types.svg,
  344.             autostart: false
  345.         });
  346.  
  347.         _.each(params, function (v, k) {
  348.             if (k === 'fullscreen' || k === 'autostart') {
  349.                 return;
  350.             }
  351.             this[k] = v;
  352.         }, this);
  353.  
  354.         // Specified domElement overrides type declaration only if the element does not support declared renderer type.
  355.         if (_.isElement(params.domElement)) {
  356.             var tagName = params.domElement.tagName.toLowerCase();
  357.             // TODO: Reconsider this if statement's logic.
  358.             if (!/^(CanvasRenderer-canvas|WebGLRenderer-canvas|SVGRenderer-svg)$/.test(this.type + '-' + tagName)) {
  359.                 this.type = Two.Types[tagName];
  360.             }
  361.         }
  362.  
  363.         this.renderer = new Two[this.type](this);
  364.         Two.Utils.setPlaying.call(this, params.autostart);
  365.         this.frameCount = 0;
  366.  
  367.         if (params.fullscreen) {
  368.  
  369.             var fitted = _.bind(fitToWindow, this);
  370.             _.extend(document.body.style, {
  371.                 overflow: 'hidden',
  372.                 margin: 0,
  373.                 padding: 0,
  374.                 top: 0,
  375.                 left: 0,
  376.                 right: 0,
  377.                 bottom: 0,
  378.                 position: 'fixed'
  379.             });
  380.             _.extend(this.renderer.domElement.style, {
  381.                 display: 'block',
  382.                 top: 0,
  383.                 left: 0,
  384.                 right: 0,
  385.                 bottom: 0,
  386.                 position: 'fixed'
  387.             });
  388.             dom.bind(root, 'resize', fitted);
  389.             fitted();
  390.  
  391.  
  392.         } else if (!_.isElement(params.domElement)) {
  393.  
  394.             this.renderer.setSize(params.width, params.height, this.ratio);
  395.             this.width = params.width;
  396.             this.height = params.height;
  397.  
  398.         }
  399.  
  400.         this.scene = this.renderer.scene;
  401.  
  402.         Two.Instances.push(this);
  403.         raf.init();
  404.  
  405.     };
  406.  
  407.     _.extend(Two, {
  408.  
  409.         /**
  410.             * Access to root in other files.
  411.             */
  412.  
  413.         root: root,
  414.  
  415.         /**
  416.             * Primitive
  417.             */
  418.  
  419.         Array: root.Float32Array || Array,
  420.  
  421.         Types: {
  422.             webgl: 'WebGLRenderer',
  423.             svg: 'SVGRenderer',
  424.             canvas: 'CanvasRenderer'
  425.         },
  426.  
  427.         Version: 'v0.7.0',
  428.  
  429.         Identifier: 'two_',
  430.  
  431.         Properties: {
  432.             hierarchy: 'hierarchy',
  433.             demotion: 'demotion'
  434.         },
  435.  
  436.         Events: {
  437.             play: 'play',
  438.             pause: 'pause',
  439.             update: 'update',
  440.             render: 'render',
  441.             resize: 'resize',
  442.             change: 'change',
  443.             remove: 'remove',
  444.             insert: 'insert',
  445.             order: 'order',
  446.             load: 'load'
  447.         },
  448.  
  449.         Commands: {
  450.             move: 'M',
  451.             line: 'L',
  452.             curve: 'C',
  453.             close: 'Z'
  454.         },
  455.  
  456.         Resolution: 8,
  457.  
  458.         Instances: [],
  459.  
  460.         noConflict: function () {
  461.             root.Two = previousTwo;
  462.             return this;
  463.         },
  464.  
  465.         uniqueId: function () {
  466.             var id = count;
  467.             count++;
  468.             return id;
  469.         },
  470.  
  471.         Utils: _.extend(_, {
  472.  
  473.             performance: perf,
  474.  
  475.             defineProperty: function (property) {
  476.  
  477.                 var object = this;
  478.                 var secret = '_' + property;
  479.                 var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1);
  480.  
  481.                 Object.defineProperty(object, property, {
  482.                     enumerable: true,
  483.                     get: function () {
  484.                         return this[secret];
  485.                     },
  486.                     set: function (v) {
  487.                         this[secret] = v;
  488.                         this[flag] = true;
  489.                     }
  490.                 });
  491.  
  492.             },
  493.  
  494.             /**
  495.                 * Release an arbitrary class' events from the two.js corpus and recurse
  496.                 * through its children and or vertices.
  497.                 */
  498.             release: function (obj) {
  499.  
  500.                 if (!_.isObject(obj)) {
  501.                     return;
  502.                 }
  503.  
  504.                 if (_.isFunction(obj.unbind)) {
  505.                     obj.unbind();
  506.                 }
  507.  
  508.                 if (obj.vertices) {
  509.                     if (_.isFunction(obj.vertices.unbind)) {
  510.                         obj.vertices.unbind();
  511.                     }
  512.                     _.each(obj.vertices, function (v) {
  513.                         if (_.isFunction(v.unbind)) {
  514.                             v.unbind();
  515.                         }
  516.                     });
  517.                 }
  518.  
  519.                 if (obj.children) {
  520.                     _.each(obj.children, function (obj) {
  521.                         Two.Utils.release(obj);
  522.                     });
  523.                 }
  524.  
  525.             },
  526.  
  527.             xhr: function (path, callback) {
  528.  
  529.                 var xhr = new XMLHttpRequest();
  530.                 xhr.open('GET', path);
  531.  
  532.                 xhr.onreadystatechange = function () {
  533.                     if (xhr.readyState === 4 && xhr.status === 200) {
  534.                         callback(xhr.responseText);
  535.                     }
  536.                 };
  537.  
  538.                 xhr.send();
  539.                 return xhr;
  540.  
  541.             },
  542.  
  543.             Curve: {
  544.  
  545.                 CollinearityEpsilon: pow(10, -30),
  546.  
  547.                 RecursionLimit: 16,
  548.  
  549.                 CuspLimit: 0,
  550.  
  551.                 Tolerance: {
  552.                     distance: 0.25,
  553.                     angle: 0,
  554.                     epsilon: 0.01
  555.                 },
  556.  
  557.                 // Lookup tables for abscissas and weights with values for n = 2 .. 16.
  558.                 // As values are symmetric, only store half of them and adapt algorithm
  559.                 // to factor in symmetry.
  560.                 abscissas: [
  561.                     [0.5773502691896257645091488],
  562.                     [0, 0.7745966692414833770358531],
  563.                     [0.3399810435848562648026658, 0.8611363115940525752239465],
  564.                     [0, 0.5384693101056830910363144, 0.9061798459386639927976269],
  565.                     [0.2386191860831969086305017, 0.6612093864662645136613996, 0.9324695142031520278123016],
  566.                     [0, 0.4058451513773971669066064, 0.7415311855993944398638648, 0.9491079123427585245261897],
  567.                     [0.1834346424956498049394761, 0.5255324099163289858177390, 0.7966664774136267395915539, 0.9602898564975362316835609],
  568.                     [0, 0.3242534234038089290385380, 0.6133714327005903973087020, 0.8360311073266357942994298, 0.9681602395076260898355762],
  569.                     [0.1488743389816312108848260, 0.4333953941292471907992659, 0.6794095682990244062343274, 0.8650633666889845107320967, 0.9739065285171717200779640],
  570.                     [0, 0.2695431559523449723315320, 0.5190961292068118159257257, 0.7301520055740493240934163, 0.8870625997680952990751578, 0.9782286581460569928039380],
  571.                     [0.1252334085114689154724414, 0.3678314989981801937526915, 0.5873179542866174472967024, 0.7699026741943046870368938, 0.9041172563704748566784659, 0.9815606342467192506905491],
  572.                     [0, 0.2304583159551347940655281, 0.4484927510364468528779129, 0.6423493394403402206439846, 0.8015780907333099127942065, 0.9175983992229779652065478, 0.9841830547185881494728294],
  573.                     [0.1080549487073436620662447, 0.3191123689278897604356718, 0.5152486363581540919652907, 0.6872929048116854701480198, 0.8272013150697649931897947, 0.9284348836635735173363911, 0.9862838086968123388415973],
  574.                     [0, 0.2011940939974345223006283, 0.3941513470775633698972074, 0.5709721726085388475372267, 0.7244177313601700474161861, 0.8482065834104272162006483, 0.9372733924007059043077589, 0.9879925180204854284895657],
  575.                     [0.0950125098376374401853193, 0.2816035507792589132304605, 0.4580167776572273863424194, 0.6178762444026437484466718, 0.7554044083550030338951012, 0.8656312023878317438804679, 0.9445750230732325760779884, 0.9894009349916499325961542]
  576.                 ],
  577.  
  578.                 weights: [
  579.                     [1],
  580.                     [0.8888888888888888888888889, 0.5555555555555555555555556],
  581.                     [0.6521451548625461426269361, 0.3478548451374538573730639],
  582.                     [0.5688888888888888888888889, 0.4786286704993664680412915, 0.2369268850561890875142640],
  583.                     [0.4679139345726910473898703, 0.3607615730481386075698335, 0.1713244923791703450402961],
  584.                     [0.4179591836734693877551020, 0.3818300505051189449503698, 0.2797053914892766679014678, 0.1294849661688696932706114],
  585.                     [0.3626837833783619829651504, 0.3137066458778872873379622, 0.2223810344533744705443560, 0.1012285362903762591525314],
  586.                     [0.3302393550012597631645251, 0.3123470770400028400686304, 0.2606106964029354623187429, 0.1806481606948574040584720, 0.0812743883615744119718922],
  587.                     [0.2955242247147528701738930, 0.2692667193099963550912269, 0.2190863625159820439955349, 0.1494513491505805931457763, 0.0666713443086881375935688],
  588.                     [0.2729250867779006307144835, 0.2628045445102466621806889, 0.2331937645919904799185237, 0.1862902109277342514260976, 0.1255803694649046246346943, 0.0556685671161736664827537],
  589.                     [0.2491470458134027850005624, 0.2334925365383548087608499, 0.2031674267230659217490645, 0.1600783285433462263346525, 0.1069393259953184309602547, 0.0471753363865118271946160],
  590.                     [0.2325515532308739101945895, 0.2262831802628972384120902, 0.2078160475368885023125232, 0.1781459807619457382800467, 0.1388735102197872384636018, 0.0921214998377284479144218, 0.0404840047653158795200216],
  591.                     [0.2152638534631577901958764, 0.2051984637212956039659241, 0.1855383974779378137417166, 0.1572031671581935345696019, 0.1215185706879031846894148, 0.0801580871597602098056333, 0.0351194603317518630318329],
  592.                     [0.2025782419255612728806202, 0.1984314853271115764561183, 0.1861610000155622110268006, 0.1662692058169939335532009, 0.1395706779261543144478048, 0.1071592204671719350118695, 0.0703660474881081247092674, 0.0307532419961172683546284],
  593.                     [0.1894506104550684962853967, 0.1826034150449235888667637, 0.1691565193950025381893121, 0.1495959888165767320815017, 0.1246289712555338720524763, 0.0951585116824927848099251, 0.0622535239386478928628438, 0.0271524594117540948517806]
  594.                 ]
  595.  
  596.             },
  597.  
  598.             /**
  599.                 * Account for high dpi rendering.
  600.                 * http://www.html5rocks.com/en/tutorials/canvas/hidpi/
  601.                 */
  602.  
  603.             devicePixelRatio: root.devicePixelRatio || 1,
  604.  
  605.             getBackingStoreRatio: function (ctx) {
  606.                 return ctx.webkitBackingStorePixelRatio ||
  607.                     ctx.mozBackingStorePixelRatio ||
  608.                     ctx.msBackingStorePixelRatio ||
  609.                     ctx.oBackingStorePixelRatio ||
  610.                     ctx.backingStorePixelRatio || 1;
  611.             },
  612.  
  613.             getRatio: function (ctx) {
  614.                 return Two.Utils.devicePixelRatio / getBackingStoreRatio(ctx);
  615.             },
  616.  
  617.             /**
  618.                 * Properly defer play calling until after all objects
  619.                 * have been updated with their newest styles.
  620.                 */
  621.             setPlaying: function (b) {
  622.  
  623.                 this.playing = !!b;
  624.                 return this;
  625.  
  626.             },
  627.  
  628.             /**
  629.                 * Return the computed matrix of a nested object.
  630.                 * TODO: Optimize traversal.
  631.                 */
  632.             getComputedMatrix: function (object, matrix) {
  633.  
  634.                 matrix = (matrix && matrix.identity()) || new Two.Matrix();
  635.                 var parent = object, matrices = [];
  636.  
  637.                 while (parent && parent._matrix) {
  638.                     matrices.push(parent._matrix);
  639.                     parent = parent.parent;
  640.                 }
  641.  
  642.                 matrices.reverse();
  643.  
  644.                 _.each(matrices, function (m) {
  645.  
  646.                     var e = m.elements;
  647.                     matrix.multiply(
  648.                         e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8], e[9]);
  649.  
  650.                 });
  651.  
  652.                 return matrix;
  653.  
  654.             },
  655.  
  656.             deltaTransformPoint: function (matrix, x, y) {
  657.  
  658.                 var dx = x * matrix.a + y * matrix.c + 0;
  659.                 var dy = x * matrix.b + y * matrix.d + 0;
  660.  
  661.                 return new Two.Vector(dx, dy);
  662.  
  663.             },
  664.  
  665.             /**
  666.                 * https://gist.github.com/2052247
  667.                 */
  668.             decomposeMatrix: function (matrix) {
  669.  
  670.                 // calculate delta transform point
  671.                 var px = Two.Utils.deltaTransformPoint(matrix, 0, 1);
  672.                 var py = Two.Utils.deltaTransformPoint(matrix, 1, 0);
  673.  
  674.                 // calculate skew
  675.                 var skewX = ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);
  676.                 var skewY = ((180 / Math.PI) * Math.atan2(py.y, py.x));
  677.  
  678.                 return {
  679.                     translateX: matrix.e,
  680.                     translateY: matrix.f,
  681.                     scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
  682.                     scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
  683.                     skewX: skewX,
  684.                     skewY: skewY,
  685.                     rotation: skewX // rotation is the same as skew x
  686.                 };
  687.  
  688.             },
  689.  
  690.             /**
  691.                 * Walk through item properties and pick the ones of interest.
  692.                 * Will try to resolve styles applied via CSS
  693.                 *
  694.                 * TODO: Reverse calculate `Two.Gradient`s for fill / stroke
  695.                 * of any given path.
  696.                 */
  697.             applySvgAttributes: function (node, elem) {
  698.  
  699.                 var attributes = {}, styles = {}, i, key, value, attr;
  700.  
  701.                 // Not available in non browser environments
  702.                 if (getComputedStyle) {
  703.                     // Convert CSSStyleDeclaration to a normal object
  704.                     var computedStyles = getComputedStyle(node);
  705.                     i = computedStyles.length;
  706.  
  707.                     while (i--) {
  708.                         key = computedStyles[i];
  709.                         value = computedStyles[key];
  710.                         // Gecko returns undefined for unset properties
  711.                         // Webkit returns the default value
  712.                         if (value !== undefined) {
  713.                             styles[key] = value;
  714.                         }
  715.                     }
  716.                 }
  717.  
  718.                 // Convert NodeMap to a normal object
  719.                 i = node.attributes.length;
  720.                 while (i--) {
  721.                     attr = node.attributes[i];
  722.                     attributes[attr.nodeName] = attr.value;
  723.                 }
  724.  
  725.                 // Getting the correct opacity is a bit tricky, since SVG path elements don't
  726.                 // support opacity as an attribute, but you can apply it via CSS.
  727.                 // So we take the opacity and set (stroke/fill)-opacity to the same value.
  728.                 if (!_.isUndefined(styles.opacity)) {
  729.                     styles['stroke-opacity'] = styles.opacity;
  730.                     styles['fill-opacity'] = styles.opacity;
  731.                 }
  732.  
  733.                 // Merge attributes and applied styles (attributes take precedence)
  734.                 _.extend(styles, attributes);
  735.  
  736.                 // Similarly visibility is influenced by the value of both display and visibility.
  737.                 // Calculate a unified value here which defaults to `true`.
  738.                 styles.visible = !(_.isUndefined(styles.display) && styles.display === 'none')
  739.                     || (_.isUndefined(styles.visibility) && styles.visibility === 'hidden');
  740.  
  741.                 // Now iterate the whole thing
  742.                 for (key in styles) {
  743.                     value = styles[key];
  744.  
  745.                     switch (key) {
  746.                         case 'transform':
  747.                             // TODO: Check this out https://github.com/paperjs/paper.js/blob/master/src/svg/SVGImport.js#L313
  748.                             if (value === 'none') break;
  749.                             var m = node.getCTM ? node.getCTM() : null;
  750.  
  751.                             // Might happen when transform string is empty or not valid.
  752.                             if (m === null) break;
  753.  
  754.                             // // Option 1: edit the underlying matrix and don't force an auto calc.
  755.                             // var m = node.getCTM();
  756.                             // elem._matrix.manual = true;
  757.                             // elem._matrix.set(m.a, m.b, m.c, m.d, m.e, m.f);
  758.  
  759.                             // Option 2: Decompose and infer Two.js related properties.
  760.                             var transforms = Two.Utils.decomposeMatrix(node.getCTM());
  761.  
  762.                             elem.translation.set(transforms.translateX, transforms.translateY);
  763.                             elem.rotation = transforms.rotation;
  764.                             // Warning: Two.js elements only support uniform scalars...
  765.                             elem.scale = transforms.scaleX;
  766.  
  767.                             var x = parseFloat((styles.x + '').replace('px'));
  768.                             var y = parseFloat((styles.y + '').replace('px'));
  769.  
  770.                             // Override based on attributes.
  771.                             if (x) {
  772.                                 elem.translation.x = x;
  773.                             }
  774.  
  775.                             if (y) {
  776.                                 elem.translation.y = y;
  777.                             }
  778.  
  779.                             break;
  780.                         case 'visible':
  781.                             elem.visible = value;
  782.                             break;
  783.                         case 'stroke-linecap':
  784.                             elem.cap = value;
  785.                             break;
  786.                         case 'stroke-linejoin':
  787.                             elem.join = value;
  788.                             break;
  789.                         case 'stroke-miterlimit':
  790.                             elem.miter = value;
  791.                             break;
  792.                         case 'stroke-width':
  793.                             elem.linewidth = parseFloat(value);
  794.                             break;
  795.                         case 'stroke-opacity':
  796.                         case 'fill-opacity':
  797.                         case 'opacity':
  798.                             elem.opacity = parseFloat(value);
  799.                             break;
  800.                         case 'fill':
  801.                         case 'stroke':
  802.                             if (/url\(\#.*\)/i.test(value)) {
  803.                                 elem[key] = this.getById(
  804.                                     value.replace(/url\(\#(.*)\)/i, '$1'));
  805.                             } else {
  806.                                 elem[key] = (value === 'none') ? 'transparent' : value;
  807.                             }
  808.                             break;
  809.                         case 'id':
  810.                             elem.id = value;
  811.                             break;
  812.                         case 'class':
  813.                             elem.classList = value.split(' ');
  814.                             break;
  815.                     }
  816.                 }
  817.  
  818.                 return elem;
  819.  
  820.             },
  821.  
  822.             /**
  823.                 * Read any number of SVG node types and create Two equivalents of them.
  824.                 */
  825.             read: {
  826.  
  827.                 svg: function () {
  828.                     return Two.Utils.read.g.apply(this, arguments);
  829.                 },
  830.  
  831.                 g: function (node) {
  832.  
  833.                     var group = new Two.Group();
  834.  
  835.                     // Switched up order to inherit more specific styles
  836.                     Two.Utils.applySvgAttributes.call(this, node, group);
  837.  
  838.                     for (var i = 0, l = node.childNodes.length; i < l; i++) {
  839.                         var n = node.childNodes[i];
  840.                         var tag = n.nodeName;
  841.                         if (!tag) return;
  842.  
  843.                         var tagName = tag.replace(/svg\:/ig, '').toLowerCase();
  844.  
  845.                         if (tagName in Two.Utils.read) {
  846.                             var o = Two.Utils.read[tagName].call(group, n);
  847.                             group.add(o);
  848.                         }
  849.                     }
  850.  
  851.                     return group;
  852.  
  853.                 },
  854.  
  855.                 polygon: function (node, open) {
  856.  
  857.                     var points = node.getAttribute('points');
  858.  
  859.                     var verts = [];
  860.                     points.replace(/(-?[\d\.?]+)[,|\s](-?[\d\.?]+)/g, function (match, p1, p2) {
  861.                         verts.push(new Two.Anchor(parseFloat(p1), parseFloat(p2)));
  862.                     });
  863.  
  864.                     var poly = new Two.Path(verts, !open).noStroke();
  865.                     poly.fill = 'black';
  866.  
  867.                     return Two.Utils.applySvgAttributes.call(this, node, poly);
  868.  
  869.                 },
  870.  
  871.                 polyline: function (node) {
  872.                     return Two.Utils.read.polygon.call(this, node, true);
  873.                 },
  874.  
  875.                 path: function (node) {
  876.  
  877.                     var path = node.getAttribute('d');
  878.  
  879.                     // Create a Two.Path from the paths.
  880.  
  881.                     var coord = new Two.Anchor();
  882.                     var control, coords;
  883.                     var closed = false, relative = false;
  884.                     var commands = path.match(/[a-df-z][^a-df-z]*/ig);
  885.                     var last = commands.length - 1;
  886.  
  887.                     // Split up polybeziers
  888.  
  889.                     _.each(commands.slice(0), function (command, i) {
  890.  
  891.                         var type = command[0];
  892.                         var lower = type.toLowerCase();
  893.                         var items = command.slice(1).trim().split(/[\s,]+|(?=\s?[+\-])/);
  894.                         var pre, post, result = [], bin;
  895.  
  896.                         if (i <= 0) {
  897.                             commands = [];
  898.                         }
  899.  
  900.                         switch (lower) {
  901.                             case 'h':
  902.                             case 'v':
  903.                                 if (items.length > 1) {
  904.                                     bin = 1;
  905.                                 }
  906.                                 break;
  907.                             case 'm':
  908.                             case 'l':
  909.                             case 't':
  910.                                 if (items.length > 2) {
  911.                                     bin = 2;
  912.                                 }
  913.                                 break;
  914.                             case 's':
  915.                             case 'q':
  916.                                 if (items.length > 4) {
  917.                                     bin = 4;
  918.                                 }
  919.                                 break;
  920.                             case 'c':
  921.                                 if (items.length > 6) {
  922.                                     bin = 6;
  923.                                 }
  924.                                 break;
  925.                             case 'a':
  926.                                 // TODO: Handle Ellipses
  927.                                 break;
  928.                         }
  929.  
  930.                         if (bin) {
  931.  
  932.                             for (var j = 0, l = items.length, times = 0; j < l; j += bin) {
  933.  
  934.                                 var ct = type;
  935.                                 if (times > 0) {
  936.  
  937.                                     switch (type) {
  938.                                         case 'm':
  939.                                             ct = 'l';
  940.                                             break;
  941.                                         case 'M':
  942.                                             ct = 'L';
  943.                                             break;
  944.                                     }
  945.  
  946.                                 }
  947.  
  948.                                 result.push([ct].concat(items.slice(j, j + bin)).join(' '));
  949.                                 times++;
  950.  
  951.                             }
  952.  
  953.                             commands = Array.prototype.concat.apply(commands, result);
  954.  
  955.                         } else {
  956.  
  957.                             commands.push(command);
  958.  
  959.                         }
  960.  
  961.                     });
  962.  
  963.                     // Create the vertices for our Two.Path
  964.  
  965.                     var points = [];
  966.                     _.each(commands, function (command, i) {
  967.  
  968.                         var result, x, y;
  969.                         var type = command[0];
  970.                         var lower = type.toLowerCase();
  971.  
  972.                         coords = command.slice(1).trim();
  973.                         coords = coords.replace(/(-?\d+(?:\.\d*)?)[eE]([+\-]?\d+)/g, function (match, n1, n2) {
  974.                             return parseFloat(n1) * pow(10, n2);
  975.                         });
  976.                         coords = coords.split(/[\s,]+|(?=\s?[+\-])/);
  977.                         relative = type === lower;
  978.  
  979.                         var x1, y1, x2, y2, x3, y3, x4, y4, reflection;
  980.  
  981.                         switch (lower) {
  982.  
  983.                             case 'z':
  984.                                 if (i >= last) {
  985.                                     closed = true;
  986.                                 } else {
  987.                                     x = coord.x;
  988.                                     y = coord.y;
  989.                                     result = new Two.Anchor(
  990.                                         x, y,
  991.                                         undefined, undefined,
  992.                                         undefined, undefined,
  993.                                         Two.Commands.close
  994.                                     );
  995.                                 }
  996.                                 break;
  997.  
  998.                             case 'm':
  999.                             case 'l':
  1000.  
  1001.                                 x = parseFloat(coords[0]);
  1002.                                 y = parseFloat(coords[1]);
  1003.  
  1004.                                 result = new Two.Anchor(
  1005.                                     x, y,
  1006.                                     undefined, undefined,
  1007.                                     undefined, undefined,
  1008.                                     lower === 'm' ? Two.Commands.move : Two.Commands.line
  1009.                                 );
  1010.  
  1011.                                 if (relative) {
  1012.                                     result.addSelf(coord);
  1013.                                 }
  1014.  
  1015.                                 // result.controls.left.copy(result);
  1016.                                 // result.controls.right.copy(result);
  1017.  
  1018.                                 coord = result;
  1019.                                 break;
  1020.  
  1021.                             case 'h':
  1022.                             case 'v':
  1023.  
  1024.                                 var a = lower === 'h' ? 'x' : 'y';
  1025.                                 var b = a === 'x' ? 'y' : 'x';
  1026.  
  1027.                                 result = new Two.Anchor(
  1028.                                     undefined, undefined,
  1029.                                     undefined, undefined,
  1030.                                     undefined, undefined,
  1031.                                     Two.Commands.line
  1032.                                 );
  1033.                                 result[a] = parseFloat(coords[0]);
  1034.                                 result[b] = coord[b];
  1035.  
  1036.                                 if (relative) {
  1037.                                     result[a] += coord[a];
  1038.                                 }
  1039.  
  1040.                                 // result.controls.left.copy(result);
  1041.                                 // result.controls.right.copy(result);
  1042.  
  1043.                                 coord = result;
  1044.                                 break;
  1045.  
  1046.                             case 'c':
  1047.                             case 's':
  1048.  
  1049.                                 x1 = coord.x;
  1050.                                 y1 = coord.y;
  1051.  
  1052.                                 if (!control) {
  1053.                                     control = new Two.Vector();//.copy(coord);
  1054.                                 }
  1055.  
  1056.                                 if (lower === 'c') {
  1057.  
  1058.                                     x2 = parseFloat(coords[0]);
  1059.                                     y2 = parseFloat(coords[1]);
  1060.                                     x3 = parseFloat(coords[2]);
  1061.                                     y3 = parseFloat(coords[3]);
  1062.                                     x4 = parseFloat(coords[4]);
  1063.                                     y4 = parseFloat(coords[5]);
  1064.  
  1065.                                 } else {
  1066.  
  1067.                                     // Calculate reflection control point for proper x2, y2
  1068.                                     // inclusion.
  1069.  
  1070.                                     reflection = getReflection(coord, control, relative);
  1071.  
  1072.                                     x2 = reflection.x;
  1073.                                     y2 = reflection.y;
  1074.                                     x3 = parseFloat(coords[0]);
  1075.                                     y3 = parseFloat(coords[1]);
  1076.                                     x4 = parseFloat(coords[2]);
  1077.                                     y4 = parseFloat(coords[3]);
  1078.  
  1079.                                 }
  1080.  
  1081.                                 if (relative) {
  1082.                                     x2 += x1;
  1083.                                     y2 += y1;
  1084.                                     x3 += x1;
  1085.                                     y3 += y1;
  1086.                                     x4 += x1;
  1087.                                     y4 += y1;
  1088.                                 }
  1089.  
  1090.                                 if (!_.isObject(coord.controls)) {
  1091.                                     Two.Anchor.AppendCurveProperties(coord);
  1092.                                 }
  1093.  
  1094.                                 coord.controls.right.set(x2 - coord.x, y2 - coord.y);
  1095.                                 result = new Two.Anchor(
  1096.                                     x4, y4,
  1097.                                     x3 - x4, y3 - y4,
  1098.                                     undefined, undefined,
  1099.                                     Two.Commands.curve
  1100.                                 );
  1101.  
  1102.                                 coord = result;
  1103.                                 control = result.controls.left;
  1104.  
  1105.                                 break;
  1106.  
  1107.                             case 't':
  1108.                             case 'q':
  1109.  
  1110.                                 x1 = coord.x;
  1111.                                 y1 = coord.y;
  1112.  
  1113.                                 if (!control) {
  1114.                                     control = new Two.Vector();//.copy(coord);
  1115.                                 }
  1116.  
  1117.                                 if (control.isZero()) {
  1118.                                     x2 = x1;
  1119.                                     y2 = y1;
  1120.                                 } else {
  1121.                                     x2 = control.x;
  1122.                                     y1 = control.y;
  1123.                                 }
  1124.  
  1125.                                 if (lower === 'q') {
  1126.  
  1127.                                     x3 = parseFloat(coords[0]);
  1128.                                     y3 = parseFloat(coords[1]);
  1129.                                     x4 = parseFloat(coords[1]);
  1130.                                     y4 = parseFloat(coords[2]);
  1131.  
  1132.                                 } else {
  1133.  
  1134.                                     reflection = getReflection(coord, control, relative);
  1135.  
  1136.                                     x3 = reflection.x;
  1137.                                     y3 = reflection.y;
  1138.                                     x4 = parseFloat(coords[0]);
  1139.                                     y4 = parseFloat(coords[1]);
  1140.  
  1141.                                 }
  1142.  
  1143.                                 if (relative) {
  1144.                                     x2 += x1;
  1145.                                     y2 += y1;
  1146.                                     x3 += x1;
  1147.                                     y3 += y1;
  1148.                                     x4 += x1;
  1149.                                     y4 += y1;
  1150.                                 }
  1151.  
  1152.                                 if (!_.isObject(coord.controls)) {
  1153.                                     Two.Anchor.AppendCurveProperties(coord);
  1154.                                 }
  1155.  
  1156.                                 coord.controls.right.set(x2 - coord.x, y2 - coord.y);
  1157.                                 result = new Two.Anchor(
  1158.                                     x4, y4,
  1159.                                     x3 - x4, y3 - y4,
  1160.                                     undefined, undefined,
  1161.                                     Two.Commands.curve
  1162.                                 );
  1163.  
  1164.                                 coord = result;
  1165.                                 control = result.controls.left;
  1166.  
  1167.                                 break;
  1168.  
  1169.                             case 'a':
  1170.  
  1171.                                 // throw new Two.Utils.Error('not yet able to interpret Elliptical Arcs.');
  1172.                                 x1 = coord.x;
  1173.                                 y1 = coord.y;
  1174.  
  1175.                                 var rx = parseFloat(coords[0]);
  1176.                                 var ry = parseFloat(coords[1]);
  1177.                                 var xAxisRotation = parseFloat(coords[2]) * Math.PI / 180;
  1178.                                 var largeArcFlag = parseFloat(coords[3]);
  1179.                                 var sweepFlag = parseFloat(coords[4]);
  1180.  
  1181.                                 x4 = parseFloat(coords[5]);
  1182.                                 y4 = parseFloat(coords[6]);
  1183.  
  1184.                                 if (relative) {
  1185.                                     x4 += x1;
  1186.                                     y4 += y1;
  1187.                                 }
  1188.  
  1189.                                 // http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
  1190.  
  1191.                                 // Calculate midpoint mx my
  1192.                                 var mx = (x4 - x1) / 2;
  1193.                                 var my = (y4 - y1) / 2;
  1194.  
  1195.                                 // Calculate x1' y1' F.6.5.1
  1196.                                 var _x = mx * Math.cos(xAxisRotation) + my * Math.sin(xAxisRotation);
  1197.                                 var _y = - mx * Math.sin(xAxisRotation) + my * Math.cos(xAxisRotation);
  1198.  
  1199.                                 var rx2 = rx * rx;
  1200.                                 var ry2 = ry * ry;
  1201.                                 var _x2 = _x * _x;
  1202.                                 var _y2 = _y * _y;
  1203.  
  1204.                                 // adjust radii
  1205.                                 var l = _x2 / rx2 + _y2 / ry2;
  1206.                                 if (l > 1) {
  1207.                                     rx *= Math.sqrt(l);
  1208.                                     ry *= Math.sqrt(l);
  1209.                                 }
  1210.  
  1211.                                 var amp = Math.sqrt((rx2 * ry2 - rx2 * _y2 - ry2 * _x2) / (rx2 * _y2 + ry2 * _x2));
  1212.  
  1213.                                 if (_.isNaN(amp)) {
  1214.                                     amp = 0;
  1215.                                 } else if (largeArcFlag != sweepFlag && amp > 0) {
  1216.                                     amp *= -1;
  1217.                                 }
  1218.  
  1219.                                 // Calculate cx' cy' F.6.5.2
  1220.                                 var _cx = amp * rx * _y / ry;
  1221.                                 var _cy = - amp * ry * _x / rx;
  1222.  
  1223.                                 // Calculate cx cy F.6.5.3
  1224.                                 var cx = _cx * Math.cos(xAxisRotation) - _cy * Math.sin(xAxisRotation) + (x1 + x4) / 2;
  1225.                                 var cy = _cx * Math.sin(xAxisRotation) + _cy * Math.cos(xAxisRotation) + (y1 + y4) / 2;
  1226.  
  1227.                                 // vector magnitude
  1228.                                 var m = function (v) { return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2)); }
  1229.                                 // ratio between two vectors
  1230.                                 var r = function (u, v) { return (u[0] * v[0] + u[1] * v[1]) / (m(u) * m(v)) }
  1231.                                 // angle between two vectors
  1232.                                 var a = function (u, v) { return (u[0] * v[1] < u[1] * v[0] ? - 1 : 1) * Math.acos(r(u, v)); }
  1233.  
  1234.                                 // Calculate theta1 and delta theta F.6.5.4 + F.6.5.5
  1235.                                 var t1 = a([1, 0], [(_x - _cx) / rx, (_y - _cy) / ry]);
  1236.                                 var u = [(_x - _cx) / rx, (_y - _cy) / ry];
  1237.                                 var v = [(- _x - _cx) / rx, (- _y - _cy) / ry];
  1238.                                 var dt = a(u, v);
  1239.  
  1240.                                 if (r(u, v) <= -1) dt = Math.PI;
  1241.                                 if (r(u, v) >= 1) dt = 0;
  1242.  
  1243.                                 // F.6.5.6
  1244.                                 if (largeArcFlag) {
  1245.                                     dt = mod(dt, Math.PI * 2);
  1246.                                 }
  1247.  
  1248.                                 if (sweepFlag && dt > 0) {
  1249.                                     dt -= Math.PI * 2;
  1250.                                 }
  1251.  
  1252.                                 var length = Two.Resolution;
  1253.  
  1254.                                 // Save a projection of our rotation and translation to apply
  1255.                                 // to the set of points.
  1256.                                 var projection = new Two.Matrix()
  1257.                                     .translate(cx, cy)
  1258.                                     .rotate(xAxisRotation);
  1259.  
  1260.                                 // Create a resulting array of Two.Anchor's to export to the
  1261.                                 // the path.
  1262.                                 result = _.map(_.range(length), function (i) {
  1263.                                     var pct = 1 - (i / (length - 1));
  1264.                                     var theta = pct * dt + t1;
  1265.                                     var x = rx * Math.cos(theta);
  1266.                                     var y = ry * Math.sin(theta);
  1267.                                     var projected = projection.multiply(x, y, 1);
  1268.                                     return new Two.Anchor(projected.x, projected.y, false, false, false, false, Two.Commands.line);;
  1269.                                 });
  1270.  
  1271.                                 result.push(new Two.Anchor(x4, y4, false, false, false, false, Two.Commands.line));
  1272.  
  1273.                                 coord = result[result.length - 1];
  1274.                                 control = coord.controls.left;
  1275.  
  1276.                                 break;
  1277.  
  1278.                         }
  1279.  
  1280.                         if (result) {
  1281.                             if (_.isArray(result)) {
  1282.                                 points = points.concat(result);
  1283.                             } else {
  1284.                                 points.push(result);
  1285.                             }
  1286.                         }
  1287.  
  1288.                     });
  1289.  
  1290.                     if (points.length <= 1) {
  1291.                         return;
  1292.                     }
  1293.  
  1294.                     var path = new Two.Path(points, closed, undefined, true).noStroke();
  1295.                     path.fill = 'black';
  1296.  
  1297.                     var rect = path.getBoundingClientRect(true);
  1298.  
  1299.                     // Center objects to stay consistent
  1300.                     // with the rest of the Two.js API.
  1301.                     rect.centroid = {
  1302.                         x: rect.left + rect.width / 2,
  1303.                         y: rect.top + rect.height / 2
  1304.                     };
  1305.  
  1306.                     _.each(path.vertices, function (v) {
  1307.                         v.subSelf(rect.centroid);
  1308.                     });
  1309.  
  1310.                     path.translation.addSelf(rect.centroid);
  1311.  
  1312.                     return Two.Utils.applySvgAttributes.call(this, node, path);
  1313.  
  1314.                 },
  1315.  
  1316.                 circle: function (node) {
  1317.  
  1318.                     var x = parseFloat(node.getAttribute('cx'));
  1319.                     var y = parseFloat(node.getAttribute('cy'));
  1320.                     var r = parseFloat(node.getAttribute('r'));
  1321.  
  1322.                     var circle = new Two.Circle(x, y, r).noStroke();
  1323.                     circle.fill = 'black';
  1324.  
  1325.                     return Two.Utils.applySvgAttributes.call(this, node, circle);
  1326.  
  1327.                 },
  1328.  
  1329.                 ellipse: function (node) {
  1330.  
  1331.                     var x = parseFloat(node.getAttribute('cx'));
  1332.                     var y = parseFloat(node.getAttribute('cy'));
  1333.                     var width = parseFloat(node.getAttribute('rx'));
  1334.                     var height = parseFloat(node.getAttribute('ry'));
  1335.  
  1336.                     var ellipse = new Two.Ellipse(x, y, width, height).noStroke();
  1337.                     ellipse.fill = 'black';
  1338.  
  1339.                     return Two.Utils.applySvgAttributes.call(this, node, ellipse);
  1340.  
  1341.                 },
  1342.  
  1343.                 rect: function (node) {
  1344.  
  1345.                     var x = parseFloat(node.getAttribute('x')) || 0;
  1346.                     var y = parseFloat(node.getAttribute('y')) || 0;
  1347.                     var width = parseFloat(node.getAttribute('width'));
  1348.                     var height = parseFloat(node.getAttribute('height'));
  1349.  
  1350.                     var w2 = width / 2;
  1351.                     var h2 = height / 2;
  1352.  
  1353.                     var rect = new Two.Rectangle(x + w2, y + h2, width, height)
  1354.                         .noStroke();
  1355.                     rect.fill = 'black';
  1356.  
  1357.                     return Two.Utils.applySvgAttributes.call(this, node, rect);
  1358.  
  1359.                 },
  1360.  
  1361.                 line: function (node) {
  1362.  
  1363.                     var x1 = parseFloat(node.getAttribute('x1'));
  1364.                     var y1 = parseFloat(node.getAttribute('y1'));
  1365.                     var x2 = parseFloat(node.getAttribute('x2'));
  1366.                     var y2 = parseFloat(node.getAttribute('y2'));
  1367.  
  1368.                     var line = new Two.Line(x1, y1, x2, y2).noFill();
  1369.  
  1370.                     return Two.Utils.applySvgAttributes.call(this, node, line);
  1371.  
  1372.                 },
  1373.  
  1374.                 lineargradient: function (node) {
  1375.  
  1376.                     var x1 = parseFloat(node.getAttribute('x1'));
  1377.                     var y1 = parseFloat(node.getAttribute('y1'));
  1378.                     var x2 = parseFloat(node.getAttribute('x2'));
  1379.                     var y2 = parseFloat(node.getAttribute('y2'));
  1380.  
  1381.                     var ox = (x2 + x1) / 2;
  1382.                     var oy = (y2 + y1) / 2;
  1383.  
  1384.                     var stops = [];
  1385.                     for (var i = 0; i < node.children.length; i++) {
  1386.  
  1387.                         var child = node.children[i];
  1388.  
  1389.                         var offset = parseFloat(child.getAttribute('offset'));
  1390.                         var color = child.getAttribute('stop-color');
  1391.                         var opacity = child.getAttribute('stop-opacity');
  1392.                         var style = child.getAttribute('style');
  1393.  
  1394.                         if (_.isNull(color)) {
  1395.                             var matches = style ? style.match(/stop\-color\:\s?([\#a-fA-F0-9]*)/) : false;
  1396.                             color = matches && matches.length > 1 ? matches[1] : undefined;
  1397.                         }
  1398.  
  1399.                         if (_.isNull(opacity)) {
  1400.                             var matches = style ? style.match(/stop\-opacity\:\s?([0-9\.\-]*)/) : false;
  1401.                             opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
  1402.                         }
  1403.  
  1404.                         stops.push(new Two.Gradient.Stop(offset, color, opacity));
  1405.  
  1406.                     }
  1407.  
  1408.                     var gradient = new Two.LinearGradient(x1 - ox, y1 - oy, x2 - ox,
  1409.                         y2 - oy, stops);
  1410.  
  1411.                     return Two.Utils.applySvgAttributes.call(this, node, gradient);
  1412.  
  1413.                 },
  1414.  
  1415.                 radialgradient: function (node) {
  1416.  
  1417.                     var cx = parseFloat(node.getAttribute('cx')) || 0;
  1418.                     var cy = parseFloat(node.getAttribute('cy')) || 0;
  1419.                     var r = parseFloat(node.getAttribute('r'));
  1420.  
  1421.                     var fx = parseFloat(node.getAttribute('fx'));
  1422.                     var fy = parseFloat(node.getAttribute('fy'));
  1423.  
  1424.                     if (_.isNaN(fx)) {
  1425.                         fx = cx;
  1426.                     }
  1427.  
  1428.                     if (_.isNaN(fy)) {
  1429.                         fy = cy;
  1430.                     }
  1431.  
  1432.                     var ox = Math.abs(cx + fx) / 2;
  1433.                     var oy = Math.abs(cy + fy) / 2;
  1434.  
  1435.                     var stops = [];
  1436.                     for (var i = 0; i < node.children.length; i++) {
  1437.  
  1438.                         var child = node.children[i];
  1439.  
  1440.                         var offset = parseFloat(child.getAttribute('offset'));
  1441.                         var color = child.getAttribute('stop-color');
  1442.                         var opacity = child.getAttribute('stop-opacity');
  1443.                         var style = child.getAttribute('style');
  1444.  
  1445.                         if (_.isNull(color)) {
  1446.                             var matches = style ? style.match(/stop\-color\:\s?([\#a-fA-F0-9]*)/) : false;
  1447.                             color = matches && matches.length > 1 ? matches[1] : undefined;
  1448.                         }
  1449.  
  1450.                         if (_.isNull(opacity)) {
  1451.                             var matches = style ? style.match(/stop\-opacity\:\s?([0-9\.\-]*)/) : false;
  1452.                             opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
  1453.                         }
  1454.  
  1455.                         stops.push(new Two.Gradient.Stop(offset, color, opacity));
  1456.  
  1457.                     }
  1458.  
  1459.                     var gradient = new Two.RadialGradient(cx - ox, cy - oy, r,
  1460.                         stops, fx - ox, fy - oy);
  1461.  
  1462.                     return Two.Utils.applySvgAttributes.call(this, node, gradient);
  1463.  
  1464.                 }
  1465.  
  1466.             },
  1467.  
  1468.             /**
  1469.                 * Given 2 points (a, b) and corresponding control point for each
  1470.                 * return an array of points that represent points plotted along
  1471.                 * the curve. Number points determined by limit.
  1472.                 */
  1473.             subdivide: function (x1, y1, x2, y2, x3, y3, x4, y4, limit) {
  1474.  
  1475.                 limit = limit || Two.Utils.Curve.RecursionLimit;
  1476.                 var amount = limit + 1;
  1477.  
  1478.                 // TODO: Issue 73
  1479.                 // Don't recurse if the end points are identical
  1480.                 if (x1 === x4 && y1 === y4) {
  1481.                     return [new Two.Anchor(x4, y4)];
  1482.                 }
  1483.  
  1484.                 return _.map(_.range(0, amount), function (i) {
  1485.  
  1486.                     var t = i / amount;
  1487.                     var x = getPointOnCubicBezier(t, x1, x2, x3, x4);
  1488.                     var y = getPointOnCubicBezier(t, y1, y2, y3, y4);
  1489.  
  1490.                     return new Two.Anchor(x, y);
  1491.  
  1492.                 });
  1493.  
  1494.             },
  1495.  
  1496.             getPointOnCubicBezier: function (t, a, b, c, d) {
  1497.                 var k = 1 - t;
  1498.                 return (k * k * k * a) + (3 * k * k * t * b) + (3 * k * t * t * c) +
  1499.                     (t * t * t * d);
  1500.             },
  1501.  
  1502.             /**
  1503.                 * Given 2 points (a, b) and corresponding control point for each
  1504.                 * return a float that represents the length of the curve using
  1505.                 * Gauss-Legendre algorithm. Limit iterations of calculation by `limit`.
  1506.                 */
  1507.             getCurveLength: function (x1, y1, x2, y2, x3, y3, x4, y4, limit) {
  1508.  
  1509.                 // TODO: Better / fuzzier equality check
  1510.                 // Linear calculation
  1511.                 if (x1 === x2 && y1 === y2 && x3 === x4 && y3 === y4) {
  1512.                     var dx = x4 - x1;
  1513.                     var dy = y4 - y1;
  1514.                     return sqrt(dx * dx + dy * dy);
  1515.                 }
  1516.  
  1517.                 // Calculate the coefficients of a Bezier derivative.
  1518.                 var ax = 9 * (x2 - x3) + 3 * (x4 - x1),
  1519.                     bx = 6 * (x1 + x3) - 12 * x2,
  1520.                     cx = 3 * (x2 - x1),
  1521.  
  1522.                     ay = 9 * (y2 - y3) + 3 * (y4 - y1),
  1523.                     by = 6 * (y1 + y3) - 12 * y2,
  1524.                     cy = 3 * (y2 - y1);
  1525.  
  1526.                 var integrand = function (t) {
  1527.                     // Calculate quadratic equations of derivatives for x and y
  1528.                     var dx = (ax * t + bx) * t + cx,
  1529.                         dy = (ay * t + by) * t + cy;
  1530.                     return sqrt(dx * dx + dy * dy);
  1531.                 };
  1532.  
  1533.                 return integrate(
  1534.                     integrand, 0, 1, limit || Two.Utils.Curve.RecursionLimit
  1535.                 );
  1536.  
  1537.             },
  1538.  
  1539.             /**
  1540.                 * Integration for `getCurveLength` calculations. Referenced from
  1541.                 * Paper.js: https://github.com/paperjs/paper.js/blob/master/src/util/Numerical.js#L101
  1542.                 */
  1543.             integrate: function (f, a, b, n) {
  1544.                 var x = Two.Utils.Curve.abscissas[n - 2],
  1545.                     w = Two.Utils.Curve.weights[n - 2],
  1546.                     A = 0.5 * (b - a),
  1547.                     B = A + a,
  1548.                     i = 0,
  1549.                     m = (n + 1) >> 1,
  1550.                     sum = n & 1 ? w[i++] * f(B) : 0; // Handle odd n
  1551.                 while (i < m) {
  1552.                     var Ax = A * x[i];
  1553.                     sum += w[i++] * (f(B + Ax) + f(B - Ax));
  1554.                 }
  1555.                 return A * sum;
  1556.             },
  1557.  
  1558.             /**
  1559.                 * Creates a set of points that have u, v values for anchor positions
  1560.                 */
  1561.             getCurveFromPoints: function (points, closed) {
  1562.  
  1563.                 var l = points.length, last = l - 1;
  1564.  
  1565.                 for (var i = 0; i < l; i++) {
  1566.  
  1567.                     var point = points[i];
  1568.  
  1569.                     if (!_.isObject(point.controls)) {
  1570.                         Two.Anchor.AppendCurveProperties(point);
  1571.                     }
  1572.  
  1573.                     var prev = closed ? mod(i - 1, l) : max(i - 1, 0);
  1574.                     var next = closed ? mod(i + 1, l) : min(i + 1, last);
  1575.  
  1576.                     var a = points[prev];
  1577.                     var b = point;
  1578.                     var c = points[next];
  1579.                     getControlPoints(a, b, c);
  1580.  
  1581.                     b._command = i === 0 ? Two.Commands.move : Two.Commands.curve;
  1582.  
  1583.                     b.controls.left.x = _.isNumber(b.controls.left.x) ? b.controls.left.x : b.x;
  1584.                     b.controls.left.y = _.isNumber(b.controls.left.y) ? b.controls.left.y : b.y;
  1585.  
  1586.                     b.controls.right.x = _.isNumber(b.controls.right.x) ? b.controls.right.x : b.x;
  1587.                     b.controls.right.y = _.isNumber(b.controls.right.y) ? b.controls.right.y : b.y;
  1588.  
  1589.                 }
  1590.  
  1591.             },
  1592.  
  1593.             /**
  1594.                 * Given three coordinates return the control points for the middle, b,
  1595.                 * vertex.
  1596.                 */
  1597.             getControlPoints: function (a, b, c) {
  1598.  
  1599.                 var a1 = angleBetween(a, b);
  1600.                 var a2 = angleBetween(c, b);
  1601.  
  1602.                 var d1 = distanceBetween(a, b);
  1603.                 var d2 = distanceBetween(c, b);
  1604.  
  1605.                 var mid = (a1 + a2) / 2;
  1606.  
  1607.                 // So we know which angle corresponds to which side.
  1608.  
  1609.                 b.u = _.isObject(b.controls.left) ? b.controls.left : new Two.Vector(0, 0);
  1610.                 b.v = _.isObject(b.controls.right) ? b.controls.right : new Two.Vector(0, 0);
  1611.  
  1612.                 // TODO: Issue 73
  1613.                 if (d1 < 0.0001 || d2 < 0.0001) {
  1614.                     if (!b._relative) {
  1615.                         b.controls.left.copy(b);
  1616.                         b.controls.right.copy(b);
  1617.                     }
  1618.                     return b;
  1619.                 }
  1620.  
  1621.                 d1 *= 0.33; // Why 0.33?
  1622.                 d2 *= 0.33;
  1623.  
  1624.                 if (a2 < a1) {
  1625.                     mid += HALF_PI;
  1626.                 } else {
  1627.                     mid -= HALF_PI;
  1628.                 }
  1629.  
  1630.                 b.controls.left.x = cos(mid) * d1;
  1631.                 b.controls.left.y = sin(mid) * d1;
  1632.  
  1633.                 mid -= PI;
  1634.  
  1635.                 b.controls.right.x = cos(mid) * d2;
  1636.                 b.controls.right.y = sin(mid) * d2;
  1637.  
  1638.                 if (!b._relative) {
  1639.                     b.controls.left.x += b.x;
  1640.                     b.controls.left.y += b.y;
  1641.                     b.controls.right.x += b.x;
  1642.                     b.controls.right.y += b.y;
  1643.                 }
  1644.  
  1645.                 return b;
  1646.  
  1647.             },
  1648.  
  1649.             /**
  1650.                 * Get the reflection of a point "b" about point "a". Where "a" is in
  1651.                 * absolute space and "b" is relative to "a".
  1652.                 *
  1653.                 * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
  1654.                 */
  1655.             getReflection: function (a, b, relative) {
  1656.  
  1657.                 return new Two.Vector(
  1658.                     2 * a.x - (b.x + a.x) - (relative ? a.x : 0),
  1659.                     2 * a.y - (b.y + a.y) - (relative ? a.y : 0)
  1660.                 );
  1661.  
  1662.             },
  1663.  
  1664.             getAnchorsFromArcData: function (center, xAxisRotation, rx, ry, ts, td, ccw) {
  1665.  
  1666.                 var matrix = new Two.Matrix()
  1667.                     .translate(center.x, center.y)
  1668.                     .rotate(xAxisRotation);
  1669.  
  1670.                 var l = Two.Resolution;
  1671.  
  1672.                 return _.map(_.range(l), function (i) {
  1673.  
  1674.                     var pct = (i + 1) / l;
  1675.                     if (!!ccw) {
  1676.                         pct = 1 - pct;
  1677.                     }
  1678.  
  1679.                     var theta = pct * td + ts;
  1680.                     var x = rx * Math.cos(theta);
  1681.                     var y = ry * Math.sin(theta);
  1682.  
  1683.                     // x += center.x;
  1684.                     // y += center.y;
  1685.  
  1686.                     var anchor = new Two.Anchor(x, y);
  1687.                     Two.Anchor.AppendCurveProperties(anchor);
  1688.                     anchor.command = Two.Commands.line;
  1689.  
  1690.                     // TODO: Calculate control points here...
  1691.  
  1692.                     return anchor;
  1693.  
  1694.                 });
  1695.  
  1696.             },
  1697.  
  1698.             ratioBetween: function (A, B) {
  1699.  
  1700.                 return (A.x * B.x + A.y * B.y) / (A.length() * B.length());
  1701.  
  1702.             },
  1703.  
  1704.             angleBetween: function (A, B) {
  1705.  
  1706.                 var dx, dy;
  1707.  
  1708.                 if (arguments.length >= 4) {
  1709.  
  1710.                     dx = arguments[0] - arguments[2];
  1711.                     dy = arguments[1] - arguments[3];
  1712.  
  1713.                     return atan2(dy, dx);
  1714.  
  1715.                 }
  1716.  
  1717.                 dx = A.x - B.x;
  1718.                 dy = A.y - B.y;
  1719.  
  1720.                 return atan2(dy, dx);
  1721.  
  1722.             },
  1723.  
  1724.             distanceBetweenSquared: function (p1, p2) {
  1725.  
  1726.                 var dx = p1.x - p2.x;
  1727.                 var dy = p1.y - p2.y;
  1728.  
  1729.                 return dx * dx + dy * dy;
  1730.  
  1731.             },
  1732.  
  1733.             distanceBetween: function (p1, p2) {
  1734.  
  1735.                 return sqrt(distanceBetweenSquared(p1, p2));
  1736.  
  1737.             },
  1738.  
  1739.             lerp: function (a, b, t) {
  1740.                 return t * (b - a) + a;
  1741.             },
  1742.  
  1743.             // A pretty fast toFixed(3) alternative
  1744.             // See http://jsperf.com/parsefloat-tofixed-vs-math-round/18
  1745.             toFixed: function (v) {
  1746.                 return Math.floor(v * 1000) / 1000;
  1747.             },
  1748.  
  1749.             mod: function (v, l) {
  1750.  
  1751.                 while (v < 0) {
  1752.                     v += l;
  1753.                 }
  1754.  
  1755.                 return v % l;
  1756.  
  1757.             },
  1758.  
  1759.             /**
  1760.                 * Array like collection that triggers inserted and removed events
  1761.                 * removed : pop / shift / splice
  1762.                 * inserted : push / unshift / splice (with > 2 arguments)
  1763.                 */
  1764.             Collection: function () {
  1765.  
  1766.                 Array.call(this);
  1767.  
  1768.                 if (arguments.length > 1) {
  1769.                     Array.prototype.push.apply(this, arguments);
  1770.                 } else if (arguments[0] && Array.isArray(arguments[0])) {
  1771.                     Array.prototype.push.apply(this, arguments[0]);
  1772.                 }
  1773.  
  1774.             },
  1775.  
  1776.             // Custom Error Throwing for Two.js
  1777.  
  1778.             Error: function (message) {
  1779.                 this.name = 'two.js';
  1780.                 this.message = message;
  1781.             },
  1782.  
  1783.             Events: {
  1784.  
  1785.                 on: function (name, callback) {
  1786.  
  1787.                     this._events || (this._events = {});
  1788.                     var list = this._events[name] || (this._events[name] = []);
  1789.  
  1790.                     list.push(callback);
  1791.  
  1792.                     return this;
  1793.  
  1794.                 },
  1795.  
  1796.                 off: function (name, callback) {
  1797.  
  1798.                     if (!this._events) {
  1799.                         return this;
  1800.                     }
  1801.                     if (!name && !callback) {
  1802.                         this._events = {};
  1803.                         return this;
  1804.                     }
  1805.  
  1806.                     var names = name ? [name] : _.keys(this._events);
  1807.                     for (var i = 0, l = names.length; i < l; i++) {
  1808.  
  1809.                         var name = names[i];
  1810.                         var list = this._events[name];
  1811.  
  1812.                         if (!!list) {
  1813.                             var events = [];
  1814.                             if (callback) {
  1815.                                 for (var j = 0, k = list.length; j < k; j++) {
  1816.                                     var ev = list[j];
  1817.                                     ev = ev.callback ? ev.callback : ev;
  1818.                                     if (callback && callback !== ev) {
  1819.                                         events.push(ev);
  1820.                                     }
  1821.                                 }
  1822.                             }
  1823.                             this._events[name] = events;
  1824.                         }
  1825.                     }
  1826.  
  1827.                     return this;
  1828.                 },
  1829.  
  1830.                 trigger: function (name) {
  1831.                     if (!this._events) return this;
  1832.                     var args = slice.call(arguments, 1);
  1833.                     var events = this._events[name];
  1834.                     if (events) trigger(this, events, args);
  1835.                     return this;
  1836.                 },
  1837.  
  1838.                 listen: function (obj, name, callback) {
  1839.  
  1840.                     var bound = this;
  1841.  
  1842.                     if (obj) {
  1843.                         var ev = function () {
  1844.                             callback.apply(bound, arguments);
  1845.                         };
  1846.  
  1847.                         // add references about the object that assigned this listener
  1848.                         ev.obj = obj;
  1849.                         ev.name = name;
  1850.                         ev.callback = callback;
  1851.  
  1852.                         obj.on(name, ev);
  1853.                     }
  1854.  
  1855.                     return this;
  1856.  
  1857.                 },
  1858.  
  1859.                 ignore: function (obj, name, callback) {
  1860.  
  1861.                     obj.off(name, callback);
  1862.  
  1863.                     return this;
  1864.  
  1865.                 }
  1866.  
  1867.             }
  1868.  
  1869.         })
  1870.  
  1871.     });
  1872.  
  1873.     Two.Utils.Events.bind = Two.Utils.Events.on;
  1874.     Two.Utils.Events.unbind = Two.Utils.Events.off;
  1875.  
  1876.     var trigger = function (obj, events, args) {
  1877.         var method;
  1878.         switch (args.length) {
  1879.             case 0:
  1880.                 method = function (i) {
  1881.                     events[i].call(obj, args[0]);
  1882.                 };
  1883.                 break;
  1884.             case 1:
  1885.                 method = function (i) {
  1886.                     events[i].call(obj, args[0], args[1]);
  1887.                 };
  1888.                 break;
  1889.             case 2:
  1890.                 method = function (i) {
  1891.                     events[i].call(obj, args[0], args[1], args[2]);
  1892.                 };
  1893.                 break;
  1894.             case 3:
  1895.                 method = function (i) {
  1896.                     events[i].call(obj, args[0], args[1], args[2], args[3]);
  1897.                 };
  1898.                 break;
  1899.             default:
  1900.                 method = function (i) {
  1901.                     events[i].apply(obj, args);
  1902.                 };
  1903.         }
  1904.         for (var i = 0; i < events.length; i++) {
  1905.             method(i);
  1906.         }
  1907.     };
  1908.  
  1909.     Two.Utils.Error.prototype = new Error();
  1910.     Two.Utils.Error.prototype.constructor = Two.Utils.Error;
  1911.  
  1912.     Two.Utils.Collection.prototype = new Array();
  1913.     Two.Utils.Collection.prototype.constructor = Two.Utils.Collection;
  1914.  
  1915.     _.extend(Two.Utils.Collection.prototype, Two.Utils.Events, {
  1916.  
  1917.         pop: function () {
  1918.             var popped = Array.prototype.pop.apply(this, arguments);
  1919.             this.trigger(Two.Events.remove, [popped]);
  1920.             return popped;
  1921.         },
  1922.  
  1923.         shift: function () {
  1924.             var shifted = Array.prototype.shift.apply(this, arguments);
  1925.             this.trigger(Two.Events.remove, [shifted]);
  1926.             return shifted;
  1927.         },
  1928.  
  1929.         push: function () {
  1930.             var pushed = Array.prototype.push.apply(this, arguments);
  1931.             this.trigger(Two.Events.insert, arguments);
  1932.             return pushed;
  1933.         },
  1934.  
  1935.         unshift: function () {
  1936.             var unshifted = Array.prototype.unshift.apply(this, arguments);
  1937.             this.trigger(Two.Events.insert, arguments);
  1938.             return unshifted;
  1939.         },
  1940.  
  1941.         splice: function () {
  1942.             var spliced = Array.prototype.splice.apply(this, arguments);
  1943.             var inserted;
  1944.  
  1945.             this.trigger(Two.Events.remove, spliced);
  1946.  
  1947.             if (arguments.length > 2) {
  1948.                 inserted = this.slice(arguments[0], arguments[0] + arguments.length - 2);
  1949.                 this.trigger(Two.Events.insert, inserted);
  1950.                 this.trigger(Two.Events.order);
  1951.             }
  1952.             return spliced;
  1953.         },
  1954.  
  1955.         sort: function () {
  1956.             Array.prototype.sort.apply(this, arguments);
  1957.             this.trigger(Two.Events.order);
  1958.             return this;
  1959.         },
  1960.  
  1961.         reverse: function () {
  1962.             Array.prototype.reverse.apply(this, arguments);
  1963.             this.trigger(Two.Events.order);
  1964.             return this;
  1965.         }
  1966.  
  1967.     });
  1968.  
  1969.     // Localize utils
  1970.  
  1971.     var distanceBetween = Two.Utils.distanceBetween,
  1972.         getAnchorsFromArcData = Two.Utils.getAnchorsFromArcData,
  1973.         distanceBetweenSquared = Two.Utils.distanceBetweenSquared,
  1974.         ratioBetween = Two.Utils.ratioBetween,
  1975.         angleBetween = Two.Utils.angleBetween,
  1976.         getControlPoints = Two.Utils.getControlPoints,
  1977.         getCurveFromPoints = Two.Utils.getCurveFromPoints,
  1978.         solveSegmentIntersection = Two.Utils.solveSegmentIntersection,
  1979.         decoupleShapes = Two.Utils.decoupleShapes,
  1980.         mod = Two.Utils.mod,
  1981.         getBackingStoreRatio = Two.Utils.getBackingStoreRatio,
  1982.         getPointOnCubicBezier = Two.Utils.getPointOnCubicBezier,
  1983.         getCurveLength = Two.Utils.getCurveLength,
  1984.         integrate = Two.Utils.integrate,
  1985.         getReflection = Two.Utils.getReflection;
  1986.  
  1987.     _.extend(Two.prototype, Two.Utils.Events, {
  1988.  
  1989.         appendTo: function (elem) {
  1990.  
  1991.             elem.appendChild(this.renderer.domElement);
  1992.             return this;
  1993.  
  1994.         },
  1995.  
  1996.         play: function () {
  1997.  
  1998.             Two.Utils.setPlaying.call(this, true);
  1999.             return this.trigger(Two.Events.play);
  2000.  
  2001.         },
  2002.  
  2003.         pause: function () {
  2004.  
  2005.             this.playing = false;
  2006.             return this.trigger(Two.Events.pause);
  2007.  
  2008.         },
  2009.  
  2010.         /**
  2011.             * Update positions and calculations in one pass before rendering.
  2012.             */
  2013.         update: function () {
  2014.  
  2015.             var animated = !!this._lastFrame;
  2016.             var now = perf.now();
  2017.  
  2018.             this.frameCount++;
  2019.  
  2020.             if (animated) {
  2021.                 this.timeDelta = parseFloat((now - this._lastFrame).toFixed(3));
  2022.             }
  2023.             this._lastFrame = now;
  2024.  
  2025.             var width = this.width;
  2026.             var height = this.height;
  2027.             var renderer = this.renderer;
  2028.  
  2029.             // Update width / height for the renderer
  2030.             if (width !== renderer.width || height !== renderer.height) {
  2031.                 renderer.setSize(width, height, this.ratio);
  2032.             }
  2033.  
  2034.             this.trigger(Two.Events.update, this.frameCount, this.timeDelta);
  2035.  
  2036.             return this.render();
  2037.  
  2038.         },
  2039.  
  2040.         /**
  2041.             * Render all drawable - visible objects of the scene.
  2042.             */
  2043.         render: function () {
  2044.  
  2045.             this.renderer.render();
  2046.             return this.trigger(Two.Events.render, this.frameCount);
  2047.  
  2048.         },
  2049.  
  2050.         /**
  2051.             * Convenience Methods
  2052.             */
  2053.  
  2054.         add: function (o) {
  2055.  
  2056.             var objects = o;
  2057.             if (!(objects instanceof Array)) {
  2058.                 objects = _.toArray(arguments);
  2059.             }
  2060.  
  2061.             this.scene.add(objects);
  2062.             return this;
  2063.  
  2064.         },
  2065.  
  2066.         remove: function (o) {
  2067.  
  2068.             var objects = o;
  2069.             if (!(objects instanceof Array)) {
  2070.                 objects = _.toArray(arguments);
  2071.             }
  2072.  
  2073.             this.scene.remove(objects);
  2074.  
  2075.             return this;
  2076.  
  2077.         },
  2078.  
  2079.         clear: function () {
  2080.  
  2081.             this.scene.remove(_.toArray(this.scene.children));
  2082.             return this;
  2083.  
  2084.         },
  2085.  
  2086.         makeLine: function (x1, y1, x2, y2) {
  2087.  
  2088.             var line = new Two.Line(x1, y1, x2, y2);
  2089.             this.scene.add(line);
  2090.  
  2091.             return line;
  2092.  
  2093.         },
  2094.  
  2095.         makeRectangle: function (x, y, width, height) {
  2096.  
  2097.             var rect = new Two.Rectangle(x, y, width, height);
  2098.             this.scene.add(rect);
  2099.  
  2100.             return rect;
  2101.  
  2102.         },
  2103.  
  2104.         makeRoundedRectangle: function (x, y, width, height, sides) {
  2105.  
  2106.             var rect = new Two.RoundedRectangle(x, y, width, height, sides);
  2107.             this.scene.add(rect);
  2108.  
  2109.             return rect;
  2110.  
  2111.         },
  2112.  
  2113.         makeCircle: function (ox, oy, r) {
  2114.  
  2115.             var circle = new Two.Circle(ox, oy, r);
  2116.             this.scene.add(circle);
  2117.  
  2118.             return circle;
  2119.  
  2120.         },
  2121.  
  2122.         makeEllipse: function (ox, oy, rx, ry) {
  2123.  
  2124.             var ellipse = new Two.Ellipse(ox, oy, rx, ry);
  2125.             this.scene.add(ellipse);
  2126.  
  2127.             return ellipse;
  2128.  
  2129.         },
  2130.  
  2131.         makeStar: function (ox, oy, or, ir, sides) {
  2132.  
  2133.             var star = new Two.Star(ox, oy, or, ir, sides);
  2134.             this.scene.add(star);
  2135.  
  2136.             return star;
  2137.  
  2138.         },
  2139.  
  2140.         makeCurve: function (p) {
  2141.  
  2142.             var l = arguments.length, points = p;
  2143.             if (!_.isArray(p)) {
  2144.                 points = [];
  2145.                 for (var i = 0; i < l; i += 2) {
  2146.                     var x = arguments[i];
  2147.                     if (!_.isNumber(x)) {
  2148.                         break;
  2149.                     }
  2150.                     var y = arguments[i + 1];
  2151.                     points.push(new Two.Anchor(x, y));
  2152.                 }
  2153.             }
  2154.  
  2155.             var last = arguments[l - 1];
  2156.             var curve = new Two.Path(points, !(_.isBoolean(last) ? last : undefined), true);
  2157.             var rect = curve.getBoundingClientRect();
  2158.             curve.center().translation
  2159.                 .set(rect.left + rect.width / 2, rect.top + rect.height / 2);
  2160.  
  2161.             this.scene.add(curve);
  2162.  
  2163.             return curve;
  2164.  
  2165.         },
  2166.  
  2167.         makePolygon: function (ox, oy, r, sides) {
  2168.  
  2169.             var poly = new Two.Polygon(ox, oy, r, sides);
  2170.             this.scene.add(poly);
  2171.  
  2172.             return poly;
  2173.  
  2174.         },
  2175.  
  2176.         /*
  2177.         * Make an Arc Segment
  2178.         */
  2179.  
  2180.         makeArcSegment: function (ox, oy, ir, or, sa, ea, res) {
  2181.             var arcSegment = new Two.ArcSegment(ox, oy, ir, or, sa, ea, res);
  2182.             this.scene.add(arcSegment);
  2183.             return arcSegment;
  2184.         },
  2185.  
  2186.         /**
  2187.             * Convenience method to make and draw a Two.Path.
  2188.             */
  2189.         makePath: function (p) {
  2190.  
  2191.             var l = arguments.length, points = p;
  2192.             if (!_.isArray(p)) {
  2193.                 points = [];
  2194.                 for (var i = 0; i < l; i += 2) {
  2195.                     var x = arguments[i];
  2196.                     if (!_.isNumber(x)) {
  2197.                         break;
  2198.                     }
  2199.                     var y = arguments[i + 1];
  2200.                     points.push(new Two.Anchor(x, y));
  2201.                 }
  2202.             }
  2203.  
  2204.             var last = arguments[l - 1];
  2205.             var path = new Two.Path(points, !(_.isBoolean(last) ? last : undefined));
  2206.             var rect = path.getBoundingClientRect();
  2207.             path.center().translation
  2208.                 .set(rect.left + rect.width / 2, rect.top + rect.height / 2);
  2209.  
  2210.             this.scene.add(path);
  2211.  
  2212.             return path;
  2213.  
  2214.         },
  2215.  
  2216.         /**
  2217.             * Convenience method to make and add a Two.Text.
  2218.             */
  2219.         makeText: function (message, x, y, styles) {
  2220.             var text = new Two.Text(message, x, y, styles);
  2221.             this.add(text);
  2222.             return text;
  2223.         },
  2224.  
  2225.         /**
  2226.             * Convenience method to make and add a Two.LinearGradient.
  2227.             */
  2228.         makeLinearGradient: function (x1, y1, x2, y2 /* stops */) {
  2229.  
  2230.             var stops = slice.call(arguments, 4);
  2231.             var gradient = new Two.LinearGradient(x1, y1, x2, y2, stops);
  2232.  
  2233.             this.add(gradient);
  2234.  
  2235.             return gradient;
  2236.  
  2237.         },
  2238.  
  2239.         /**
  2240.             * Convenience method to make and add a Two.RadialGradient.
  2241.             */
  2242.         makeRadialGradient: function (x1, y1, r /* stops */) {
  2243.  
  2244.             var stops = slice.call(arguments, 3);
  2245.             var gradient = new Two.RadialGradient(x1, y1, r, stops);
  2246.  
  2247.             this.add(gradient);
  2248.  
  2249.             return gradient;
  2250.  
  2251.         },
  2252.  
  2253.         makeSprite: function (path, x, y, cols, rows, frameRate, autostart) {
  2254.  
  2255.             var sprite = new Two.Sprite(path, x, y, cols, rows, frameRate);
  2256.             if (!!autostart) {
  2257.                 sprite.play();
  2258.             }
  2259.             this.add(sprite);
  2260.  
  2261.             return sprite;
  2262.  
  2263.         },
  2264.  
  2265.         makeImageSequence: function (paths, x, y, frameRate, autostart) {
  2266.  
  2267.             var imageSequence = new Two.ImageSequence(paths, x, y, frameRate);
  2268.             if (!!autostart) {
  2269.                 imageSequence.play();
  2270.             }
  2271.             this.add(imageSequence);
  2272.  
  2273.             return imageSequence;
  2274.  
  2275.         },
  2276.  
  2277.         makeTexture: function (path, callback) {
  2278.  
  2279.             var texture = new Two.Texture(path, callback);
  2280.             return texture;
  2281.  
  2282.         },
  2283.  
  2284.         makeGroup: function (o) {
  2285.  
  2286.             var objects = o;
  2287.             if (!(objects instanceof Array)) {
  2288.                 objects = _.toArray(arguments);
  2289.             }
  2290.  
  2291.             var group = new Two.Group();
  2292.             this.scene.add(group);
  2293.             group.add(objects);
  2294.  
  2295.             return group;
  2296.  
  2297.         },
  2298.  
  2299.         /**
  2300.             * Interpret an SVG Node and add it to this instance's scene. The
  2301.             * distinction should be made that this doesn't `import` svg's, it solely
  2302.             * interprets them into something compatible for Two.js — this is slightly
  2303.             * different than a direct transcription.
  2304.             *
  2305.             * @param {Object} svgNode - The node to be parsed
  2306.             * @param {Boolean} shallow - Don't create a top-most group but
  2307.             *                                    append all contents directly
  2308.             */
  2309.         interpret: function (svgNode, shallow) {
  2310.  
  2311.             var tag = svgNode.tagName.toLowerCase();
  2312.  
  2313.             if (!(tag in Two.Utils.read)) {
  2314.                 return null;
  2315.             }
  2316.  
  2317.             var node = Two.Utils.read[tag].call(this, svgNode);
  2318.  
  2319.             if (shallow && node instanceof Two.Group) {
  2320.                 this.add(node.children);
  2321.             } else {
  2322.                 this.add(node);
  2323.             }
  2324.  
  2325.             return node;
  2326.  
  2327.         },
  2328.  
  2329.         /**
  2330.             * Load an SVG file / text and interpret.
  2331.             */
  2332.         load: function (text, callback) {
  2333.  
  2334.             var nodes = [], elem, i;
  2335.  
  2336.             if (/.*\.svg/ig.test(text)) {
  2337.  
  2338.                 Two.Utils.xhr(text, _.bind(function (data) {
  2339.  
  2340.                     dom.temp.innerHTML = data;
  2341.                     for (i = 0; i < dom.temp.children.length; i++) {
  2342.                         elem = dom.temp.children[i];
  2343.                         nodes.push(this.interpret(elem));
  2344.                     }
  2345.  
  2346.                     callback(nodes.length <= 1 ? nodes[0] : nodes,
  2347.                         dom.temp.children.length <= 1 ? dom.temp.children[0] : dom.temp.children);
  2348.  
  2349.                 }, this));
  2350.  
  2351.                 return this;
  2352.  
  2353.             }
  2354.  
  2355.             dom.temp.innerHTML = text;
  2356.             for (i = 0; i < dom.temp.children.length; i++) {
  2357.                 elem = dom.temp.children[i];
  2358.                 nodes.push(this.interpret(elem));
  2359.             }
  2360.  
  2361.             callback(nodes.length <= 1 ? nodes[0] : nodes,
  2362.                 dom.temp.children.length <= 1 ? dom.temp.children[0] : dom.temp.children);
  2363.  
  2364.             return this;
  2365.  
  2366.         }
  2367.  
  2368.     });
  2369.  
  2370.     function fitToWindow() {
  2371.  
  2372.         var wr = document.body.getBoundingClientRect();
  2373.  
  2374.         var width = this.width = wr.width;
  2375.         var height = this.height = wr.height;
  2376.  
  2377.         this.renderer.setSize(width, height, this.ratio);
  2378.         this.trigger(Two.Events.resize, width, height);
  2379.  
  2380.     }
  2381.  
  2382.     // Request Animation Frame
  2383.  
  2384.     var raf = dom.getRequestAnimationFrame();
  2385.  
  2386.     function loop() {
  2387.  
  2388.         raf(loop);
  2389.  
  2390.         for (var i = 0; i < Two.Instances.length; i++) {
  2391.             var t = Two.Instances[i];
  2392.             if (t.playing) {
  2393.                 t.update();
  2394.             }
  2395.         }
  2396.  
  2397.     }
  2398.  
  2399.     if (typeof define === 'function' && define.amd) {
  2400.         define('two', [], function () {
  2401.             return Two;
  2402.         });
  2403.     } else if (typeof module != 'undefined' && module.exports) {
  2404.         module.exports = Two;
  2405.     }
  2406.  
  2407.     return Two;
  2408.  
  2409. })((typeof global !== 'undefined' ? global : this).Two);
  2410.  
  2411. (function (Two) {
  2412.  
  2413.     var _ = Two.Utils;
  2414.  
  2415.     var Registry = Two.Registry = function () {
  2416.  
  2417.         this.map = {};
  2418.  
  2419.     };
  2420.  
  2421.     _.extend(Registry, {
  2422.  
  2423.     });
  2424.  
  2425.     _.extend(Registry.prototype, {
  2426.  
  2427.         add: function (id, obj) {
  2428.             this.map[id] = obj;
  2429.             return this;
  2430.         },
  2431.  
  2432.         remove: function (id) {
  2433.             delete this.map[id];
  2434.             return this;
  2435.         },
  2436.  
  2437.         get: function (id) {
  2438.             return this.map[id];
  2439.         },
  2440.  
  2441.         contains: function (id) {
  2442.             return id in this.map;
  2443.         }
  2444.  
  2445.     });
  2446.  
  2447. })((typeof global !== 'undefined' ? global : this).Two);
  2448.  
  2449. (function (Two) {
  2450.  
  2451.     var _ = Two.Utils;
  2452.  
  2453.     var Vector = Two.Vector = function (x, y) {
  2454.  
  2455.         this.x = x || 0;
  2456.         this.y = y || 0;
  2457.  
  2458.     };
  2459.  
  2460.     _.extend(Vector, {
  2461.  
  2462.         zero: new Two.Vector()
  2463.  
  2464.     });
  2465.  
  2466.     _.extend(Vector.prototype, Two.Utils.Events, {
  2467.  
  2468.         set: function (x, y) {
  2469.             this.x = x;
  2470.             this.y = y;
  2471.             return this;
  2472.         },
  2473.  
  2474.         copy: function (v) {
  2475.             this.x = v.x;
  2476.             this.y = v.y;
  2477.             return this;
  2478.         },
  2479.  
  2480.         clear: function () {
  2481.             this.x = 0;
  2482.             this.y = 0;
  2483.             return this;
  2484.         },
  2485.  
  2486.         clone: function () {
  2487.             return new Vector(this.x, this.y);
  2488.         },
  2489.  
  2490.         add: function (v1, v2) {
  2491.             this.x = v1.x + v2.x;
  2492.             this.y = v1.y + v2.y;
  2493.             return this;
  2494.         },
  2495.  
  2496.         addSelf: function (v) {
  2497.             this.x += v.x;
  2498.             this.y += v.y;
  2499.             return this;
  2500.         },
  2501.  
  2502.         sub: function (v1, v2) {
  2503.             this.x = v1.x - v2.x;
  2504.             this.y = v1.y - v2.y;
  2505.             return this;
  2506.         },
  2507.  
  2508.         subSelf: function (v) {
  2509.             this.x -= v.x;
  2510.             this.y -= v.y;
  2511.             return this;
  2512.         },
  2513.  
  2514.         multiplySelf: function (v) {
  2515.             this.x *= v.x;
  2516.             this.y *= v.y;
  2517.             return this;
  2518.         },
  2519.  
  2520.         multiplyScalar: function (s) {
  2521.             this.x *= s;
  2522.             this.y *= s;
  2523.             return this;
  2524.         },
  2525.  
  2526.         divideScalar: function (s) {
  2527.             if (s) {
  2528.                 this.x /= s;
  2529.                 this.y /= s;
  2530.             } else {
  2531.                 this.set(0, 0);
  2532.             }
  2533.             return this;
  2534.         },
  2535.  
  2536.         negate: function () {
  2537.             return this.multiplyScalar(-1);
  2538.         },
  2539.  
  2540.         dot: function (v) {
  2541.             return this.x * v.x + this.y * v.y;
  2542.         },
  2543.  
  2544.         lengthSquared: function () {
  2545.             return this.x * this.x + this.y * this.y;
  2546.         },
  2547.  
  2548.         length: function () {
  2549.             return Math.sqrt(this.lengthSquared());
  2550.         },
  2551.  
  2552.         normalize: function () {
  2553.             return this.divideScalar(this.length());
  2554.         },
  2555.  
  2556.         distanceTo: function (v) {
  2557.             return Math.sqrt(this.distanceToSquared(v));
  2558.         },
  2559.  
  2560.         distanceToSquared: function (v) {
  2561.             var dx = this.x - v.x,
  2562.                 dy = this.y - v.y;
  2563.             return dx * dx + dy * dy;
  2564.         },
  2565.  
  2566.         setLength: function (l) {
  2567.             return this.normalize().multiplyScalar(l);
  2568.         },
  2569.  
  2570.         equals: function (v, eps) {
  2571.             eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  2572.             return (this.distanceTo(v) < eps);
  2573.         },
  2574.  
  2575.         lerp: function (v, t) {
  2576.             var x = (v.x - this.x) * t + this.x;
  2577.             var y = (v.y - this.y) * t + this.y;
  2578.             return this.set(x, y);
  2579.         },
  2580.  
  2581.         isZero: function (eps) {
  2582.             eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  2583.             return (this.length() < eps);
  2584.         },
  2585.  
  2586.         toString: function () {
  2587.             return this.x + ', ' + this.y;
  2588.         },
  2589.  
  2590.         toObject: function () {
  2591.             return { x: this.x, y: this.y };
  2592.         },
  2593.  
  2594.         rotate: function (radians) {
  2595.             var cos = Math.cos(radians);
  2596.             var sin = Math.sin(radians);
  2597.             this.x = this.x * cos - this.y * sin;
  2598.             this.y = this.x * sin + this.y * cos;
  2599.             return this;
  2600.         }
  2601.  
  2602.     });
  2603.  
  2604.     var BoundProto = {
  2605.  
  2606.         set: function (x, y) {
  2607.             this._x = x;
  2608.             this._y = y;
  2609.             return this.trigger(Two.Events.change);
  2610.         },
  2611.  
  2612.         copy: function (v) {
  2613.             this._x = v.x;
  2614.             this._y = v.y;
  2615.             return this.trigger(Two.Events.change);
  2616.         },
  2617.  
  2618.         clear: function () {
  2619.             this._x = 0;
  2620.             this._y = 0;
  2621.             return this.trigger(Two.Events.change);
  2622.         },
  2623.  
  2624.         clone: function () {
  2625.             return new Vector(this._x, this._y);
  2626.         },
  2627.  
  2628.         add: function (v1, v2) {
  2629.             this._x = v1.x + v2.x;
  2630.             this._y = v1.y + v2.y;
  2631.             return this.trigger(Two.Events.change);
  2632.         },
  2633.  
  2634.         addSelf: function (v) {
  2635.             this._x += v.x;
  2636.             this._y += v.y;
  2637.             return this.trigger(Two.Events.change);
  2638.         },
  2639.  
  2640.         sub: function (v1, v2) {
  2641.             this._x = v1.x - v2.x;
  2642.             this._y = v1.y - v2.y;
  2643.             return this.trigger(Two.Events.change);
  2644.         },
  2645.  
  2646.         subSelf: function (v) {
  2647.             this._x -= v.x;
  2648.             this._y -= v.y;
  2649.             return this.trigger(Two.Events.change);
  2650.         },
  2651.  
  2652.         multiplySelf: function (v) {
  2653.             this._x *= v.x;
  2654.             this._y *= v.y;
  2655.             return this.trigger(Two.Events.change);
  2656.         },
  2657.  
  2658.         multiplyScalar: function (s) {
  2659.             this._x *= s;
  2660.             this._y *= s;
  2661.             return this.trigger(Two.Events.change);
  2662.         },
  2663.  
  2664.         divideScalar: function (s) {
  2665.             if (s) {
  2666.                 this._x /= s;
  2667.                 this._y /= s;
  2668.                 return this.trigger(Two.Events.change);
  2669.             }
  2670.             return this.clear();
  2671.         },
  2672.  
  2673.         negate: function () {
  2674.             return this.multiplyScalar(-1);
  2675.         },
  2676.  
  2677.         dot: function (v) {
  2678.             return this._x * v.x + this._y * v.y;
  2679.         },
  2680.  
  2681.         lengthSquared: function () {
  2682.             return this._x * this._x + this._y * this._y;
  2683.         },
  2684.  
  2685.         length: function () {
  2686.             return Math.sqrt(this.lengthSquared());
  2687.         },
  2688.  
  2689.         normalize: function () {
  2690.             return this.divideScalar(this.length());
  2691.         },
  2692.  
  2693.         distanceTo: function (v) {
  2694.             return Math.sqrt(this.distanceToSquared(v));
  2695.         },
  2696.  
  2697.         distanceToSquared: function (v) {
  2698.             var dx = this._x - v.x,
  2699.                 dy = this._y - v.y;
  2700.             return dx * dx + dy * dy;
  2701.         },
  2702.  
  2703.         setLength: function (l) {
  2704.             return this.normalize().multiplyScalar(l);
  2705.         },
  2706.  
  2707.         equals: function (v, eps) {
  2708.             eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  2709.             return (this.distanceTo(v) < eps);
  2710.         },
  2711.  
  2712.         lerp: function (v, t) {
  2713.             var x = (v.x - this._x) * t + this._x;
  2714.             var y = (v.y - this._y) * t + this._y;
  2715.             return this.set(x, y);
  2716.         },
  2717.  
  2718.         isZero: function (eps) {
  2719.             eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  2720.             return (this.length() < eps);
  2721.         },
  2722.  
  2723.         toString: function () {
  2724.             return this._x + ', ' + this._y;
  2725.         },
  2726.  
  2727.         toObject: function () {
  2728.             return { x: this._x, y: this._y };
  2729.         },
  2730.  
  2731.         rotate: function (radians) {
  2732.             var cos = Math.cos(radians);
  2733.             var sin = Math.sin(radians);
  2734.             this._x = this._x * cos - this._y * sin;
  2735.             this._y = this._x * sin + this._y * cos;
  2736.             return this;
  2737.         }
  2738.  
  2739.     };
  2740.  
  2741.     var xgs = {
  2742.         enumerable: true,
  2743.         get: function () {
  2744.             return this._x;
  2745.         },
  2746.         set: function (v) {
  2747.             this._x = v;
  2748.             this.trigger(Two.Events.change, 'x');
  2749.         }
  2750.     };
  2751.  
  2752.     var ygs = {
  2753.         enumerable: true,
  2754.         get: function () {
  2755.             return this._y;
  2756.         },
  2757.         set: function (v) {
  2758.             this._y = v;
  2759.             this.trigger(Two.Events.change, 'y');
  2760.         }
  2761.     };
  2762.  
  2763.     /**
  2764.         * Override Backbone bind / on in order to add properly broadcasting.
  2765.         * This allows Two.Vector to not broadcast events unless event listeners
  2766.         * are explicity bound to it.
  2767.         */
  2768.  
  2769.     Two.Vector.prototype.bind = Two.Vector.prototype.on = function () {
  2770.  
  2771.         if (!this._bound) {
  2772.             this._x = this.x;
  2773.             this._y = this.y;
  2774.             Object.defineProperty(this, 'x', xgs);
  2775.             Object.defineProperty(this, 'y', ygs);
  2776.             _.extend(this, BoundProto);
  2777.             this._bound = true; // Reserved for event initialization check
  2778.         }
  2779.  
  2780.         Two.Utils.Events.bind.apply(this, arguments);
  2781.  
  2782.         return this;
  2783.  
  2784.     };
  2785.  
  2786. })((typeof global !== 'undefined' ? global : this).Two);
  2787.  
  2788. (function (Two) {
  2789.  
  2790.     // Localized variables
  2791.     var commands = Two.Commands;
  2792.     var _ = Two.Utils;
  2793.  
  2794.     /**
  2795.         * An object that holds 3 `Two.Vector`s, the anchor point and its
  2796.         * corresponding handles: `left` and `right`.
  2797.         */
  2798.     var Anchor = Two.Anchor = function (x, y, ux, uy, vx, vy, command) {
  2799.  
  2800.         Two.Vector.call(this, x, y);
  2801.  
  2802.         this._broadcast = _.bind(function () {
  2803.             this.trigger(Two.Events.change);
  2804.         }, this);
  2805.  
  2806.         this._command = command || commands.move;
  2807.         this._relative = true;
  2808.  
  2809.         if (!command) {
  2810.             return this;
  2811.         }
  2812.  
  2813.         Anchor.AppendCurveProperties(this);
  2814.  
  2815.         if (_.isNumber(ux)) {
  2816.             this.controls.left.x = ux;
  2817.         }
  2818.         if (_.isNumber(uy)) {
  2819.             this.controls.left.y = uy;
  2820.         }
  2821.         if (_.isNumber(vx)) {
  2822.             this.controls.right.x = vx;
  2823.         }
  2824.         if (_.isNumber(vy)) {
  2825.             this.controls.right.y = vy;
  2826.         }
  2827.  
  2828.     };
  2829.  
  2830.     _.extend(Anchor, {
  2831.  
  2832.         AppendCurveProperties: function (anchor) {
  2833.             anchor.controls = {
  2834.                 left: new Two.Vector(0, 0),
  2835.                 right: new Two.Vector(0, 0)
  2836.             };
  2837.         }
  2838.  
  2839.     });
  2840.  
  2841.     var AnchorProto = {
  2842.  
  2843.         listen: function () {
  2844.  
  2845.             if (!_.isObject(this.controls)) {
  2846.                 Anchor.AppendCurveProperties(this);
  2847.             }
  2848.  
  2849.             this.controls.left.bind(Two.Events.change, this._broadcast);
  2850.             this.controls.right.bind(Two.Events.change, this._broadcast);
  2851.  
  2852.             return this;
  2853.  
  2854.         },
  2855.  
  2856.         ignore: function () {
  2857.  
  2858.             this.controls.left.unbind(Two.Events.change, this._broadcast);
  2859.             this.controls.right.unbind(Two.Events.change, this._broadcast);
  2860.  
  2861.             return this;
  2862.  
  2863.         },
  2864.  
  2865.         clone: function () {
  2866.  
  2867.             var controls = this.controls;
  2868.  
  2869.             var clone = new Two.Anchor(
  2870.                 this.x,
  2871.                 this.y,
  2872.                 controls && controls.left.x,
  2873.                 controls && controls.left.y,
  2874.                 controls && controls.right.x,
  2875.                 controls && controls.right.y,
  2876.                 this.command
  2877.             );
  2878.             clone.relative = this._relative;
  2879.             return clone;
  2880.  
  2881.         },
  2882.  
  2883.         toObject: function () {
  2884.             var o = {
  2885.                 x: this.x,
  2886.                 y: this.y
  2887.             };
  2888.             if (this._command) {
  2889.                 o.command = this._command;
  2890.             }
  2891.             if (this._relative) {
  2892.                 o.relative = this._relative;
  2893.             }
  2894.             if (this.controls) {
  2895.                 o.controls = {
  2896.                     left: this.controls.left.toObject(),
  2897.                     right: this.controls.right.toObject()
  2898.                 };
  2899.             }
  2900.             return o;
  2901.         },
  2902.  
  2903.         toString: function () {
  2904.             if (!this.controls) {
  2905.                 return [this._x, this._y].join(', ');
  2906.             }
  2907.             return [this._x, this._y, this.controls.left.x, this.controls.left.y,
  2908.             this.controls.right.x, this.controls.right.y].join(', ');
  2909.         }
  2910.  
  2911.     };
  2912.  
  2913.     Object.defineProperty(Anchor.prototype, 'command', {
  2914.  
  2915.         enumerable: true,
  2916.  
  2917.         get: function () {
  2918.             return this._command;
  2919.         },
  2920.  
  2921.         set: function (c) {
  2922.             this._command = c;
  2923.             if (this._command === commands.curve && !_.isObject(this.controls)) {
  2924.                 Anchor.AppendCurveProperties(this);
  2925.             }
  2926.             return this.trigger(Two.Events.change);
  2927.         }
  2928.  
  2929.     });
  2930.  
  2931.     Object.defineProperty(Anchor.prototype, 'relative', {
  2932.  
  2933.         enumerable: true,
  2934.  
  2935.         get: function () {
  2936.             return this._relative;
  2937.         },
  2938.  
  2939.         set: function (b) {
  2940.             if (this._relative == b) {
  2941.                 return this;
  2942.             }
  2943.             this._relative = !!b;
  2944.             return this.trigger(Two.Events.change);
  2945.         }
  2946.  
  2947.     });
  2948.  
  2949.     _.extend(Anchor.prototype, Two.Vector.prototype, AnchorProto);
  2950.  
  2951.     // Make it possible to bind and still have the Anchor specific
  2952.     // inheritance from Two.Vector
  2953.     Two.Anchor.prototype.bind = Two.Anchor.prototype.on = function () {
  2954.         Two.Vector.prototype.bind.apply(this, arguments);
  2955.         _.extend(this, AnchorProto);
  2956.     };
  2957.  
  2958.     Two.Anchor.prototype.unbind = Two.Anchor.prototype.off = function () {
  2959.         Two.Vector.prototype.unbind.apply(this, arguments);
  2960.         _.extend(this, AnchorProto);
  2961.     };
  2962.  
  2963. })((typeof global !== 'undefined' ? global : this).Two);
  2964.  
  2965. (function (Two) {
  2966.  
  2967.     /**
  2968.         * Constants
  2969.         */
  2970.     var cos = Math.cos, sin = Math.sin, tan = Math.tan;
  2971.     var _ = Two.Utils;
  2972.  
  2973.     /**
  2974.         * Two.Matrix contains an array of elements that represent
  2975.         * the two dimensional 3 x 3 matrix as illustrated below:
  2976.         *
  2977.         * =====
  2978.         * a b c
  2979.         * d e f
  2980.         * g h i  // this row is not really used in 2d transformations
  2981.         * =====
  2982.         *
  2983.         * String order is for transform strings: a, d, b, e, c, f
  2984.         *
  2985.         * @class
  2986.         */
  2987.     var Matrix = Two.Matrix = function (a, b, c, d, e, f) {
  2988.  
  2989.         this.elements = new Two.Array(9);
  2990.  
  2991.         var elements = a;
  2992.         if (!_.isArray(elements)) {
  2993.             elements = _.toArray(arguments);
  2994.         }
  2995.  
  2996.         // initialize the elements with default values.
  2997.  
  2998.         this.identity().set(elements);
  2999.  
  3000.     };
  3001.  
  3002.     _.extend(Matrix, {
  3003.  
  3004.         Identity: [
  3005.             1, 0, 0,
  3006.             0, 1, 0,
  3007.             0, 0, 1
  3008.         ],
  3009.  
  3010.         /**
  3011.             * Multiply two matrix 3x3 arrays
  3012.             */
  3013.         Multiply: function (A, B, C) {
  3014.  
  3015.             if (B.length <= 3) { // Multiply Vector
  3016.  
  3017.                 var x, y, z, e = A;
  3018.  
  3019.                 var a = B[0] || 0,
  3020.                     b = B[1] || 0,
  3021.                     c = B[2] || 0;
  3022.  
  3023.                 // Go down rows first
  3024.                 // a, d, g, b, e, h, c, f, i
  3025.  
  3026.                 x = e[0] * a + e[1] * b + e[2] * c;
  3027.                 y = e[3] * a + e[4] * b + e[5] * c;
  3028.                 z = e[6] * a + e[7] * b + e[8] * c;
  3029.  
  3030.                 return { x: x, y: y, z: z };
  3031.  
  3032.             }
  3033.  
  3034.             var A0 = A[0], A1 = A[1], A2 = A[2];
  3035.             var A3 = A[3], A4 = A[4], A5 = A[5];
  3036.             var A6 = A[6], A7 = A[7], A8 = A[8];
  3037.  
  3038.             var B0 = B[0], B1 = B[1], B2 = B[2];
  3039.             var B3 = B[3], B4 = B[4], B5 = B[5];
  3040.             var B6 = B[6], B7 = B[7], B8 = B[8];
  3041.  
  3042.             C = C || new Two.Array(9);
  3043.  
  3044.             C[0] = A0 * B0 + A1 * B3 + A2 * B6;
  3045.             C[1] = A0 * B1 + A1 * B4 + A2 * B7;
  3046.             C[2] = A0 * B2 + A1 * B5 + A2 * B8;
  3047.             C[3] = A3 * B0 + A4 * B3 + A5 * B6;
  3048.             C[4] = A3 * B1 + A4 * B4 + A5 * B7;
  3049.             C[5] = A3 * B2 + A4 * B5 + A5 * B8;
  3050.             C[6] = A6 * B0 + A7 * B3 + A8 * B6;
  3051.             C[7] = A6 * B1 + A7 * B4 + A8 * B7;
  3052.             C[8] = A6 * B2 + A7 * B5 + A8 * B8;
  3053.  
  3054.             return C;
  3055.  
  3056.         }
  3057.  
  3058.     });
  3059.  
  3060.     _.extend(Matrix.prototype, Two.Utils.Events, {
  3061.  
  3062.         /**
  3063.             * Takes an array of elements or the arguments list itself to
  3064.             * set and update the current matrix's elements. Only updates
  3065.             * specified values.
  3066.             */
  3067.         set: function (a) {
  3068.  
  3069.             var elements = a;
  3070.             if (!_.isArray(elements)) {
  3071.                 elements = _.toArray(arguments);
  3072.             }
  3073.  
  3074.             _.extend(this.elements, elements);
  3075.  
  3076.             return this.trigger(Two.Events.change);
  3077.  
  3078.         },
  3079.  
  3080.         /**
  3081.             * Turn matrix to identity, like resetting.
  3082.             */
  3083.         identity: function () {
  3084.  
  3085.             this.set(Matrix.Identity);
  3086.  
  3087.             return this;
  3088.  
  3089.         },
  3090.  
  3091.         /**
  3092.             * Multiply scalar or multiply by another matrix.
  3093.             */
  3094.         multiply: function (a, b, c, d, e, f, g, h, i) {
  3095.  
  3096.             var elements = arguments, l = elements.length;
  3097.  
  3098.             // Multiply scalar
  3099.  
  3100.             if (l <= 1) {
  3101.  
  3102.                 _.each(this.elements, function (v, i) {
  3103.                     this.elements[i] = v * a;
  3104.                 }, this);
  3105.  
  3106.                 return this.trigger(Two.Events.change);
  3107.  
  3108.             }
  3109.  
  3110.             if (l <= 3) { // Multiply Vector
  3111.  
  3112.                 var x, y, z;
  3113.                 a = a || 0;
  3114.                 b = b || 0;
  3115.                 c = c || 0;
  3116.                 e = this.elements;
  3117.  
  3118.                 // Go down rows first
  3119.                 // a, d, g, b, e, h, c, f, i
  3120.  
  3121.                 x = e[0] * a + e[1] * b + e[2] * c;
  3122.                 y = e[3] * a + e[4] * b + e[5] * c;
  3123.                 z = e[6] * a + e[7] * b + e[8] * c;
  3124.  
  3125.                 return { x: x, y: y, z: z };
  3126.  
  3127.             }
  3128.  
  3129.             // Multiple matrix
  3130.  
  3131.             var A = this.elements;
  3132.             var B = elements;
  3133.  
  3134.             var A0 = A[0], A1 = A[1], A2 = A[2];
  3135.             var A3 = A[3], A4 = A[4], A5 = A[5];
  3136.             var A6 = A[6], A7 = A[7], A8 = A[8];
  3137.  
  3138.             var B0 = B[0], B1 = B[1], B2 = B[2];
  3139.             var B3 = B[3], B4 = B[4], B5 = B[5];
  3140.             var B6 = B[6], B7 = B[7], B8 = B[8];
  3141.  
  3142.             this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6;
  3143.             this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7;
  3144.             this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8;
  3145.  
  3146.             this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6;
  3147.             this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7;
  3148.             this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8;
  3149.  
  3150.             this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6;
  3151.             this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7;
  3152.             this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8;
  3153.  
  3154.             return this.trigger(Two.Events.change);
  3155.  
  3156.         },
  3157.  
  3158.         inverse: function (out) {
  3159.  
  3160.             var a = this.elements;
  3161.             out = out || new Two.Matrix();
  3162.  
  3163.             var a00 = a[0], a01 = a[1], a02 = a[2];
  3164.             var a10 = a[3], a11 = a[4], a12 = a[5];
  3165.             var a20 = a[6], a21 = a[7], a22 = a[8];
  3166.  
  3167.             var b01 = a22 * a11 - a12 * a21;
  3168.             var b11 = -a22 * a10 + a12 * a20;
  3169.             var b21 = a21 * a10 - a11 * a20;
  3170.  
  3171.             // Calculate the determinant
  3172.             var det = a00 * b01 + a01 * b11 + a02 * b21;
  3173.  
  3174.             if (!det) {
  3175.                 return null;
  3176.             }
  3177.  
  3178.             det = 1.0 / det;
  3179.  
  3180.             out.elements[0] = b01 * det;
  3181.             out.elements[1] = (-a22 * a01 + a02 * a21) * det;
  3182.             out.elements[2] = (a12 * a01 - a02 * a11) * det;
  3183.             out.elements[3] = b11 * det;
  3184.             out.elements[4] = (a22 * a00 - a02 * a20) * det;
  3185.             out.elements[5] = (-a12 * a00 + a02 * a10) * det;
  3186.             out.elements[6] = b21 * det;
  3187.             out.elements[7] = (-a21 * a00 + a01 * a20) * det;
  3188.             out.elements[8] = (a11 * a00 - a01 * a10) * det;
  3189.  
  3190.             return out;
  3191.  
  3192.         },
  3193.  
  3194.         /**
  3195.             * Set a scalar onto the matrix.
  3196.             */
  3197.         scale: function (sx, sy) {
  3198.  
  3199.             var l = arguments.length;
  3200.             if (l <= 1) {
  3201.                 sy = sx;
  3202.             }
  3203.  
  3204.             return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1);
  3205.  
  3206.         },
  3207.  
  3208.         /**
  3209.             * Rotate the matrix.
  3210.             */
  3211.         rotate: function (radians) {
  3212.  
  3213.             var c = cos(radians);
  3214.             var s = sin(radians);
  3215.  
  3216.             return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1);
  3217.  
  3218.         },
  3219.  
  3220.         /**
  3221.             * Translate the matrix.
  3222.             */
  3223.         translate: function (x, y) {
  3224.  
  3225.             return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1);
  3226.  
  3227.         },
  3228.  
  3229.         /*
  3230.             * Skew the matrix by an angle in the x axis direction.
  3231.             */
  3232.         skewX: function (radians) {
  3233.  
  3234.             var a = tan(radians);
  3235.  
  3236.             return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1);
  3237.  
  3238.         },
  3239.  
  3240.         /*
  3241.             * Skew the matrix by an angle in the y axis direction.
  3242.             */
  3243.         skewY: function (radians) {
  3244.  
  3245.             var a = tan(radians);
  3246.  
  3247.             return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1);
  3248.  
  3249.         },
  3250.  
  3251.         /**
  3252.             * Create a transform string to be used with rendering apis.
  3253.             */
  3254.         toString: function (fullMatrix) {
  3255.             var temp = [];
  3256.  
  3257.             this.toArray(fullMatrix, temp);
  3258.  
  3259.             return temp.join(' ');
  3260.  
  3261.         },
  3262.  
  3263.         /**
  3264.             * Create a transform array to be used with rendering apis.
  3265.             */
  3266.         toArray: function (fullMatrix, output) {
  3267.  
  3268.             var elements = this.elements;
  3269.             var hasOutput = !!output;
  3270.  
  3271.             var a = parseFloat(elements[0].toFixed(3));
  3272.             var b = parseFloat(elements[1].toFixed(3));
  3273.             var c = parseFloat(elements[2].toFixed(3));
  3274.             var d = parseFloat(elements[3].toFixed(3));
  3275.             var e = parseFloat(elements[4].toFixed(3));
  3276.             var f = parseFloat(elements[5].toFixed(3));
  3277.  
  3278.             if (!!fullMatrix) {
  3279.  
  3280.                 var g = parseFloat(elements[6].toFixed(3));
  3281.                 var h = parseFloat(elements[7].toFixed(3));
  3282.                 var i = parseFloat(elements[8].toFixed(3));
  3283.  
  3284.                 if (hasOutput) {
  3285.                     output[0] = a;
  3286.                     output[1] = d;
  3287.                     output[2] = g;
  3288.                     output[3] = b;
  3289.                     output[4] = e;
  3290.                     output[5] = h;
  3291.                     output[6] = c;
  3292.                     output[7] = f;
  3293.                     output[8] = i;
  3294.                     return;
  3295.                 }
  3296.  
  3297.                 return [
  3298.                     a, d, g, b, e, h, c, f, i
  3299.                 ];
  3300.             }
  3301.  
  3302.             if (hasOutput) {
  3303.                 output[0] = a;
  3304.                 output[1] = d;
  3305.                 output[2] = b;
  3306.                 output[3] = e;
  3307.                 output[4] = c;
  3308.                 output[5] = f;
  3309.                 return;
  3310.             }
  3311.  
  3312.             return [
  3313.                 a, d, b, e, c, f  // Specific format see LN:19
  3314.             ];
  3315.  
  3316.         },
  3317.  
  3318.         /**
  3319.             * Clone the current matrix.
  3320.             */
  3321.         clone: function () {
  3322.             var a, b, c, d, e, f, g, h, i;
  3323.  
  3324.             a = this.elements[0];
  3325.             b = this.elements[1];
  3326.             c = this.elements[2];
  3327.             d = this.elements[3];
  3328.             e = this.elements[4];
  3329.             f = this.elements[5];
  3330.             g = this.elements[6];
  3331.             h = this.elements[7];
  3332.             i = this.elements[8];
  3333.  
  3334.             return new Two.Matrix(a, b, c, d, e, f, g, h, i);
  3335.  
  3336.         }
  3337.  
  3338.     });
  3339.  
  3340. })((typeof global !== 'undefined' ? global : this).Two);
  3341.  
  3342. (function (Two) {
  3343.  
  3344.     // Localize variables
  3345.     var mod = Two.Utils.mod, toFixed = Two.Utils.toFixed;
  3346.     var _ = Two.Utils;
  3347.  
  3348.     var svg = {
  3349.  
  3350.         version: 1.1,
  3351.  
  3352.         ns: 'http://www.w3.org/2000/svg',
  3353.         xlink: 'http://www.w3.org/1999/xlink',
  3354.  
  3355.         alignments: {
  3356.             left: 'start',
  3357.             center: 'middle',
  3358.             right: 'end'
  3359.         },
  3360.  
  3361.         /**
  3362.             * Create an svg namespaced element.
  3363.             */
  3364.         createElement: function (name, attrs) {
  3365.             var tag = name;
  3366.             var elem = document.createElementNS(svg.ns, tag);
  3367.             if (tag === 'svg') {
  3368.                 attrs = _.defaults(attrs || {}, {
  3369.                     version: svg.version
  3370.                 });
  3371.             }
  3372.             if (!_.isEmpty(attrs)) {
  3373.                 svg.setAttributes(elem, attrs);
  3374.             }
  3375.             return elem;
  3376.         },
  3377.  
  3378.         /**
  3379.             * Add attributes from an svg element.
  3380.             */
  3381.         setAttributes: function (elem, attrs) {
  3382.             var keys = Object.keys(attrs);
  3383.             for (var i = 0; i < keys.length; i++) {
  3384.                 if (/href/.test(keys[i])) {
  3385.                     elem.setAttributeNS(svg.xlink, keys[i], attrs[keys[i]]);
  3386.                 } else {
  3387.                     elem.setAttribute(keys[i], attrs[keys[i]]);
  3388.                 }
  3389.             }
  3390.             return this;
  3391.         },
  3392.  
  3393.         /**
  3394.             * Remove attributes from an svg element.
  3395.             */
  3396.         removeAttributes: function (elem, attrs) {
  3397.             for (var key in attrs) {
  3398.                 elem.removeAttribute(key);
  3399.             }
  3400.             return this;
  3401.         },
  3402.  
  3403.         /**
  3404.             * Turn a set of vertices into a string for the d property of a path
  3405.             * element. It is imperative that the string collation is as fast as
  3406.             * possible, because this call will be happening multiple times a
  3407.             * second.
  3408.             */
  3409.         toString: function (points, closed) {
  3410.  
  3411.             var l = points.length,
  3412.                 last = l - 1,
  3413.                 d, // The elusive last Two.Commands.move point
  3414.                 ret = '';
  3415.  
  3416.             for (var i = 0; i < l; i++) {
  3417.                 var b = points[i];
  3418.                 var command;
  3419.                 var prev = closed ? mod(i - 1, l) : Math.max(i - 1, 0);
  3420.                 var next = closed ? mod(i + 1, l) : Math.min(i + 1, last);
  3421.  
  3422.                 var a = points[prev];
  3423.                 var c = points[next];
  3424.  
  3425.                 var vx, vy, ux, uy, ar, bl, br, cl;
  3426.  
  3427.                 // Access x and y directly,
  3428.                 // bypassing the getter
  3429.                 var x = toFixed(b._x);
  3430.                 var y = toFixed(b._y);
  3431.  
  3432.                 switch (b._command) {
  3433.  
  3434.                     case Two.Commands.close:
  3435.                         command = Two.Commands.close;
  3436.                         break;
  3437.  
  3438.                     case Two.Commands.curve:
  3439.  
  3440.                         ar = (a.controls && a.controls.right) || Two.Vector.zero;
  3441.                         bl = (b.controls && b.controls.left) || Two.Vector.zero;
  3442.  
  3443.                         if (a._relative) {
  3444.                             vx = toFixed((ar.x + a.x));
  3445.                             vy = toFixed((ar.y + a.y));
  3446.                         } else {
  3447.                             vx = toFixed(ar.x);
  3448.                             vy = toFixed(ar.y);
  3449.                         }
  3450.  
  3451.                         if (b._relative) {
  3452.                             ux = toFixed((bl.x + b.x));
  3453.                             uy = toFixed((bl.y + b.y));
  3454.                         } else {
  3455.                             ux = toFixed(bl.x);
  3456.                             uy = toFixed(bl.y);
  3457.                         }
  3458.  
  3459.                         command = ((i === 0) ? Two.Commands.move : Two.Commands.curve) +
  3460.                             ' ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y;
  3461.                         break;
  3462.  
  3463.                     case Two.Commands.move:
  3464.                         d = b;
  3465.                         command = Two.Commands.move + ' ' + x + ' ' + y;
  3466.                         break;
  3467.  
  3468.                     default:
  3469.                         command = b._command + ' ' + x + ' ' + y;
  3470.  
  3471.                 }
  3472.  
  3473.                 // Add a final point and close it off
  3474.  
  3475.                 if (i >= last && closed) {
  3476.  
  3477.                     if (b._command === Two.Commands.curve) {
  3478.  
  3479.                         // Make sure we close to the most previous Two.Commands.move
  3480.                         c = d;
  3481.  
  3482.                         br = (b.controls && b.controls.right) || b;
  3483.                         cl = (c.controls && c.controls.left) || c;
  3484.  
  3485.                         if (b._relative) {
  3486.                             vx = toFixed((br.x + b.x));
  3487.                             vy = toFixed((br.y + b.y));
  3488.                         } else {
  3489.                             vx = toFixed(br.x);
  3490.                             vy = toFixed(br.y);
  3491.                         }
  3492.  
  3493.                         if (c._relative) {
  3494.                             ux = toFixed((cl.x + c.x));
  3495.                             uy = toFixed((cl.y + c.y));
  3496.                         } else {
  3497.                             ux = toFixed(cl.x);
  3498.                             uy = toFixed(cl.y);
  3499.                         }
  3500.  
  3501.                         x = toFixed(c.x);
  3502.                         y = toFixed(c.y);
  3503.  
  3504.                         command +=
  3505.                             ' C ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y;
  3506.                     }
  3507.  
  3508.                     command += ' Z';
  3509.  
  3510.                 }
  3511.  
  3512.                 ret += command + ' ';
  3513.  
  3514.             }
  3515.  
  3516.             return ret;
  3517.  
  3518.         },
  3519.  
  3520.         getClip: function (shape) {
  3521.  
  3522.             var clip = shape._renderer.clip;
  3523.  
  3524.             if (!clip) {
  3525.  
  3526.                 var root = shape;
  3527.  
  3528.                 while (root.parent) {
  3529.                     root = root.parent;
  3530.                 }
  3531.  
  3532.                 clip = shape._renderer.clip = svg.createElement('clipPath');
  3533.                 root.defs.appendChild(clip);
  3534.  
  3535.             }
  3536.  
  3537.             return clip;
  3538.  
  3539.         },
  3540.  
  3541.         group: {
  3542.  
  3543.             // TODO: Can speed up.
  3544.             // TODO: How does this effect a f
  3545.             appendChild: function (object) {
  3546.  
  3547.                 var elem = object._renderer.elem;
  3548.  
  3549.                 if (!elem) {
  3550.                     return;
  3551.                 }
  3552.  
  3553.                 var tag = elem.nodeName;
  3554.  
  3555.                 if (!tag || /(radial|linear)gradient/i.test(tag) || object._clip) {
  3556.                     return;
  3557.                 }
  3558.  
  3559.                 this.elem.appendChild(elem);
  3560.  
  3561.             },
  3562.  
  3563.             removeChild: function (object) {
  3564.  
  3565.                 var elem = object._renderer.elem;
  3566.  
  3567.                 if (!elem || elem.parentNode != this.elem) {
  3568.                     return;
  3569.                 }
  3570.  
  3571.                 var tag = elem.nodeName;
  3572.  
  3573.                 if (!tag) {
  3574.                     return;
  3575.                 }
  3576.  
  3577.                 // Defer subtractions while clipping.
  3578.                 if (object._clip) {
  3579.                     return;
  3580.                 }
  3581.  
  3582.                 this.elem.removeChild(elem);
  3583.  
  3584.             },
  3585.  
  3586.             orderChild: function (object) {
  3587.                 this.elem.appendChild(object._renderer.elem);
  3588.             },
  3589.  
  3590.             renderChild: function (child) {
  3591.                 svg[child._renderer.type].render.call(child, this);
  3592.             },
  3593.  
  3594.             render: function (domElement) {
  3595.  
  3596.                 this._update();
  3597.  
  3598.                 // Shortcut for hidden objects.
  3599.                 // Doesn't reset the flags, so changes are stored and
  3600.                 // applied once the object is visible again
  3601.                 if (this._opacity === 0 && !this._flagOpacity) {
  3602.                     return this;
  3603.                 }
  3604.  
  3605.                 if (!this._renderer.elem) {
  3606.                     this._renderer.elem = svg.createElement('g', {
  3607.                         id: this.id
  3608.                     });
  3609.                     domElement.appendChild(this._renderer.elem);
  3610.                 }
  3611.  
  3612.                 // _Update styles for the <g>
  3613.                 var flagMatrix = this._matrix.manual || this._flagMatrix;
  3614.                 var context = {
  3615.                     domElement: domElement,
  3616.                     elem: this._renderer.elem
  3617.                 };
  3618.  
  3619.                 if (flagMatrix) {
  3620.                     this._renderer.elem.setAttribute('transform', 'matrix(' + this._matrix.toString() + ')');
  3621.                 }
  3622.  
  3623.                 for (var i = 0; i < this.children.length; i++) {
  3624.                     var child = this.children[i];
  3625.                     svg[child._renderer.type].render.call(child, domElement);
  3626.                 }
  3627.  
  3628.                 if (this._flagOpacity) {
  3629.                     this._renderer.elem.setAttribute('opacity', this._opacity);
  3630.                 }
  3631.  
  3632.                 if (this._flagAdditions) {
  3633.                     this.additions.forEach(svg.group.appendChild, context);
  3634.                 }
  3635.  
  3636.                 if (this._flagSubtractions) {
  3637.                     this.subtractions.forEach(svg.group.removeChild, context);
  3638.                 }
  3639.  
  3640.                 if (this._flagOrder) {
  3641.                     this.children.forEach(svg.group.orderChild, context);
  3642.                 }
  3643.  
  3644.                 /**
  3645.                     * Commented two-way functionality of clips / masks with groups and
  3646.                     * polygons. Uncomment when this bug is fixed:
  3647.                     * https://code.google.com/p/chromium/issues/detail?id=370951
  3648.                     */
  3649.  
  3650.                 // if (this._flagClip) {
  3651.  
  3652.                 //   clip = svg.getClip(this);
  3653.                 //   elem = this._renderer.elem;
  3654.  
  3655.                 //   if (this._clip) {
  3656.                 //     elem.removeAttribute('id');
  3657.                 //     clip.setAttribute('id', this.id);
  3658.                 //     clip.appendChild(elem);
  3659.                 //   } else {
  3660.                 //     clip.removeAttribute('id');
  3661.                 //     elem.setAttribute('id', this.id);
  3662.                 //     this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  3663.                 //   }
  3664.  
  3665.                 // }
  3666.  
  3667.                 if (this._flagMask) {
  3668.                     if (this._mask) {
  3669.                         this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  3670.                     } else {
  3671.                         this._renderer.elem.removeAttribute('clip-path');
  3672.                     }
  3673.                 }
  3674.  
  3675.                 return this.flagReset();
  3676.  
  3677.             }
  3678.  
  3679.         },
  3680.  
  3681.         path: {
  3682.  
  3683.             render: function (domElement) {
  3684.  
  3685.                 this._update();
  3686.  
  3687.                 // Shortcut for hidden objects.
  3688.                 // Doesn't reset the flags, so changes are stored and
  3689.                 // applied once the object is visible again
  3690.                 if (this._opacity === 0 && !this._flagOpacity) {
  3691.                     return this;
  3692.                 }
  3693.  
  3694.                 // Collect any attribute that needs to be changed here
  3695.                 var changed = {};
  3696.  
  3697.                 var flagMatrix = this._matrix.manual || this._flagMatrix;
  3698.  
  3699.                 if (flagMatrix) {
  3700.                     changed.transform = 'matrix(' + this._matrix.toString() + ')';
  3701.                 }
  3702.  
  3703.                 if (this._flagVertices) {
  3704.                     var vertices = svg.toString(this._vertices, this._closed);
  3705.                     changed.d = vertices;
  3706.                 }
  3707.  
  3708.                 if (this._fill && this._fill._renderer) {
  3709.                     this._fill._update();
  3710.                     svg[this._fill._renderer.type].render.call(this._fill, domElement, true);
  3711.                 }
  3712.  
  3713.                 if (this._flagFill) {
  3714.                     changed.fill = this._fill && this._fill.id
  3715.                         ? 'url(#' + this._fill.id + ')' : this._fill;
  3716.                 }
  3717.  
  3718.                 if (this._stroke && this._stroke._renderer) {
  3719.                     this._stroke._update();
  3720.                     svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true);
  3721.                 }
  3722.  
  3723.                 if (this._flagStroke) {
  3724.                     changed.stroke = this._stroke && this._stroke.id
  3725.                         ? 'url(#' + this._stroke.id + ')' : this._stroke;
  3726.                 }
  3727.  
  3728.                 if (this._flagLinewidth) {
  3729.                     changed['stroke-width'] = this._linewidth;
  3730.                 }
  3731.  
  3732.                 if (this._flagOpacity) {
  3733.                     changed['stroke-opacity'] = this._opacity;
  3734.                     changed['fill-opacity'] = this._opacity;
  3735.                 }
  3736.  
  3737.                 if (this._flagVisible) {
  3738.                     changed.visibility = this._visible ? 'visible' : 'hidden';
  3739.                 }
  3740.  
  3741.                 if (this._flagCap) {
  3742.                     changed['stroke-linecap'] = this._cap;
  3743.                 }
  3744.  
  3745.                 if (this._flagJoin) {
  3746.                     changed['stroke-linejoin'] = this._join;
  3747.                 }
  3748.  
  3749.                 if (this._flagMiter) {
  3750.                     changed['stroke-miterlimit'] = this._miter;
  3751.                 }
  3752.  
  3753.                 // If there is no attached DOM element yet,
  3754.                 // create it with all necessary attributes.
  3755.                 if (!this._renderer.elem) {
  3756.  
  3757.                     changed.id = this.id;
  3758.                     this._renderer.elem = svg.createElement('path', changed);
  3759.                     domElement.appendChild(this._renderer.elem);
  3760.  
  3761.                     // Otherwise apply all pending attributes
  3762.                 } else {
  3763.                     svg.setAttributes(this._renderer.elem, changed);
  3764.                 }
  3765.  
  3766.                 if (this._flagClip) {
  3767.  
  3768.                     var clip = svg.getClip(this);
  3769.                     var elem = this._renderer.elem;
  3770.  
  3771.                     if (this._clip) {
  3772.                         elem.removeAttribute('id');
  3773.                         clip.setAttribute('id', this.id);
  3774.                         clip.appendChild(elem);
  3775.                     } else {
  3776.                         clip.removeAttribute('id');
  3777.                         elem.setAttribute('id', this.id);
  3778.                         this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  3779.                     }
  3780.  
  3781.                 }
  3782.  
  3783.                 /**
  3784.                     * Commented two-way functionality of clips / masks with groups and
  3785.                     * polygons. Uncomment when this bug is fixed:
  3786.                     * https://code.google.com/p/chromium/issues/detail?id=370951
  3787.                     */
  3788.  
  3789.                 // if (this._flagMask) {
  3790.                 //   if (this._mask) {
  3791.                 //     elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  3792.                 //   } else {
  3793.                 //     elem.removeAttribute('clip-path');
  3794.                 //   }
  3795.                 // }
  3796.  
  3797.                 return this.flagReset();
  3798.  
  3799.             }
  3800.  
  3801.         },
  3802.  
  3803.         text: {
  3804.  
  3805.             render: function (domElement) {
  3806.  
  3807.                 this._update();
  3808.  
  3809.                 var changed = {};
  3810.  
  3811.                 var flagMatrix = this._matrix.manual || this._flagMatrix;
  3812.  
  3813.                 if (flagMatrix) {
  3814.                     changed.transform = 'matrix(' + this._matrix.toString() + ')';
  3815.                 }
  3816.  
  3817.                 if (this._flagFamily) {
  3818.                     changed['font-family'] = this._family;
  3819.                 }
  3820.                 if (this._flagSize) {
  3821.                     changed['font-size'] = this._size;
  3822.                 }
  3823.                 if (this._flagLeading) {
  3824.                     changed['line-height'] = this._leading;
  3825.                 }
  3826.                 if (this._flagAlignment) {
  3827.                     changed['text-anchor'] = svg.alignments[this._alignment] || this._alignment;
  3828.                 }
  3829.                 if (this._flagBaseline) {
  3830.                     changed['alignment-baseline'] = changed['dominant-baseline'] = this._baseline;
  3831.                 }
  3832.                 if (this._flagStyle) {
  3833.                     changed['font-style'] = this._style;
  3834.                 }
  3835.                 if (this._flagWeight) {
  3836.                     changed['font-weight'] = this._weight;
  3837.                 }
  3838.                 if (this._flagDecoration) {
  3839.                     changed['text-decoration'] = this._decoration;
  3840.                 }
  3841.                 if (this._fill && this._fill._renderer) {
  3842.                     this._fill._update();
  3843.                     svg[this._fill._renderer.type].render.call(this._fill, domElement, true);
  3844.                 }
  3845.                 if (this._flagFill) {
  3846.                     changed.fill = this._fill && this._fill.id
  3847.                         ? 'url(#' + this._fill.id + ')' : this._fill;
  3848.                 }
  3849.                 if (this._stroke && this._stroke._renderer) {
  3850.                     this._stroke._update();
  3851.                     svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true);
  3852.                 }
  3853.                 if (this._flagStroke) {
  3854.                     changed.stroke = this._stroke && this._stroke.id
  3855.                         ? 'url(#' + this._stroke.id + ')' : this._stroke;
  3856.                 }
  3857.                 if (this._flagLinewidth) {
  3858.                     changed['stroke-width'] = this._linewidth;
  3859.                 }
  3860.                 if (this._flagOpacity) {
  3861.                     changed.opacity = this._opacity;
  3862.                 }
  3863.                 if (this._flagVisible) {
  3864.                     changed.visibility = this._visible ? 'visible' : 'hidden';
  3865.                 }
  3866.  
  3867.                 if (!this._renderer.elem) {
  3868.  
  3869.                     changed.id = this.id;
  3870.  
  3871.                     this._renderer.elem = svg.createElement('text', changed);
  3872.                     domElement.defs.appendChild(this._renderer.elem);
  3873.  
  3874.                 } else {
  3875.  
  3876.                     svg.setAttributes(this._renderer.elem, changed);
  3877.  
  3878.                 }
  3879.  
  3880.                 if (this._flagClip) {
  3881.  
  3882.                     var clip = svg.getClip(this);
  3883.                     var elem = this._renderer.elem;
  3884.  
  3885.                     if (this._clip) {
  3886.                         elem.removeAttribute('id');
  3887.                         clip.setAttribute('id', this.id);
  3888.                         clip.appendChild(elem);
  3889.                     } else {
  3890.                         clip.removeAttribute('id');
  3891.                         elem.setAttribute('id', this.id);
  3892.                         this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  3893.                     }
  3894.  
  3895.                 }
  3896.  
  3897.                 if (this._flagValue) {
  3898.                     this._renderer.elem.textContent = this._value;
  3899.                 }
  3900.  
  3901.                 return this.flagReset();
  3902.  
  3903.             }
  3904.  
  3905.         },
  3906.  
  3907.         'linear-gradient': {
  3908.  
  3909.             render: function (domElement, silent) {
  3910.  
  3911.                 if (!silent) {
  3912.                     this._update();
  3913.                 }
  3914.  
  3915.                 var changed = {};
  3916.  
  3917.                 if (this._flagEndPoints) {
  3918.                     changed.x1 = this.left._x;
  3919.                     changed.y1 = this.left._y;
  3920.                     changed.x2 = this.right._x;
  3921.                     changed.y2 = this.right._y;
  3922.                 }
  3923.  
  3924.                 if (this._flagSpread) {
  3925.                     changed.spreadMethod = this._spread;
  3926.                 }
  3927.  
  3928.                 // If there is no attached DOM element yet,
  3929.                 // create it with all necessary attributes.
  3930.                 if (!this._renderer.elem) {
  3931.  
  3932.                     changed.id = this.id;
  3933.                     changed.gradientUnits = 'userSpaceOnUse';
  3934.                     this._renderer.elem = svg.createElement('linearGradient', changed);
  3935.                     domElement.defs.appendChild(this._renderer.elem);
  3936.  
  3937.                     // Otherwise apply all pending attributes
  3938.                 } else {
  3939.  
  3940.                     svg.setAttributes(this._renderer.elem, changed);
  3941.  
  3942.                 }
  3943.  
  3944.                 if (this._flagStops) {
  3945.  
  3946.                     var lengthChanged = this._renderer.elem.childNodes.length
  3947.                         !== this.stops.length;
  3948.  
  3949.                     if (lengthChanged) {
  3950.                         this._renderer.elem.childNodes.length = 0;
  3951.                     }
  3952.  
  3953.                     for (var i = 0; i < this.stops.length; i++) {
  3954.  
  3955.                         var stop = this.stops[i];
  3956.                         var attrs = {};
  3957.  
  3958.                         if (stop._flagOffset) {
  3959.                             attrs.offset = 100 * stop._offset + '%';
  3960.                         }
  3961.                         if (stop._flagColor) {
  3962.                             attrs['stop-color'] = stop._color;
  3963.                         }
  3964.                         if (stop._flagOpacity) {
  3965.                             attrs['stop-opacity'] = stop._opacity;
  3966.                         }
  3967.  
  3968.                         if (!stop._renderer.elem) {
  3969.                             stop._renderer.elem = svg.createElement('stop', attrs);
  3970.                         } else {
  3971.                             svg.setAttributes(stop._renderer.elem, attrs);
  3972.                         }
  3973.  
  3974.                         if (lengthChanged) {
  3975.                             this._renderer.elem.appendChild(stop._renderer.elem);
  3976.                         }
  3977.                         stop.flagReset();
  3978.  
  3979.                     }
  3980.  
  3981.                 }
  3982.  
  3983.                 return this.flagReset();
  3984.  
  3985.             }
  3986.  
  3987.         },
  3988.  
  3989.         'radial-gradient': {
  3990.  
  3991.             render: function (domElement, silent) {
  3992.  
  3993.                 if (!silent) {
  3994.                     this._update();
  3995.                 }
  3996.  
  3997.                 var changed = {};
  3998.  
  3999.                 if (this._flagCenter) {
  4000.                     changed.cx = this.center._x;
  4001.                     changed.cy = this.center._y;
  4002.                 }
  4003.                 if (this._flagFocal) {
  4004.                     changed.fx = this.focal._x;
  4005.                     changed.fy = this.focal._y;
  4006.                 }
  4007.  
  4008.                 if (this._flagRadius) {
  4009.                     changed.r = this._radius;
  4010.                 }
  4011.  
  4012.                 if (this._flagSpread) {
  4013.                     changed.spreadMethod = this._spread;
  4014.                 }
  4015.  
  4016.                 // If there is no attached DOM element yet,
  4017.                 // create it with all necessary attributes.
  4018.                 if (!this._renderer.elem) {
  4019.  
  4020.                     changed.id = this.id;
  4021.                     changed.gradientUnits = 'userSpaceOnUse';
  4022.                     this._renderer.elem = svg.createElement('radialGradient', changed);
  4023.                     domElement.defs.appendChild(this._renderer.elem);
  4024.  
  4025.                     // Otherwise apply all pending attributes
  4026.                 } else {
  4027.  
  4028.                     svg.setAttributes(this._renderer.elem, changed);
  4029.  
  4030.                 }
  4031.  
  4032.                 if (this._flagStops) {
  4033.  
  4034.                     var lengthChanged = this._renderer.elem.childNodes.length
  4035.                         !== this.stops.length;
  4036.  
  4037.                     if (lengthChanged) {
  4038.                         this._renderer.elem.childNodes.length = 0;
  4039.                     }
  4040.  
  4041.                     for (var i = 0; i < this.stops.length; i++) {
  4042.  
  4043.                         var stop = this.stops[i];
  4044.                         var attrs = {};
  4045.  
  4046.                         if (stop._flagOffset) {
  4047.                             attrs.offset = 100 * stop._offset + '%';
  4048.                         }
  4049.                         if (stop._flagColor) {
  4050.                             attrs['stop-color'] = stop._color;
  4051.                         }
  4052.                         if (stop._flagOpacity) {
  4053.                             attrs['stop-opacity'] = stop._opacity;
  4054.                         }
  4055.  
  4056.                         if (!stop._renderer.elem) {
  4057.                             stop._renderer.elem = svg.createElement('stop', attrs);
  4058.                         } else {
  4059.                             svg.setAttributes(stop._renderer.elem, attrs);
  4060.                         }
  4061.  
  4062.                         if (lengthChanged) {
  4063.                             this._renderer.elem.appendChild(stop._renderer.elem);
  4064.                         }
  4065.                         stop.flagReset();
  4066.  
  4067.                     }
  4068.  
  4069.                 }
  4070.  
  4071.                 return this.flagReset();
  4072.  
  4073.             }
  4074.  
  4075.         },
  4076.  
  4077.         texture: {
  4078.  
  4079.             render: function (domElement, silent) {
  4080.  
  4081.                 if (!silent) {
  4082.                     this._update();
  4083.                 }
  4084.  
  4085.                 var changed = {};
  4086.                 var styles = { x: 0, y: 0 };
  4087.                 var image = this.image;
  4088.  
  4089.                 if (this._flagLoaded && this.loaded) {
  4090.  
  4091.                     switch (image.nodeName.toLowerCase()) {
  4092.  
  4093.                         case 'canvas':
  4094.                             styles.href = styles['xlink:href'] = image.toDataURL('image/png');
  4095.                             break;
  4096.                         case 'img':
  4097.                         case 'image':
  4098.                             styles.href = styles['xlink:href'] = this.src;
  4099.                             break;
  4100.  
  4101.                     }
  4102.  
  4103.                 }
  4104.  
  4105.                 if (this._flagOffset || this._flagLoaded || this._flagScale) {
  4106.  
  4107.                     changed.x = this._offset.x;
  4108.                     changed.y = this._offset.y;
  4109.  
  4110.                     if (image) {
  4111.  
  4112.                         changed.x -= image.width / 2;
  4113.                         changed.y -= image.height / 2;
  4114.  
  4115.                         if (this._scale instanceof Two.Vector) {
  4116.                             changed.x *= this._scale.x;
  4117.                             changed.y *= this._scale.y;
  4118.                         } else {
  4119.                             changed.x *= this._scale;
  4120.                             changed.y *= this._scale;
  4121.                         }
  4122.                     }
  4123.  
  4124.                     if (changed.x > 0) {
  4125.                         changed.x *= - 1;
  4126.                     }
  4127.                     if (changed.y > 0) {
  4128.                         changed.y *= - 1;
  4129.                     }
  4130.  
  4131.                 }
  4132.  
  4133.                 if (this._flagScale || this._flagLoaded || this._flagRepeat) {
  4134.  
  4135.                     changed.width = 0;
  4136.                     changed.height = 0;
  4137.  
  4138.                     if (image) {
  4139.  
  4140.                         styles.width = changed.width = image.width;
  4141.                         styles.height = changed.height = image.height;
  4142.  
  4143.                         // TODO: Hack / Bandaid
  4144.                         switch (this._repeat) {
  4145.                             case 'no-repeat':
  4146.                                 changed.width += 1;
  4147.                                 changed.height += 1;
  4148.                                 break;
  4149.                         }
  4150.  
  4151.                         if (this._scale instanceof Two.Vector) {
  4152.                             changed.width *= this._scale.x;
  4153.                             changed.height *= this._scale.y;
  4154.                         } else {
  4155.                             changed.width *= this._scale;
  4156.                             changed.height *= this._scale;
  4157.                         }
  4158.                     }
  4159.  
  4160.                 }
  4161.  
  4162.                 if (this._flagScale || this._flagLoaded) {
  4163.                     if (!this._renderer.image) {
  4164.                         this._renderer.image = svg.createElement('image', styles);
  4165.                     } else if (!_.isEmpty(styles)) {
  4166.                         svg.setAttributes(this._renderer.image, styles);
  4167.                     }
  4168.                 }
  4169.  
  4170.                 if (!this._renderer.elem) {
  4171.  
  4172.                     changed.id = this.id;
  4173.                     changed.patternUnits = 'userSpaceOnUse';
  4174.                     this._renderer.elem = svg.createElement('pattern', changed);
  4175.                     domElement.defs.appendChild(this._renderer.elem);
  4176.  
  4177.                 } else if (!_.isEmpty(changed)) {
  4178.  
  4179.                     svg.setAttributes(this._renderer.elem, changed);
  4180.  
  4181.                 }
  4182.  
  4183.                 if (this._renderer.elem && this._renderer.image && !this._renderer.appended) {
  4184.                     this._renderer.elem.appendChild(this._renderer.image);
  4185.                     this._renderer.appended = true;
  4186.                 }
  4187.  
  4188.                 return this.flagReset();
  4189.  
  4190.             }
  4191.  
  4192.         }
  4193.  
  4194.     };
  4195.  
  4196.     /**
  4197.         * @class
  4198.         */
  4199.     var Renderer = Two[Two.Types.svg] = function (params) {
  4200.  
  4201.         this.domElement = params.domElement || svg.createElement('svg');
  4202.  
  4203.         this.scene = new Two.Group();
  4204.         this.scene.parent = this;
  4205.  
  4206.         this.defs = svg.createElement('defs');
  4207.         this.domElement.appendChild(this.defs);
  4208.         this.domElement.defs = this.defs;
  4209.         this.domElement.style.overflow = 'hidden';
  4210.  
  4211.     };
  4212.  
  4213.     _.extend(Renderer, {
  4214.  
  4215.         Utils: svg
  4216.  
  4217.     });
  4218.  
  4219.     _.extend(Renderer.prototype, Two.Utils.Events, {
  4220.  
  4221.         setSize: function (width, height) {
  4222.  
  4223.             this.width = width;
  4224.             this.height = height;
  4225.  
  4226.             svg.setAttributes(this.domElement, {
  4227.                 width: width,
  4228.                 height: height
  4229.             });
  4230.  
  4231.             return this;
  4232.  
  4233.         },
  4234.  
  4235.         render: function () {
  4236.  
  4237.             svg.group.render.call(this.scene, this.domElement);
  4238.  
  4239.             return this;
  4240.  
  4241.         }
  4242.  
  4243.     });
  4244.  
  4245. })((typeof global !== 'undefined' ? global : this).Two);
  4246.  
  4247. (function (Two) {
  4248.  
  4249.     /**
  4250.         * Constants
  4251.         */
  4252.     var mod = Two.Utils.mod, toFixed = Two.Utils.toFixed;
  4253.     var getRatio = Two.Utils.getRatio;
  4254.     var _ = Two.Utils;
  4255.  
  4256.     // Returns true if this is a non-transforming matrix
  4257.     var isDefaultMatrix = function (m) {
  4258.         return (m[0] == 1 && m[3] == 0 && m[1] == 0 && m[4] == 1 && m[2] == 0 && m[5] == 0);
  4259.     };
  4260.  
  4261.     var canvas = {
  4262.  
  4263.         isHidden: /(none|transparent)/i,
  4264.  
  4265.         alignments: {
  4266.             left: 'start',
  4267.             middle: 'center',
  4268.             right: 'end'
  4269.         },
  4270.  
  4271.         shim: function (elem) {
  4272.             elem.tagName = 'canvas';
  4273.             elem.nodeType = 1;
  4274.             return elem;
  4275.         },
  4276.  
  4277.         group: {
  4278.  
  4279.             renderChild: function (child) {
  4280.                 canvas[child._renderer.type].render.call(child, this.ctx, true, this.clip);
  4281.             },
  4282.  
  4283.             render: function (ctx) {
  4284.  
  4285.                 // TODO: Add a check here to only invoke _update if need be.
  4286.                 this._update();
  4287.  
  4288.                 var matrix = this._matrix.elements;
  4289.                 var parent = this.parent;
  4290.                 this._renderer.opacity = this._opacity * (parent && parent._renderer ? parent._renderer.opacity : 1);
  4291.  
  4292.                 var defaultMatrix = isDefaultMatrix(matrix);
  4293.  
  4294.                 var mask = this._mask;
  4295.                 // var clip = this._clip;
  4296.  
  4297.                 if (!this._renderer.context) {
  4298.                     this._renderer.context = {};
  4299.                 }
  4300.  
  4301.                 this._renderer.context.ctx = ctx;
  4302.                 // this._renderer.context.clip = clip;
  4303.  
  4304.                 if (!defaultMatrix) {
  4305.                     ctx.save();
  4306.                     ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]);
  4307.                 }
  4308.  
  4309.                 if (mask) {
  4310.                     canvas[mask._renderer.type].render.call(mask, ctx, true);
  4311.                 }
  4312.  
  4313.                 if (this.opacity > 0 && this.scale !== 0) {
  4314.                     for (var i = 0; i < this.children.length; i++) {
  4315.                         var child = this.children[i];
  4316.                         canvas[child._renderer.type].render.call(child, ctx);
  4317.                     }
  4318.                 }
  4319.  
  4320.                 if (!defaultMatrix) {
  4321.                     ctx.restore();
  4322.                 }
  4323.  
  4324.                 /**
  4325.                     * Commented two-way functionality of clips / masks with groups and
  4326.                     * polygons. Uncomment when this bug is fixed:
  4327.                     * https://code.google.com/p/chromium/issues/detail?id=370951
  4328.                     */
  4329.  
  4330.                 // if (clip) {
  4331.                 //   ctx.clip();
  4332.                 // }
  4333.  
  4334.                 return this.flagReset();
  4335.  
  4336.             }
  4337.  
  4338.         },
  4339.  
  4340.         path: {
  4341.  
  4342.             render: function (ctx, forced, parentClipped) {
  4343.  
  4344.                 var matrix, stroke, linewidth, fill, opacity, visible, cap, join, miter,
  4345.                     closed, commands, length, last, next, prev, a, b, c, d, ux, uy, vx, vy,
  4346.                     ar, bl, br, cl, x, y, mask, clip, defaultMatrix, isOffset;
  4347.  
  4348.                 // TODO: Add a check here to only invoke _update if need be.
  4349.                 this._update();
  4350.  
  4351.                 matrix = this._matrix.elements;
  4352.                 stroke = this._stroke;
  4353.                 linewidth = this._linewidth;
  4354.                 fill = this._fill;
  4355.                 opacity = this._opacity * this.parent._renderer.opacity;
  4356.                 visible = this._visible;
  4357.                 cap = this._cap;
  4358.                 join = this._join;
  4359.                 miter = this._miter;
  4360.                 closed = this._closed;
  4361.                 commands = this._vertices; // Commands
  4362.                 length = commands.length;
  4363.                 last = length - 1;
  4364.                 defaultMatrix = isDefaultMatrix(matrix);
  4365.  
  4366.                 // mask = this._mask;
  4367.                 clip = this._clip;
  4368.  
  4369.                 if (!forced && (!visible || clip)) {
  4370.                     return this;
  4371.                 }
  4372.  
  4373.                 // Transform
  4374.                 if (!defaultMatrix) {
  4375.                     ctx.save();
  4376.                     ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]);
  4377.                 }
  4378.  
  4379.                 /**
  4380.                     * Commented two-way functionality of clips / masks with groups and
  4381.                     * polygons. Uncomment when this bug is fixed:
  4382.                     * https://code.google.com/p/chromium/issues/detail?id=370951
  4383.                     */
  4384.  
  4385.                 // if (mask) {
  4386.                 //   canvas[mask._renderer.type].render.call(mask, ctx, true);
  4387.                 // }
  4388.  
  4389.                 // Styles
  4390.                 if (fill) {
  4391.                     if (_.isString(fill)) {
  4392.                         ctx.fillStyle = fill;
  4393.                     } else {
  4394.                         canvas[fill._renderer.type].render.call(fill, ctx);
  4395.                         ctx.fillStyle = fill._renderer.effect;
  4396.                     }
  4397.                 }
  4398.                 if (stroke) {
  4399.                     if (_.isString(stroke)) {
  4400.                         ctx.strokeStyle = stroke;
  4401.                     } else {
  4402.                         canvas[stroke._renderer.type].render.call(stroke, ctx);
  4403.                         ctx.strokeStyle = stroke._renderer.effect;
  4404.                     }
  4405.                 }
  4406.                 if (linewidth) {
  4407.                     ctx.lineWidth = linewidth;
  4408.                 }
  4409.                 if (miter) {
  4410.                     ctx.miterLimit = miter;
  4411.                 }
  4412.                 if (join) {
  4413.                     ctx.lineJoin = join;
  4414.                 }
  4415.                 if (cap) {
  4416.                     ctx.lineCap = cap;
  4417.                 }
  4418.                 if (_.isNumber(opacity)) {
  4419.                     ctx.globalAlpha = opacity;
  4420.                 }
  4421.  
  4422.                 ctx.beginPath();
  4423.  
  4424.                 for (var i = 0; i < commands.length; i++) {
  4425.  
  4426.                     b = commands[i];
  4427.  
  4428.                     x = toFixed(b._x);
  4429.                     y = toFixed(b._y);
  4430.  
  4431.                     switch (b._command) {
  4432.  
  4433.                         case Two.Commands.close:
  4434.                             ctx.closePath();
  4435.                             break;
  4436.  
  4437.                         case Two.Commands.curve:
  4438.  
  4439.                             prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  4440.                             next = closed ? mod(i + 1, length) : Math.min(i + 1, last);
  4441.  
  4442.                             a = commands[prev];
  4443.                             c = commands[next];
  4444.                             ar = (a.controls && a.controls.right) || Two.Vector.zero;
  4445.                             bl = (b.controls && b.controls.left) || Two.Vector.zero;
  4446.  
  4447.                             if (a._relative) {
  4448.                                 vx = (ar.x + toFixed(a._x));
  4449.                                 vy = (ar.y + toFixed(a._y));
  4450.                             } else {
  4451.                                 vx = toFixed(ar.x);
  4452.                                 vy = toFixed(ar.y);
  4453.                             }
  4454.  
  4455.                             if (b._relative) {
  4456.                                 ux = (bl.x + toFixed(b._x));
  4457.                                 uy = (bl.y + toFixed(b._y));
  4458.                             } else {
  4459.                                 ux = toFixed(bl.x);
  4460.                                 uy = toFixed(bl.y);
  4461.                             }
  4462.  
  4463.                             ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  4464.  
  4465.                             if (i >= last && closed) {
  4466.  
  4467.                                 c = d;
  4468.  
  4469.                                 br = (b.controls && b.controls.right) || Two.Vector.zero;
  4470.                                 cl = (c.controls && c.controls.left) || Two.Vector.zero;
  4471.  
  4472.                                 if (b._relative) {
  4473.                                     vx = (br.x + toFixed(b._x));
  4474.                                     vy = (br.y + toFixed(b._y));
  4475.                                 } else {
  4476.                                     vx = toFixed(br.x);
  4477.                                     vy = toFixed(br.y);
  4478.                                 }
  4479.  
  4480.                                 if (c._relative) {
  4481.                                     ux = (cl.x + toFixed(c._x));
  4482.                                     uy = (cl.y + toFixed(c._y));
  4483.                                 } else {
  4484.                                     ux = toFixed(cl.x);
  4485.                                     uy = toFixed(cl.y);
  4486.                                 }
  4487.  
  4488.                                 x = toFixed(c._x);
  4489.                                 y = toFixed(c._y);
  4490.  
  4491.                                 ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  4492.  
  4493.                             }
  4494.  
  4495.                             break;
  4496.  
  4497.                         case Two.Commands.line:
  4498.                             ctx.lineTo(x, y);
  4499.                             break;
  4500.  
  4501.                         case Two.Commands.move:
  4502.                             d = b;
  4503.                             ctx.moveTo(x, y);
  4504.                             break;
  4505.  
  4506.                     }
  4507.                 }
  4508.  
  4509.                 // Loose ends
  4510.  
  4511.                 if (closed) {
  4512.                     ctx.closePath();
  4513.                 }
  4514.  
  4515.                 if (!clip && !parentClipped) {
  4516.                     if (!canvas.isHidden.test(fill)) {
  4517.                         isOffset = fill._renderer && fill._renderer.offset
  4518.                         if (isOffset) {
  4519.                             ctx.save();
  4520.                             ctx.translate(
  4521.                                 - fill._renderer.offset.x, - fill._renderer.offset.y);
  4522.                             ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
  4523.                         }
  4524.                         ctx.fill();
  4525.                         if (isOffset) {
  4526.                             ctx.restore();
  4527.                         }
  4528.                     }
  4529.                     if (!canvas.isHidden.test(stroke)) {
  4530.                         isOffset = stroke._renderer && stroke._renderer.offset;
  4531.                         if (isOffset) {
  4532.                             ctx.save();
  4533.                             ctx.translate(
  4534.                                 - stroke._renderer.offset.x, - stroke._renderer.offset.y);
  4535.                             ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
  4536.                             ctx.lineWidth = linewidth / stroke._renderer.scale.x;
  4537.                         }
  4538.                         ctx.stroke();
  4539.                         if (isOffset) {
  4540.                             ctx.restore();
  4541.                         }
  4542.                     }
  4543.                 }
  4544.  
  4545.                 if (!defaultMatrix) {
  4546.                     ctx.restore();
  4547.                 }
  4548.  
  4549.                 if (clip && !parentClipped) {
  4550.                     ctx.clip();
  4551.                 }
  4552.  
  4553.                 return this.flagReset();
  4554.  
  4555.             }
  4556.  
  4557.         },
  4558.  
  4559.         text: {
  4560.  
  4561.             render: function (ctx, forced, parentClipped) {
  4562.  
  4563.                 // TODO: Add a check here to only invoke _update if need be.
  4564.                 this._update();
  4565.  
  4566.                 var matrix = this._matrix.elements;
  4567.                 var stroke = this._stroke;
  4568.                 var linewidth = this._linewidth;
  4569.                 var fill = this._fill;
  4570.                 var opacity = this._opacity * this.parent._renderer.opacity;
  4571.                 var visible = this._visible;
  4572.                 var defaultMatrix = isDefaultMatrix(matrix);
  4573.                 var isOffset = fill._renderer && fill._renderer.offset
  4574.                     && stroke._renderer && stroke._renderer.offset;
  4575.  
  4576.                 var a, b, c, d, e, sx, sy;
  4577.  
  4578.                 // mask = this._mask;
  4579.                 var clip = this._clip;
  4580.  
  4581.                 if (!forced && (!visible || clip)) {
  4582.                     return this;
  4583.                 }
  4584.  
  4585.                 // Transform
  4586.                 if (!defaultMatrix) {
  4587.                     ctx.save();
  4588.                     ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]);
  4589.                 }
  4590.  
  4591.                 /**
  4592.                     * Commented two-way functionality of clips / masks with groups and
  4593.                     * polygons. Uncomment when this bug is fixed:
  4594.                     * https://code.google.com/p/chromium/issues/detail?id=370951
  4595.                     */
  4596.  
  4597.                 // if (mask) {
  4598.                 //   canvas[mask._renderer.type].render.call(mask, ctx, true);
  4599.                 // }
  4600.  
  4601.                 if (!isOffset) {
  4602.                     ctx.font = [this._style, this._weight, this._size + 'px/' +
  4603.                         this._leading + 'px', this._family].join(' ');
  4604.                 }
  4605.  
  4606.                 ctx.textAlign = canvas.alignments[this._alignment] || this._alignment;
  4607.                 ctx.textBaseline = this._baseline;
  4608.  
  4609.                 // Styles
  4610.                 if (fill) {
  4611.                     if (_.isString(fill)) {
  4612.                         ctx.fillStyle = fill;
  4613.                     } else {
  4614.                         canvas[fill._renderer.type].render.call(fill, ctx);
  4615.                         ctx.fillStyle = fill._renderer.effect;
  4616.                     }
  4617.                 }
  4618.                 if (stroke) {
  4619.                     if (_.isString(stroke)) {
  4620.                         ctx.strokeStyle = stroke;
  4621.                     } else {
  4622.                         canvas[stroke._renderer.type].render.call(stroke, ctx);
  4623.                         ctx.strokeStyle = stroke._renderer.effect;
  4624.                     }
  4625.                 }
  4626.                 if (linewidth) {
  4627.                     ctx.lineWidth = linewidth;
  4628.                 }
  4629.                 if (_.isNumber(opacity)) {
  4630.                     ctx.globalAlpha = opacity;
  4631.                 }
  4632.  
  4633.                 if (!clip && !parentClipped) {
  4634.  
  4635.                     if (!canvas.isHidden.test(fill)) {
  4636.  
  4637.                         if (fill._renderer && fill._renderer.offset) {
  4638.  
  4639.                             sx = toFixed(fill._renderer.scale.x);
  4640.                             sy = toFixed(fill._renderer.scale.y);
  4641.  
  4642.                             ctx.save();
  4643.                             ctx.translate(- toFixed(fill._renderer.offset.x),
  4644.                                 - toFixed(fill._renderer.offset.y));
  4645.                             ctx.scale(sx, sy);
  4646.  
  4647.                             a = this._size / fill._renderer.scale.y;
  4648.                             b = this._leading / fill._renderer.scale.y;
  4649.                             ctx.font = [this._style, this._weight, toFixed(a) + 'px/',
  4650.                             toFixed(b) + 'px', this._family].join(' ');
  4651.  
  4652.                             c = fill._renderer.offset.x / fill._renderer.scale.x;
  4653.                             d = fill._renderer.offset.y / fill._renderer.scale.y;
  4654.  
  4655.                             ctx.fillText(this.value, toFixed(c), toFixed(d));
  4656.                             ctx.restore();
  4657.  
  4658.                         } else {
  4659.                             ctx.fillText(this.value, 0, 0);
  4660.                         }
  4661.  
  4662.                     }
  4663.  
  4664.                     if (!canvas.isHidden.test(stroke)) {
  4665.  
  4666.                         if (stroke._renderer && stroke._renderer.offset) {
  4667.  
  4668.                             sx = toFixed(stroke._renderer.scale.x);
  4669.                             sy = toFixed(stroke._renderer.scale.y);
  4670.  
  4671.                             ctx.save();
  4672.                             ctx.translate(- toFixed(stroke._renderer.offset.x),
  4673.                                 - toFixed(stroke._renderer.offset.y));
  4674.                             ctx.scale(sx, sy);
  4675.  
  4676.                             a = this._size / stroke._renderer.scale.y;
  4677.                             b = this._leading / stroke._renderer.scale.y;
  4678.                             ctx.font = [this._style, this._weight, toFixed(a) + 'px/',
  4679.                             toFixed(b) + 'px', this._family].join(' ');
  4680.  
  4681.                             c = stroke._renderer.offset.x / stroke._renderer.scale.x;
  4682.                             d = stroke._renderer.offset.y / stroke._renderer.scale.y;
  4683.                             e = linewidth / stroke._renderer.scale.x;
  4684.  
  4685.                             ctx.lineWidth = toFixed(e);
  4686.                             ctx.strokeText(this.value, toFixed(c), toFixed(d));
  4687.                             ctx.restore();
  4688.  
  4689.                         } else {
  4690.                             ctx.strokeText(this.value, 0, 0);
  4691.                         }
  4692.                     }
  4693.                 }
  4694.  
  4695.                 if (!defaultMatrix) {
  4696.                     ctx.restore();
  4697.                 }
  4698.  
  4699.                 // TODO: Test for text
  4700.                 if (clip && !parentClipped) {
  4701.                     ctx.clip();
  4702.                 }
  4703.  
  4704.                 return this.flagReset();
  4705.  
  4706.             }
  4707.  
  4708.         },
  4709.  
  4710.         'linear-gradient': {
  4711.  
  4712.             render: function (ctx) {
  4713.  
  4714.                 this._update();
  4715.  
  4716.                 if (!this._renderer.effect || this._flagEndPoints || this._flagStops) {
  4717.  
  4718.                     this._renderer.effect = ctx.createLinearGradient(
  4719.                         this.left._x, this.left._y,
  4720.                         this.right._x, this.right._y
  4721.                     );
  4722.  
  4723.                     for (var i = 0; i < this.stops.length; i++) {
  4724.                         var stop = this.stops[i];
  4725.                         this._renderer.effect.addColorStop(stop._offset, stop._color);
  4726.                     }
  4727.  
  4728.                 }
  4729.  
  4730.                 return this.flagReset();
  4731.  
  4732.             }
  4733.  
  4734.         },
  4735.  
  4736.         'radial-gradient': {
  4737.  
  4738.             render: function (ctx) {
  4739.  
  4740.                 this._update();
  4741.  
  4742.                 if (!this._renderer.effect || this._flagCenter || this._flagFocal
  4743.                     || this._flagRadius || this._flagStops) {
  4744.  
  4745.                     this._renderer.effect = ctx.createRadialGradient(
  4746.                         this.center._x, this.center._y, 0,
  4747.                         this.focal._x, this.focal._y, this._radius
  4748.                     );
  4749.  
  4750.                     for (var i = 0; i < this.stops.length; i++) {
  4751.                         var stop = this.stops[i];
  4752.                         this._renderer.effect.addColorStop(stop._offset, stop._color);
  4753.                     }
  4754.  
  4755.                 }
  4756.  
  4757.                 return this.flagReset();
  4758.  
  4759.             }
  4760.  
  4761.         },
  4762.  
  4763.         texture: {
  4764.  
  4765.             render: function (ctx) {
  4766.  
  4767.                 this._update();
  4768.  
  4769.                 var image = this.image;
  4770.                 var repeat;
  4771.  
  4772.                 if (!this._renderer.effect || ((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded)) {
  4773.                     this._renderer.effect = ctx.createPattern(this.image, this._repeat);
  4774.                 }
  4775.  
  4776.                 if (this._flagOffset || this._flagLoaded || this._flagScale) {
  4777.  
  4778.                     if (!(this._renderer.offset instanceof Two.Vector)) {
  4779.                         this._renderer.offset = new Two.Vector();
  4780.                     }
  4781.  
  4782.                     this._renderer.offset.x = - this._offset.x;
  4783.                     this._renderer.offset.y = - this._offset.y;
  4784.  
  4785.                     if (image) {
  4786.  
  4787.                         this._renderer.offset.x += image.width / 2;
  4788.                         this._renderer.offset.y += image.height / 2;
  4789.  
  4790.                         if (this._scale instanceof Two.Vector) {
  4791.                             this._renderer.offset.x *= this._scale.x;
  4792.                             this._renderer.offset.y *= this._scale.y;
  4793.                         } else {
  4794.                             this._renderer.offset.x *= this._scale;
  4795.                             this._renderer.offset.y *= this._scale;
  4796.                         }
  4797.                     }
  4798.  
  4799.                 }
  4800.  
  4801.                 if (this._flagScale || this._flagLoaded) {
  4802.  
  4803.                     if (!(this._renderer.scale instanceof Two.Vector)) {
  4804.                         this._renderer.scale = new Two.Vector();
  4805.                     }
  4806.  
  4807.                     if (this._scale instanceof Two.Vector) {
  4808.                         this._renderer.scale.copy(this._scale);
  4809.                     } else {
  4810.                         this._renderer.scale.set(this._scale, this._scale);
  4811.                     }
  4812.  
  4813.                 }
  4814.  
  4815.                 return this.flagReset();
  4816.  
  4817.             }
  4818.  
  4819.         }
  4820.  
  4821.     };
  4822.  
  4823.     var Renderer = Two[Two.Types.canvas] = function (params) {
  4824.         // Smoothing property. Defaults to true
  4825.         // Set it to false when working with pixel art.
  4826.         // false can lead to better performance, since it would use a cheaper interpolation algorithm.
  4827.         // It might not make a big difference on GPU backed canvases.
  4828.         var smoothing = (params.smoothing !== false);
  4829.         this.domElement = params.domElement || document.createElement('canvas');
  4830.         this.ctx = this.domElement.getContext('2d');
  4831.         this.overdraw = params.overdraw || false;
  4832.  
  4833.         if (!_.isUndefined(this.ctx.imageSmoothingEnabled)) {
  4834.             this.ctx.imageSmoothingEnabled = smoothing;
  4835.         }
  4836.  
  4837.         // Everything drawn on the canvas needs to be added to the scene.
  4838.         this.scene = new Two.Group();
  4839.         this.scene.parent = this;
  4840.     };
  4841.  
  4842.  
  4843.     _.extend(Renderer, {
  4844.  
  4845.         Utils: canvas
  4846.  
  4847.     });
  4848.  
  4849.     _.extend(Renderer.prototype, Two.Utils.Events, {
  4850.  
  4851.         setSize: function (width, height, ratio) {
  4852.  
  4853.             this.width = width;
  4854.             this.height = height;
  4855.  
  4856.             this.ratio = _.isUndefined(ratio) ? getRatio(this.ctx) : ratio;
  4857.  
  4858.             this.domElement.width = width * this.ratio;
  4859.             this.domElement.height = height * this.ratio;
  4860.  
  4861.             if (this.domElement.style) {
  4862.                 _.extend(this.domElement.style, {
  4863.                     width: width + 'px',
  4864.                     height: height + 'px'
  4865.                 });
  4866.             }
  4867.  
  4868.             return this;
  4869.  
  4870.         },
  4871.  
  4872.         render: function () {
  4873.  
  4874.             var isOne = this.ratio === 1;
  4875.  
  4876.             if (!isOne) {
  4877.                 this.ctx.save();
  4878.                 this.ctx.scale(this.ratio, this.ratio);
  4879.             }
  4880.  
  4881.             if (!this.overdraw) {
  4882.                 this.ctx.clearRect(0, 0, this.width, this.height);
  4883.             }
  4884.  
  4885.             canvas.group.render.call(this.scene, this.ctx);
  4886.  
  4887.             if (!isOne) {
  4888.                 this.ctx.restore();
  4889.             }
  4890.  
  4891.             return this;
  4892.  
  4893.         }
  4894.  
  4895.     });
  4896.  
  4897.     function resetTransform(ctx) {
  4898.         ctx.setTransform(1, 0, 0, 1, 0, 0);
  4899.     }
  4900.  
  4901. })((typeof global !== 'undefined' ? global : this).Two);
  4902.  
  4903. (function (Two) {
  4904.  
  4905.     /**
  4906.         * Constants
  4907.         */
  4908.  
  4909.     var root = Two.root,
  4910.         multiplyMatrix = Two.Matrix.Multiply,
  4911.         mod = Two.Utils.mod,
  4912.         identity = [1, 0, 0, 0, 1, 0, 0, 0, 1],
  4913.         transformation = new Two.Array(9),
  4914.         getRatio = Two.Utils.getRatio,
  4915.         getComputedMatrix = Two.Utils.getComputedMatrix,
  4916.         toFixed = Two.Utils.toFixed,
  4917.         _ = Two.Utils;
  4918.  
  4919.     var webgl = {
  4920.  
  4921.         isHidden: /(none|transparent)/i,
  4922.  
  4923.         canvas: (root.document ? root.document.createElement('canvas') : { getContext: _.identity }),
  4924.  
  4925.         alignments: {
  4926.             left: 'start',
  4927.             middle: 'center',
  4928.             right: 'end'
  4929.         },
  4930.  
  4931.         matrix: new Two.Matrix(),
  4932.  
  4933.         uv: new Two.Array([
  4934.             0, 0,
  4935.             1, 0,
  4936.             0, 1,
  4937.             0, 1,
  4938.             1, 0,
  4939.             1, 1
  4940.         ]),
  4941.  
  4942.         group: {
  4943.  
  4944.             removeChild: function (child, gl) {
  4945.                 if (child.children) {
  4946.                     for (var i = 0; i < child.children.length; i++) {
  4947.                         webgl.group.removeChild(child.children[i], gl);
  4948.                     }
  4949.                     return;
  4950.                 }
  4951.                 // Deallocate texture to free up gl memory.
  4952.                 gl.deleteTexture(child._renderer.texture);
  4953.                 delete child._renderer.texture;
  4954.             },
  4955.  
  4956.             renderChild: function (child) {
  4957.                 webgl[child._renderer.type].render.call(child, this.gl, this.program);
  4958.             },
  4959.  
  4960.             render: function (gl, program) {
  4961.  
  4962.                 this._update();
  4963.  
  4964.                 var parent = this.parent;
  4965.                 var flagParentMatrix = (parent._matrix && parent._matrix.manual) || parent._flagMatrix;
  4966.                 var flagMatrix = this._matrix.manual || this._flagMatrix;
  4967.  
  4968.                 if (flagParentMatrix || flagMatrix) {
  4969.  
  4970.                     if (!this._renderer.matrix) {
  4971.                         this._renderer.matrix = new Two.Array(9);
  4972.                     }
  4973.  
  4974.                     // Reduce amount of object / array creation / deletion
  4975.                     this._matrix.toArray(true, transformation);
  4976.  
  4977.                     multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  4978.                     this._renderer.scale = this._scale * parent._renderer.scale;
  4979.  
  4980.                     if (flagParentMatrix) {
  4981.                         this._flagMatrix = true;
  4982.                     }
  4983.  
  4984.                 }
  4985.  
  4986.                 if (this._mask) {
  4987.  
  4988.                     gl.enable(gl.STENCIL_TEST);
  4989.                     gl.stencilFunc(gl.ALWAYS, 1, 1);
  4990.  
  4991.                     gl.colorMask(false, false, false, true);
  4992.                     gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
  4993.  
  4994.                     webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  4995.  
  4996.                     gl.colorMask(true, true, true, true);
  4997.                     gl.stencilFunc(gl.NOTEQUAL, 0, 1);
  4998.                     gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  4999.  
  5000.                 }
  5001.  
  5002.                 this._flagOpacity = parent._flagOpacity || this._flagOpacity;
  5003.  
  5004.                 this._renderer.opacity = this._opacity
  5005.                     * (parent && parent._renderer ? parent._renderer.opacity : 1);
  5006.  
  5007.                 if (this._flagSubtractions) {
  5008.                     for (var i = 0; i < this.subtractions.length; i++) {
  5009.                         webgl.group.removeChild(this.subtractions[i], gl);
  5010.                     }
  5011.                 }
  5012.  
  5013.                 this.children.forEach(webgl.group.renderChild, {
  5014.                     gl: gl,
  5015.                     program: program
  5016.                 });
  5017.  
  5018.                 if (this._mask) {
  5019.  
  5020.                     gl.colorMask(false, false, false, false);
  5021.                     gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR);
  5022.  
  5023.                     webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  5024.  
  5025.                     gl.colorMask(true, true, true, true);
  5026.                     gl.stencilFunc(gl.NOTEQUAL, 0, 1);
  5027.                     gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  5028.  
  5029.                     gl.disable(gl.STENCIL_TEST);
  5030.  
  5031.                 }
  5032.  
  5033.                 return this.flagReset();
  5034.  
  5035.             }
  5036.  
  5037.         },
  5038.  
  5039.         path: {
  5040.  
  5041.             updateCanvas: function (elem) {
  5042.  
  5043.                 var next, prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y;
  5044.                 var isOffset;
  5045.  
  5046.                 var commands = elem._vertices;
  5047.                 var canvas = this.canvas;
  5048.                 var ctx = this.ctx;
  5049.  
  5050.                 // Styles
  5051.                 var scale = elem._renderer.scale;
  5052.                 var stroke = elem._stroke;
  5053.                 var linewidth = elem._linewidth;
  5054.                 var fill = elem._fill;
  5055.                 var opacity = elem._renderer.opacity || elem._opacity;
  5056.                 var cap = elem._cap;
  5057.                 var join = elem._join;
  5058.                 var miter = elem._miter;
  5059.                 var closed = elem._closed;
  5060.                 var length = commands.length;
  5061.                 var last = length - 1;
  5062.  
  5063.                 canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale), 1);
  5064.                 canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale), 1);
  5065.  
  5066.                 var centroid = elem._renderer.rect.centroid;
  5067.                 var cx = centroid.x;
  5068.                 var cy = centroid.y;
  5069.  
  5070.                 ctx.clearRect(0, 0, canvas.width, canvas.height);
  5071.  
  5072.                 if (fill) {
  5073.                     if (_.isString(fill)) {
  5074.                         ctx.fillStyle = fill;
  5075.                     } else {
  5076.                         webgl[fill._renderer.type].render.call(fill, ctx, elem);
  5077.                         ctx.fillStyle = fill._renderer.effect;
  5078.                     }
  5079.                 }
  5080.                 if (stroke) {
  5081.                     if (_.isString(stroke)) {
  5082.                         ctx.strokeStyle = stroke;
  5083.                     } else {
  5084.                         webgl[stroke._renderer.type].render.call(stroke, ctx, elem);
  5085.                         ctx.strokeStyle = stroke._renderer.effect;
  5086.                     }
  5087.                 }
  5088.                 if (linewidth) {
  5089.                     ctx.lineWidth = linewidth;
  5090.                 }
  5091.                 if (miter) {
  5092.                     ctx.miterLimit = miter;
  5093.                 }
  5094.                 if (join) {
  5095.                     ctx.lineJoin = join;
  5096.                 }
  5097.                 if (cap) {
  5098.                     ctx.lineCap = cap;
  5099.                 }
  5100.                 if (_.isNumber(opacity)) {
  5101.                     ctx.globalAlpha = opacity;
  5102.                 }
  5103.  
  5104.                 var d;
  5105.                 ctx.save();
  5106.                 ctx.scale(scale, scale);
  5107.                 ctx.translate(cx, cy);
  5108.  
  5109.                 ctx.beginPath();
  5110.                 for (var i = 0; i < commands.length; i++) {
  5111.  
  5112.                     b = commands[i];
  5113.  
  5114.                     x = toFixed(b._x);
  5115.                     y = toFixed(b._y);
  5116.  
  5117.                     switch (b._command) {
  5118.  
  5119.                         case Two.Commands.close:
  5120.                             ctx.closePath();
  5121.                             break;
  5122.  
  5123.                         case Two.Commands.curve:
  5124.  
  5125.                             prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  5126.                             next = closed ? mod(i + 1, length) : Math.min(i + 1, last);
  5127.  
  5128.                             a = commands[prev];
  5129.                             c = commands[next];
  5130.                             ar = (a.controls && a.controls.right) || Two.Vector.zero;
  5131.                             bl = (b.controls && b.controls.left) || Two.Vector.zero;
  5132.  
  5133.                             if (a._relative) {
  5134.                                 vx = toFixed((ar.x + a._x));
  5135.                                 vy = toFixed((ar.y + a._y));
  5136.                             } else {
  5137.                                 vx = toFixed(ar.x);
  5138.                                 vy = toFixed(ar.y);
  5139.                             }
  5140.  
  5141.                             if (b._relative) {
  5142.                                 ux = toFixed((bl.x + b._x));
  5143.                                 uy = toFixed((bl.y + b._y));
  5144.                             } else {
  5145.                                 ux = toFixed(bl.x);
  5146.                                 uy = toFixed(bl.y);
  5147.                             }
  5148.  
  5149.                             ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  5150.  
  5151.                             if (i >= last && closed) {
  5152.  
  5153.                                 c = d;
  5154.  
  5155.                                 br = (b.controls && b.controls.right) || Two.Vector.zero;
  5156.                                 cl = (c.controls && c.controls.left) || Two.Vector.zero;
  5157.  
  5158.                                 if (b._relative) {
  5159.                                     vx = toFixed((br.x + b._x));
  5160.                                     vy = toFixed((br.y + b._y));
  5161.                                 } else {
  5162.                                     vx = toFixed(br.x);
  5163.                                     vy = toFixed(br.y);
  5164.                                 }
  5165.  
  5166.                                 if (c._relative) {
  5167.                                     ux = toFixed((cl.x + c._x));
  5168.                                     uy = toFixed((cl.y + c._y));
  5169.                                 } else {
  5170.                                     ux = toFixed(cl.x);
  5171.                                     uy = toFixed(cl.y);
  5172.                                 }
  5173.  
  5174.                                 x = toFixed(c._x);
  5175.                                 y = toFixed(c._y);
  5176.  
  5177.                                 ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  5178.  
  5179.                             }
  5180.  
  5181.                             break;
  5182.  
  5183.                         case Two.Commands.line:
  5184.                             ctx.lineTo(x, y);
  5185.                             break;
  5186.  
  5187.                         case Two.Commands.move:
  5188.                             d = b;
  5189.                             ctx.moveTo(x, y);
  5190.                             break;
  5191.  
  5192.                     }
  5193.  
  5194.                 }
  5195.  
  5196.                 // Loose ends
  5197.  
  5198.                 if (closed) {
  5199.                     ctx.closePath();
  5200.                 }
  5201.  
  5202.                 if (!webgl.isHidden.test(fill)) {
  5203.                     isOffset = fill._renderer && fill._renderer.offset
  5204.                     if (isOffset) {
  5205.                         ctx.save();
  5206.                         ctx.translate(
  5207.                             - fill._renderer.offset.x, - fill._renderer.offset.y);
  5208.                         ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
  5209.                     }
  5210.                     ctx.fill();
  5211.                     if (isOffset) {
  5212.                         ctx.restore();
  5213.                     }
  5214.                 }
  5215.  
  5216.                 if (!webgl.isHidden.test(stroke)) {
  5217.                     isOffset = stroke._renderer && stroke._renderer.offset;
  5218.                     if (isOffset) {
  5219.                         ctx.save();
  5220.                         ctx.translate(
  5221.                             - stroke._renderer.offset.x, - stroke._renderer.offset.y);
  5222.                         ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
  5223.                         ctx.lineWidth = linewidth / stroke._renderer.scale.x;
  5224.                     }
  5225.                     ctx.stroke();
  5226.                     if (isOffset) {
  5227.                         ctx.restore();
  5228.                     }
  5229.                 }
  5230.  
  5231.                 ctx.restore();
  5232.  
  5233.             },
  5234.  
  5235.             /**
  5236.                 * Returns the rect of a set of verts. Typically takes vertices that are
  5237.                 * "centered" around 0 and returns them to be anchored upper-left.
  5238.                 */
  5239.             getBoundingClientRect: function (vertices, border, rect) {
  5240.  
  5241.                 var left = Infinity, right = -Infinity,
  5242.                     top = Infinity, bottom = -Infinity,
  5243.                     width, height;
  5244.  
  5245.                 vertices.forEach(function (v) {
  5246.  
  5247.                     var x = v.x, y = v.y, controls = v.controls;
  5248.                     var a, b, c, d, cl, cr;
  5249.  
  5250.                     top = Math.min(y, top);
  5251.                     left = Math.min(x, left);
  5252.                     right = Math.max(x, right);
  5253.                     bottom = Math.max(y, bottom);
  5254.  
  5255.                     if (!v.controls) {
  5256.                         return;
  5257.                     }
  5258.  
  5259.                     cl = controls.left;
  5260.                     cr = controls.right;
  5261.  
  5262.                     if (!cl || !cr) {
  5263.                         return;
  5264.                     }
  5265.  
  5266.                     a = v._relative ? cl.x + x : cl.x;
  5267.                     b = v._relative ? cl.y + y : cl.y;
  5268.                     c = v._relative ? cr.x + x : cr.x;
  5269.                     d = v._relative ? cr.y + y : cr.y;
  5270.  
  5271.                     if (!a || !b || !c || !d) {
  5272.                         return;
  5273.                     }
  5274.  
  5275.                     top = Math.min(b, d, top);
  5276.                     left = Math.min(a, c, left);
  5277.                     right = Math.max(a, c, right);
  5278.                     bottom = Math.max(b, d, bottom);
  5279.  
  5280.                 });
  5281.  
  5282.                 // Expand borders
  5283.  
  5284.                 if (_.isNumber(border)) {
  5285.                     top -= border;
  5286.                     left -= border;
  5287.                     right += border;
  5288.                     bottom += border;
  5289.                 }
  5290.  
  5291.                 width = right - left;
  5292.                 height = bottom - top;
  5293.  
  5294.                 rect.top = top;
  5295.                 rect.left = left;
  5296.                 rect.right = right;
  5297.                 rect.bottom = bottom;
  5298.                 rect.width = width;
  5299.                 rect.height = height;
  5300.  
  5301.                 if (!rect.centroid) {
  5302.                     rect.centroid = {};
  5303.                 }
  5304.  
  5305.                 rect.centroid.x = - left;
  5306.                 rect.centroid.y = - top;
  5307.  
  5308.             },
  5309.  
  5310.             render: function (gl, program, forcedParent) {
  5311.  
  5312.                 if (!this._visible || !this._opacity) {
  5313.                     return this;
  5314.                 }
  5315.  
  5316.                 this._update();
  5317.  
  5318.                 // Calculate what changed
  5319.  
  5320.                 var parent = this.parent;
  5321.                 var flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
  5322.                 var flagMatrix = this._matrix.manual || this._flagMatrix;
  5323.                 var flagTexture = this._flagVertices || this._flagFill
  5324.                     || (this._fill instanceof Two.LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints))
  5325.                     || (this._fill instanceof Two.RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal))
  5326.                     || (this._fill instanceof Two.Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagOffset || this._fill._flagScale))
  5327.                     || (this._stroke instanceof Two.LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints))
  5328.                     || (this._stroke instanceof Two.RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal))
  5329.                     || (this._stroke instanceof Two.Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagOffset || this._fill._flagScale))
  5330.                     || this._flagStroke || this._flagLinewidth || this._flagOpacity
  5331.                     || parent._flagOpacity || this._flagVisible || this._flagCap
  5332.                     || this._flagJoin || this._flagMiter || this._flagScale
  5333.                     || !this._renderer.texture;
  5334.  
  5335.                 if (flagParentMatrix || flagMatrix) {
  5336.  
  5337.                     if (!this._renderer.matrix) {
  5338.                         this._renderer.matrix = new Two.Array(9);
  5339.                     }
  5340.  
  5341.                     // Reduce amount of object / array creation / deletion
  5342.  
  5343.                     this._matrix.toArray(true, transformation);
  5344.  
  5345.                     multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  5346.                     this._renderer.scale = this._scale * parent._renderer.scale;
  5347.  
  5348.                 }
  5349.  
  5350.                 if (flagTexture) {
  5351.  
  5352.                     if (!this._renderer.rect) {
  5353.                         this._renderer.rect = {};
  5354.                     }
  5355.  
  5356.                     if (!this._renderer.triangles) {
  5357.                         this._renderer.triangles = new Two.Array(12);
  5358.                     }
  5359.  
  5360.                     this._renderer.opacity = this._opacity * parent._renderer.opacity;
  5361.  
  5362.                     webgl.path.getBoundingClientRect(this._vertices, this._linewidth, this._renderer.rect);
  5363.                     webgl.getTriangles(this._renderer.rect, this._renderer.triangles);
  5364.  
  5365.                     webgl.updateBuffer.call(webgl, gl, this, program);
  5366.                     webgl.updateTexture.call(webgl, gl, this);
  5367.  
  5368.                 }
  5369.  
  5370.                 // if (this._mask) {
  5371.                 //   webgl[this._mask._renderer.type].render.call(mask, gl, program, this);
  5372.                 // }
  5373.  
  5374.                 if (this._clip && !forcedParent) {
  5375.                     return;
  5376.                 }
  5377.  
  5378.                 // Draw Texture
  5379.  
  5380.                 gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.textureCoordsBuffer);
  5381.  
  5382.                 gl.vertexAttribPointer(program.textureCoords, 2, gl.FLOAT, false, 0, 0);
  5383.  
  5384.                 gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
  5385.  
  5386.  
  5387.                 // Draw Rect
  5388.  
  5389.                 gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
  5390.  
  5391.                 gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.buffer);
  5392.  
  5393.                 gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
  5394.  
  5395.                 gl.drawArrays(gl.TRIANGLES, 0, 6);
  5396.  
  5397.                 return this.flagReset();
  5398.  
  5399.             }
  5400.  
  5401.         },
  5402.  
  5403.         text: {
  5404.  
  5405.             updateCanvas: function (elem) {
  5406.  
  5407.                 var canvas = this.canvas;
  5408.                 var ctx = this.ctx;
  5409.  
  5410.                 // Styles
  5411.                 var scale = elem._renderer.scale;
  5412.                 var stroke = elem._stroke;
  5413.                 var linewidth = elem._linewidth * scale;
  5414.                 var fill = elem._fill;
  5415.                 var opacity = elem._renderer.opacity || elem._opacity;
  5416.  
  5417.                 canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale), 1);
  5418.                 canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale), 1);
  5419.  
  5420.                 var centroid = elem._renderer.rect.centroid;
  5421.                 var cx = centroid.x;
  5422.                 var cy = centroid.y;
  5423.  
  5424.                 var a, b, c, d, e, sx, sy;
  5425.                 var isOffset = fill._renderer && fill._renderer.offset
  5426.                     && stroke._renderer && stroke._renderer.offset;
  5427.  
  5428.                 ctx.clearRect(0, 0, canvas.width, canvas.height);
  5429.  
  5430.                 if (!isOffset) {
  5431.                     ctx.font = [elem._style, elem._weight, elem._size + 'px/' +
  5432.                         elem._leading + 'px', elem._family].join(' ');
  5433.                 }
  5434.  
  5435.                 ctx.textAlign = 'center';
  5436.                 ctx.textBaseline = 'middle';
  5437.  
  5438.                 // Styles
  5439.                 if (fill) {
  5440.                     if (_.isString(fill)) {
  5441.                         ctx.fillStyle = fill;
  5442.                     } else {
  5443.                         webgl[fill._renderer.type].render.call(fill, ctx, elem);
  5444.                         ctx.fillStyle = fill._renderer.effect;
  5445.                     }
  5446.                 }
  5447.                 if (stroke) {
  5448.                     if (_.isString(stroke)) {
  5449.                         ctx.strokeStyle = stroke;
  5450.                     } else {
  5451.                         webgl[stroke._renderer.type].render.call(stroke, ctx, elem);
  5452.                         ctx.strokeStyle = stroke._renderer.effect;
  5453.                     }
  5454.                 }
  5455.                 if (linewidth) {
  5456.                     ctx.lineWidth = linewidth;
  5457.                 }
  5458.                 if (_.isNumber(opacity)) {
  5459.                     ctx.globalAlpha = opacity;
  5460.                 }
  5461.  
  5462.                 ctx.save();
  5463.                 ctx.scale(scale, scale);
  5464.                 ctx.translate(cx, cy);
  5465.  
  5466.                 if (!webgl.isHidden.test(fill)) {
  5467.  
  5468.                     if (fill._renderer && fill._renderer.offset) {
  5469.  
  5470.                         sx = toFixed(fill._renderer.scale.x);
  5471.                         sy = toFixed(fill._renderer.scale.y);
  5472.  
  5473.                         ctx.save();
  5474.                         ctx.translate(- toFixed(fill._renderer.offset.x),
  5475.                             - toFixed(fill._renderer.offset.y));
  5476.                         ctx.scale(sx, sy);
  5477.  
  5478.                         a = elem._size / fill._renderer.scale.y;
  5479.                         b = elem._leading / fill._renderer.scale.y;
  5480.                         ctx.font = [elem._style, elem._weight, toFixed(a) + 'px/',
  5481.                         toFixed(b) + 'px', elem._family].join(' ');
  5482.  
  5483.                         c = fill._renderer.offset.x / fill._renderer.scale.x;
  5484.                         d = fill._renderer.offset.y / fill._renderer.scale.y;
  5485.  
  5486.                         ctx.fillText(elem.value, toFixed(c), toFixed(d));
  5487.                         ctx.restore();
  5488.  
  5489.                     } else {
  5490.                         ctx.fillText(elem.value, 0, 0);
  5491.                     }
  5492.  
  5493.                 }
  5494.  
  5495.                 if (!webgl.isHidden.test(stroke)) {
  5496.  
  5497.                     if (stroke._renderer && stroke._renderer.offset) {
  5498.  
  5499.                         sx = toFixed(stroke._renderer.scale.x);
  5500.                         sy = toFixed(stroke._renderer.scale.y);
  5501.  
  5502.                         ctx.save();
  5503.                         ctx.translate(- toFixed(stroke._renderer.offset.x),
  5504.                             - toFixed(stroke._renderer.offset.y));
  5505.                         ctx.scale(sx, sy);
  5506.  
  5507.                         a = elem._size / stroke._renderer.scale.y;
  5508.                         b = elem._leading / stroke._renderer.scale.y;
  5509.                         ctx.font = [elem._style, elem._weight, toFixed(a) + 'px/',
  5510.                         toFixed(b) + 'px', elem._family].join(' ');
  5511.  
  5512.                         c = stroke._renderer.offset.x / stroke._renderer.scale.x;
  5513.                         d = stroke._renderer.offset.y / stroke._renderer.scale.y;
  5514.                         e = linewidth / stroke._renderer.scale.x;
  5515.  
  5516.                         ctx.lineWidth = toFixed(e);
  5517.                         ctx.strokeText(elem.value, toFixed(c), toFixed(d));
  5518.                         ctx.restore();
  5519.  
  5520.                     } else {
  5521.                         ctx.strokeText(elem.value, 0, 0);
  5522.                     }
  5523.  
  5524.                 }
  5525.  
  5526.                 ctx.restore();
  5527.  
  5528.             },
  5529.  
  5530.             getBoundingClientRect: function (elem, rect) {
  5531.  
  5532.                 var ctx = webgl.ctx;
  5533.  
  5534.                 ctx.font = [elem._style, elem._weight, elem._size + 'px/' +
  5535.                     elem._leading + 'px', elem._family].join(' ');
  5536.  
  5537.                 ctx.textAlign = 'center';
  5538.                 ctx.textBaseline = elem._baseline;
  5539.  
  5540.                 // TODO: Estimate this better
  5541.                 var width = ctx.measureText(elem._value).width;
  5542.                 var height = Math.max(elem._size || elem._leading);
  5543.  
  5544.                 if (this._linewidth && !webgl.isHidden.test(this._stroke)) {
  5545.                     // width += this._linewidth; // TODO: Not sure if the `measure` calcs this.
  5546.                     height += this._linewidth;
  5547.                 }
  5548.  
  5549.                 var w = width / 2;
  5550.                 var h = height / 2;
  5551.  
  5552.                 switch (webgl.alignments[elem._alignment] || elem._alignment) {
  5553.  
  5554.                     case webgl.alignments.left:
  5555.                         rect.left = 0;
  5556.                         rect.right = width;
  5557.                         break;
  5558.                     case webgl.alignments.right:
  5559.                         rect.left = - width;
  5560.                         rect.right = 0;
  5561.                         break;
  5562.                     default:
  5563.                         rect.left = - w;
  5564.                         rect.right = w;
  5565.                 }
  5566.  
  5567.                 // TODO: Gradients aren't inherited...
  5568.                 switch (elem._baseline) {
  5569.                     case 'bottom':
  5570.                         rect.top = - height;
  5571.                         rect.bottom = 0;
  5572.                         break;
  5573.                     case 'top':
  5574.                         rect.top = 0;
  5575.                         rect.bottom = height;
  5576.                         break;
  5577.                     default:
  5578.                         rect.top = - h;
  5579.                         rect.bottom = h;
  5580.                 }
  5581.  
  5582.                 rect.width = width;
  5583.                 rect.height = height;
  5584.  
  5585.                 if (!rect.centroid) {
  5586.                     rect.centroid = {};
  5587.                 }
  5588.  
  5589.                 // TODO:
  5590.                 rect.centroid.x = w;
  5591.                 rect.centroid.y = h;
  5592.  
  5593.             },
  5594.  
  5595.             render: function (gl, program, forcedParent) {
  5596.  
  5597.                 if (!this._visible || !this._opacity) {
  5598.                     return this;
  5599.                 }
  5600.  
  5601.                 this._update();
  5602.  
  5603.                 // Calculate what changed
  5604.  
  5605.                 var parent = this.parent;
  5606.                 var flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
  5607.                 var flagMatrix = this._matrix.manual || this._flagMatrix;
  5608.                 var flagTexture = this._flagVertices || this._flagFill
  5609.                     || (this._fill instanceof Two.LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints))
  5610.                     || (this._fill instanceof Two.RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal))
  5611.                     || (this._fill instanceof Two.Texture && (this._fill._flagLoaded && this._fill.loaded))
  5612.                     || (this._stroke instanceof Two.LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints))
  5613.                     || (this._stroke instanceof Two.RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal))
  5614.                     || (this._texture instanceof Two.Texture && (this._texture._flagLoaded && this._texture.loaded))
  5615.                     || this._flagStroke || this._flagLinewidth || this._flagOpacity
  5616.                     || parent._flagOpacity || this._flagVisible || this._flagScale
  5617.                     || this._flagValue || this._flagFamily || this._flagSize
  5618.                     || this._flagLeading || this._flagAlignment || this._flagBaseline
  5619.                     || this._flagStyle || this._flagWeight || this._flagDecoration
  5620.                     || !this._renderer.texture;
  5621.  
  5622.                 if (flagParentMatrix || flagMatrix) {
  5623.  
  5624.                     if (!this._renderer.matrix) {
  5625.                         this._renderer.matrix = new Two.Array(9);
  5626.                     }
  5627.  
  5628.                     // Reduce amount of object / array creation / deletion
  5629.  
  5630.                     this._matrix.toArray(true, transformation);
  5631.  
  5632.                     multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  5633.                     this._renderer.scale = this._scale * parent._renderer.scale;
  5634.  
  5635.                 }
  5636.  
  5637.                 if (flagTexture) {
  5638.  
  5639.                     if (!this._renderer.rect) {
  5640.                         this._renderer.rect = {};
  5641.                     }
  5642.  
  5643.                     if (!this._renderer.triangles) {
  5644.                         this._renderer.triangles = new Two.Array(12);
  5645.                     }
  5646.  
  5647.                     this._renderer.opacity = this._opacity * parent._renderer.opacity;
  5648.  
  5649.                     webgl.text.getBoundingClientRect(this, this._renderer.rect);
  5650.                     webgl.getTriangles(this._renderer.rect, this._renderer.triangles);
  5651.  
  5652.                     webgl.updateBuffer.call(webgl, gl, this, program);
  5653.                     webgl.updateTexture.call(webgl, gl, this);
  5654.  
  5655.                 }
  5656.  
  5657.                 // if (this._mask) {
  5658.                 //   webgl[this._mask._renderer.type].render.call(mask, gl, program, this);
  5659.                 // }
  5660.  
  5661.                 if (this._clip && !forcedParent) {
  5662.                     return;
  5663.                 }
  5664.  
  5665.                 // Draw Texture
  5666.  
  5667.                 gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.textureCoordsBuffer);
  5668.  
  5669.                 gl.vertexAttribPointer(program.textureCoords, 2, gl.FLOAT, false, 0, 0);
  5670.  
  5671.                 gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
  5672.  
  5673.  
  5674.                 // Draw Rect
  5675.  
  5676.                 gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
  5677.  
  5678.                 gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.buffer);
  5679.  
  5680.                 gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
  5681.  
  5682.                 gl.drawArrays(gl.TRIANGLES, 0, 6);
  5683.  
  5684.                 return this.flagReset();
  5685.  
  5686.             }
  5687.  
  5688.         },
  5689.  
  5690.         'linear-gradient': {
  5691.  
  5692.             render: function (ctx, elem) {
  5693.  
  5694.                 if (!ctx.canvas.getContext('2d')) {
  5695.                     return;
  5696.                 }
  5697.  
  5698.                 this._update();
  5699.  
  5700.                 if (!this._renderer.effect || this._flagEndPoints || this._flagStops) {
  5701.  
  5702.                     this._renderer.effect = ctx.createLinearGradient(
  5703.                         this.left._x, this.left._y,
  5704.                         this.right._x, this.right._y
  5705.                     );
  5706.  
  5707.                     for (var i = 0; i < this.stops.length; i++) {
  5708.                         var stop = this.stops[i];
  5709.                         this._renderer.effect.addColorStop(stop._offset, stop._color);
  5710.                     }
  5711.  
  5712.                 }
  5713.  
  5714.                 return this.flagReset();
  5715.  
  5716.             }
  5717.  
  5718.         },
  5719.  
  5720.         'radial-gradient': {
  5721.  
  5722.             render: function (ctx, elem) {
  5723.  
  5724.                 if (!ctx.canvas.getContext('2d')) {
  5725.                     return;
  5726.                 }
  5727.  
  5728.                 this._update();
  5729.  
  5730.                 if (!this._renderer.effect || this._flagCenter || this._flagFocal
  5731.                     || this._flagRadius || this._flagStops) {
  5732.  
  5733.                     this._renderer.effect = ctx.createRadialGradient(
  5734.                         this.center._x, this.center._y, 0,
  5735.                         this.focal._x, this.focal._y, this._radius
  5736.                     );
  5737.  
  5738.                     for (var i = 0; i < this.stops.length; i++) {
  5739.                         var stop = this.stops[i];
  5740.                         this._renderer.effect.addColorStop(stop._offset, stop._color);
  5741.                     }
  5742.  
  5743.                 }
  5744.  
  5745.                 return this.flagReset();
  5746.  
  5747.             }
  5748.  
  5749.         },
  5750.  
  5751.         texture: {
  5752.  
  5753.             render: function (ctx, elem) {
  5754.  
  5755.                 if (!ctx.canvas.getContext('2d')) {
  5756.                     return;
  5757.                 }
  5758.  
  5759.                 this._update();
  5760.  
  5761.                 var image = this.image;
  5762.                 var repeat;
  5763.  
  5764.                 if (!this._renderer.effect || ((this._flagLoaded || this._flagRepeat) && this.loaded)) {
  5765.                     this._renderer.effect = ctx.createPattern(image, this._repeat);
  5766.                 }
  5767.  
  5768.                 if (this._flagOffset || this._flagLoaded || this._flagScale) {
  5769.  
  5770.                     if (!(this._renderer.offset instanceof Two.Vector)) {
  5771.                         this._renderer.offset = new Two.Vector();
  5772.                     }
  5773.  
  5774.                     this._renderer.offset.x = this._offset.x;
  5775.                     this._renderer.offset.y = this._offset.y;
  5776.  
  5777.                     if (image) {
  5778.  
  5779.                         this._renderer.offset.x -= image.width / 2;
  5780.                         this._renderer.offset.y += image.height / 2;
  5781.  
  5782.                         if (this._scale instanceof Two.Vector) {
  5783.                             this._renderer.offset.x *= this._scale.x;
  5784.                             this._renderer.offset.y *= this._scale.y;
  5785.                         } else {
  5786.                             this._renderer.offset.x *= this._scale;
  5787.                             this._renderer.offset.y *= this._scale;
  5788.                         }
  5789.                     }
  5790.  
  5791.                 }
  5792.  
  5793.                 if (this._flagScale || this._flagLoaded) {
  5794.  
  5795.                     if (!(this._renderer.scale instanceof Two.Vector)) {
  5796.                         this._renderer.scale = new Two.Vector();
  5797.                     }
  5798.  
  5799.                     if (this._scale instanceof Two.Vector) {
  5800.                         this._renderer.scale.copy(this._scale);
  5801.                     } else {
  5802.                         this._renderer.scale.set(this._scale, this._scale);
  5803.                     }
  5804.  
  5805.                 }
  5806.  
  5807.                 return this.flagReset();
  5808.  
  5809.             }
  5810.  
  5811.         },
  5812.  
  5813.         getTriangles: function (rect, triangles) {
  5814.  
  5815.             var top = rect.top,
  5816.                 left = rect.left,
  5817.                 right = rect.right,
  5818.                 bottom = rect.bottom;
  5819.  
  5820.             // First Triangle
  5821.  
  5822.             triangles[0] = left;
  5823.             triangles[1] = top;
  5824.  
  5825.             triangles[2] = right;
  5826.             triangles[3] = top;
  5827.  
  5828.             triangles[4] = left;
  5829.             triangles[5] = bottom;
  5830.  
  5831.             // Second Triangle
  5832.  
  5833.             triangles[6] = left;
  5834.             triangles[7] = bottom;
  5835.  
  5836.             triangles[8] = right;
  5837.             triangles[9] = top;
  5838.  
  5839.             triangles[10] = right;
  5840.             triangles[11] = bottom;
  5841.  
  5842.         },
  5843.  
  5844.         updateTexture: function (gl, elem) {
  5845.  
  5846.             this[elem._renderer.type].updateCanvas.call(webgl, elem);
  5847.  
  5848.             if (elem._renderer.texture) {
  5849.                 gl.deleteTexture(elem._renderer.texture);
  5850.             }
  5851.  
  5852.             gl.bindBuffer(gl.ARRAY_BUFFER, elem._renderer.textureCoordsBuffer);
  5853.  
  5854.             // TODO: Is this necessary every time or can we do once?
  5855.             // TODO: Create a registry for textures
  5856.             elem._renderer.texture = gl.createTexture();
  5857.             gl.bindTexture(gl.TEXTURE_2D, elem._renderer.texture);
  5858.  
  5859.             // Set the parameters so we can render any size image.
  5860.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  5861.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  5862.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  5863.             // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  5864.             // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  5865.             // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  5866.  
  5867.             if (this.canvas.width <= 0 || this.canvas.height <= 0) {
  5868.                 return;
  5869.             }
  5870.  
  5871.             // Upload the image into the texture.
  5872.             gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);
  5873.  
  5874.         },
  5875.  
  5876.         updateBuffer: function (gl, elem, program) {
  5877.  
  5878.             if (_.isObject(elem._renderer.buffer)) {
  5879.                 gl.deleteBuffer(elem._renderer.buffer);
  5880.             }
  5881.  
  5882.             elem._renderer.buffer = gl.createBuffer();
  5883.  
  5884.             gl.bindBuffer(gl.ARRAY_BUFFER, elem._renderer.buffer);
  5885.             gl.enableVertexAttribArray(program.position);
  5886.  
  5887.             gl.bufferData(gl.ARRAY_BUFFER, elem._renderer.triangles, gl.STATIC_DRAW);
  5888.  
  5889.             if (_.isObject(elem._renderer.textureCoordsBuffer)) {
  5890.                 gl.deleteBuffer(elem._renderer.textureCoordsBuffer);
  5891.             }
  5892.  
  5893.             elem._renderer.textureCoordsBuffer = gl.createBuffer();
  5894.  
  5895.             gl.bindBuffer(gl.ARRAY_BUFFER, elem._renderer.textureCoordsBuffer);
  5896.             gl.enableVertexAttribArray(program.textureCoords);
  5897.  
  5898.             gl.bufferData(gl.ARRAY_BUFFER, this.uv, gl.STATIC_DRAW);
  5899.  
  5900.         },
  5901.  
  5902.         program: {
  5903.  
  5904.             create: function (gl, shaders) {
  5905.                 var program, linked, error;
  5906.                 program = gl.createProgram();
  5907.                 _.each(shaders, function (s) {
  5908.                     gl.attachShader(program, s);
  5909.                 });
  5910.  
  5911.                 gl.linkProgram(program);
  5912.                 linked = gl.getProgramParameter(program, gl.LINK_STATUS);
  5913.                 if (!linked) {
  5914.                     error = gl.getProgramInfoLog(program);
  5915.                     gl.deleteProgram(program);
  5916.                     throw new Two.Utils.Error('unable to link program: ' + error);
  5917.                 }
  5918.  
  5919.                 return program;
  5920.  
  5921.             }
  5922.  
  5923.         },
  5924.  
  5925.         shaders: {
  5926.  
  5927.             create: function (gl, source, type) {
  5928.                 var shader, compiled, error;
  5929.                 shader = gl.createShader(gl[type]);
  5930.                 gl.shaderSource(shader, source);
  5931.                 gl.compileShader(shader);
  5932.  
  5933.                 compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  5934.                 if (!compiled) {
  5935.                     error = gl.getShaderInfoLog(shader);
  5936.                     gl.deleteShader(shader);
  5937.                     throw new Two.Utils.Error('unable to compile shader ' + shader + ': ' + error);
  5938.                 }
  5939.  
  5940.                 return shader;
  5941.  
  5942.             },
  5943.  
  5944.             types: {
  5945.                 vertex: 'VERTEX_SHADER',
  5946.                 fragment: 'FRAGMENT_SHADER'
  5947.             },
  5948.  
  5949.             vertex: [
  5950.                 'attribute vec2 a_position;',
  5951.                 'attribute vec2 a_textureCoords;',
  5952.                 '',
  5953.                 'uniform mat3 u_matrix;',
  5954.                 'uniform vec2 u_resolution;',
  5955.                 '',
  5956.                 'varying vec2 v_textureCoords;',
  5957.                 '',
  5958.                 'void main() {',
  5959.                 '   vec2 projected = (u_matrix * vec3(a_position, 1.0)).xy;',
  5960.                 '   vec2 normal = projected / u_resolution;',
  5961.                 '   vec2 clipspace = (normal * 2.0) - 1.0;',
  5962.                 '',
  5963.                 '   gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0);',
  5964.                 '   v_textureCoords = a_textureCoords;',
  5965.                 '}'
  5966.             ].join('\n'),
  5967.  
  5968.             fragment: [
  5969.                 'precision mediump float;',
  5970.                 '',
  5971.                 'uniform sampler2D u_image;',
  5972.                 'varying vec2 v_textureCoords;',
  5973.                 '',
  5974.                 'void main() {',
  5975.                 '  gl_FragColor = texture2D(u_image, v_textureCoords);',
  5976.                 '}'
  5977.             ].join('\n')
  5978.  
  5979.         },
  5980.  
  5981.         TextureRegistry: new Two.Registry()
  5982.  
  5983.     };
  5984.  
  5985.     webgl.ctx = webgl.canvas.getContext('2d');
  5986.  
  5987.     var Renderer = Two[Two.Types.webgl] = function (options) {
  5988.  
  5989.         var params, gl, vs, fs;
  5990.         this.domElement = options.domElement || document.createElement('canvas');
  5991.  
  5992.         // Everything drawn on the canvas needs to come from the stage.
  5993.         this.scene = new Two.Group();
  5994.         this.scene.parent = this;
  5995.  
  5996.         this._renderer = {
  5997.             matrix: new Two.Array(identity),
  5998.             scale: 1,
  5999.             opacity: 1
  6000.         };
  6001.         this._flagMatrix = true;
  6002.  
  6003.         // http://games.greggman.com/game/webgl-and-alpha/
  6004.         // http://www.khronos.org/registry/webgl/specs/latest/#5.2
  6005.         params = _.defaults(options || {}, {
  6006.             antialias: false,
  6007.             alpha: true,
  6008.             premultipliedAlpha: true,
  6009.             stencil: true,
  6010.             preserveDrawingBuffer: true,
  6011.             overdraw: false
  6012.         });
  6013.  
  6014.         this.overdraw = params.overdraw;
  6015.  
  6016.         gl = this.ctx = this.domElement.getContext('webgl', params) ||
  6017.             this.domElement.getContext('experimental-webgl', params);
  6018.  
  6019.         if (!this.ctx) {
  6020.             throw new Two.Utils.Error(
  6021.                 'unable to create a webgl context. Try using another renderer.');
  6022.         }
  6023.  
  6024.         // Compile Base Shaders to draw in pixel space.
  6025.         vs = webgl.shaders.create(
  6026.             gl, webgl.shaders.vertex, webgl.shaders.types.vertex);
  6027.         fs = webgl.shaders.create(
  6028.             gl, webgl.shaders.fragment, webgl.shaders.types.fragment);
  6029.  
  6030.         this.program = webgl.program.create(gl, [vs, fs]);
  6031.         gl.useProgram(this.program);
  6032.  
  6033.         // Create and bind the drawing buffer
  6034.  
  6035.         // look up where the vertex data needs to go.
  6036.         this.program.position = gl.getAttribLocation(this.program, 'a_position');
  6037.         this.program.matrix = gl.getUniformLocation(this.program, 'u_matrix');
  6038.         this.program.textureCoords = gl.getAttribLocation(this.program, 'a_textureCoords');
  6039.  
  6040.         // Copied from Three.js WebGLRenderer
  6041.         gl.disable(gl.DEPTH_TEST);
  6042.  
  6043.         // Setup some initial statements of the gl context
  6044.         gl.enable(gl.BLEND);
  6045.  
  6046.         // https://code.google.com/p/chromium/issues/detail?id=316393
  6047.         // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, gl.TRUE);
  6048.  
  6049.         gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  6050.         gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA,
  6051.             gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  6052.  
  6053.     };
  6054.  
  6055.     _.extend(Renderer, {
  6056.  
  6057.         Utils: webgl
  6058.  
  6059.     });
  6060.  
  6061.     _.extend(Renderer.prototype, Two.Utils.Events, {
  6062.  
  6063.         setSize: function (width, height, ratio) {
  6064.  
  6065.             this.width = width;
  6066.             this.height = height;
  6067.  
  6068.             this.ratio = _.isUndefined(ratio) ? getRatio(this.ctx) : ratio;
  6069.  
  6070.             this.domElement.width = width * this.ratio;
  6071.             this.domElement.height = height * this.ratio;
  6072.  
  6073.             _.extend(this.domElement.style, {
  6074.                 width: width + 'px',
  6075.                 height: height + 'px'
  6076.             });
  6077.  
  6078.             width *= this.ratio;
  6079.             height *= this.ratio;
  6080.  
  6081.             // Set for this.stage parent scaling to account for HDPI
  6082.             this._renderer.matrix[0] = this._renderer.matrix[4] = this._renderer.scale = this.ratio;
  6083.  
  6084.             this._flagMatrix = true;
  6085.  
  6086.             this.ctx.viewport(0, 0, width, height);
  6087.  
  6088.             var resolutionLocation = this.ctx.getUniformLocation(
  6089.                 this.program, 'u_resolution');
  6090.             this.ctx.uniform2f(resolutionLocation, width, height);
  6091.  
  6092.             return this;
  6093.  
  6094.         },
  6095.  
  6096.         render: function () {
  6097.  
  6098.             var gl = this.ctx;
  6099.  
  6100.             if (!this.overdraw) {
  6101.                 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  6102.             }
  6103.  
  6104.             webgl.group.render.call(this.scene, gl, this.program);
  6105.             this._flagMatrix = false;
  6106.  
  6107.             return this;
  6108.  
  6109.         }
  6110.  
  6111.     });
  6112.  
  6113. })((typeof global !== 'undefined' ? global : this).Two);
  6114.  
  6115. (function (Two) {
  6116.  
  6117.     var _ = Two.Utils;
  6118.  
  6119.     var Shape = Two.Shape = function () {
  6120.  
  6121.         // Private object for renderer specific variables.
  6122.         this._renderer = {};
  6123.         this._renderer.flagMatrix = _.bind(Shape.FlagMatrix, this);
  6124.         this.isShape = true;
  6125.  
  6126.         this.id = Two.Identifier + Two.uniqueId();
  6127.         this.classList = [];
  6128.  
  6129.         // Define matrix properties which all inherited
  6130.         // objects of Shape have.
  6131.  
  6132.         this._matrix = new Two.Matrix();
  6133.  
  6134.         this.translation = new Two.Vector();
  6135.         this.rotation = 0;
  6136.         this.scale = 1;
  6137.  
  6138.     };
  6139.  
  6140.     _.extend(Shape, {
  6141.  
  6142.         FlagMatrix: function () {
  6143.             this._flagMatrix = true;
  6144.         },
  6145.  
  6146.         MakeObservable: function (object) {
  6147.  
  6148.             Object.defineProperty(object, 'translation', {
  6149.                 enumerable: true,
  6150.                 get: function () {
  6151.                     return this._translation;
  6152.                 },
  6153.                 set: function (v) {
  6154.                     if (this._translation) {
  6155.                         this._translation.unbind(Two.Events.change, this._renderer.flagMatrix);
  6156.                     }
  6157.                     this._translation = v;
  6158.                     this._translation.bind(Two.Events.change, this._renderer.flagMatrix);
  6159.                     Shape.FlagMatrix.call(this);
  6160.                 }
  6161.             });
  6162.  
  6163.             Object.defineProperty(object, 'rotation', {
  6164.                 enumerable: true,
  6165.                 get: function () {
  6166.                     return this._rotation;
  6167.                 },
  6168.                 set: function (v) {
  6169.                     this._rotation = v;
  6170.                     this._flagMatrix = true;
  6171.                 }
  6172.             });
  6173.  
  6174.             Object.defineProperty(object, 'scale', {
  6175.                 enumerable: true,
  6176.                 get: function () {
  6177.                     return this._scale;
  6178.                 },
  6179.                 set: function (v) {
  6180.  
  6181.                     if (this._scale instanceof Two.Vector) {
  6182.                         this._scale.unbind(Two.Events.change, this._renderer.flagMatrix);
  6183.                     }
  6184.  
  6185.                     this._scale = v;
  6186.  
  6187.                     if (this._scale instanceof Two.Vector) {
  6188.                         this._scale.bind(Two.Events.change, this._renderer.flagMatrix);
  6189.                     }
  6190.  
  6191.                     this._flagMatrix = true;
  6192.                     this._flagScale = true;
  6193.  
  6194.                 }
  6195.             });
  6196.  
  6197.         }
  6198.  
  6199.     });
  6200.  
  6201.     _.extend(Shape.prototype, Two.Utils.Events, {
  6202.  
  6203.         // Flags
  6204.  
  6205.         _flagMatrix: true,
  6206.         _flagScale: false,
  6207.  
  6208.         // _flagMask: false,
  6209.         // _flagClip: false,
  6210.  
  6211.         // Underlying Properties
  6212.  
  6213.         _rotation: 0,
  6214.         _scale: 1,
  6215.         _translation: null,
  6216.  
  6217.         // _mask: null,
  6218.         // _clip: false,
  6219.  
  6220.         addTo: function (group) {
  6221.             group.add(this);
  6222.             return this;
  6223.         },
  6224.  
  6225.         clone: function () {
  6226.             var clone = new Shape();
  6227.             clone.translation.copy(this.translation);
  6228.             clone.rotation = this.rotation;
  6229.             clone.scale = this.scale;
  6230.             _.each(Shape.Properties, function (k) {
  6231.                 clone[k] = this[k];
  6232.             }, this);
  6233.             return clone._update();
  6234.         },
  6235.  
  6236.         /**
  6237.             * To be called before render that calculates and collates all information
  6238.             * to be as up-to-date as possible for the render. Called once a frame.
  6239.             */
  6240.         _update: function (deep) {
  6241.  
  6242.             if (!this._matrix.manual && this._flagMatrix) {
  6243.  
  6244.                 this._matrix
  6245.                     .identity()
  6246.                     .translate(this.translation.x, this.translation.y);
  6247.  
  6248.                 if (this._scale instanceof Two.Vector) {
  6249.                     this._matrix.scale(this._scale.x, this._scale.y);
  6250.                 } else {
  6251.                     this._matrix.scale(this._scale);
  6252.                 }
  6253.  
  6254.                 this._matrix.rotate(this.rotation);
  6255.  
  6256.             }
  6257.  
  6258.             if (deep) {
  6259.                 // Bubble up to parents mainly for `getBoundingClientRect` method.
  6260.                 if (this.parent && this.parent._update) {
  6261.                     this.parent._update();
  6262.                 }
  6263.             }
  6264.  
  6265.             return this;
  6266.  
  6267.         },
  6268.  
  6269.         flagReset: function () {
  6270.  
  6271.             this._flagMatrix = this._flagScale = false;
  6272.  
  6273.             return this;
  6274.  
  6275.         }
  6276.  
  6277.     });
  6278.  
  6279.     Shape.MakeObservable(Shape.prototype);
  6280.  
  6281. })((typeof global !== 'undefined' ? global : this).Two);
  6282.  
  6283. (function (Two) {
  6284.  
  6285.     /**
  6286.         * Constants
  6287.         */
  6288.  
  6289.     var min = Math.min, max = Math.max, round = Math.round,
  6290.         getComputedMatrix = Two.Utils.getComputedMatrix;
  6291.  
  6292.     var commands = {};
  6293.     var _ = Two.Utils;
  6294.  
  6295.     _.each(Two.Commands, function (v, k) {
  6296.         commands[k] = new RegExp(v);
  6297.     });
  6298.  
  6299.     var Path = Two.Path = function (vertices, closed, curved, manual) {
  6300.  
  6301.         Two.Shape.call(this);
  6302.  
  6303.         this._renderer.type = 'path';
  6304.         this._renderer.flagVertices = _.bind(Path.FlagVertices, this);
  6305.         this._renderer.bindVertices = _.bind(Path.BindVertices, this);
  6306.         this._renderer.unbindVertices = _.bind(Path.UnbindVertices, this);
  6307.  
  6308.         this._renderer.flagFill = _.bind(Path.FlagFill, this);
  6309.         this._renderer.flagStroke = _.bind(Path.FlagStroke, this);
  6310.  
  6311.         this._closed = !!closed;
  6312.         this._curved = !!curved;
  6313.  
  6314.         this.beginning = 0;
  6315.         this.ending = 1;
  6316.  
  6317.         // Style properties
  6318.  
  6319.         this.fill = '#fff';
  6320.         this.stroke = '#000';
  6321.         this.linewidth = 1.0;
  6322.         this.opacity = 1.0;
  6323.         this.visible = true;
  6324.  
  6325.         this.cap = 'butt';      // Default of Adobe Illustrator
  6326.         this.join = 'miter';    // Default of Adobe Illustrator
  6327.         this.miter = 4;         // Default of Adobe Illustrator
  6328.  
  6329.         this._vertices = [];
  6330.         this.vertices = vertices;
  6331.  
  6332.         // Determines whether or not two.js should calculate curves, lines, and
  6333.         // commands automatically for you or to let the developer manipulate them
  6334.         // for themselves.
  6335.         this.automatic = !manual;
  6336.  
  6337.     };
  6338.  
  6339.     _.extend(Path, {
  6340.  
  6341.         Properties: [
  6342.             'fill',
  6343.             'stroke',
  6344.             'linewidth',
  6345.             'opacity',
  6346.             'visible',
  6347.             'cap',
  6348.             'join',
  6349.             'miter',
  6350.  
  6351.             'closed',
  6352.             'curved',
  6353.             'automatic',
  6354.             'beginning',
  6355.             'ending'
  6356.         ],
  6357.  
  6358.         FlagVertices: function () {
  6359.             this._flagVertices = true;
  6360.             this._flagLength = true;
  6361.         },
  6362.  
  6363.         BindVertices: function (items) {
  6364.  
  6365.             // This function is called a lot
  6366.             // when importing a large SVG
  6367.             var i = items.length;
  6368.             while (i--) {
  6369.                 items[i].bind(Two.Events.change, this._renderer.flagVertices);
  6370.             }
  6371.  
  6372.             this._renderer.flagVertices();
  6373.  
  6374.         },
  6375.  
  6376.         UnbindVertices: function (items) {
  6377.  
  6378.             var i = items.length;
  6379.             while (i--) {
  6380.                 items[i].unbind(Two.Events.change, this._renderer.flagVertices);
  6381.             }
  6382.  
  6383.             this._renderer.flagVertices();
  6384.  
  6385.         },
  6386.  
  6387.         FlagFill: function () {
  6388.             this._flagFill = true;
  6389.         },
  6390.  
  6391.         FlagStroke: function () {
  6392.             this._flagStroke = true;
  6393.         },
  6394.  
  6395.         MakeObservable: function (object) {
  6396.  
  6397.             Two.Shape.MakeObservable(object);
  6398.  
  6399.             // Only the 6 defined properties are flagged like this. The subsequent
  6400.             // properties behave differently and need to be hand written.
  6401.             _.each(Path.Properties.slice(2, 8), Two.Utils.defineProperty, object);
  6402.  
  6403.             Object.defineProperty(object, 'fill', {
  6404.                 enumerable: true,
  6405.                 get: function () {
  6406.                     return this._fill;
  6407.                 },
  6408.                 set: function (f) {
  6409.  
  6410.                     if (this._fill instanceof Two.Gradient
  6411.                         || this._fill instanceof Two.LinearGradient
  6412.                         || this._fill instanceof Two.RadialGradient
  6413.                         || this._fill instanceof Two.Texture) {
  6414.                         this._fill.unbind(Two.Events.change, this._renderer.flagFill);
  6415.                     }
  6416.  
  6417.                     this._fill = f;
  6418.                     this._flagFill = true;
  6419.  
  6420.                     if (this._fill instanceof Two.Gradient
  6421.                         || this._fill instanceof Two.LinearGradient
  6422.                         || this._fill instanceof Two.RadialGradient
  6423.                         || this._fill instanceof Two.Texture) {
  6424.                         this._fill.bind(Two.Events.change, this._renderer.flagFill);
  6425.                     }
  6426.  
  6427.                 }
  6428.             });
  6429.  
  6430.             Object.defineProperty(object, 'stroke', {
  6431.                 enumerable: true,
  6432.                 get: function () {
  6433.                     return this._stroke;
  6434.                 },
  6435.                 set: function (f) {
  6436.  
  6437.                     if (this._stroke instanceof Two.Gradient
  6438.                         || this._stroke instanceof Two.LinearGradient
  6439.                         || this._stroke instanceof Two.RadialGradient
  6440.                         || this._stroke instanceof Two.Texture) {
  6441.                         this._stroke.unbind(Two.Events.change, this._renderer.flagStroke);
  6442.                     }
  6443.  
  6444.                     this._stroke = f;
  6445.                     this._flagStroke = true;
  6446.  
  6447.                     if (this._stroke instanceof Two.Gradient
  6448.                         || this._stroke instanceof Two.LinearGradient
  6449.                         || this._stroke instanceof Two.RadialGradient
  6450.                         || this._stroke instanceof Two.Texture) {
  6451.                         this._stroke.bind(Two.Events.change, this._renderer.flagStroke);
  6452.                     }
  6453.  
  6454.                 }
  6455.             });
  6456.  
  6457.             Object.defineProperty(object, 'length', {
  6458.                 get: function () {
  6459.                     if (this._flagLength) {
  6460.                         this._updateLength();
  6461.                     }
  6462.                     return this._length;
  6463.                 }
  6464.             });
  6465.  
  6466.             Object.defineProperty(object, 'closed', {
  6467.                 enumerable: true,
  6468.                 get: function () {
  6469.                     return this._closed;
  6470.                 },
  6471.                 set: function (v) {
  6472.                     this._closed = !!v;
  6473.                     this._flagVertices = true;
  6474.                 }
  6475.             });
  6476.  
  6477.             Object.defineProperty(object, 'curved', {
  6478.                 enumerable: true,
  6479.                 get: function () {
  6480.                     return this._curved;
  6481.                 },
  6482.                 set: function (v) {
  6483.                     this._curved = !!v;
  6484.                     this._flagVertices = true;
  6485.                 }
  6486.             });
  6487.  
  6488.             Object.defineProperty(object, 'automatic', {
  6489.                 enumerable: true,
  6490.                 get: function () {
  6491.                     return this._automatic;
  6492.                 },
  6493.                 set: function (v) {
  6494.                     if (v === this._automatic) {
  6495.                         return;
  6496.                     }
  6497.                     this._automatic = !!v;
  6498.                     var method = this._automatic ? 'ignore' : 'listen';
  6499.                     _.each(this.vertices, function (v) {
  6500.                         v[method]();
  6501.                     });
  6502.                 }
  6503.             });
  6504.  
  6505.             Object.defineProperty(object, 'beginning', {
  6506.                 enumerable: true,
  6507.                 get: function () {
  6508.                     return this._beginning;
  6509.                 },
  6510.                 set: function (v) {
  6511.                     this._beginning = v;
  6512.                     this._flagVertices = true;
  6513.                 }
  6514.             });
  6515.  
  6516.             Object.defineProperty(object, 'ending', {
  6517.                 enumerable: true,
  6518.                 get: function () {
  6519.                     return this._ending;
  6520.                 },
  6521.                 set: function (v) {
  6522.                     this._ending = v;
  6523.                     this._flagVertices = true;
  6524.                 }
  6525.             });
  6526.  
  6527.             Object.defineProperty(object, 'vertices', {
  6528.  
  6529.                 enumerable: true,
  6530.  
  6531.                 get: function () {
  6532.                     return this._collection;
  6533.                 },
  6534.  
  6535.                 set: function (vertices) {
  6536.  
  6537.                     var updateVertices = this._renderer.flagVertices;
  6538.                     var bindVertices = this._renderer.bindVertices;
  6539.                     var unbindVertices = this._renderer.unbindVertices;
  6540.  
  6541.                     // Remove previous listeners
  6542.                     if (this._collection) {
  6543.                         this._collection
  6544.                             .unbind(Two.Events.insert, bindVertices)
  6545.                             .unbind(Two.Events.remove, unbindVertices);
  6546.                     }
  6547.  
  6548.                     // Create new Collection with copy of vertices
  6549.                     this._collection = new Two.Utils.Collection((vertices || []).slice(0));
  6550.  
  6551.                     // Listen for Collection changes and bind / unbind
  6552.                     this._collection
  6553.                         .bind(Two.Events.insert, bindVertices)
  6554.                         .bind(Two.Events.remove, unbindVertices);
  6555.  
  6556.                     // Bind Initial Vertices
  6557.                     bindVertices(this._collection);
  6558.  
  6559.                 }
  6560.  
  6561.             });
  6562.  
  6563.             Object.defineProperty(object, 'clip', {
  6564.                 enumerable: true,
  6565.                 get: function () {
  6566.                     return this._clip;
  6567.                 },
  6568.                 set: function (v) {
  6569.                     this._clip = v;
  6570.                     this._flagClip = true;
  6571.                 }
  6572.             });
  6573.  
  6574.         }
  6575.  
  6576.     });
  6577.  
  6578.     _.extend(Path.prototype, Two.Shape.prototype, {
  6579.  
  6580.         // Flags
  6581.         // http://en.wikipedia.org/wiki/Flag
  6582.  
  6583.         _flagVertices: true,
  6584.         _flagLength: true,
  6585.  
  6586.         _flagFill: true,
  6587.         _flagStroke: true,
  6588.         _flagLinewidth: true,
  6589.         _flagOpacity: true,
  6590.         _flagVisible: true,
  6591.  
  6592.         _flagCap: true,
  6593.         _flagJoin: true,
  6594.         _flagMiter: true,
  6595.  
  6596.         _flagClip: false,
  6597.  
  6598.         // Underlying Properties
  6599.  
  6600.         _length: 0,
  6601.  
  6602.         _fill: '#fff',
  6603.         _stroke: '#000',
  6604.         _linewidth: 1.0,
  6605.         _opacity: 1.0,
  6606.         _visible: true,
  6607.  
  6608.         _cap: 'round',
  6609.         _join: 'round',
  6610.         _miter: 4,
  6611.  
  6612.         _closed: true,
  6613.         _curved: false,
  6614.         _automatic: true,
  6615.         _beginning: 0,
  6616.         _ending: 1.0,
  6617.  
  6618.         _clip: false,
  6619.  
  6620.         clone: function (parent) {
  6621.  
  6622.             parent = parent || this.parent;
  6623.  
  6624.             var points = _.map(this.vertices, function (v) {
  6625.                 return v.clone();
  6626.             });
  6627.  
  6628.             var clone = new Path(points, this.closed, this.curved, !this.automatic);
  6629.  
  6630.             _.each(Two.Path.Properties, function (k) {
  6631.                 clone[k] = this[k];
  6632.             }, this);
  6633.  
  6634.             clone.translation.copy(this.translation);
  6635.             clone.rotation = this.rotation;
  6636.             clone.scale = this.scale;
  6637.  
  6638.             if (parent) {
  6639.                 parent.add(clone);
  6640.             }
  6641.  
  6642.             return clone;
  6643.  
  6644.         },
  6645.  
  6646.         toObject: function () {
  6647.  
  6648.             var result = {
  6649.                 vertices: _.map(this.vertices, function (v) {
  6650.                     return v.toObject();
  6651.                 })
  6652.             };
  6653.  
  6654.             _.each(Two.Shape.Properties, function (k) {
  6655.                 result[k] = this[k];
  6656.             }, this);
  6657.  
  6658.             result.translation = this.translation.toObject;
  6659.             result.rotation = this.rotation;
  6660.             result.scale = this.scale;
  6661.  
  6662.             return result;
  6663.  
  6664.         },
  6665.  
  6666.         noFill: function () {
  6667.             this.fill = 'transparent';
  6668.             return this;
  6669.         },
  6670.  
  6671.         noStroke: function () {
  6672.             this.stroke = 'transparent';
  6673.             return this;
  6674.         },
  6675.  
  6676.         /**
  6677.             * Orient the vertices of the shape to the upper lefthand
  6678.             * corner of the path.
  6679.             */
  6680.         corner: function () {
  6681.  
  6682.             var rect = this.getBoundingClientRect(true);
  6683.  
  6684.             rect.centroid = {
  6685.                 x: rect.left + rect.width / 2,
  6686.                 y: rect.top + rect.height / 2
  6687.             };
  6688.  
  6689.             _.each(this.vertices, function (v) {
  6690.                 v.addSelf(rect.centroid);
  6691.             });
  6692.  
  6693.             return this;
  6694.  
  6695.         },
  6696.  
  6697.         /**
  6698.             * Orient the vertices of the shape to the center of the
  6699.             * path.
  6700.             */
  6701.         center: function () {
  6702.  
  6703.             var rect = this.getBoundingClientRect(true);
  6704.  
  6705.             rect.centroid = {
  6706.                 x: rect.left + rect.width / 2,
  6707.                 y: rect.top + rect.height / 2
  6708.             };
  6709.  
  6710.             _.each(this.vertices, function (v) {
  6711.                 v.subSelf(rect.centroid);
  6712.             });
  6713.  
  6714.             // this.translation.addSelf(rect.centroid);
  6715.  
  6716.             return this;
  6717.  
  6718.         },
  6719.  
  6720.         /**
  6721.             * Remove self from the scene / parent.
  6722.             */
  6723.         remove: function () {
  6724.  
  6725.             if (!this.parent) {
  6726.                 return this;
  6727.             }
  6728.  
  6729.             this.parent.remove(this);
  6730.  
  6731.             return this;
  6732.  
  6733.         },
  6734.  
  6735.         /**
  6736.             * Return an object with top, left, right, bottom, width, and height
  6737.             * parameters of the group.
  6738.             */
  6739.         getBoundingClientRect: function (shallow) {
  6740.             var matrix, border, l, x, y, i, v;
  6741.  
  6742.             var left = Infinity, right = -Infinity,
  6743.                 top = Infinity, bottom = -Infinity;
  6744.  
  6745.             // TODO: Update this to not __always__ update. Just when it needs to.
  6746.             this._update(true);
  6747.  
  6748.             matrix = !!shallow ? this._matrix : getComputedMatrix(this);
  6749.  
  6750.             border = this.linewidth / 2;
  6751.             l = this._vertices.length;
  6752.  
  6753.             if (l <= 0) {
  6754.                 v = matrix.multiply(0, 0, 1);
  6755.                 return {
  6756.                     top: v.y,
  6757.                     left: v.x,
  6758.                     right: v.x,
  6759.                     bottom: v.y,
  6760.                     width: 0,
  6761.                     height: 0
  6762.                 };
  6763.             }
  6764.  
  6765.             for (i = 0; i < l; i++) {
  6766.                 v = this._vertices[i];
  6767.  
  6768.                 x = v.x;
  6769.                 y = v.y;
  6770.  
  6771.                 v = matrix.multiply(x, y, 1);
  6772.                 top = min(v.y - border, top);
  6773.                 left = min(v.x - border, left);
  6774.                 right = max(v.x + border, right);
  6775.                 bottom = max(v.y + border, bottom);
  6776.             }
  6777.  
  6778.             return {
  6779.                 top: top,
  6780.                 left: left,
  6781.                 right: right,
  6782.                 bottom: bottom,
  6783.                 width: right - left,
  6784.                 height: bottom - top
  6785.             };
  6786.  
  6787.         },
  6788.  
  6789.         /**
  6790.             * Given a float `t` from 0 to 1, return a point or assign a passed `obj`'s
  6791.             * coordinates to that percentage on this Two.Path's curve.
  6792.             */
  6793.         getPointAt: function (t, obj) {
  6794.             var ia, ib;
  6795.             var x, x1, x2, x3, x4, y, y1, y2, y3, y4, left, right;
  6796.             var target = this.length * Math.min(Math.max(t, 0), 1);
  6797.             var length = this.vertices.length;
  6798.             var last = length - 1;
  6799.  
  6800.             var a = null;
  6801.             var b = null;
  6802.  
  6803.             for (var i = 0, l = this._lengths.length, sum = 0; i < l; i++) {
  6804.  
  6805.                 if (sum + this._lengths[i] >= target) {
  6806.  
  6807.                     if (this._closed) {
  6808.                         ia = Two.Utils.mod(i, length);
  6809.                         ib = Two.Utils.mod(i - 1, length);
  6810.                         if (i === 0) {
  6811.                             ia = ib;
  6812.                             ib = i;
  6813.                         }
  6814.                     } else {
  6815.                         ia = i;
  6816.                         ib = Math.min(Math.max(i - 1, 0), last);
  6817.                     }
  6818.  
  6819.                     a = this.vertices[ia];
  6820.                     b = this.vertices[ib];
  6821.                     target -= sum;
  6822.                     if (this._lengths[i] !== 0) {
  6823.                         t = target / this._lengths[i];
  6824.                     }
  6825.  
  6826.                     break;
  6827.  
  6828.                 }
  6829.  
  6830.                 sum += this._lengths[i];
  6831.  
  6832.             }
  6833.  
  6834.             // console.log(sum, a.command, b.command);
  6835.  
  6836.             if (_.isNull(a) || _.isNull(b)) {
  6837.                 return null;
  6838.             }
  6839.  
  6840.             right = b.controls && b.controls.right;
  6841.             left = a.controls && a.controls.left;
  6842.  
  6843.             x1 = b.x;
  6844.             y1 = b.y;
  6845.             x2 = (right || b).x;
  6846.             y2 = (right || b).y;
  6847.             x3 = (left || a).x;
  6848.             y3 = (left || a).y;
  6849.             x4 = a.x;
  6850.             y4 = a.y;
  6851.  
  6852.             if (right && b._relative) {
  6853.                 x2 += b.x;
  6854.                 y2 += b.y;
  6855.             }
  6856.  
  6857.             if (left && a._relative) {
  6858.                 x3 += a.x;
  6859.                 y3 += a.y;
  6860.             }
  6861.  
  6862.             x = Two.Utils.getPointOnCubicBezier(t, x1, x2, x3, x4);
  6863.             y = Two.Utils.getPointOnCubicBezier(t, y1, y2, y3, y4);
  6864.  
  6865.             if (_.isObject(obj)) {
  6866.                 obj.x = x;
  6867.                 obj.y = y;
  6868.                 return obj;
  6869.             }
  6870.  
  6871.             return new Two.Vector(x, y);
  6872.  
  6873.         },
  6874.  
  6875.         /**
  6876.             * Based on closed / curved and sorting of vertices plot where all points
  6877.             * should be and where the respective handles should be too.
  6878.             */
  6879.         plot: function () {
  6880.  
  6881.             if (this.curved) {
  6882.                 Two.Utils.getCurveFromPoints(this._vertices, this.closed);
  6883.                 return this;
  6884.             }
  6885.  
  6886.             for (var i = 0; i < this._vertices.length; i++) {
  6887.                 this._vertices[i]._command = i === 0 ? Two.Commands.move : Two.Commands.line;
  6888.             }
  6889.  
  6890.             return this;
  6891.  
  6892.         },
  6893.  
  6894.         subdivide: function (limit) {
  6895.             //TODO: DRYness (function below)
  6896.             this._update();
  6897.  
  6898.             var last = this.vertices.length - 1;
  6899.             var b = this.vertices[last];
  6900.             var closed = this._closed || this.vertices[last]._command === Two.Commands.close;
  6901.             var points = [];
  6902.             _.each(this.vertices, function (a, i) {
  6903.  
  6904.                 if (i <= 0 && !closed) {
  6905.                     b = a;
  6906.                     return;
  6907.                 }
  6908.  
  6909.                 if (a.command === Two.Commands.move) {
  6910.                     points.push(new Two.Anchor(b.x, b.y));
  6911.                     if (i > 0) {
  6912.                         points[points.length - 1].command = Two.Commands.line;
  6913.                     }
  6914.                     b = a;
  6915.                     return;
  6916.                 }
  6917.  
  6918.                 var verts = getSubdivisions(a, b, limit);
  6919.                 points = points.concat(verts);
  6920.  
  6921.                 // Assign commands to all the verts
  6922.                 _.each(verts, function (v, i) {
  6923.                     if (i <= 0 && b.command === Two.Commands.move) {
  6924.                         v.command = Two.Commands.move;
  6925.                     } else {
  6926.                         v.command = Two.Commands.line;
  6927.                     }
  6928.                 });
  6929.  
  6930.                 if (i >= last) {
  6931.  
  6932.                     // TODO: Add check if the two vectors in question are the same values.
  6933.                     if (this._closed && this._automatic) {
  6934.  
  6935.                         b = a;
  6936.  
  6937.                         verts = getSubdivisions(a, b, limit);
  6938.                         points = points.concat(verts);
  6939.  
  6940.                         // Assign commands to all the verts
  6941.                         _.each(verts, function (v, i) {
  6942.                             if (i <= 0 && b.command === Two.Commands.move) {
  6943.                                 v.command = Two.Commands.move;
  6944.                             } else {
  6945.                                 v.command = Two.Commands.line;
  6946.                             }
  6947.                         });
  6948.  
  6949.                     } else if (closed) {
  6950.                         points.push(new Two.Anchor(a.x, a.y));
  6951.                     }
  6952.  
  6953.                     points[points.length - 1].command = closed ? Two.Commands.close : Two.Commands.line;
  6954.  
  6955.                 }
  6956.  
  6957.                 b = a;
  6958.  
  6959.             }, this);
  6960.  
  6961.             this._automatic = false;
  6962.             this._curved = false;
  6963.             this.vertices = points;
  6964.  
  6965.             return this;
  6966.  
  6967.         },
  6968.  
  6969.         _updateLength: function (limit) {
  6970.             //TODO: DRYness (function above)
  6971.             this._update();
  6972.  
  6973.             var length = this.vertices.length;
  6974.             var last = length - 1;
  6975.             var b = this.vertices[last];
  6976.             var closed = this._closed || this.vertices[last]._command === Two.Commands.close;
  6977.             var sum = 0;
  6978.  
  6979.             if (_.isUndefined(this._lengths)) {
  6980.                 this._lengths = [];
  6981.             }
  6982.  
  6983.             _.each(this.vertices, function (a, i) {
  6984.  
  6985.                 if ((i <= 0 && !closed) || a.command === Two.Commands.move) {
  6986.                     b = a;
  6987.                     this._lengths[i] = 0;
  6988.                     return;
  6989.                 }
  6990.  
  6991.                 this._lengths[i] = getCurveLength(a, b, limit);
  6992.                 sum += this._lengths[i];
  6993.  
  6994.                 if (i >= last && closed) {
  6995.  
  6996.                     b = this.vertices[(i + 1) % length];
  6997.  
  6998.                     this._lengths[i + 1] = getCurveLength(a, b, limit);
  6999.                     sum += this._lengths[i + 1];
  7000.  
  7001.                 }
  7002.  
  7003.                 b = a;
  7004.  
  7005.             }, this);
  7006.  
  7007.             this._length = sum;
  7008.  
  7009.             return this;
  7010.  
  7011.         },
  7012.  
  7013.         _update: function () {
  7014.  
  7015.             if (this._flagVertices) {
  7016.  
  7017.                 var l = this.vertices.length;
  7018.                 var last = l - 1, v;
  7019.  
  7020.                 // TODO: Should clamp this so that `ia` and `ib`
  7021.                 // cannot select non-verts.
  7022.                 var ia = round((this._beginning) * last);
  7023.                 var ib = round((this._ending) * last);
  7024.  
  7025.                 this._vertices.length = 0;
  7026.  
  7027.                 for (var i = ia; i < ib + 1; i++) {
  7028.                     v = this.vertices[i];
  7029.                     this._vertices.push(v);
  7030.                 }
  7031.  
  7032.                 if (this._automatic) {
  7033.                     this.plot();
  7034.                 }
  7035.  
  7036.             }
  7037.  
  7038.             Two.Shape.prototype._update.apply(this, arguments);
  7039.  
  7040.             return this;
  7041.  
  7042.         },
  7043.  
  7044.         flagReset: function () {
  7045.  
  7046.             this._flagVertices = this._flagFill = this._flagStroke =
  7047.                 this._flagLinewidth = this._flagOpacity = this._flagVisible =
  7048.                 this._flagCap = this._flagJoin = this._flagMiter =
  7049.                 this._flagClip = false;
  7050.  
  7051.             Two.Shape.prototype.flagReset.call(this);
  7052.  
  7053.             return this;
  7054.  
  7055.         }
  7056.  
  7057.     });
  7058.  
  7059.     Path.MakeObservable(Path.prototype);
  7060.  
  7061.     /**
  7062.         * Utility functions
  7063.         */
  7064.  
  7065.     function getCurveLength(a, b, limit) {
  7066.         // TODO: DRYness
  7067.         var x1, x2, x3, x4, y1, y2, y3, y4;
  7068.  
  7069.         var right = b.controls && b.controls.right;
  7070.         var left = a.controls && a.controls.left;
  7071.  
  7072.         x1 = b.x;
  7073.         y1 = b.y;
  7074.         x2 = (right || b).x;
  7075.         y2 = (right || b).y;
  7076.         x3 = (left || a).x;
  7077.         y3 = (left || a).y;
  7078.         x4 = a.x;
  7079.         y4 = a.y;
  7080.  
  7081.         if (right && b._relative) {
  7082.             x2 += b.x;
  7083.             y2 += b.y;
  7084.         }
  7085.  
  7086.         if (left && a._relative) {
  7087.             x3 += a.x;
  7088.             y3 += a.y;
  7089.         }
  7090.  
  7091.         return Two.Utils.getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  7092.  
  7093.     }
  7094.  
  7095.     function getSubdivisions(a, b, limit) {
  7096.         // TODO: DRYness
  7097.         var x1, x2, x3, x4, y1, y2, y3, y4;
  7098.  
  7099.         var right = b.controls && b.controls.right;
  7100.         var left = a.controls && a.controls.left;
  7101.  
  7102.         x1 = b.x;
  7103.         y1 = b.y;
  7104.         x2 = (right || b).x;
  7105.         y2 = (right || b).y;
  7106.         x3 = (left || a).x;
  7107.         y3 = (left || a).y;
  7108.         x4 = a.x;
  7109.         y4 = a.y;
  7110.  
  7111.         if (right && b._relative) {
  7112.             x2 += b.x;
  7113.             y2 += b.y;
  7114.         }
  7115.  
  7116.         if (left && a._relative) {
  7117.             x3 += a.x;
  7118.             y3 += a.y;
  7119.         }
  7120.  
  7121.         return Two.Utils.subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  7122.  
  7123.     }
  7124.  
  7125. })((typeof global !== 'undefined' ? global : this).Two);
  7126.  
  7127. (function (Two) {
  7128.  
  7129.     var Path = Two.Path;
  7130.     var _ = Two.Utils;
  7131.  
  7132.     var Line = Two.Line = function (x1, y1, x2, y2) {
  7133.  
  7134.         var width = x2 - x1;
  7135.         var height = y2 - y1;
  7136.  
  7137.         var w2 = width / 2;
  7138.         var h2 = height / 2;
  7139.  
  7140.         Path.call(this, [
  7141.             new Two.Anchor(- w2, - h2),
  7142.             new Two.Anchor(w2, h2)
  7143.         ]);
  7144.  
  7145.         this.translation.set(x1 + w2, y1 + h2);
  7146.  
  7147.     };
  7148.  
  7149.     _.extend(Line.prototype, Path.prototype);
  7150.  
  7151.     Path.MakeObservable(Line.prototype);
  7152.  
  7153. })((typeof global !== 'undefined' ? global : this).Two);
  7154.  
  7155. (function (Two) {
  7156.  
  7157.     var Path = Two.Path;
  7158.     var _ = Two.Utils;
  7159.  
  7160.     var Rectangle = Two.Rectangle = function (x, y, width, height) {
  7161.  
  7162.         Path.call(this, [
  7163.             new Two.Anchor(),
  7164.             new Two.Anchor(),
  7165.             new Two.Anchor(),
  7166.             new Two.Anchor()
  7167.         ], true);
  7168.  
  7169.         this.width = width;
  7170.         this.height = height;
  7171.         this._update();
  7172.  
  7173.         this.translation.set(x, y);
  7174.  
  7175.     };
  7176.  
  7177.     _.extend(Rectangle, {
  7178.  
  7179.         Properties: ['width', 'height'],
  7180.  
  7181.         MakeObservable: function (obj) {
  7182.             Path.MakeObservable(obj);
  7183.             _.each(Rectangle.Properties, Two.Utils.defineProperty, obj);
  7184.         }
  7185.  
  7186.     });
  7187.  
  7188.     _.extend(Rectangle.prototype, Path.prototype, {
  7189.  
  7190.         _width: 0,
  7191.         _height: 0,
  7192.  
  7193.         _flagWidth: 0,
  7194.         _flagHeight: 0,
  7195.  
  7196.         _update: function () {
  7197.  
  7198.             if (this._flagWidth || this._flagHeight) {
  7199.  
  7200.                 var xr = this._width / 2;
  7201.                 var yr = this._height / 2;
  7202.  
  7203.                 this.vertices[0].set(-xr, -yr);
  7204.                 this.vertices[1].set(xr, -yr);
  7205.                 this.vertices[2].set(xr, yr);
  7206.                 this.vertices[3].set(-xr, yr);
  7207.  
  7208.             }
  7209.  
  7210.             Path.prototype._update.call(this);
  7211.  
  7212.             return this;
  7213.  
  7214.         },
  7215.  
  7216.         flagReset: function () {
  7217.  
  7218.             this._flagWidth = this._flagHeight = false;
  7219.             Path.prototype.flagReset.call(this);
  7220.  
  7221.             return this;
  7222.  
  7223.         }
  7224.  
  7225.     });
  7226.  
  7227.     Rectangle.MakeObservable(Rectangle.prototype);
  7228.  
  7229. })((typeof global !== 'undefined' ? global : this).Two);
  7230.  
  7231. (function (Two) {
  7232.  
  7233.     var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin;
  7234.     var _ = Two.Utils;
  7235.  
  7236.     var Ellipse = Two.Ellipse = function (ox, oy, rx, ry) {
  7237.  
  7238.         if (!_.isNumber(ry)) {
  7239.             ry = rx;
  7240.         }
  7241.  
  7242.         var amount = Two.Resolution;
  7243.  
  7244.         var points = _.map(_.range(amount), function (i) {
  7245.             return new Two.Anchor();
  7246.         }, this);
  7247.  
  7248.         Path.call(this, points, true, true);
  7249.  
  7250.         this.width = rx * 2;
  7251.         this.height = ry * 2;
  7252.  
  7253.         this._update();
  7254.         this.translation.set(ox, oy);
  7255.  
  7256.     };
  7257.  
  7258.     _.extend(Ellipse, {
  7259.  
  7260.         Properties: ['width', 'height'],
  7261.  
  7262.         MakeObservable: function (obj) {
  7263.  
  7264.             Path.MakeObservable(obj);
  7265.             _.each(Ellipse.Properties, Two.Utils.defineProperty, obj);
  7266.  
  7267.         }
  7268.  
  7269.     });
  7270.  
  7271.     _.extend(Ellipse.prototype, Path.prototype, {
  7272.  
  7273.         _width: 0,
  7274.         _height: 0,
  7275.  
  7276.         _flagWidth: false,
  7277.         _flagHeight: false,
  7278.  
  7279.         _update: function () {
  7280.  
  7281.             if (this._flagWidth || this._flagHeight) {
  7282.                 for (var i = 0, l = this.vertices.length; i < l; i++) {
  7283.                     var pct = i / l;
  7284.                     var theta = pct * TWO_PI;
  7285.                     var x = this._width * cos(theta) / 2;
  7286.                     var y = this._height * sin(theta) / 2;
  7287.                     this.vertices[i].set(x, y);
  7288.                 }
  7289.             }
  7290.  
  7291.             Path.prototype._update.call(this);
  7292.             return this;
  7293.  
  7294.         },
  7295.  
  7296.         flagReset: function () {
  7297.  
  7298.             this._flagWidth = this._flagHeight = false;
  7299.  
  7300.             Path.prototype.flagReset.call(this);
  7301.             return this;
  7302.  
  7303.         }
  7304.  
  7305.     });
  7306.  
  7307.     Ellipse.MakeObservable(Ellipse.prototype);
  7308.  
  7309. })((typeof global !== 'undefined' ? global : this).Two);
  7310.  
  7311. (function (Two) {
  7312.  
  7313.     var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin;
  7314.     var _ = Two.Utils;
  7315.  
  7316.     var Circle = Two.Circle = function (ox, oy, r) {
  7317.  
  7318.         var amount = Two.Resolution;
  7319.  
  7320.         var points = _.map(_.range(amount), function (i) {
  7321.             return new Two.Anchor();
  7322.         }, this);
  7323.  
  7324.         Path.call(this, points, true, true);
  7325.  
  7326.         this.radius = r;
  7327.  
  7328.         this._update();
  7329.         this.translation.set(ox, oy);
  7330.  
  7331.     };
  7332.  
  7333.     _.extend(Circle, {
  7334.  
  7335.         Properties: ['radius'],
  7336.  
  7337.         MakeObservable: function (obj) {
  7338.  
  7339.             Path.MakeObservable(obj);
  7340.             _.each(Circle.Properties, Two.Utils.defineProperty, obj);
  7341.  
  7342.         }
  7343.  
  7344.     });
  7345.  
  7346.     _.extend(Circle.prototype, Path.prototype, {
  7347.  
  7348.         _radius: 0,
  7349.         _flagRadius: false,
  7350.  
  7351.         _update: function () {
  7352.  
  7353.             if (this._flagRadius) {
  7354.                 for (var i = 0, l = this.vertices.length; i < l; i++) {
  7355.                     var pct = i / l;
  7356.                     var theta = pct * TWO_PI;
  7357.                     var x = this._radius * cos(theta);
  7358.                     var y = this._radius * sin(theta);
  7359.                     this.vertices[i].set(x, y);
  7360.                 }
  7361.             }
  7362.  
  7363.             Path.prototype._update.call(this);
  7364.             return this;
  7365.  
  7366.         },
  7367.  
  7368.         flagReset: function () {
  7369.  
  7370.             this._flagRadius = false;
  7371.  
  7372.             Path.prototype.flagReset.call(this);
  7373.             return this;
  7374.  
  7375.         }
  7376.  
  7377.     });
  7378.  
  7379.     Circle.MakeObservable(Circle.prototype);
  7380.  
  7381. })((typeof global !== 'undefined' ? global : this).Two);
  7382.  
  7383. (function (Two) {
  7384.  
  7385.     var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin;
  7386.     var _ = Two.Utils;
  7387.  
  7388.     var Polygon = Two.Polygon = function (ox, oy, r, sides) {
  7389.  
  7390.         sides = Math.max(sides || 0, 3);
  7391.  
  7392.         var points = _.map(_.range(sides), function (i) {
  7393.             return new Two.Anchor();
  7394.         });
  7395.  
  7396.         Path.call(this, points, true);
  7397.  
  7398.         this.width = r * 2;
  7399.         this.height = r * 2;
  7400.         this.sides = sides;
  7401.  
  7402.         this._update();
  7403.         this.translation.set(ox, oy);
  7404.  
  7405.     };
  7406.  
  7407.     _.extend(Polygon, {
  7408.  
  7409.         Properties: ['width', 'height', 'sides'],
  7410.  
  7411.         MakeObservable: function (obj) {
  7412.  
  7413.             Path.MakeObservable(obj);
  7414.             _.each(Polygon.Properties, Two.Utils.defineProperty, obj);
  7415.  
  7416.         }
  7417.  
  7418.     });
  7419.  
  7420.     _.extend(Polygon.prototype, Path.prototype, {
  7421.  
  7422.         _width: 0,
  7423.         _height: 0,
  7424.         _sides: 0,
  7425.  
  7426.         _flagWidth: false,
  7427.         _flagHeight: false,
  7428.         _flagSides: false,
  7429.  
  7430.         _update: function () {
  7431.  
  7432.             if (this._flagWidth || this._flagHeight || this._flagSides) {
  7433.  
  7434.                 var sides = this._sides;
  7435.                 var amount = this.vertices.length;
  7436.  
  7437.                 if (amount > sides) {
  7438.                     this.vertices.splice(sides - 1, amount - sides);
  7439.                 }
  7440.  
  7441.                 for (var i = 0; i < sides; i++) {
  7442.  
  7443.                     var pct = (i + 0.5) / sides;
  7444.                     var theta = TWO_PI * pct + Math.PI / 2;
  7445.                     var x = this._width * cos(theta);
  7446.                     var y = this._height * sin(theta);
  7447.  
  7448.                     if (i >= amount) {
  7449.                         this.vertices.push(new Two.Anchor(x, y));
  7450.                     } else {
  7451.                         this.vertices[i].set(x, y);
  7452.                     }
  7453.  
  7454.                 }
  7455.  
  7456.             }
  7457.  
  7458.             Path.prototype._update.call(this);
  7459.             return this;
  7460.  
  7461.         },
  7462.  
  7463.         flagReset: function () {
  7464.  
  7465.             this._flagWidth = this._flagHeight = this._flagSides = false;
  7466.             Path.prototype.flagReset.call(this);
  7467.  
  7468.             return this;
  7469.  
  7470.         }
  7471.  
  7472.     });
  7473.  
  7474.     Polygon.MakeObservable(Polygon.prototype);
  7475.  
  7476. })((typeof global !== 'undefined' ? global : this).Two);
  7477.  
  7478. (function (Two) {
  7479.  
  7480.     var Path = Two.Path, PI = Math.PI, TWO_PI = Math.PI * 2, HALF_PI = Math.PI / 2,
  7481.         cos = Math.cos, sin = Math.sin, abs = Math.abs, _ = Two.Utils;
  7482.  
  7483.     var ArcSegment = Two.ArcSegment = function (ox, oy, ir, or, sa, ea, res) {
  7484.  
  7485.         var points = _.map(_.range(res || (Two.Resolution * 3)), function () {
  7486.             return new Two.Anchor();
  7487.         });
  7488.  
  7489.         Path.call(this, points, false, false, true);
  7490.  
  7491.         this.innerRadius = ir;
  7492.         this.outerRadius = or;
  7493.  
  7494.         this.startAngle = sa;
  7495.         this.endAngle = ea;
  7496.  
  7497.         this._update();
  7498.         this.translation.set(ox, oy);
  7499.  
  7500.     }
  7501.  
  7502.     _.extend(ArcSegment, {
  7503.  
  7504.         Properties: ['startAngle', 'endAngle', 'innerRadius', 'outerRadius'],
  7505.  
  7506.         MakeObservable: function (obj) {
  7507.  
  7508.             Path.MakeObservable(obj);
  7509.             _.each(ArcSegment.Properties, Two.Utils.defineProperty, obj);
  7510.  
  7511.         }
  7512.  
  7513.     });
  7514.  
  7515.     _.extend(ArcSegment.prototype, Path.prototype, {
  7516.  
  7517.         _flagStartAngle: false,
  7518.         _flagEndAngle: false,
  7519.         _flagInnerRadius: false,
  7520.         _flagOuterRadius: false,
  7521.  
  7522.         _startAngle: 0,
  7523.         _endAngle: TWO_PI,
  7524.         _innerRadius: 0,
  7525.         _outerRadius: 0,
  7526.  
  7527.         _update: function () {
  7528.  
  7529.             if (this._flagStartAngle || this._flagEndAngle || this._flagInnerRadius
  7530.                 || this._flagOuterRadius) {
  7531.  
  7532.                 var sa = this._startAngle;
  7533.                 var ea = this._endAngle;
  7534.  
  7535.                 var ir = this._innerRadius;
  7536.                 var or = this._outerRadius;
  7537.  
  7538.                 var connected = mod(sa, TWO_PI) === mod(ea, TWO_PI);
  7539.                 var punctured = ir > 0;
  7540.  
  7541.                 var vertices = this.vertices;
  7542.                 var length = (punctured ? vertices.length / 2 : vertices.length);
  7543.                 var command, id = 0;
  7544.  
  7545.                 if (connected) {
  7546.                     length--;
  7547.                 } else if (!punctured) {
  7548.                     length -= 2;
  7549.                 }
  7550.  
  7551.                 /**
  7552.                     * Outer Circle
  7553.                     */
  7554.                 for (var i = 0, last = length - 1; i < length; i++) {
  7555.  
  7556.                     var pct = i / last;
  7557.                     var v = vertices[id];
  7558.                     var theta = pct * (ea - sa) + sa;
  7559.                     var step = (ea - sa) / length;
  7560.  
  7561.                     var x = or * Math.cos(theta);
  7562.                     var y = or * Math.sin(theta);
  7563.  
  7564.                     switch (i) {
  7565.                         case 0:
  7566.                             command = Two.Commands.move;
  7567.                             break;
  7568.                         default:
  7569.                             command = Two.Commands.curve;
  7570.                     }
  7571.  
  7572.                     v.command = command;
  7573.                     v.x = x;
  7574.                     v.y = y;
  7575.                     v.controls.left.clear();
  7576.                     v.controls.right.clear();
  7577.  
  7578.                     if (v.command === Two.Commands.curve) {
  7579.                         var amp = or * step / Math.PI;
  7580.                         v.controls.left.x = amp * Math.cos(theta - HALF_PI);
  7581.                         v.controls.left.y = amp * Math.sin(theta - HALF_PI);
  7582.                         v.controls.right.x = amp * Math.cos(theta + HALF_PI);
  7583.                         v.controls.right.y = amp * Math.sin(theta + HALF_PI);
  7584.                         if (i === 1) {
  7585.                             v.controls.left.multiplyScalar(2);
  7586.                         }
  7587.                         if (i === last) {
  7588.                             v.controls.right.multiplyScalar(2);
  7589.                         }
  7590.                     }
  7591.  
  7592.                     id++;
  7593.  
  7594.                 }
  7595.  
  7596.                 if (punctured) {
  7597.  
  7598.                     if (connected) {
  7599.                         vertices[id].command = Two.Commands.close;
  7600.                         id++;
  7601.                     } else {
  7602.                         length--;
  7603.                         last = length - 1;
  7604.                     }
  7605.  
  7606.                     /**
  7607.                         * Inner Circle
  7608.                         */
  7609.                     for (i = 0; i < length; i++) {
  7610.  
  7611.                         pct = i / last;
  7612.                         v = vertices[id];
  7613.                         theta = (1 - pct) * (ea - sa) + sa;
  7614.                         step = (ea - sa) / length;
  7615.  
  7616.                         x = ir * Math.cos(theta);
  7617.                         y = ir * Math.sin(theta);
  7618.                         command = Two.Commands.curve;
  7619.                         if (i <= 0) {
  7620.                             command = connected ? Two.Commands.move : Two.Commands.line;
  7621.                         }
  7622.  
  7623.                         v.command = command;
  7624.                         v.x = x;
  7625.                         v.y = y;
  7626.                         v.controls.left.clear();
  7627.                         v.controls.right.clear();
  7628.  
  7629.                         if (v.command === Two.Commands.curve) {
  7630.                             amp = ir * step / Math.PI;
  7631.                             v.controls.left.x = amp * Math.cos(theta + HALF_PI);
  7632.                             v.controls.left.y = amp * Math.sin(theta + HALF_PI);
  7633.                             v.controls.right.x = amp * Math.cos(theta - HALF_PI);
  7634.                             v.controls.right.y = amp * Math.sin(theta - HALF_PI);
  7635.                             if (i === 1) {
  7636.                                 v.controls.left.multiplyScalar(2);
  7637.                             }
  7638.                             if (i === last) {
  7639.                                 v.controls.right.multiplyScalar(2);
  7640.                             }
  7641.                         }
  7642.  
  7643.                         id++;
  7644.  
  7645.                     }
  7646.  
  7647.                 } else if (!connected) {
  7648.  
  7649.                     vertices[id].command = Two.Commands.line;
  7650.                     vertices[id].x = 0;
  7651.                     vertices[id].y = 0;
  7652.                     id++;
  7653.  
  7654.                 }
  7655.  
  7656.                 /**
  7657.                     * Final Point
  7658.                     */
  7659.                 vertices[id].command = Two.Commands.close;
  7660.  
  7661.             }
  7662.  
  7663.             Path.prototype._update.call(this);
  7664.  
  7665.             return this;
  7666.  
  7667.         },
  7668.  
  7669.         flagReset: function () {
  7670.  
  7671.             Path.prototype.flagReset.call(this);
  7672.  
  7673.             this._flagStartAngle = this._flagEndAngle
  7674.                 = this._flagInnerRadius = this._flagOuterRadius = false;
  7675.  
  7676.             return this;
  7677.  
  7678.         }
  7679.  
  7680.     });
  7681.  
  7682.     ArcSegment.MakeObservable(ArcSegment.prototype);
  7683.  
  7684.     function mod(v, l) {
  7685.         while (v < 0) {
  7686.             v += l;
  7687.         }
  7688.         return v % l;
  7689.     }
  7690.  
  7691. })((typeof global !== 'undefined' ? global : this).Two);
  7692.  
  7693. (function (Two) {
  7694.  
  7695.     var Path = Two.Path, TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin;
  7696.     var _ = Two.Utils;
  7697.  
  7698.     var Star = Two.Star = function (ox, oy, or, ir, sides) {
  7699.  
  7700.         if (!_.isNumber(ir)) {
  7701.             ir = or / 2;
  7702.         }
  7703.  
  7704.         if (!_.isNumber(sides) || sides <= 0) {
  7705.             sides = 5;
  7706.         }
  7707.  
  7708.         var length = sides * 2;
  7709.  
  7710.         var points = _.map(_.range(length), function (i) {
  7711.             return new Two.Anchor();
  7712.         });
  7713.  
  7714.         Path.call(this, points, true);
  7715.  
  7716.         this.innerRadius = ir;
  7717.         this.outerRadius = or;
  7718.         this.sides = sides;
  7719.  
  7720.         this._update();
  7721.         this.translation.set(ox, oy);
  7722.  
  7723.     };
  7724.  
  7725.     _.extend(Star, {
  7726.  
  7727.         Properties: ['innerRadius', 'outerRadius', 'sides'],
  7728.  
  7729.         MakeObservable: function (obj) {
  7730.  
  7731.             Path.MakeObservable(obj);
  7732.             _.each(Star.Properties, Two.Utils.defineProperty, obj);
  7733.  
  7734.         }
  7735.  
  7736.     });
  7737.  
  7738.     _.extend(Star.prototype, Path.prototype, {
  7739.  
  7740.         _innerRadius: 0,
  7741.         _outerRadius: 0,
  7742.         _sides: 0,
  7743.  
  7744.         _flagInnerRadius: false,
  7745.         _flagOuterRadius: false,
  7746.         _flagSides: false,
  7747.  
  7748.         _update: function () {
  7749.  
  7750.             if (this._flagInnerRadius || this._flagOuterRadius || this._flagSides) {
  7751.  
  7752.                 var sides = this._sides * 2;
  7753.                 var amount = this.vertices.length;
  7754.  
  7755.                 if (amount > sides) {
  7756.                     this.vertices.splice(sides - 1, amount - sides);
  7757.                 }
  7758.  
  7759.                 for (var i = 0; i < sides; i++) {
  7760.  
  7761.                     var pct = (i + 0.5) / sides;
  7762.                     var theta = TWO_PI * pct;
  7763.                     var r = (i % 2 ? this._innerRadius : this._outerRadius);
  7764.                     var x = r * cos(theta);
  7765.                     var y = r * sin(theta);
  7766.  
  7767.                     if (i >= amount) {
  7768.                         this.vertices.push(new Two.Anchor(x, y));
  7769.                     } else {
  7770.                         this.vertices[i].set(x, y);
  7771.                     }
  7772.  
  7773.                 }
  7774.  
  7775.             }
  7776.  
  7777.             Path.prototype._update.call(this);
  7778.  
  7779.             return this;
  7780.  
  7781.         },
  7782.  
  7783.         flagReset: function () {
  7784.  
  7785.             this._flagInnerRadius = this._flagOuterRadius = this._flagSides = false;
  7786.             Path.prototype.flagReset.call(this);
  7787.  
  7788.             return this;
  7789.  
  7790.         }
  7791.  
  7792.     });
  7793.  
  7794.     Star.MakeObservable(Star.prototype);
  7795.  
  7796. })((typeof global !== 'undefined' ? global : this).Two);
  7797.  
  7798. (function (Two) {
  7799.  
  7800.     var Path = Two.Path;
  7801.     var _ = Two.Utils;
  7802.  
  7803.     var RoundedRectangle = Two.RoundedRectangle = function (ox, oy, width, height, radius) {
  7804.  
  7805.         if (!_.isNumber(radius)) {
  7806.             radius = Math.floor(Math.min(width, height) / 12);
  7807.         }
  7808.  
  7809.         var amount = 10;
  7810.  
  7811.         var points = _.map(_.range(amount), function (i) {
  7812.             return new Two.Anchor(0, 0, 0, 0, 0, 0,
  7813.                 i === 0 ? Two.Commands.move : Two.Commands.curve);
  7814.         });
  7815.  
  7816.         points[points.length - 1].command = Two.Commands.close;
  7817.  
  7818.         Path.call(this, points, false, false, true);
  7819.  
  7820.         this.width = width;
  7821.         this.height = height;
  7822.         this.radius = radius;
  7823.  
  7824.         this._update();
  7825.         this.translation.set(ox, oy);
  7826.  
  7827.     };
  7828.  
  7829.     _.extend(RoundedRectangle, {
  7830.  
  7831.         Properties: ['width', 'height', 'radius'],
  7832.  
  7833.         MakeObservable: function (obj) {
  7834.  
  7835.             Path.MakeObservable(obj);
  7836.             _.each(RoundedRectangle.Properties, Two.Utils.defineProperty, obj);
  7837.  
  7838.         }
  7839.  
  7840.     });
  7841.  
  7842.     _.extend(RoundedRectangle.prototype, Path.prototype, {
  7843.  
  7844.         _width: 0,
  7845.         _height: 0,
  7846.         _radius: 0,
  7847.  
  7848.         _flagWidth: false,
  7849.         _flagHeight: false,
  7850.         _flagRadius: false,
  7851.  
  7852.         _update: function () {
  7853.  
  7854.             if (this._flagWidth || this._flagHeight || this._flagRadius) {
  7855.  
  7856.                 var width = this._width;
  7857.                 var height = this._height;
  7858.                 var radius = Math.min(Math.max(this._radius, 0),
  7859.                     Math.min(width, height));
  7860.  
  7861.                 var v;
  7862.                 var w = width / 2;
  7863.                 var h = height / 2;
  7864.  
  7865.                 v = this.vertices[0];
  7866.                 v.x = - (w - radius);
  7867.                 v.y = - h;
  7868.  
  7869.                 // Upper Right Corner
  7870.  
  7871.                 v = this.vertices[1];
  7872.                 v.x = (w - radius);
  7873.                 v.y = - h;
  7874.                 v.controls.left.clear();
  7875.                 v.controls.right.x = radius;
  7876.                 v.controls.right.y = 0;
  7877.  
  7878.                 v = this.vertices[2];
  7879.                 v.x = w;
  7880.                 v.y = - (h - radius);
  7881.                 v.controls.right.clear();
  7882.                 v.controls.left.clear();
  7883.  
  7884.                 // Bottom Right Corner
  7885.  
  7886.                 v = this.vertices[3];
  7887.                 v.x = w;
  7888.                 v.y = (h - radius);
  7889.                 v.controls.left.clear();
  7890.                 v.controls.right.x = 0;
  7891.                 v.controls.right.y = radius;
  7892.  
  7893.                 v = this.vertices[4];
  7894.                 v.x = (w - radius);
  7895.                 v.y = h;
  7896.                 v.controls.right.clear();
  7897.                 v.controls.left.clear();
  7898.  
  7899.                 // Bottom Left Corner
  7900.  
  7901.                 v = this.vertices[5];
  7902.                 v.x = - (w - radius);
  7903.                 v.y = h;
  7904.                 v.controls.left.clear();
  7905.                 v.controls.right.x = - radius;
  7906.                 v.controls.right.y = 0;
  7907.  
  7908.                 v = this.vertices[6];
  7909.                 v.x = - w;
  7910.                 v.y = (h - radius);
  7911.                 v.controls.left.clear();
  7912.                 v.controls.right.clear();
  7913.  
  7914.                 // Upper Left Corner
  7915.  
  7916.                 v = this.vertices[7];
  7917.                 v.x = - w;
  7918.                 v.y = - (h - radius);
  7919.                 v.controls.left.clear();
  7920.                 v.controls.right.x = 0;
  7921.                 v.controls.right.y = - radius;
  7922.  
  7923.                 v = this.vertices[8];
  7924.                 v.x = - (w - radius);
  7925.                 v.y = - h;
  7926.                 v.controls.left.clear();
  7927.                 v.controls.right.clear();
  7928.  
  7929.                 v = this.vertices[9];
  7930.                 v.copy(this.vertices[8]);
  7931.  
  7932.             }
  7933.  
  7934.             Path.prototype._update.call(this);
  7935.  
  7936.             return this;
  7937.  
  7938.         },
  7939.  
  7940.         flagReset: function () {
  7941.  
  7942.             this._flagWidth = this._flagHeight = this._flagRadius = false;
  7943.             Path.prototype.flagReset.call(this);
  7944.  
  7945.             return this;
  7946.  
  7947.         }
  7948.  
  7949.     });
  7950.  
  7951.     RoundedRectangle.MakeObservable(RoundedRectangle.prototype);
  7952.  
  7953. })((typeof global !== 'undefined' ? global : this).Two);
  7954.  
  7955. (function (Two) {
  7956.  
  7957.     var root = Two.root;
  7958.     var getComputedMatrix = Two.Utils.getComputedMatrix;
  7959.     var _ = Two.Utils;
  7960.  
  7961.     var canvas = (root.document ? root.document.createElement('canvas') : { getContext: _.identity });
  7962.     var ctx = canvas.getContext('2d');
  7963.  
  7964.     var Text = Two.Text = function (message, x, y, styles) {
  7965.  
  7966.         Two.Shape.call(this);
  7967.  
  7968.         this._renderer.type = 'text';
  7969.         this._renderer.flagFill = _.bind(Text.FlagFill, this);
  7970.         this._renderer.flagStroke = _.bind(Text.FlagStroke, this);
  7971.  
  7972.         this.value = message;
  7973.  
  7974.         if (_.isNumber(x)) {
  7975.             this.translation.x = x;
  7976.         }
  7977.         if (_.isNumber(y)) {
  7978.             this.translation.y = y;
  7979.         }
  7980.  
  7981.         if (!_.isObject(styles)) {
  7982.             return this;
  7983.         }
  7984.  
  7985.         _.each(Two.Text.Properties, function (property) {
  7986.  
  7987.             if (property in styles) {
  7988.                 this[property] = styles[property];
  7989.             }
  7990.  
  7991.         }, this);
  7992.  
  7993.     };
  7994.  
  7995.     _.extend(Two.Text, {
  7996.  
  7997.         Properties: [
  7998.             'value', 'family', 'size', 'leading', 'alignment', 'linewidth', 'style',
  7999.             'weight', 'decoration', 'baseline', 'opacity', 'visible', 'fill', 'stroke'
  8000.         ],
  8001.  
  8002.         FlagFill: function () {
  8003.             this._flagFill = true;
  8004.         },
  8005.  
  8006.         FlagStroke: function () {
  8007.             this._flagStroke = true;
  8008.         },
  8009.  
  8010.         MakeObservable: function (object) {
  8011.  
  8012.             Two.Shape.MakeObservable(object);
  8013.  
  8014.             _.each(Two.Text.Properties.slice(0, 12), Two.Utils.defineProperty, object);
  8015.  
  8016.             Object.defineProperty(object, 'fill', {
  8017.                 enumerable: true,
  8018.                 get: function () {
  8019.                     return this._fill;
  8020.                 },
  8021.                 set: function (f) {
  8022.  
  8023.                     if (this._fill instanceof Two.Gradient
  8024.                         || this._fill instanceof Two.LinearGradient
  8025.                         || this._fill instanceof Two.RadialGradient
  8026.                         || this._fill instanceof Two.Texture) {
  8027.                         this._fill.unbind(Two.Events.change, this._renderer.flagFill);
  8028.                     }
  8029.  
  8030.                     this._fill = f;
  8031.                     this._flagFill = true;
  8032.  
  8033.                     if (this._fill instanceof Two.Gradient
  8034.                         || this._fill instanceof Two.LinearGradient
  8035.                         || this._fill instanceof Two.RadialGradient
  8036.                         || this._fill instanceof Two.Texture) {
  8037.                         this._fill.bind(Two.Events.change, this._renderer.flagFill);
  8038.                     }
  8039.  
  8040.                 }
  8041.             });
  8042.  
  8043.             Object.defineProperty(object, 'stroke', {
  8044.                 enumerable: true,
  8045.                 get: function () {
  8046.                     return this._stroke;
  8047.                 },
  8048.                 set: function (f) {
  8049.  
  8050.                     if (this._stroke instanceof Two.Gradient
  8051.                         || this._stroke instanceof Two.LinearGradient
  8052.                         || this._stroke instanceof Two.RadialGradient
  8053.                         || this._stroke instanceof Two.Texture) {
  8054.                         this._stroke.unbind(Two.Events.change, this._renderer.flagStroke);
  8055.                     }
  8056.  
  8057.                     this._stroke = f;
  8058.                     this._flagStroke = true;
  8059.  
  8060.                     if (this._stroke instanceof Two.Gradient
  8061.                         || this._stroke instanceof Two.LinearGradient
  8062.                         || this._stroke instanceof Two.RadialGradient
  8063.                         || this._stroke instanceof Two.Texture) {
  8064.                         this._stroke.bind(Two.Events.change, this._renderer.flagStroke);
  8065.                     }
  8066.  
  8067.                 }
  8068.             });
  8069.  
  8070.             Object.defineProperty(object, 'clip', {
  8071.                 enumerable: true,
  8072.                 get: function () {
  8073.                     return this._clip;
  8074.                 },
  8075.                 set: function (v) {
  8076.                     this._clip = v;
  8077.                     this._flagClip = true;
  8078.                 }
  8079.             });
  8080.  
  8081.         }
  8082.  
  8083.     });
  8084.  
  8085.     _.extend(Two.Text.prototype, Two.Shape.prototype, {
  8086.  
  8087.         // Flags
  8088.         // http://en.wikipedia.org/wiki/Flag
  8089.  
  8090.         _flagValue: true,
  8091.         _flagFamily: true,
  8092.         _flagSize: true,
  8093.         _flagLeading: true,
  8094.         _flagAlignment: true,
  8095.         _flagBaseline: true,
  8096.         _flagStyle: true,
  8097.         _flagWeight: true,
  8098.         _flagDecoration: true,
  8099.  
  8100.         _flagFill: true,
  8101.         _flagStroke: true,
  8102.         _flagLinewidth: true,
  8103.         _flagOpacity: true,
  8104.         _flagVisible: true,
  8105.  
  8106.         _flagClip: false,
  8107.  
  8108.         // Underlying Properties
  8109.  
  8110.         _value: '',
  8111.         _family: 'sans-serif',
  8112.         _size: 13,
  8113.         _leading: 17,
  8114.         _alignment: 'center',
  8115.         _baseline: 'middle',
  8116.         _style: 'normal',
  8117.         _weight: 500,
  8118.         _decoration: 'none',
  8119.  
  8120.         _fill: '#000',
  8121.         _stroke: 'transparent',
  8122.         _linewidth: 1,
  8123.         _opacity: 1,
  8124.         _visible: true,
  8125.  
  8126.         _clip: false,
  8127.  
  8128.         remove: function () {
  8129.  
  8130.             if (!this.parent) {
  8131.                 return this;
  8132.             }
  8133.  
  8134.             this.parent.remove(this);
  8135.  
  8136.             return this;
  8137.  
  8138.         },
  8139.  
  8140.         clone: function (parent) {
  8141.  
  8142.             var parent = parent || this.parent;
  8143.  
  8144.             var clone = new Two.Text(this.value);
  8145.             clone.translation.copy(this.translation);
  8146.             clone.rotation = this.rotation;
  8147.             clone.scale = this.scale;
  8148.  
  8149.             _.each(Two.Text.Properties, function (property) {
  8150.                 clone[property] = this[property];
  8151.             }, this);
  8152.  
  8153.             if (parent) {
  8154.                 parent.add(clone);
  8155.             }
  8156.  
  8157.             return clone;
  8158.  
  8159.         },
  8160.  
  8161.         toObject: function () {
  8162.  
  8163.             var result = {
  8164.                 translation: this.translation.toObject(),
  8165.                 rotation: this.rotation,
  8166.                 scale: this.scale
  8167.             };
  8168.  
  8169.             _.each(Two.Text.Properties, function (property) {
  8170.                 result[property] = this[property];
  8171.             }, this);
  8172.  
  8173.             return result;
  8174.  
  8175.         },
  8176.  
  8177.         noStroke: function () {
  8178.             this.stroke = 'transparent';
  8179.             return this;
  8180.         },
  8181.  
  8182.         noFill: function () {
  8183.             this.fill = 'transparent';
  8184.             return this;
  8185.         },
  8186.  
  8187.         /**
  8188.             * A shim to not break `getBoundingClientRect` calls. TODO: Implement a
  8189.             * way to calculate proper bounding boxes of `Two.Text`.
  8190.             */
  8191.         getBoundingClientRect: function (shallow) {
  8192.  
  8193.             var matrix, border, l, x, y, i, v;
  8194.  
  8195.             var left = Infinity, right = -Infinity,
  8196.                 top = Infinity, bottom = -Infinity;
  8197.  
  8198.             // TODO: Update this to not __always__ update. Just when it needs to.
  8199.             this._update(true);
  8200.  
  8201.             matrix = !!shallow ? this._matrix : getComputedMatrix(this);
  8202.  
  8203.             v = matrix.multiply(0, 0, 1);
  8204.  
  8205.             return {
  8206.                 top: v.x,
  8207.                 left: v.y,
  8208.                 right: v.x,
  8209.                 bottom: v.y,
  8210.                 width: 0,
  8211.                 height: 0
  8212.             };
  8213.  
  8214.         },
  8215.  
  8216.         flagReset: function () {
  8217.  
  8218.             this._flagValue = this._flagFamily = this._flagSize =
  8219.                 this._flagLeading = this._flagAlignment = this._flagFill =
  8220.                 this._flagStroke = this._flagLinewidth = this._flagOpaicty =
  8221.                 this._flagVisible = this._flagClip = this._flagDecoration =
  8222.                 this._flagBaseline = false;
  8223.  
  8224.             Two.Shape.prototype.flagReset.call(this);
  8225.  
  8226.             return this;
  8227.  
  8228.         }
  8229.  
  8230.     });
  8231.  
  8232.     Two.Text.MakeObservable(Two.Text.prototype);
  8233.  
  8234. })((typeof global !== 'undefined' ? global : this).Two);
  8235.  
  8236. (function (Two) {
  8237.  
  8238.     var _ = Two.Utils;
  8239.  
  8240.     var Stop = Two.Stop = function (offset, color, opacity) {
  8241.  
  8242.         this._renderer = {};
  8243.         this._renderer.type = 'stop';
  8244.  
  8245.         this.offset = _.isNumber(offset) ? offset
  8246.             : Stop.Index <= 0 ? 0 : 1;
  8247.  
  8248.         this.opacity = _.isNumber(opacity) ? opacity : 1;
  8249.  
  8250.         this.color = _.isString(color) ? color
  8251.             : Stop.Index <= 0 ? '#fff' : '#000';
  8252.  
  8253.         Stop.Index = (Stop.Index + 1) % 2;
  8254.  
  8255.     };
  8256.  
  8257.     _.extend(Stop, {
  8258.  
  8259.         Index: 0,
  8260.  
  8261.         Properties: [
  8262.             'offset',
  8263.             'opacity',
  8264.             'color'
  8265.         ],
  8266.  
  8267.         MakeObservable: function (object) {
  8268.  
  8269.             _.each(Stop.Properties, function (property) {
  8270.  
  8271.                 var object = this;
  8272.                 var secret = '_' + property;
  8273.                 var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1);
  8274.  
  8275.                 Object.defineProperty(object, property, {
  8276.                     enumerable: true,
  8277.                     get: function () {
  8278.                         return this[secret];
  8279.                     },
  8280.                     set: function (v) {
  8281.                         this[secret] = v;
  8282.                         this[flag] = true;
  8283.                         if (this.parent) {
  8284.                             this.parent._flagStops = true;
  8285.                         }
  8286.                     }
  8287.                 });
  8288.  
  8289.             }, object);
  8290.  
  8291.         }
  8292.  
  8293.     });
  8294.  
  8295.     _.extend(Stop.prototype, Two.Utils.Events, {
  8296.  
  8297.         clone: function () {
  8298.  
  8299.             var clone = new Stop();
  8300.  
  8301.             _.each(Stop.Properties, function (property) {
  8302.                 clone[property] = this[property];
  8303.             }, this);
  8304.  
  8305.             return clone;
  8306.  
  8307.         },
  8308.  
  8309.         toObject: function () {
  8310.  
  8311.             var result = {};
  8312.  
  8313.             _.each(Stop.Properties, function (k) {
  8314.                 result[k] = this[k];
  8315.             }, this);
  8316.  
  8317.             return result;
  8318.  
  8319.         },
  8320.  
  8321.         flagReset: function () {
  8322.  
  8323.             this._flagOffset = this._flagColor = this._flagOpacity = false;
  8324.  
  8325.             return this;
  8326.  
  8327.         }
  8328.  
  8329.     });
  8330.  
  8331.     Stop.MakeObservable(Stop.prototype);
  8332.  
  8333.     var Gradient = Two.Gradient = function (stops) {
  8334.  
  8335.         this._renderer = {};
  8336.         this._renderer.type = 'gradient';
  8337.  
  8338.         this.id = Two.Identifier + Two.uniqueId();
  8339.         this.classList = [];
  8340.  
  8341.         this._renderer.flagStops = _.bind(Gradient.FlagStops, this);
  8342.         this._renderer.bindStops = _.bind(Gradient.BindStops, this);
  8343.         this._renderer.unbindStops = _.bind(Gradient.UnbindStops, this);
  8344.  
  8345.         this.spread = 'pad';
  8346.  
  8347.         this.stops = stops;
  8348.  
  8349.     };
  8350.  
  8351.     _.extend(Gradient, {
  8352.  
  8353.         Stop: Stop,
  8354.  
  8355.         Properties: [
  8356.             'spread'
  8357.         ],
  8358.  
  8359.         MakeObservable: function (object) {
  8360.  
  8361.             _.each(Gradient.Properties, Two.Utils.defineProperty, object);
  8362.  
  8363.             Object.defineProperty(object, 'stops', {
  8364.  
  8365.                 enumerable: true,
  8366.  
  8367.                 get: function () {
  8368.                     return this._stops;
  8369.                 },
  8370.  
  8371.                 set: function (stops) {
  8372.  
  8373.                     var updateStops = this._renderer.flagStops;
  8374.                     var bindStops = this._renderer.bindStops;
  8375.                     var unbindStops = this._renderer.unbindStops;
  8376.  
  8377.                     // Remove previous listeners
  8378.                     if (this._stops) {
  8379.                         this._stops
  8380.                             .unbind(Two.Events.insert, bindStops)
  8381.                             .unbind(Two.Events.remove, unbindStops);
  8382.                     }
  8383.  
  8384.                     // Create new Collection with copy of Stops
  8385.                     this._stops = new Two.Utils.Collection((stops || []).slice(0));
  8386.  
  8387.                     // Listen for Collection changes and bind / unbind
  8388.                     this._stops
  8389.                         .bind(Two.Events.insert, bindStops)
  8390.                         .bind(Two.Events.remove, unbindStops);
  8391.  
  8392.                     // Bind Initial Stops
  8393.                     bindStops(this._stops);
  8394.  
  8395.                 }
  8396.  
  8397.             });
  8398.  
  8399.         },
  8400.  
  8401.         FlagStops: function () {
  8402.             this._flagStops = true;
  8403.         },
  8404.  
  8405.         BindStops: function (items) {
  8406.  
  8407.             // This function is called a lot
  8408.             // when importing a large SVG
  8409.             var i = items.length;
  8410.             while (i--) {
  8411.                 items[i].bind(Two.Events.change, this._renderer.flagStops);
  8412.                 items[i].parent = this;
  8413.             }
  8414.  
  8415.             this._renderer.flagStops();
  8416.  
  8417.         },
  8418.  
  8419.         UnbindStops: function (items) {
  8420.  
  8421.             var i = items.length;
  8422.             while (i--) {
  8423.                 items[i].unbind(Two.Events.change, this._renderer.flagStops);
  8424.                 delete items[i].parent;
  8425.             }
  8426.  
  8427.             this._renderer.flagStops();
  8428.  
  8429.         }
  8430.  
  8431.     });
  8432.  
  8433.     _.extend(Gradient.prototype, Two.Utils.Events, {
  8434.  
  8435.         _flagStops: false,
  8436.         _flagSpread: false,
  8437.  
  8438.         clone: function (parent) {
  8439.  
  8440.             parent = parent || this.parent;
  8441.  
  8442.             var stops = _.map(this.stops, function (s) {
  8443.                 return s.clone();
  8444.             });
  8445.  
  8446.             var clone = new Gradient(stops);
  8447.  
  8448.             _.each(Two.Gradient.Properties, function (k) {
  8449.                 clone[k] = this[k];
  8450.             }, this);
  8451.  
  8452.             if (parent) {
  8453.                 parent.add(clone);
  8454.             }
  8455.  
  8456.             return clone;
  8457.  
  8458.         },
  8459.  
  8460.         toObject: function () {
  8461.  
  8462.             var result = {
  8463.                 stops: _.map(this.stops, function (s) {
  8464.                     return s.toObject();
  8465.                 })
  8466.             };
  8467.  
  8468.             _.each(Gradient.Properties, function (k) {
  8469.                 result[k] = this[k];
  8470.             }, this);
  8471.  
  8472.             return result;
  8473.  
  8474.         },
  8475.  
  8476.         _update: function () {
  8477.  
  8478.             if (this._flagSpread || this._flagStops) {
  8479.                 this.trigger(Two.Events.change);
  8480.             }
  8481.  
  8482.             return this;
  8483.  
  8484.         },
  8485.  
  8486.         flagReset: function () {
  8487.  
  8488.             this._flagSpread = this._flagStops = false;
  8489.  
  8490.             return this;
  8491.  
  8492.         }
  8493.  
  8494.     });
  8495.  
  8496.     Gradient.MakeObservable(Gradient.prototype);
  8497.  
  8498. })((typeof global !== 'undefined' ? global : this).Two);
  8499.  
  8500. (function (Two) {
  8501.  
  8502.     var _ = Two.Utils;
  8503.  
  8504.     var LinearGradient = Two.LinearGradient = function (x1, y1, x2, y2, stops) {
  8505.  
  8506.         Two.Gradient.call(this, stops);
  8507.  
  8508.         this._renderer.type = 'linear-gradient';
  8509.  
  8510.         var flagEndPoints = _.bind(LinearGradient.FlagEndPoints, this);
  8511.         this.left = new Two.Vector().bind(Two.Events.change, flagEndPoints);
  8512.         this.right = new Two.Vector().bind(Two.Events.change, flagEndPoints);
  8513.  
  8514.         if (_.isNumber(x1)) {
  8515.             this.left.x = x1;
  8516.         }
  8517.         if (_.isNumber(y1)) {
  8518.             this.left.y = y1;
  8519.         }
  8520.         if (_.isNumber(x2)) {
  8521.             this.right.x = x2;
  8522.         }
  8523.         if (_.isNumber(y2)) {
  8524.             this.right.y = y2;
  8525.         }
  8526.  
  8527.     };
  8528.  
  8529.     _.extend(LinearGradient, {
  8530.  
  8531.         Stop: Two.Gradient.Stop,
  8532.  
  8533.         MakeObservable: function (object) {
  8534.             Two.Gradient.MakeObservable(object);
  8535.         },
  8536.  
  8537.         FlagEndPoints: function () {
  8538.             this._flagEndPoints = true;
  8539.         }
  8540.  
  8541.     });
  8542.  
  8543.     _.extend(LinearGradient.prototype, Two.Gradient.prototype, {
  8544.  
  8545.         _flagEndPoints: false,
  8546.  
  8547.         clone: function (parent) {
  8548.  
  8549.             parent = parent || this.parent;
  8550.  
  8551.             var stops = _.map(this.stops, function (stop) {
  8552.                 return stop.clone();
  8553.             });
  8554.  
  8555.             var clone = new LinearGradient(this.left._x, this.left._y,
  8556.                 this.right._x, this.right._y, stops);
  8557.  
  8558.             _.each(Two.Gradient.Properties, function (k) {
  8559.                 clone[k] = this[k];
  8560.             }, this);
  8561.  
  8562.             if (parent) {
  8563.                 parent.add(clone);
  8564.             }
  8565.  
  8566.             return clone;
  8567.  
  8568.         },
  8569.  
  8570.         toObject: function () {
  8571.  
  8572.             var result = Two.Gradient.prototype.toObject.call(this);
  8573.  
  8574.             result.left = this.left.toObject();
  8575.             result.right = this.right.toObject();
  8576.  
  8577.             return result;
  8578.  
  8579.         },
  8580.  
  8581.         _update: function () {
  8582.  
  8583.             if (this._flagEndPoints || this._flagSpread || this._flagStops) {
  8584.                 this.trigger(Two.Events.change);
  8585.             }
  8586.  
  8587.             return this;
  8588.  
  8589.         },
  8590.  
  8591.         flagReset: function () {
  8592.  
  8593.             this._flagEndPoints = false;
  8594.  
  8595.             Two.Gradient.prototype.flagReset.call(this);
  8596.  
  8597.             return this;
  8598.  
  8599.         }
  8600.  
  8601.     });
  8602.  
  8603.     LinearGradient.MakeObservable(LinearGradient.prototype);
  8604.  
  8605. })((typeof global !== 'undefined' ? global : this).Two);
  8606.  
  8607. (function (Two) {
  8608.  
  8609.     var _ = Two.Utils;
  8610.  
  8611.     var RadialGradient = Two.RadialGradient = function (cx, cy, r, stops, fx, fy) {
  8612.  
  8613.         Two.Gradient.call(this, stops);
  8614.  
  8615.         this._renderer.type = 'radial-gradient';
  8616.  
  8617.         this.center = new Two.Vector()
  8618.             .bind(Two.Events.change, _.bind(function () {
  8619.                 this._flagCenter = true;
  8620.             }, this));
  8621.  
  8622.         this.radius = _.isNumber(r) ? r : 20;
  8623.  
  8624.         this.focal = new Two.Vector()
  8625.             .bind(Two.Events.change, _.bind(function () {
  8626.                 this._flagFocal = true;
  8627.             }, this));
  8628.  
  8629.         if (_.isNumber(cx)) {
  8630.             this.center.x = cx;
  8631.         }
  8632.         if (_.isNumber(cy)) {
  8633.             this.center.y = cy;
  8634.         }
  8635.  
  8636.         this.focal.copy(this.center);
  8637.  
  8638.         if (_.isNumber(fx)) {
  8639.             this.focal.x = fx;
  8640.         }
  8641.         if (_.isNumber(fy)) {
  8642.             this.focal.y = fy;
  8643.         }
  8644.  
  8645.     };
  8646.  
  8647.     _.extend(RadialGradient, {
  8648.  
  8649.         Stop: Two.Gradient.Stop,
  8650.  
  8651.         Properties: [
  8652.             'radius'
  8653.         ],
  8654.  
  8655.         MakeObservable: function (object) {
  8656.  
  8657.             Two.Gradient.MakeObservable(object);
  8658.  
  8659.             _.each(RadialGradient.Properties, Two.Utils.defineProperty, object);
  8660.  
  8661.         }
  8662.  
  8663.     });
  8664.  
  8665.     _.extend(RadialGradient.prototype, Two.Gradient.prototype, {
  8666.  
  8667.         _flagRadius: false,
  8668.         _flagCenter: false,
  8669.         _flagFocal: false,
  8670.  
  8671.         clone: function (parent) {
  8672.  
  8673.             parent = parent || this.parent;
  8674.  
  8675.             var stops = _.map(this.stops, function (stop) {
  8676.                 return stop.clone();
  8677.             });
  8678.  
  8679.             var clone = new RadialGradient(this.center._x, this.center._y,
  8680.                 this._radius, stops, this.focal._x, this.focal._y);
  8681.  
  8682.             _.each(Two.Gradient.Properties.concat(RadialGradient.Properties), function (k) {
  8683.                 clone[k] = this[k];
  8684.             }, this);
  8685.  
  8686.             if (parent) {
  8687.                 parent.add(clone);
  8688.             }
  8689.  
  8690.             return clone;
  8691.  
  8692.         },
  8693.  
  8694.         toObject: function () {
  8695.  
  8696.             var result = Two.Gradient.prototype.toObject.call(this);
  8697.  
  8698.             _.each(RadialGradient.Properties, function (k) {
  8699.                 result[k] = this[k];
  8700.             }, this);
  8701.  
  8702.             result.center = this.center.toObject();
  8703.             result.focal = this.focal.toObject();
  8704.  
  8705.             return result;
  8706.  
  8707.         },
  8708.  
  8709.         _update: function () {
  8710.  
  8711.             if (this._flagRadius || this._flatCenter || this._flagFocal
  8712.                 || this._flagSpread || this._flagStops) {
  8713.                 this.trigger(Two.Events.change);
  8714.             }
  8715.  
  8716.             return this;
  8717.  
  8718.         },
  8719.  
  8720.         flagReset: function () {
  8721.  
  8722.             this._flagRadius = this._flagCenter = this._flagFocal = false;
  8723.  
  8724.             Two.Gradient.prototype.flagReset.call(this);
  8725.  
  8726.             return this;
  8727.  
  8728.         }
  8729.  
  8730.     });
  8731.  
  8732.     RadialGradient.MakeObservable(RadialGradient.prototype);
  8733.  
  8734. })((typeof global !== 'undefined' ? global : this).Two);
  8735.  
  8736. (function (Two) {
  8737.  
  8738.     var _ = Two.Utils;
  8739.     var anchor;
  8740.     var regex = {
  8741.         video: /\.(mp4|webm)$/i,
  8742.         image: /\.(jpe?g|png|gif|tiff)$/i
  8743.     };
  8744.  
  8745.     if (this.document) {
  8746.         anchor = document.createElement('a');
  8747.     }
  8748.  
  8749.     var Texture = Two.Texture = function (src, callback) {
  8750.  
  8751.         this._renderer = {};
  8752.         this._renderer.type = 'texture';
  8753.         this._renderer.flagOffset = _.bind(Texture.FlagOffset, this);
  8754.         this._renderer.flagScale = _.bind(Texture.FlagScale, this);
  8755.  
  8756.         this.id = Two.Identifier + Two.uniqueId();
  8757.         this.classList = [];
  8758.  
  8759.         this.offset = new Two.Vector();
  8760.  
  8761.         if (_.isFunction(callback)) {
  8762.             var loaded = _.bind(function () {
  8763.                 this.unbind(Two.Events.load, loaded);
  8764.                 if (_.isFunction(callback)) {
  8765.                     callback();
  8766.                 }
  8767.             }, this);
  8768.             this.bind(Two.Events.load, loaded);
  8769.         }
  8770.  
  8771.         if (_.isString(src)) {
  8772.             this.src = src;
  8773.         } else if (_.isElement(src)) {
  8774.             this.image = src;
  8775.         }
  8776.  
  8777.         this._update();
  8778.  
  8779.     };
  8780.  
  8781.     _.extend(Texture, {
  8782.  
  8783.         Properties: [
  8784.             'src',
  8785.             'loaded',
  8786.             'repeat'
  8787.         ],
  8788.  
  8789.         ImageRegistry: new Two.Registry(),
  8790.  
  8791.         getAbsoluteURL: function (path) {
  8792.             if (!anchor) {
  8793.                 // TODO: Fix for headless environment
  8794.                 return path;
  8795.             }
  8796.             anchor.href = path;
  8797.             return anchor.href;
  8798.         },
  8799.  
  8800.         getImage: function (src) {
  8801.  
  8802.             var absoluteSrc = Texture.getAbsoluteURL(src);
  8803.  
  8804.             if (Texture.ImageRegistry.contains(absoluteSrc)) {
  8805.                 return Texture.ImageRegistry.get(absoluteSrc);
  8806.             }
  8807.  
  8808.             var image;
  8809.  
  8810.             if (regex.video.test(absoluteSrc)) {
  8811.                 image = document.createElement('video');
  8812.             } else {
  8813.                 image = document.createElement('img');
  8814.             }
  8815.  
  8816.             image.crossOrigin = 'anonymous';
  8817.  
  8818.             return image;
  8819.  
  8820.         },
  8821.  
  8822.         Register: {
  8823.             canvas: function (texture, callback) {
  8824.                 texture._src = '#' + texture.id;
  8825.                 Texture.ImageRegistry.add(texture.src, texture.image);
  8826.                 if (_.isFunction(callback)) {
  8827.                     callback();
  8828.                 }
  8829.             },
  8830.             img: function (texture, callback) {
  8831.  
  8832.                 var loaded = function (e) {
  8833.                     texture.image.removeEventListener('load', loaded, false);
  8834.                     texture.image.removeEventListener('error', error, false);
  8835.                     if (_.isFunction(callback)) {
  8836.                         callback();
  8837.                     }
  8838.                 };
  8839.                 var error = function (e) {
  8840.                     texture.image.removeEventListener('load', loaded, false);
  8841.                     texture.image.removeEventListener('error', error, false);
  8842.                     throw new Two.Utils.Error('unable to load ' + texture.src);
  8843.                 };
  8844.  
  8845.                 if (_.isNumber(texture.image.width) && texture.image.width > 0
  8846.                     && _.isNumber(texture.image.height) && texture.image.height > 0) {
  8847.                     loaded();
  8848.                 } else {
  8849.                     texture.image.addEventListener('load', loaded, false);
  8850.                     texture.image.addEventListener('error', error, false);
  8851.                 }
  8852.  
  8853.                 texture._src = Texture.getAbsoluteURL(texture._src);
  8854.  
  8855.                 if (texture.image && texture.image.getAttribute('two-src')) {
  8856.                     return;
  8857.                 }
  8858.  
  8859.                 texture.image.setAttribute('two-src', texture.src);
  8860.                 Texture.ImageRegistry.add(texture.src, texture.image);
  8861.                 texture.image.src = texture.src;
  8862.  
  8863.             },
  8864.             video: function (texture, callback) {
  8865.  
  8866.                 var loaded = function (e) {
  8867.                     texture.image.removeEventListener('load', loaded, false);
  8868.                     texture.image.removeEventListener('error', error, false);
  8869.                     texture.image.width = texture.image.videoWidth;
  8870.                     texture.image.height = texture.image.videoHeight;
  8871.                     texture.image.play();
  8872.                     if (_.isFunction(callback)) {
  8873.                         callback();
  8874.                     }
  8875.                 };
  8876.                 var error = function (e) {
  8877.                     texture.image.removeEventListener('load', loaded, false);
  8878.                     texture.image.removeEventListener('error', error, false);
  8879.                     throw new Two.Utils.Error('unable to load ' + texture.src);
  8880.                 };
  8881.  
  8882.                 texture._src = Texture.getAbsoluteURL(texture._src);
  8883.                 texture.image.addEventListener('canplaythrough', loaded, false);
  8884.                 texture.image.addEventListener('error', error, false);
  8885.  
  8886.                 if (texture.image && texture.image.getAttribute('two-src')) {
  8887.                     return;
  8888.                 }
  8889.  
  8890.                 texture.image.setAttribute('two-src', texture.src);
  8891.                 Texture.ImageRegistry.add(texture.src, texture.image);
  8892.                 texture.image.src = texture.src;
  8893.                 texture.image.loop = true;
  8894.                 texture.image.load();
  8895.  
  8896.             }
  8897.         },
  8898.  
  8899.         load: function (texture, callback) {
  8900.  
  8901.             var src = texture.src;
  8902.             var image = texture.image;
  8903.             var tag = image && image.nodeName.toLowerCase();
  8904.  
  8905.             if (texture._flagImage) {
  8906.                 if (/canvas/i.test(tag)) {
  8907.                     Texture.Register.canvas(texture, callback);
  8908.                 } else {
  8909.                     texture._src = image.getAttribute('two-src') || image.src;
  8910.                     Texture.Register[tag](texture, callback);
  8911.                 }
  8912.             }
  8913.  
  8914.             if (texture._flagSrc) {
  8915.                 if (!image) {
  8916.                     texture.image = Texture.getImage(texture.src);
  8917.                 }
  8918.                 tag = texture.image.nodeName.toLowerCase();
  8919.                 Texture.Register[tag](texture, callback);
  8920.             }
  8921.  
  8922.         },
  8923.  
  8924.         FlagOffset: function () {
  8925.             this._flagOffset = true;
  8926.         },
  8927.  
  8928.         FlagScale: function () {
  8929.             this._flagScale = true;
  8930.         },
  8931.  
  8932.         MakeObservable: function (object) {
  8933.  
  8934.             _.each(Texture.Properties, Two.Utils.defineProperty, object);
  8935.  
  8936.             Object.defineProperty(object, 'image', {
  8937.                 enumerable: true,
  8938.                 get: function () {
  8939.                     return this._image;
  8940.                 },
  8941.                 set: function (image) {
  8942.  
  8943.                     var tag = image && image.nodeName.toLowerCase();
  8944.                     var index;
  8945.  
  8946.                     switch (tag) {
  8947.                         case 'canvas':
  8948.                             index = '#' + image.id;
  8949.                             break;
  8950.                         default:
  8951.                             index = image.src;
  8952.                     }
  8953.  
  8954.                     if (Texture.ImageRegistry.contains(index)) {
  8955.                         this._image = Texture.ImageRegistry.get(image.src);
  8956.                     } else {
  8957.                         this._image = image;
  8958.                     }
  8959.  
  8960.                     this._flagImage = true;
  8961.  
  8962.                 }
  8963.  
  8964.             });
  8965.  
  8966.             Object.defineProperty(object, 'offset', {
  8967.                 enumerable: true,
  8968.                 get: function () {
  8969.                     return this._offset;
  8970.                 },
  8971.                 set: function (v) {
  8972.                     if (this._offset) {
  8973.                         this._offset.unbind(Two.Events.change, this._renderer.flagOffset);
  8974.                     }
  8975.                     this._offset = v;
  8976.                     this._offset.bind(Two.Events.change, this._renderer.flagOffset);
  8977.                     this._flagOffset = true;
  8978.                 }
  8979.             });
  8980.  
  8981.             Object.defineProperty(object, 'scale', {
  8982.                 enumerable: true,
  8983.                 get: function () {
  8984.                     return this._scale;
  8985.                 },
  8986.                 set: function (v) {
  8987.  
  8988.                     if (this._scale instanceof Two.Vector) {
  8989.                         this._scale.unbind(Two.Events.change, this._renderer.flagScale);
  8990.                     }
  8991.  
  8992.                     this._scale = v;
  8993.  
  8994.                     if (this._scale instanceof Two.Vector) {
  8995.                         this._scale.bind(Two.Events.change, this._renderer.flagScale);
  8996.                     }
  8997.  
  8998.                     this._flagScale = true;
  8999.  
  9000.                 }
  9001.             });
  9002.  
  9003.         }
  9004.  
  9005.     });
  9006.  
  9007.     _.extend(Texture.prototype, Two.Utils.Events, Two.Shape.prototype, {
  9008.  
  9009.         _flagSrc: false,
  9010.         _flagImage: false,
  9011.         _flagVideo: false,
  9012.         _flagLoaded: false,
  9013.         _flagRepeat: false,
  9014.  
  9015.         _flagOffset: false,
  9016.         _flagScale: false,
  9017.  
  9018.         _src: '',
  9019.         _image: null,
  9020.         _loaded: false,
  9021.         _repeat: 'no-repeat',
  9022.  
  9023.         _scale: 1,
  9024.         _offset: null,
  9025.  
  9026.         clone: function () {
  9027.             return new Texture(this.src);
  9028.         },
  9029.  
  9030.         toObject: function () {
  9031.             return {
  9032.                 src: this.src,
  9033.                 image: this.image
  9034.             }
  9035.         },
  9036.  
  9037.         _update: function () {
  9038.  
  9039.             if (this._flagSrc || this._flagImage || this._flagVideo) {
  9040.  
  9041.                 this.trigger(Two.Events.change);
  9042.  
  9043.                 if (this._flagSrc || this._flagImage) {
  9044.                     this.loaded = false;
  9045.                     Texture.load(this, _.bind(function () {
  9046.                         this.loaded = true;
  9047.                         this
  9048.                             .trigger(Two.Events.change)
  9049.                             .trigger(Two.Events.load);
  9050.                     }, this));
  9051.                 }
  9052.  
  9053.             }
  9054.  
  9055.             if (this._image && this._image.readyState >= 4) {
  9056.                 this._flagVideo = true;
  9057.             }
  9058.  
  9059.             return this;
  9060.  
  9061.         },
  9062.  
  9063.         flagReset: function () {
  9064.  
  9065.             this._flagSrc = this._flagImage = this._flagLoaded
  9066.                 = this._flagVideo = this._flagScale = this._flagOffset = false;
  9067.  
  9068.             return this;
  9069.  
  9070.         }
  9071.  
  9072.     });
  9073.  
  9074.     Texture.MakeObservable(Texture.prototype);
  9075.  
  9076. })((typeof global !== 'undefined' ? global : this).Two);
  9077.  
  9078. (function (Two) {
  9079.  
  9080.     var _ = Two.Utils;
  9081.     var Path = Two.Path;
  9082.     var Rectangle = Two.Rectangle;
  9083.  
  9084.     var Sprite = Two.Sprite = function (path, ox, oy, cols, rows, frameRate) {
  9085.  
  9086.         Path.call(this, [
  9087.             new Two.Anchor(),
  9088.             new Two.Anchor(),
  9089.             new Two.Anchor(),
  9090.             new Two.Anchor()
  9091.         ], true);
  9092.  
  9093.         this.noStroke();
  9094.         this.noFill();
  9095.  
  9096.         if (path instanceof Two.Texture) {
  9097.             this.texture = path;
  9098.         } else if (_.isString(path)) {
  9099.             this.texture = new Two.Texture(path);
  9100.         }
  9101.  
  9102.         this._update();
  9103.         this.translation.set(ox || 0, oy || 0);
  9104.  
  9105.         if (_.isNumber(cols)) {
  9106.             this.columns = cols;
  9107.         }
  9108.         if (_.isNumber(rows)) {
  9109.             this.rows = rows;
  9110.         }
  9111.         if (_.isNumber(frameRate)) {
  9112.             this.frameRate = frameRate;
  9113.         }
  9114.  
  9115.     };
  9116.  
  9117.     _.extend(Sprite, {
  9118.  
  9119.         Properties: [
  9120.             'texture', 'columns', 'rows', 'frameRate', 'index'
  9121.         ],
  9122.  
  9123.         MakeObservable: function (obj) {
  9124.  
  9125.             Rectangle.MakeObservable(obj);
  9126.             _.each(Sprite.Properties, Two.Utils.defineProperty, obj);
  9127.  
  9128.         }
  9129.  
  9130.     })
  9131.  
  9132.     _.extend(Sprite.prototype, Rectangle.prototype, {
  9133.  
  9134.         _flagTexture: false,
  9135.         _flagColumns: false,
  9136.         _flagRows: false,
  9137.         _flagFrameRate: false,
  9138.         flagIndex: false,
  9139.  
  9140.         // Private variables
  9141.         _amount: 1,
  9142.         _duration: 0,
  9143.         _startTime: 0,
  9144.         _playing: false,
  9145.         _firstFrame: 0,
  9146.         _lastFrame: 0,
  9147.         _loop: true,
  9148.  
  9149.         // Exposed through getter-setter
  9150.         _texture: null,
  9151.         _columns: 1,
  9152.         _rows: 1,
  9153.         _frameRate: 0,
  9154.         _index: 0,
  9155.  
  9156.         play: function (firstFrame, lastFrame, onLastFrame) {
  9157.  
  9158.             this._playing = true;
  9159.             this._firstFrame = 0;
  9160.             this._lastFrame = this.amount - 1;
  9161.             this._startTime = _.performance.now();
  9162.  
  9163.             if (_.isNumber(firstFrame)) {
  9164.                 this._firstFrame = firstFrame;
  9165.             }
  9166.             if (_.isNumber(lastFrame)) {
  9167.                 this._lastFrame = lastFrame;
  9168.             }
  9169.             if (_.isFunction(onLastFrame)) {
  9170.                 this._onLastFrame = onLastFrame;
  9171.             } else {
  9172.                 delete this._onLastFrame;
  9173.             }
  9174.  
  9175.             if (this._index !== this._firstFrame) {
  9176.                 this._startTime -= 1000 * Math.abs(this._index - this._firstFrame)
  9177.                     / this._frameRate;
  9178.             }
  9179.  
  9180.             return this;
  9181.  
  9182.         },
  9183.  
  9184.         pause: function () {
  9185.  
  9186.             this._playing = false;
  9187.             return this;
  9188.  
  9189.         },
  9190.  
  9191.         stop: function () {
  9192.  
  9193.             this._playing = false;
  9194.             this._index = 0;
  9195.  
  9196.             return this;
  9197.  
  9198.         },
  9199.  
  9200.         clone: function (parent) {
  9201.  
  9202.             parent = parent || this.parent;
  9203.  
  9204.             var clone = new Sprite(
  9205.                 this.texture, this.translation.x, this.translation.y,
  9206.                 this.columns, this.rows, this.frameRate
  9207.             );
  9208.  
  9209.             if (this.playing) {
  9210.                 clone.play(this._firstFrame, this._lastFrame);
  9211.                 clone._loop = this._loop;
  9212.             }
  9213.  
  9214.             if (parent) {
  9215.                 parent.add(clone);
  9216.             }
  9217.  
  9218.             return clone;
  9219.  
  9220.         },
  9221.  
  9222.         _update: function () {
  9223.  
  9224.             var effect = this._texture;
  9225.             var cols = this._columns;
  9226.             var rows = this._rows;
  9227.  
  9228.             var width, height, elapsed, amount, duration;
  9229.             var index, iw, ih, isRange, frames;
  9230.  
  9231.             if (this._flagColumns || this._flagRows) {
  9232.                 this._amount = this._columns * this._rows;
  9233.             }
  9234.  
  9235.             if (this._flagFrameRate) {
  9236.                 this._duration = 1000 * this._amount / this._frameRate;
  9237.             }
  9238.  
  9239.             if (this._flagTexture) {
  9240.                 this.fill = this._texture;
  9241.             }
  9242.  
  9243.             if (this._texture.loaded) {
  9244.  
  9245.                 iw = effect.image.width;
  9246.                 ih = effect.image.height;
  9247.  
  9248.                 width = iw / cols;
  9249.                 height = ih / rows;
  9250.                 amount = this._amount;
  9251.  
  9252.                 if (this.width !== width) {
  9253.                     this.width = width;
  9254.                 }
  9255.                 if (this.height !== height) {
  9256.                     this.height = height;
  9257.                 }
  9258.  
  9259.                 if (this._playing && this._frameRate > 0) {
  9260.  
  9261.                     if (_.isNaN(this._lastFrame)) {
  9262.                         this._lastFrame = amount - 1;
  9263.                     }
  9264.  
  9265.                     // TODO: Offload perf logic to instance of `Two`.
  9266.                     elapsed = _.performance.now() - this._startTime;
  9267.                     frames = this._lastFrame + 1;
  9268.                     duration = 1000 * (frames - this._firstFrame) / this._frameRate;
  9269.  
  9270.                     if (this._loop) {
  9271.                         elapsed = elapsed % duration;
  9272.                     } else {
  9273.                         elapsed = Math.min(elapsed, duration);
  9274.                     }
  9275.  
  9276.                     index = _.lerp(this._firstFrame, frames, elapsed / duration);
  9277.                     index = Math.floor(index);
  9278.  
  9279.                     if (index !== this._index) {
  9280.                         this._index = index;
  9281.                         if (index >= this._lastFrame - 1 && this._onLastFrame) {
  9282.                             this._onLastFrame();  // Shortcut for chainable sprite animations
  9283.                         }
  9284.                     }
  9285.  
  9286.                 }
  9287.  
  9288.                 var col = this._index % cols;
  9289.                 var row = Math.floor(this._index / cols);
  9290.  
  9291.                 var ox = - width * col + (iw - width) / 2;
  9292.                 var oy = - height * row + (ih - height) / 2;
  9293.  
  9294.                 // TODO: Improve performance
  9295.                 if (ox !== effect.offset.x) {
  9296.                     effect.offset.x = ox;
  9297.                 }
  9298.                 if (oy !== effect.offset.y) {
  9299.                     effect.offset.y = oy;
  9300.                 }
  9301.  
  9302.             }
  9303.  
  9304.             Rectangle.prototype._update.call(this);
  9305.  
  9306.             return this;
  9307.  
  9308.         },
  9309.  
  9310.         flagReset: function () {
  9311.  
  9312.             this._flagTexture = this._flagColumns = this._flagRows
  9313.                 = this._flagFrameRate = false;
  9314.  
  9315.             Rectangle.prototype.flagReset.call(this);
  9316.  
  9317.             return this;
  9318.         }
  9319.  
  9320.  
  9321.     });
  9322.  
  9323.     Sprite.MakeObservable(Sprite.prototype);
  9324.  
  9325. })((typeof global !== 'undefined' ? global : this).Two);
  9326.  
  9327. (function (Two) {
  9328.  
  9329.     var _ = Two.Utils;
  9330.     var Path = Two.Path;
  9331.     var Rectangle = Two.Rectangle;
  9332.  
  9333.     var ImageSequence = Two.ImageSequence = function (paths, ox, oy, frameRate) {
  9334.  
  9335.         Path.call(this, [
  9336.             new Two.Anchor(),
  9337.             new Two.Anchor(),
  9338.             new Two.Anchor(),
  9339.             new Two.Anchor()
  9340.         ], true);
  9341.  
  9342.         this._renderer.flagTextures = _.bind(ImageSequence.FlagTextures, this);
  9343.         this._renderer.bindTextures = _.bind(ImageSequence.BindTextures, this);
  9344.         this._renderer.unbindTextures = _.bind(ImageSequence.UnbindTextures, this);
  9345.  
  9346.         this.noStroke();
  9347.         this.noFill();
  9348.  
  9349.         this.textures = _.map(paths, ImageSequence.GenerateTexture, this);
  9350.  
  9351.         this._update();
  9352.         this.translation.set(ox || 0, oy || 0);
  9353.  
  9354.         if (_.isNumber(frameRate)) {
  9355.             this.frameRate = frameRate;
  9356.         } else {
  9357.             this.frameRate = ImageSequence.DefaultFrameRate;
  9358.         }
  9359.  
  9360.     };
  9361.  
  9362.     _.extend(ImageSequence, {
  9363.  
  9364.         Properties: [
  9365.             'frameRate',
  9366.             'index'
  9367.         ],
  9368.  
  9369.         DefaultFrameRate: 30,
  9370.  
  9371.         FlagTextures: function () {
  9372.             this._flagTextures = true;
  9373.         },
  9374.  
  9375.         BindTextures: function (items) {
  9376.  
  9377.             var i = items.length;
  9378.             while (i--) {
  9379.                 items[i].bind(Two.Events.change, this._renderer.flagTextures);
  9380.             }
  9381.  
  9382.             this._renderer.flagTextures();
  9383.  
  9384.         },
  9385.  
  9386.         UnbindTextures: function (items) {
  9387.  
  9388.             var i = items.length;
  9389.             while (i--) {
  9390.                 items[i].unbind(Two.Events.change, this._renderer.flagTextures);
  9391.             }
  9392.  
  9393.             this._renderer.flagTextures();
  9394.  
  9395.         },
  9396.  
  9397.         MakeObservable: function (obj) {
  9398.  
  9399.             Rectangle.MakeObservable(obj);
  9400.             _.each(ImageSequence.Properties, Two.Utils.defineProperty, obj);
  9401.  
  9402.             Object.defineProperty(obj, 'textures', {
  9403.  
  9404.                 enumerable: true,
  9405.  
  9406.                 get: function () {
  9407.                     return this._textures;
  9408.                 },
  9409.  
  9410.                 set: function (textures) {
  9411.  
  9412.                     var updateTextures = this._renderer.flagTextures;
  9413.                     var bindTextures = this._renderer.bindTextures;
  9414.                     var unbindTextures = this._renderer.unbindTextures;
  9415.  
  9416.                     // Remove previous listeners
  9417.                     if (this._textures) {
  9418.                         this._textures
  9419.                             .unbind(Two.Events.insert, bindTextures)
  9420.                             .unbind(Two.Events.remove, unbindTextures);
  9421.                     }
  9422.  
  9423.                     // Create new Collection with copy of vertices
  9424.                     this._textures = new Two.Utils.Collection((textures || []).slice(0));
  9425.  
  9426.                     // Listen for Collection changes and bind / unbind
  9427.                     this._textures
  9428.                         .bind(Two.Events.insert, bindTextures)
  9429.                         .bind(Two.Events.remove, unbindTextures);
  9430.  
  9431.                     // Bind Initial Textures
  9432.                     bindTextures(this._textures);
  9433.  
  9434.                 }
  9435.  
  9436.             });
  9437.  
  9438.         },
  9439.  
  9440.         GenerateTexture: function (obj) {
  9441.             if (obj instanceof Two.Texture) {
  9442.                 return obj;
  9443.             } else if (_.isString(obj)) {
  9444.                 return new Two.Texture(obj);
  9445.             }
  9446.         }
  9447.  
  9448.     });
  9449.  
  9450.     _.extend(ImageSequence.prototype, Rectangle.prototype, {
  9451.  
  9452.         _flagTextures: false,
  9453.         _flagFrameRate: false,
  9454.         _flagIndex: false,
  9455.  
  9456.         // Private variables
  9457.         _amount: 1,
  9458.         _duration: 0,
  9459.         _index: 0,
  9460.         _startTime: 0,
  9461.         _playing: false,
  9462.         _firstFrame: 0,
  9463.         _lastFrame: 0,
  9464.         _loop: true,
  9465.  
  9466.         // Exposed through getter-setter
  9467.         _textures: null,
  9468.         _frameRate: 0,
  9469.  
  9470.         play: function (firstFrame, lastFrame, onLastFrame) {
  9471.  
  9472.             this._playing = true;
  9473.             this._firstFrame = 0;
  9474.             this._lastFrame = this.amount - 1;
  9475.             this._startTime = _.performance.now();
  9476.  
  9477.             if (_.isNumber(firstFrame)) {
  9478.                 this._firstFrame = firstFrame;
  9479.             }
  9480.             if (_.isNumber(lastFrame)) {
  9481.                 this._lastFrame = lastFrame;
  9482.             }
  9483.             if (_.isFunction(onLastFrame)) {
  9484.                 this._onLastFrame = onLastFrame;
  9485.             } else {
  9486.                 delete this._onLastFrame;
  9487.             }
  9488.  
  9489.             if (this._index !== this._firstFrame) {
  9490.                 this._startTime -= 1000 * Math.abs(this._index - this._firstFrame)
  9491.                     / this._frameRate;
  9492.             }
  9493.  
  9494.             return this;
  9495.  
  9496.         },
  9497.  
  9498.         pause: function () {
  9499.  
  9500.             this._playing = false;
  9501.             return this;
  9502.  
  9503.         },
  9504.  
  9505.         stop: function () {
  9506.  
  9507.             this._playing = false;
  9508.             this._index = 0;
  9509.  
  9510.             return this;
  9511.  
  9512.         },
  9513.  
  9514.         clone: function (parent) {
  9515.  
  9516.             parent = parent || this.parent;
  9517.  
  9518.             var clone = new ImageSequence(this.textures, this.translation.x,
  9519.                 this.translation.y, this.frameRate)
  9520.  
  9521.             clone._loop = this._loop;
  9522.  
  9523.             if (this._playing) {
  9524.                 clone.play();
  9525.             }
  9526.  
  9527.             if (parent) {
  9528.                 parent.add(clone);
  9529.             }
  9530.  
  9531.             return clone;
  9532.  
  9533.         },
  9534.  
  9535.         _update: function () {
  9536.  
  9537.             var effects = this._textures;
  9538.             var width, height, elapsed, amount, duration, texture;
  9539.             var index, frames;
  9540.  
  9541.             if (this._flagTextures) {
  9542.                 this._amount = effects.length;
  9543.             }
  9544.  
  9545.             if (this._flagFrameRate) {
  9546.                 this._duration = 1000 * this._amount / this._frameRate;
  9547.             }
  9548.  
  9549.             if (this._playing && this._frameRate > 0) {
  9550.  
  9551.                 amount = this._amount;
  9552.  
  9553.                 if (_.isNaN(this._lastFrame)) {
  9554.                     this._lastFrame = amount - 1;
  9555.                 }
  9556.  
  9557.                 // TODO: Offload perf logic to instance of `Two`.
  9558.                 elapsed = _.performance.now() - this._startTime;
  9559.                 frames = this._lastFrame + 1;
  9560.                 duration = 1000 * (frames - this._firstFrame) / this._frameRate;
  9561.  
  9562.                 if (this._loop) {
  9563.                     elapsed = elapsed % duration;
  9564.                 } else {
  9565.                     elapsed = Math.min(elapsed, duration);
  9566.                 }
  9567.  
  9568.                 index = _.lerp(this._firstFrame, frames, elapsed / duration);
  9569.                 index = Math.floor(index);
  9570.  
  9571.                 if (index !== this._index) {
  9572.  
  9573.                     this._index = index;
  9574.                     texture = effects[this._index];
  9575.  
  9576.                     if (texture.loaded) {
  9577.  
  9578.                         width = texture.image.width;
  9579.                         height = texture.image.height;
  9580.  
  9581.                         if (this.width !== width) {
  9582.                             this.width = width;
  9583.                         }
  9584.                         if (this.height !== height) {
  9585.                             this.height = height;
  9586.                         }
  9587.  
  9588.                         this.fill = texture;
  9589.  
  9590.                         if (index >= this._lastFrame - 1 && this._onLastFrame) {
  9591.                             this._onLastFrame();  // Shortcut for chainable sprite animations
  9592.                         }
  9593.  
  9594.                     }
  9595.  
  9596.                 }
  9597.  
  9598.             } else if (this._flagIndex || !(this.fill instanceof Two.Texture)) {
  9599.  
  9600.                 texture = effects[this._index];
  9601.  
  9602.                 if (texture.loaded) {
  9603.  
  9604.                     width = texture.image.width;
  9605.                     height = texture.image.height;
  9606.  
  9607.                     if (this.width !== width) {
  9608.                         this.width = width;
  9609.                     }
  9610.                     if (this.height !== height) {
  9611.                         this.height = height;
  9612.                     }
  9613.  
  9614.                 }
  9615.  
  9616.                 this.fill = texture;
  9617.  
  9618.             }
  9619.  
  9620.             Rectangle.prototype._update.call(this);
  9621.  
  9622.             return this;
  9623.  
  9624.         },
  9625.  
  9626.         flagReset: function () {
  9627.  
  9628.             this._flagTextures = this._flagFrameRate = false;
  9629.             Rectangle.prototype.flagReset.call(this);
  9630.  
  9631.             return this;
  9632.  
  9633.         }
  9634.  
  9635.     });
  9636.  
  9637.     ImageSequence.MakeObservable(ImageSequence.prototype);
  9638.  
  9639. })((typeof global !== 'undefined' ? global : this).Two);
  9640.  
  9641. (function (Two) {
  9642.  
  9643.     /**
  9644.         * Constants
  9645.         */
  9646.     var min = Math.min, max = Math.max;
  9647.     var _ = Two.Utils;
  9648.  
  9649.     /**
  9650.         * A children collection which is accesible both by index and by object id
  9651.         * @constructor
  9652.         */
  9653.     var Children = function () {
  9654.  
  9655.         Two.Utils.Collection.apply(this, arguments);
  9656.  
  9657.         Object.defineProperty(this, '_events', {
  9658.             value: {},
  9659.             enumerable: false
  9660.         });
  9661.  
  9662.         this.ids = {};
  9663.  
  9664.         this.on(Two.Events.insert, this.attach);
  9665.         this.on(Two.Events.remove, this.detach);
  9666.         Children.prototype.attach.apply(this, arguments);
  9667.  
  9668.     };
  9669.  
  9670.     Children.prototype = new Two.Utils.Collection();
  9671.     Children.prototype.constructor = Children;
  9672.  
  9673.     _.extend(Children.prototype, {
  9674.  
  9675.         attach: function (children) {
  9676.             for (var i = 0; i < children.length; i++) {
  9677.                 this.ids[children[i].id] = children[i];
  9678.             }
  9679.             return this;
  9680.         },
  9681.  
  9682.         detach: function (children) {
  9683.             for (var i = 0; i < children.length; i++) {
  9684.                 delete this.ids[children[i].id];
  9685.             }
  9686.             return this;
  9687.         }
  9688.  
  9689.     });
  9690.  
  9691.     var Group = Two.Group = function () {
  9692.  
  9693.         Two.Shape.call(this, true);
  9694.  
  9695.         this._renderer.type = 'group';
  9696.  
  9697.         this.additions = [];
  9698.         this.subtractions = [];
  9699.  
  9700.         this.children = arguments;
  9701.  
  9702.     };
  9703.  
  9704.     _.extend(Group, {
  9705.  
  9706.         Children: Children,
  9707.  
  9708.         InsertChildren: function (children) {
  9709.             for (var i = 0; i < children.length; i++) {
  9710.                 replaceParent.call(this, children[i], this);
  9711.             }
  9712.         },
  9713.  
  9714.         RemoveChildren: function (children) {
  9715.             for (var i = 0; i < children.length; i++) {
  9716.                 replaceParent.call(this, children[i]);
  9717.             }
  9718.         },
  9719.  
  9720.         OrderChildren: function (children) {
  9721.             this._flagOrder = true;
  9722.         },
  9723.  
  9724.         MakeObservable: function (object) {
  9725.  
  9726.             var properties = Two.Path.Properties.slice(0);
  9727.             var oi = _.indexOf(properties, 'opacity');
  9728.  
  9729.             if (oi >= 0) {
  9730.  
  9731.                 properties.splice(oi, 1);
  9732.  
  9733.                 Object.defineProperty(object, 'opacity', {
  9734.  
  9735.                     enumerable: true,
  9736.  
  9737.                     get: function () {
  9738.                         return this._opacity;
  9739.                     },
  9740.  
  9741.                     set: function (v) {
  9742.                         // Only set flag if there is an actual difference
  9743.                         this._flagOpacity = (this._opacity != v);
  9744.                         this._opacity = v;
  9745.                     }
  9746.  
  9747.                 });
  9748.  
  9749.             }
  9750.  
  9751.             Two.Shape.MakeObservable(object);
  9752.             Group.MakeGetterSetters(object, properties);
  9753.  
  9754.             Object.defineProperty(object, 'children', {
  9755.  
  9756.                 enumerable: true,
  9757.  
  9758.                 get: function () {
  9759.                     return this._children;
  9760.                 },
  9761.  
  9762.                 set: function (children) {
  9763.  
  9764.                     var insertChildren = _.bind(Group.InsertChildren, this);
  9765.                     var removeChildren = _.bind(Group.RemoveChildren, this);
  9766.                     var orderChildren = _.bind(Group.OrderChildren, this);
  9767.  
  9768.                     if (this._children) {
  9769.                         this._children.unbind();
  9770.                     }
  9771.  
  9772.                     this._children = new Children(children);
  9773.                     this._children.bind(Two.Events.insert, insertChildren);
  9774.                     this._children.bind(Two.Events.remove, removeChildren);
  9775.                     this._children.bind(Two.Events.order, orderChildren);
  9776.  
  9777.                 }
  9778.  
  9779.             });
  9780.  
  9781.             Object.defineProperty(object, 'mask', {
  9782.  
  9783.                 enumerable: true,
  9784.  
  9785.                 get: function () {
  9786.                     return this._mask;
  9787.                 },
  9788.  
  9789.                 set: function (v) {
  9790.                     this._mask = v;
  9791.                     this._flagMask = true;
  9792.                     if (!v.clip) {
  9793.                         v.clip = true;
  9794.                     }
  9795.                 }
  9796.  
  9797.             });
  9798.  
  9799.         },
  9800.  
  9801.         MakeGetterSetters: function (group, properties) {
  9802.  
  9803.             if (!_.isArray(properties)) {
  9804.                 properties = [properties];
  9805.             }
  9806.  
  9807.             _.each(properties, function (k) {
  9808.                 Group.MakeGetterSetter(group, k);
  9809.             });
  9810.  
  9811.         },
  9812.  
  9813.         MakeGetterSetter: function (group, k) {
  9814.  
  9815.             var secret = '_' + k;
  9816.  
  9817.             Object.defineProperty(group, k, {
  9818.  
  9819.                 enumerable: true,
  9820.  
  9821.                 get: function () {
  9822.                     return this[secret];
  9823.                 },
  9824.  
  9825.                 set: function (v) {
  9826.                     this[secret] = v;
  9827.                     _.each(this.children, function (child) { // Trickle down styles
  9828.                         child[k] = v;
  9829.                     });
  9830.                 }
  9831.  
  9832.             });
  9833.  
  9834.         }
  9835.  
  9836.     });
  9837.  
  9838.     _.extend(Group.prototype, Two.Shape.prototype, {
  9839.  
  9840.         // Flags
  9841.         // http://en.wikipedia.org/wiki/Flag
  9842.  
  9843.         _flagAdditions: false,
  9844.         _flagSubtractions: false,
  9845.         _flagOrder: false,
  9846.         _flagOpacity: true,
  9847.  
  9848.         _flagMask: false,
  9849.  
  9850.         // Underlying Properties
  9851.  
  9852.         _fill: '#fff',
  9853.         _stroke: '#000',
  9854.         _linewidth: 1.0,
  9855.         _opacity: 1.0,
  9856.         _visible: true,
  9857.  
  9858.         _cap: 'round',
  9859.         _join: 'round',
  9860.         _miter: 4,
  9861.  
  9862.         _closed: true,
  9863.         _curved: false,
  9864.         _automatic: true,
  9865.         _beginning: 0,
  9866.         _ending: 1.0,
  9867.  
  9868.         _mask: null,
  9869.  
  9870.         /**
  9871.             * TODO: Group has a gotcha in that it's at the moment required to be bound to
  9872.             * an instance of two in order to add elements correctly. This needs to
  9873.             * be rethought and fixed.
  9874.             */
  9875.         clone: function (parent) {
  9876.  
  9877.             parent = parent || this.parent;
  9878.  
  9879.             var group = new Group();
  9880.             var children = _.map(this.children, function (child) {
  9881.                 return child.clone(group);
  9882.             });
  9883.  
  9884.             group.add(children);
  9885.  
  9886.             group.opacity = this.opacity;
  9887.  
  9888.             if (this.mask) {
  9889.                 group.mask = this.mask;
  9890.             }
  9891.  
  9892.             group.translation.copy(this.translation);
  9893.             group.rotation = this.rotation;
  9894.             group.scale = this.scale;
  9895.  
  9896.             if (parent) {
  9897.                 parent.add(group);
  9898.             }
  9899.  
  9900.             return group;
  9901.  
  9902.         },
  9903.  
  9904.         /**
  9905.             * Export the data from the instance of Two.Group into a plain JavaScript
  9906.             * object. This also makes all children plain JavaScript objects. Great
  9907.             * for turning into JSON and storing in a database.
  9908.             */
  9909.         toObject: function () {
  9910.  
  9911.             var result = {
  9912.                 children: [],
  9913.                 translation: this.translation.toObject(),
  9914.                 rotation: this.rotation,
  9915.                 scale: this.scale,
  9916.                 opacity: this.opacity,
  9917.                 mask: (this.mask ? this.mask.toObject() : null)
  9918.             };
  9919.  
  9920.             _.each(this.children, function (child, i) {
  9921.                 result.children[i] = child.toObject();
  9922.             }, this);
  9923.  
  9924.             return result;
  9925.  
  9926.         },
  9927.  
  9928.         /**
  9929.             * Anchor all children to the upper left hand corner
  9930.             * of the group.
  9931.             */
  9932.         corner: function () {
  9933.  
  9934.             var rect = this.getBoundingClientRect(true),
  9935.                 corner = { x: rect.left, y: rect.top };
  9936.  
  9937.             this.children.forEach(function (child) {
  9938.                 child.translation.subSelf(corner);
  9939.             });
  9940.  
  9941.             return this;
  9942.  
  9943.         },
  9944.  
  9945.         /**
  9946.             * Anchors all children around the center of the group,
  9947.             * effectively placing the shape around the unit circle.
  9948.             */
  9949.         center: function () {
  9950.  
  9951.             var rect = this.getBoundingClientRect(true);
  9952.  
  9953.             rect.centroid = {
  9954.                 x: rect.left + rect.width / 2,
  9955.                 y: rect.top + rect.height / 2
  9956.             };
  9957.  
  9958.             this.children.forEach(function (child) {
  9959.                 if (child.isShape) {
  9960.                     child.translation.subSelf(rect.centroid);
  9961.                 }
  9962.             });
  9963.  
  9964.             // this.translation.copy(rect.centroid);
  9965.  
  9966.             return this;
  9967.  
  9968.         },
  9969.  
  9970.         /**
  9971.             * Recursively search for id. Returns the first element found.
  9972.             * Returns null if none found.
  9973.             */
  9974.         getById: function (id) {
  9975.             var search = function (node, id) {
  9976.                 if (node.id === id) {
  9977.                     return node;
  9978.                 } else if (node.children) {
  9979.                     var i = node.children.length;
  9980.                     while (i--) {
  9981.                         var found = search(node.children[i], id);
  9982.                         if (found) return found;
  9983.                     }
  9984.                 }
  9985.  
  9986.             };
  9987.             return search(this, id) || null;
  9988.         },
  9989.  
  9990.         /**
  9991.             * Recursively search for classes. Returns an array of matching elements.
  9992.             * Empty array if none found.
  9993.             */
  9994.         getByClassName: function (cl) {
  9995.             var found = [];
  9996.             var search = function (node, cl) {
  9997.                 if (node.classList.indexOf(cl) != -1) {
  9998.                     found.push(node);
  9999.                 } else if (node.children) {
  10000.                     node.children.forEach(function (child) {
  10001.                         search(child, cl);
  10002.                     });
  10003.                 }
  10004.                 return found;
  10005.             };
  10006.             return search(this, cl);
  10007.         },
  10008.  
  10009.         /**
  10010.             * Recursively search for children of a specific type,
  10011.             * e.g. Two.Polygon. Pass a reference to this type as the param.
  10012.             * Returns an empty array if none found.
  10013.             */
  10014.         getByType: function (type) {
  10015.             var found = [];
  10016.             var search = function (node, type) {
  10017.                 for (var id in node.children) {
  10018.                     if (node.children[id] instanceof type) {
  10019.                         found.push(node.children[id]);
  10020.                     } else if (node.children[id] instanceof Two.Group) {
  10021.                         search(node.children[id], type);
  10022.                     }
  10023.                 }
  10024.                 return found;
  10025.             };
  10026.             return search(this, type);
  10027.         },
  10028.  
  10029.         /**
  10030.             * Add objects to the group.
  10031.             */
  10032.         add: function (objects) {
  10033.  
  10034.             // Allow to pass multiple objects either as array or as multiple arguments
  10035.             // If it's an array also create copy of it in case we're getting passed
  10036.             // a childrens array directly.
  10037.             if (!(objects instanceof Array)) {
  10038.                 objects = _.toArray(arguments);
  10039.             } else {
  10040.                 objects = objects.slice();
  10041.             }
  10042.  
  10043.             // Add the objects
  10044.             for (var i = 0; i < objects.length; i++) {
  10045.                 if (!(objects[i] && objects[i].id)) continue;
  10046.                 this.children.push(objects[i]);
  10047.             }
  10048.  
  10049.             return this;
  10050.  
  10051.         },
  10052.  
  10053.         /**
  10054.             * Remove objects from the group.
  10055.             */
  10056.         remove: function (objects) {
  10057.  
  10058.             var l = arguments.length,
  10059.                 grandparent = this.parent;
  10060.  
  10061.             // Allow to call remove without arguments
  10062.             // This will detach the object from the scene.
  10063.             if (l <= 0 && grandparent) {
  10064.                 grandparent.remove(this);
  10065.                 return this;
  10066.             }
  10067.  
  10068.             // Allow to pass multiple objects either as array or as multiple arguments
  10069.             // If it's an array also create copy of it in case we're getting passed
  10070.             // a childrens array directly.
  10071.             if (!(objects instanceof Array)) {
  10072.                 objects = _.toArray(arguments);
  10073.             } else {
  10074.                 objects = objects.slice();
  10075.             }
  10076.  
  10077.             // Remove the objects
  10078.             for (var i = 0; i < objects.length; i++) {
  10079.                 if (!objects[i] || !(this.children.ids[objects[i].id])) continue;
  10080.                 this.children.splice(_.indexOf(this.children, objects[i]), 1);
  10081.             }
  10082.  
  10083.             return this;
  10084.  
  10085.         },
  10086.  
  10087.         /**
  10088.             * Return an object with top, left, right, bottom, width, and height
  10089.             * parameters of the group.
  10090.             */
  10091.         getBoundingClientRect: function (shallow) {
  10092.             var rect;
  10093.  
  10094.             // TODO: Update this to not __always__ update. Just when it needs to.
  10095.             this._update(true);
  10096.  
  10097.             // Variables need to be defined here, because of nested nature of groups.
  10098.             var left = Infinity, right = -Infinity,
  10099.                 top = Infinity, bottom = -Infinity;
  10100.  
  10101.             this.children.forEach(function (child) {
  10102.  
  10103.                 if (/(linear-gradient|radial-gradient|gradient)/.test(child._renderer.type)) {
  10104.                     return;
  10105.                 }
  10106.  
  10107.                 rect = child.getBoundingClientRect(shallow);
  10108.  
  10109.                 if (!_.isNumber(rect.top) || !_.isNumber(rect.left) ||
  10110.                     !_.isNumber(rect.right) || !_.isNumber(rect.bottom)) {
  10111.                     return;
  10112.                 }
  10113.  
  10114.                 top = min(rect.top, top);
  10115.                 left = min(rect.left, left);
  10116.                 right = max(rect.right, right);
  10117.                 bottom = max(rect.bottom, bottom);
  10118.  
  10119.             }, this);
  10120.  
  10121.             return {
  10122.                 top: top,
  10123.                 left: left,
  10124.                 right: right,
  10125.                 bottom: bottom,
  10126.                 width: right - left,
  10127.                 height: bottom - top
  10128.             };
  10129.  
  10130.         },
  10131.  
  10132.         /**
  10133.             * Trickle down of noFill
  10134.             */
  10135.         noFill: function () {
  10136.             this.children.forEach(function (child) {
  10137.                 child.noFill();
  10138.             });
  10139.             return this;
  10140.         },
  10141.  
  10142.         /**
  10143.             * Trickle down of noStroke
  10144.             */
  10145.         noStroke: function () {
  10146.             this.children.forEach(function (child) {
  10147.                 child.noStroke();
  10148.             });
  10149.             return this;
  10150.         },
  10151.  
  10152.         /**
  10153.             * Trickle down subdivide
  10154.             */
  10155.         subdivide: function () {
  10156.             var args = arguments;
  10157.             this.children.forEach(function (child) {
  10158.                 child.subdivide.apply(child, args);
  10159.             });
  10160.             return this;
  10161.         },
  10162.  
  10163.         flagReset: function () {
  10164.  
  10165.             if (this._flagAdditions) {
  10166.                 this.additions.length = 0;
  10167.                 this._flagAdditions = false;
  10168.             }
  10169.  
  10170.             if (this._flagSubtractions) {
  10171.                 this.subtractions.length = 0;
  10172.                 this._flagSubtractions = false;
  10173.             }
  10174.  
  10175.             this._flagOrder = this._flagMask = this._flagOpacity = false;
  10176.  
  10177.             Two.Shape.prototype.flagReset.call(this);
  10178.  
  10179.             return this;
  10180.  
  10181.         }
  10182.  
  10183.     });
  10184.  
  10185.     Group.MakeObservable(Group.prototype);
  10186.  
  10187.     /**
  10188.         * Helper function used to sync parent-child relationship within the
  10189.         * `Two.Group.children` object.
  10190.         *
  10191.         * Set the parent of the passed object to another object
  10192.         * and updates parent-child relationships
  10193.         * Calling with one arguments will simply remove the parenting
  10194.         */
  10195.     function replaceParent(child, newParent) {
  10196.  
  10197.         var parent = child.parent;
  10198.         var index;
  10199.  
  10200.         if (parent === newParent) {
  10201.             this.additions.push(child);
  10202.             this._flagAdditions = true;
  10203.             return;
  10204.         }
  10205.  
  10206.         if (parent && parent.children.ids[child.id]) {
  10207.  
  10208.             index = _.indexOf(parent.children, child);
  10209.             parent.children.splice(index, 1);
  10210.  
  10211.             // If we're passing from one parent to another...
  10212.             index = _.indexOf(parent.additions, child);
  10213.  
  10214.             if (index >= 0) {
  10215.                 parent.additions.splice(index, 1);
  10216.             } else {
  10217.                 parent.subtractions.push(child);
  10218.                 parent._flagSubtractions = true;
  10219.             }
  10220.  
  10221.         }
  10222.  
  10223.         if (newParent) {
  10224.             child.parent = newParent;
  10225.             this.additions.push(child);
  10226.             this._flagAdditions = true;
  10227.             return;
  10228.         }
  10229.  
  10230.         // If we're passing from one parent to another...
  10231.         index = _.indexOf(this.additions, child);
  10232.  
  10233.         if (index >= 0) {
  10234.             this.additions.splice(index, 1);
  10235.         } else {
  10236.             this.subtractions.push(child);
  10237.             this._flagSubtractions = true;
  10238.         }
  10239.  
  10240.         delete child.parent;
  10241.  
  10242.     }
  10243.  
  10244. })((typeof global !== 'undefined' ? global : this).Two);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement