From 8f8f1534a584dbb0f9d687fe6c0c81d23c78e9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Fri, 8 Feb 2013 19:15:10 -0800 Subject: [PATCH] Replace accidentally checked in compiled library with load.sh version. --- dist/paper.js | 9974 +------------------------------------------------ 1 file changed, 6 insertions(+), 9968 deletions(-) diff --git a/dist/paper.js b/dist/paper.js index 7dba3637..5696e26a 100644 --- a/dist/paper.js +++ b/dist/paper.js @@ -1,9969 +1,7 @@ -/*! - * Paper.js v0.3 - The Swiss Army Knife of Vector Graphics Scripting. - * http://paperjs.org/ - * - * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey - * http://lehni.org/ & http://jonathanpuckey.com/ - * - * Distributed under the MIT license. See LICENSE file for details. - * - * All rights reserved. - * - * Date: Mon Jan 28 17:32:46 2013 -0800 - * - *** - * - * Bootstrap.js JavaScript Framework. - * http://bootstrapjs.org/ - * - * Copyright (c) 2006 - 2011 Juerg Lehni - * http://lehni.org/ - * - * Distributed under the MIT license. - * - *** - * - * Acorn.js - * http://marijnhaverbeke.nl/acorn/ - * - * Acorn is a tiny, fast JavaScript parser written in JavaScript. - * - * Acorn was written by Marijn Haverbeke and released under an MIT - * license. - * - */ +// Paper.js loader for development, as produced by the build/load.sh script +document.write(''); +document.write(''); -var paper = new function() { - -var Base = new function() { - var hidden = /^(statics|generics|preserve|enumerable|prototype|toString|valueOf)$/, - proto = Object.prototype, - toString = proto.toString, - proto = Array.prototype, - isArray = Array.isArray = Array.isArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }, - slice = proto.slice, - forEach = proto.forEach || function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) - iter.call(bind, this[i], i, this); - }, - forIn = function(iter, bind) { - for (var i in this) - if (this.hasOwnProperty(i)) - iter.call(bind, this[i], i, this); - }, - create = Object.create || function(proto) { - return { __proto__: proto }; - }, - _define = Object.defineProperty, - _describe = Object.getOwnPropertyDescriptor; - - function define(obj, name, desc) { - if (_define) { - try { - delete obj[name]; - return _define(obj, name, desc); - } catch (e) {} - } - if ((desc.get || desc.set) && obj.__defineGetter__) { - desc.get && obj.__defineGetter__(name, desc.get); - desc.set && obj.__defineSetter__(name, desc.set); - } else { - obj[name] = desc.value; - } - return obj; - } - - function describe(obj, name) { - if (_describe) { - try { - return _describe(obj, name); - } catch (e) {} - } - var get = obj.__lookupGetter__ && obj.__lookupGetter__(name); - return get - ? { get: get, set: obj.__lookupSetter__(name), enumerable: true, - configurable: true } - : obj.hasOwnProperty(name) - ? { value: obj[name], enumerable: true, configurable: true, - writable: true } - : null; - } - - function inject(dest, src, enumerable, base, preserve, generics) { - var beans, bean; - - function field(name, val, dontCheck, generics) { - var val = val || (val = describe(src, name)) - && (val.get ? val : val.value), - func = typeof val === 'function', - res = val, - prev = preserve || func - ? (val && val.get ? name in dest : dest[name]) : null; - if ((dontCheck || val !== undefined && src.hasOwnProperty(name)) - && (!preserve || !prev)) { - if (func) { - if (prev && /\bthis\.base\b/.test(val)) { - var fromBase = base && base[name] == prev; - res = function() { - var tmp = describe(this, 'base'); - define(this, 'base', { value: fromBase - ? base[name] : prev, configurable: true }); - try { - return val.apply(this, arguments); - } finally { - tmp ? define(this, 'base', tmp) - : delete this.base; - } - }; - res.toString = function() { - return val.toString(); - }; - res.valueOf = function() { - return val.valueOf(); - }; - } - if (beans && val.length === 0 - && (bean = name.match(/^(get|is)(([A-Z])(.*))$/))) - beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]); - } - if (!res || func || !res.get) - res = { value: res, writable: true }; - if ((describe(dest, name) - || { configurable: true }).configurable) { - res.configurable = true; - res.enumerable = enumerable; - } - define(dest, name, res); - } - if (generics && func && (!preserve || !generics[name])) { - generics[name] = function(bind) { - return bind && dest[name].apply(bind, - slice.call(arguments, 1)); - }; - } - } - if (src) { - beans = []; - for (var name in src) - if (src.hasOwnProperty(name) && !hidden.test(name)) - field(name, null, true, generics); - field('toString'); - field('valueOf'); - for (var i = 0, l = beans && beans.length; i < l; i++) - try { - var bean = beans[i], part = bean[1]; - field(bean[0], { - get: dest['get' + part] || dest['is' + part], - set: dest['set' + part] - }, true); - } catch (e) {} - } - return dest; - } - - function each(obj, iter, bind, asArray) { - try { - if (obj) - (asArray || asArray === undefined && isArray(obj) - ? forEach : forIn).call(obj, iter, bind = bind || obj); - } catch (e) { - if (e !== Base.stop) throw e; - } - return bind; - } - - function clone(obj) { - return each(obj, function(val, i) { - this[i] = val; - }, new obj.constructor()); - } - - return inject(function() {}, { - inject: function(src) { - if (src) { - var proto = this.prototype, - base = Object.getPrototypeOf(proto).constructor, - statics = src.statics === true ? src : src.statics; - if (statics != src) - inject(proto, src, src.enumerable, base && base.prototype, - src.preserve, src.generics && this); - inject(this, statics, true, base, src.preserve); - } - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - }, - - extend: function(src) { - var ctor = function() { - if (this.initialize) - return this.initialize.apply(this, arguments); - }; - ctor.prototype = create(this.prototype); - ctor.toString = function() { - return (this.prototype.initialize || function() {}).toString(); - }; - define(ctor.prototype, 'constructor', - { value: ctor, writable: true, configurable: true }); - inject(ctor, this, true); - return arguments.length ? this.inject.apply(ctor, arguments) : ctor; - } - }, true).inject({ - inject: function() { - for (var i = 0, l = arguments.length; i < l; i++) - inject(this, arguments[i], arguments[i].enumerable); - return this; - }, - - extend: function() { - var res = create(this); - return res.inject.apply(res, arguments); - }, - - each: function(iter, bind) { - return each(this, iter, bind); - }, - - clone: function() { - return clone(this); - }, - - statics: { - each: each, - clone: clone, - define: define, - describe: describe, - - create: function(ctor) { - return create(ctor.prototype); - }, - - isPlainObject: function(obj) { - var proto = obj !== null && typeof obj === 'object' - && Object.getPrototypeOf(obj); - return proto && (proto === Object.prototype - || proto === Base.prototype); - }, - - check: function(obj) { - return !!(obj || obj === 0); - }, - - pick: function() { - for (var i = 0, l = arguments.length; i < l; i++) - if (arguments[i] !== undefined) - return arguments[i]; - return null; - }, - - stop: {} - } - }); -}; - -this.Base = Base.inject({ - generics: true, - - clone: function() { - return new this.constructor(this); - }, - - toString: function() { - return '{ ' + Base.each(this, function(value, key) { - if (!/^_/.test(key)) { - var type = typeof value; - this.push(key + ': ' + (type === 'number' - ? Base.formatFloat(value) - : type === 'string' ? "'" + value + "'" : value)); - } - }, []).join(', ') + ' }'; - }, - - toJson: function() { - return Base.toJson(this); - }, - - statics: { - - _types: {}, - - extend: function(src) { - var res = this.base.apply(this, arguments); - if (src._type) - Base._types[src._type] = res; - return res; - }, - - equals: function(obj1, obj2) { - if (obj1 == obj2) - return true; - if (obj1 != null && obj1.equals) - return obj1.equals(obj2); - if (obj2 != null && obj2.equals) - return obj2.equals(obj1); - if (Array.isArray(obj1) && Array.isArray(obj2)) { - if (obj1.length !== obj2.length) - return false; - for (var i = 0, l = obj1.length; i < l; i++) { - if (!Base.equals(obj1[i], obj2[i])) - return false; - } - return true; - } - if (typeof obj1 === 'object' && typeof obj2 === 'object') { - function checkKeys(o1, o2) { - for (var i in o1) - if (o1.hasOwnProperty(i) && typeof o2[i] === 'undefined') - return false; - return true; - } - if (!checkKeys(obj1, obj2) || !checkKeys(obj2, obj1)) - return false; - for (var i in obj1) { - if (obj1.hasOwnProperty(i) && !Base.equals(obj1[i], obj2[i])) - return false; - } - return true; - } - return false; - }, - - read: function(list, start, length, clone, readNull) { - if (this === Base) { - var value = this.peek(list, start); - list._index++; - list._read = 1; - return value; - } - var proto = this.prototype, - readIndex = proto._readIndex, - index = start || readIndex && list._index || 0; - if (!length) - length = list.length - index; - var obj = list[index]; - if (obj instanceof this - || (proto._readNull || readNull) && obj == null && length <= 1) { - if (readIndex) - list._index = index + 1; - return obj && clone ? obj.clone() : obj; - } - obj = Base.create(this); - if (readIndex) - obj._read = true; - obj = obj.initialize.apply(obj, index > 0 || length < list.length - ? Array.prototype.slice.call(list, index, index + length) - : list) || obj; - if (readIndex) { - list._index = index + obj._read; - list._read = obj._read; - delete obj._read; - } - return obj; - }, - - peek: function(list, start) { - return list[list._index = start || list._index || 0]; - }, - - readAll: function(list, start, clone) { - var res = [], entry; - for (var i = start || 0, l = list.length; i < l; i++) { - res.push(Array.isArray(entry = list[i]) - ? this.read(entry, 0, 0, clone) - : this.read(list, i, 1, clone)); - } - return res; - }, - - readNamed: function(list, name, filter) { - var value = this.getNamed(list, name), - hasObject = value !== undefined; - if (hasObject && filter !== false) { - if (!list._filtered) - list._filtered = Base.merge(list[0]); - delete list._filtered[name]; - } - return this.read(hasObject ? [value] : list); - }, - - getNamed: function(list, name) { - var arg = list[0]; - if (list._hasObject === undefined) - list._hasObject = list.length === 1 && Base.isPlainObject(arg); - if (list._hasObject) { - value = arg[name]; - return value !== undefined ? value : null; - } - }, - - hasNamed: function(list, name) { - return !!this.getNamed(list, name); - }, - - serialize: function(obj, compact) { - if (obj && obj._serialize) { - var res = obj._serialize(); - if (!compact && res[0] !== obj._type) - res.unshift(obj._type); - return res; - } - if (typeof obj !== 'object') - return obj; - var res = obj; - if (Array.isArray(obj)) { - res = []; - for (var i = 0, l = obj.length; i < l; i++) - res[i] = Base.serialize(obj[i], true); - } else if (Base.isPlainObject(obj)) { - res = {}; - for (var i in obj) - if (obj.hasOwnProperty(i)) - res[i] = Base.serialize(obj[i], true); - } - return res; - }, - - deserialize: function(obj) { - var res = obj; - if (Array.isArray(obj)) { - var type = Base._types[obj[0]]; - res = []; - for (var i = type ? 1 : 0, l = obj.length; i < l; i++) - res.push(Base.deserialize(obj[i])); - if (type) { - var args = res; - res = Base.create(type); - res.initialize.apply(res, args); - } - } else if (Base.isPlainObject(obj)) { - res = {}; - for (var key in obj) - res[key] = Base.deserialize(obj[key]); - } - return res; - }, - - toJson: function(obj) { - return JSON.stringify(Base.serialize(obj)); - }, - - fromJson: function(json) { - return Base.deserialize(JSON.parse(json)); - }, - - splice: function(list, items, index, remove) { - var amount = items && items.length, - append = index === undefined; - index = append ? list.length : index; - for (var i = 0; i < amount; i++) - items[i]._index = index + i; - if (append) { - list.push.apply(list, items); - return []; - } else { - var args = [index, remove]; - if (items) - args.push.apply(args, items); - var removed = list.splice.apply(list, args); - for (var i = 0, l = removed.length; i < l; i++) - delete removed[i]._index; - for (var i = index + amount, l = list.length; i < l; i++) - list[i]._index = i; - return removed; - } - }, - - merge: function() { - return Base.each(arguments, function(hash) { - Base.each(hash, function(value, key) { - this[key] = value; - }, this); - }, new Base(), true); - }, - - capitalize: function(str) { - return str.replace(/\b[a-z]/g, function(match) { - return match.toUpperCase(); - }); - }, - - camelize: function(str) { - return str.replace(/-(.)/g, function(all, chr) { - return chr.toUpperCase(); - }); - }, - - hyphenate: function(str) { - return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - }, - - formatFloat: function(num) { - return (Math.round(num * 100000) / 100000).toString(); - }, - - toFloat: function(str) { - return parseFloat(str, 10); - } - } -}); - -var Callback = { - attach: function(type, func) { - if (typeof type !== 'string') { - return Base.each(type, function(value, key) { - this.attach(key, value); - }, this); - } - var entry = this._eventTypes[type]; - if (!entry) - return this; - var handlers = this._handlers = this._handlers || {}; - handlers = handlers[type] = handlers[type] || []; - if (handlers.indexOf(func) == -1) { - handlers.push(func); - if (entry.install && handlers.length == 1) - entry.install.call(this, type); - } - return this; - }, - - detach: function(type, func) { - if (typeof type !== 'string') { - return Base.each(type, function(value, key) { - this.detach(key, value); - }, this); - } - var entry = this._eventTypes[type], - handlers = this._handlers && this._handlers[type], - index; - if (entry && handlers) { - if (!func || (index = handlers.indexOf(func)) != -1 - && handlers.length == 1) { - if (entry.uninstall) - entry.uninstall.call(this, type); - delete this._handlers[type]; - } else if (index != -1) { - handlers.splice(index, 1); - } - } - return this; - }, - - fire: function(type, event) { - var handlers = this._handlers && this._handlers[type]; - if (!handlers) - return false; - var args = [].slice.call(arguments, 1); - Base.each(handlers, function(func) { - if (func.apply(this, args) === false && event && event.stop) - event.stop(); - }, this); - return true; - }, - - responds: function(type) { - return !!(this._handlers && this._handlers[type]); - }, - - statics: { - inject: function() { - for (var i = 0, l = arguments.length; i < l; i++) { - var src = arguments[i], - events = src._events; - if (events) { - var types = {}; - Base.each(events, function(entry, key) { - var isString = typeof entry === 'string', - name = isString ? entry : key, - part = Base.capitalize(name), - type = name.substring(2).toLowerCase(); - types[type] = isString ? {} : entry; - name = '_' + name; - src['get' + part] = function() { - return this[name]; - }; - src['set' + part] = function(func) { - if (func) { - this.attach(type, func); - } else if (this[name]) { - this.detach(type, this[name]); - } - this[name] = func; - }; - }); - src._eventTypes = types; - } - this.base(src); - } - return this; - } - } -}; - -var PaperScope = this.PaperScope = Base.extend({ - - initialize: function(script) { - paper = this; - this.project = null; - this.projects = []; - this.tools = []; - this.palettes = []; - this._id = script && (script.getAttribute('id') || script.src) - || ('paperscope-' + (PaperScope._id++)); - if (script) - script.setAttribute('id', this._id); - PaperScope._scopes[this._id] = this; - }, - - version: 0.3, - - getView: function() { - return this.project && this.project.view; - }, - - getTool: function() { - if (!this._tool) - this._tool = new Tool(); - return this._tool; - }, - - evaluate: function(code) { - var res = PaperScript.evaluate(code, this); - View.updateFocus(); - return res; - }, - - install: function(scope) { - var that = this; - Base.each(['project', 'view', 'tool'], function(key) { - Base.define(scope, key, { - configurable: true, - writable: true, - get: function() { - return that[key]; - } - }); - }); - for (var key in this) { - if (!/^(version|_id|load)/.test(key) && !(key in scope)) - scope[key] = this[key]; - } - }, - - setup: function(canvas) { - paper = this; - this.project = new Project(canvas); - }, - - clear: function() { - for (var i = this.projects.length - 1; i >= 0; i--) - this.projects[i].remove(); - for (var i = this.tools.length - 1; i >= 0; i--) - this.tools[i].remove(); - for (var i = this.palettes.length - 1; i >= 0; i--) - this.palettes[i].remove(); - }, - - remove: function() { - this.clear(); - delete PaperScope._scopes[this._id]; - }, - - statics: { - _scopes: {}, - _id: 0, - - get: function(id) { - if (typeof id === 'object') - id = id.getAttribute('id'); - return this._scopes[id] || null; - } - } -}); - -var PaperScopeItem = Base.extend(Callback, { - - initialize: function(activate) { - this._scope = paper; - this._index = this._scope[this._list].push(this) - 1; - if (activate || !this._scope[this._reference]) - this.activate(); - }, - - activate: function() { - if (!this._scope) - return false; - var prev = this._scope[this._reference]; - if (prev && prev != this) - prev.fire('deactivate'); - this._scope[this._reference] = this; - this.fire('activate', prev); - return true; - }, - - isActive: function() { - return this._scope[this._reference] === this; - }, - - remove: function() { - if (this._index == null) - return false; - Base.splice(this._scope[this._list], null, this._index, 1); - if (this._scope[this._reference] == this) - this._scope[this._reference] = null; - this._scope = null; - return true; - } -}); - -var Point = this.Point = Base.extend({ - _readIndex: true, - - initialize: function(arg0, arg1) { - var type = typeof arg0; - if (type === 'number') { - var hasY = typeof arg1 === 'number'; - this.x = arg0; - this.y = hasY ? arg1 : arg0; - if (this._read) - this._read = hasY ? 2 : 1; - } else if (type === 'undefined' || arg0 === null) { - this.x = this.y = 0; - if (this._read) - this._read = arg0 === null ? 1 : 0; - } else { - if (Array.isArray(arg0)) { - this.x = arg0[0]; - this.y = arg0.length > 1 ? arg0[1] : arg0[0]; - } else if (arg0.x != null) { - this.x = arg0.x; - this.y = arg0.y; - } else if (arg0.width != null) { - this.x = arg0.width; - this.y = arg0.height; - } else if (arg0.angle != null) { - this.x = arg0.length; - this.y = 0; - this.setAngle(arg0.angle); - } else { - this.x = this.y = 0; - if (this._read) - this._read = 0; - } - if (this._read) - this._read = 1; - } - }, - - _serialize: function() { - return [this.x, this.y]; - }, - - set: function(x, y) { - this.x = x; - this.y = y; - return this; - }, - - clone: function() { - return Point.create(this.x, this.y); - }, - - toString: function() { - var format = Base.formatFloat; - return '{ x: ' + format(this.x) + ', y: ' + format(this.y) + ' }'; - }, - - add: function(point) { - point = Point.read(arguments); - return Point.create(this.x + point.x, this.y + point.y); - }, - - subtract: function(point) { - point = Point.read(arguments); - return Point.create(this.x - point.x, this.y - point.y); - }, - - multiply: function(point) { - point = Point.read(arguments); - return Point.create(this.x * point.x, this.y * point.y); - }, - - divide: function(point) { - point = Point.read(arguments); - return Point.create(this.x / point.x, this.y / point.y); - }, - - modulo: function(point) { - point = Point.read(arguments); - return Point.create(this.x % point.x, this.y % point.y); - }, - - negate: function() { - return Point.create(-this.x, -this.y); - }, - - transform: function(matrix) { - return matrix ? matrix._transformPoint(this) : this; - }, - - getDistance: function(point, squared) { - point = Point.read(arguments); - var x = point.x - this.x, - y = point.y - this.y, - d = x * x + y * y; - return squared ? d : Math.sqrt(d); - }, - - getLength: function() { - var l = this.x * this.x + this.y * this.y; - return arguments.length && arguments[0] ? l : Math.sqrt(l); - }, - - setLength: function(length) { - if (this.isZero()) { - var angle = this._angle || 0; - this.set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } else { - var scale = length / this.getLength(); - if (scale == 0) - this.getAngle(); - this.set( - this.x * scale, - this.y * scale - ); - } - return this; - }, - - normalize: function(length) { - if (length === undefined) - length = 1; - var current = this.getLength(), - scale = current != 0 ? length / current : 0, - point = Point.create(this.x * scale, this.y * scale); - point._angle = this._angle; - return point; - }, - - getAngle: function() { - return this.getAngleInRadians(arguments[0]) * 180 / Math.PI; - }, - - setAngle: function(angle) { - angle = this._angle = angle * Math.PI / 180; - if (!this.isZero()) { - var length = this.getLength(); - this.set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } - return this; - }, - - getAngleInRadians: function() { - if (arguments[0] === undefined) { - if (this._angle == null) - this._angle = Math.atan2(this.y, this.x); - return this._angle; - } else { - var point = Point.read(arguments), - div = this.getLength() * point.getLength(); - if (Numerical.isZero(div)) { - return NaN; - } else { - return Math.acos(this.dot(point) / div); - } - } - }, - - getAngleInDegrees: function() { - return this.getAngle(arguments[0]); - }, - - getQuadrant: function() { - return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3; - }, - - getDirectedAngle: function(point) { - point = Point.read(arguments); - return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI; - }, - - rotate: function(angle, center) { - if (angle === 0) - return this.clone(); - angle = angle * Math.PI / 180; - var point = center ? this.subtract(center) : this, - s = Math.sin(angle), - c = Math.cos(angle); - point = Point.create( - point.x * c - point.y * s, - point.y * c + point.x * s - ); - return center ? point.add(center) : point; - }, - - equals: function(point) { - point = Point.read(arguments); - return this.x == point.x && this.y == point.y; - }, - - isInside: function(rect) { - return rect.contains(this); - }, - - isClose: function(point, tolerance) { - return this.getDistance(point) < tolerance; - }, - - isColinear: function(point) { - return this.cross(point) < 0.00001; - }, - - isOrthogonal: function(point) { - return this.dot(point) < 0.00001; - }, - - isZero: function() { - return Numerical.isZero(this.x) && Numerical.isZero(this.y); - }, - - isNaN: function() { - return isNaN(this.x) || isNaN(this.y); - }, - - dot: function(point) { - point = Point.read(arguments); - return this.x * point.x + this.y * point.y; - }, - - cross: function(point) { - point = Point.read(arguments); - return this.x * point.y - this.y * point.x; - }, - - project: function(point) { - point = Point.read(arguments); - if (point.isZero()) { - return Point.create(0, 0); - } else { - var scale = this.dot(point) / point.dot(point); - return Point.create( - point.x * scale, - point.y * scale - ); - } - }, - - statics: { - create: function(x, y) { - var point = Base.create(Point); - point.x = x; - point.y = y; - return point; - }, - - min: function(point1, point2) { - var _point1 = Point.read(arguments); - _point2 = Point.read(arguments); - return Point.create( - Math.min(_point1.x, _point2.x), - Math.min(_point1.y, _point2.y) - ); - }, - - max: function(point1, point2) { - var _point1 = Point.read(arguments); - _point2 = Point.read(arguments); - return Point.create( - Math.max(_point1.x, _point2.x), - Math.max(_point1.y, _point2.y) - ); - }, - - random: function() { - return Point.create(Math.random(), Math.random()); - } - } -}, new function() { - - return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { - var op = Math[name]; - this[name] = function() { - return Point.create(op(this.x), op(this.y)); - }; - }, {}); -}); - -var LinkedPoint = Point.extend({ - set: function(x, y, dontNotify) { - this._x = x; - this._y = y; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner[this._setter](this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner[this._setter](this); - }, - - statics: { - create: function(owner, setter, x, y, dontLink) { - if (dontLink) - return Point.create(x, y); - var point = Base.create(LinkedPoint); - point._x = x; - point._y = y; - point._owner = owner; - point._setter = setter; - return point; - } - } -}); - -var Size = this.Size = Base.extend({ - _readIndex: true, - - initialize: function(arg0, arg1) { - var type = typeof arg0; - if (type === 'number') { - var hasHeight = typeof arg1 === 'number'; - this.width = arg0; - this.height = hasHeight ? arg1 : arg0; - if (this._read) - this._read = hasHeight ? 2 : 1; - } else if (type === 'undefined' || arg0 === null) { - this.width = this.height = 0; - if (this._read) - this._read = arg0 === null ? 1 : 0; - } else { - if (Array.isArray(arg0)) { - this.width = arg0[0]; - this.height = arg0.length > 1 ? arg0[1] : arg0[0]; - } else if (arg0.width != null) { - this.width = arg0.width; - this.height = arg0.height; - } else if (arg0.x != null) { - this.width = arg0.x; - this.height = arg0.y; - } else { - this.width = this.height = 0; - if (this._read) - this._read = 0; - } - if (this._read) - this._read = 1; - } - }, - - toString: function() { - var format = Base.formatFloat; - return '{ width: ' + format(this.width) - + ', height: ' + format(this.height) + ' }'; - }, - - set: function(width, height) { - this.width = width; - this.height = height; - return this; - }, - - clone: function() { - return Size.create(this.width, this.height); - }, - - add: function(size) { - size = Size.read(arguments); - return Size.create(this.width + size.width, this.height + size.height); - }, - - subtract: function(size) { - size = Size.read(arguments); - return Size.create(this.width - size.width, this.height - size.height); - }, - - multiply: function(size) { - size = Size.read(arguments); - return Size.create(this.width * size.width, this.height * size.height); - }, - - divide: function(size) { - size = Size.read(arguments); - return Size.create(this.width / size.width, this.height / size.height); - }, - - modulo: function(size) { - size = Size.read(arguments); - return Size.create(this.width % size.width, this.height % size.height); - }, - - negate: function() { - return Size.create(-this.width, -this.height); - }, - - equals: function(size) { - size = Size.read(arguments); - return this.width == size.width && this.height == size.height; - }, - - isZero: function() { - return Numerical.isZero(this.width) && Numerical.isZero(this.height); - }, - - isNaN: function() { - return isNaN(this.width) || isNaN(this.height); - }, - - statics: { - create: function(width, height) { - return Base.create(Size).set(width, height); - }, - - min: function(size1, size2) { - return Size.create( - Math.min(size1.width, size2.width), - Math.min(size1.height, size2.height)); - }, - - max: function(size1, size2) { - return Size.create( - Math.max(size1.width, size2.width), - Math.max(size1.height, size2.height)); - }, - - random: function() { - return Size.create(Math.random(), Math.random()); - } - } -}, new function() { - - return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { - var op = Math[name]; - this[name] = function() { - return Size.create(op(this.width), op(this.height)); - }; - }, {}); -}); - -var LinkedSize = Size.extend({ - set: function(width, height, dontNotify) { - this._width = width; - this._height = height; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - getWidth: function() { - return this._width; - }, - - setWidth: function(width) { - this._width = width; - this._owner[this._setter](this); - }, - - getHeight: function() { - return this._height; - }, - - setHeight: function(height) { - this._height = height; - this._owner[this._setter](this); - }, - - statics: { - create: function(owner, setter, width, height, dontLink) { - if (dontLink) - return Size.create(width, height); - var size = Base.create(LinkedSize); - size._width = width; - size._height = height; - size._owner = owner; - size._setter = setter; - return size; - } - } -}); - -var Rectangle = this.Rectangle = Base.extend({ - _readIndex: true, - - initialize: function(arg0, arg1, arg2, arg3) { - var type = typeof arg0; - if (type === 'number') { - this.x = arg0; - this.y = arg1; - this.width = arg2; - this.height = arg3; - if (this._read) - this._read = 4; - } else if (type === 'undefined' || arg0 === null) { - this.x = this.y = this.width = this.height = 0; - if (this._read) - this._read = arg0 === null ? 1 : 0; - } else { - var args = arguments, - center = null; - if (arguments.length == 1) { - args = null; - if (Array.isArray(arg0)) { - this.x = arg0[0]; - this.y = arg0[1]; - this.width = arg0[2]; - this.height = arg0[3]; - } else { - if (arg0.size) { - args = [Point.read([arg0.point]), Size.read([arg0.size])]; - if (arg0.center) - center = Point.read([arg0.center]); - } else { - this.x = arg0.x || 0; - this.y = arg0.y || 0; - this.width = arg0.width || 0; - this.height = arg0.height || 0; - } - } - if (this._read) - this._read = 1; - } - if (args && args.length > 1) { - var point = Point.read(args), - next = Base.peek(args); - this.x = point.x; - this.y = point.y; - if (next && next.x !== undefined) { - var point2 = Point.read(args); - this.width = point2.x - point.x; - this.height = point2.y - point.y; - if (this.width < 0) { - this.x = point2.x; - this.width = -this.width; - } - if (this.height < 0) { - this.y = point2.y; - this.height = -this.height; - } - } else { - var size = Size.read(args); - this.width = size.width; - this.height = size.height; - } - if (this._read) - this._read = arguments._index; - } - if (center) - this.setCenter(center); - } - }, - - set: function(x, y, width, height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - return this; - }, - - getPoint: function() { - return LinkedPoint.create(this, 'setPoint', this.x, this.y, arguments[0]); - }, - - setPoint: function(point) { - point = Point.read(arguments); - this.x = point.x; - this.y = point.y; - return this; - }, - - getSize: function() { - return LinkedSize.create(this, 'setSize', this.width, this.height, - arguments[0]); - }, - - setSize: function(size) { - size = Size.read(arguments); - this.width = size.width; - this.height = size.height; - return this; - }, - - getLeft: function() { - return this.x; - }, - - setLeft: function(left) { - this.width -= left - this.x; - this.x = left; - return this; - }, - - getTop: function() { - return this.y; - }, - - setTop: function(top) { - this.height -= top - this.y; - this.y = top; - return this; - }, - - getRight: function() { - return this.x + this.width; - }, - - setRight: function(right) { - this.width = right - this.x; - return this; - }, - - getBottom: function() { - return this.y + this.height; - }, - - setBottom: function(bottom) { - this.height = bottom - this.y; - return this; - }, - - getCenterX: function() { - return this.x + this.width * 0.5; - }, - - setCenterX: function(x) { - this.x = x - this.width * 0.5; - return this; - }, - - getCenterY: function() { - return this.y + this.height * 0.5; - }, - - setCenterY: function(y) { - this.y = y - this.height * 0.5; - return this; - }, - - getCenter: function() { - return LinkedPoint.create(this, 'setCenter', - this.getCenterX(), this.getCenterY(), arguments[0]); - }, - - setCenter: function(point) { - point = Point.read(arguments); - return this.setCenterX(point.x).setCenterY(point.y); - }, - - equals: function(rect) { - rect = Rectangle.read(arguments); - return this.x == rect.x && this.y == rect.y - && this.width == rect.width && this.height == rect.height; - }, - - isEmpty: function() { - return this.width == 0 || this.height == 0; - }, - - toString: function() { - var format = Base.formatFloat; - return '{ x: ' + format(this.x) - + ', y: ' + format(this.y) - + ', width: ' + format(this.width) - + ', height: ' + format(this.height) - + ' }'; - }, - - contains: function(arg) { - return arg && arg.width !== undefined - || (Array.isArray(arg) ? arg : arguments).length == 4 - ? this._containsRectangle(Rectangle.read(arguments)) - : this._containsPoint(Point.read(arguments)); - }, - - _containsPoint: function(point) { - var x = point.x, - y = point.y; - return x >= this.x && y >= this.y - && x <= this.x + this.width - && y <= this.y + this.height; - }, - - _containsRectangle: function(rect) { - var x = rect.x, - y = rect.y; - return x >= this.x && y >= this.y - && x + rect.width <= this.x + this.width - && y + rect.height <= this.y + this.height; - }, - - intersects: function(rect) { - rect = Rectangle.read(arguments); - return rect.x + rect.width > this.x - && rect.y + rect.height > this.y - && rect.x < this.x + this.width - && rect.y < this.y + this.height; - }, - - intersect: function(rect) { - rect = Rectangle.read(arguments); - var x1 = Math.max(this.x, rect.x), - y1 = Math.max(this.y, rect.y), - x2 = Math.min(this.x + this.width, rect.x + rect.width), - y2 = Math.min(this.y + this.height, rect.y + rect.height); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - unite: function(rect) { - rect = Rectangle.read(arguments); - var x1 = Math.min(this.x, rect.x), - y1 = Math.min(this.y, rect.y), - x2 = Math.max(this.x + this.width, rect.x + rect.width), - y2 = Math.max(this.y + this.height, rect.y + rect.height); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - include: function(point) { - point = Point.read(arguments); - var x1 = Math.min(this.x, point.x), - y1 = Math.min(this.y, point.y), - x2 = Math.max(this.x + this.width, point.x), - y2 = Math.max(this.y + this.height, point.y); - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - expand: function(hor, ver) { - if (ver === undefined) - ver = hor; - return Rectangle.create(this.x - hor / 2, this.y - ver / 2, - this.width + hor, this.height + ver); - }, - - scale: function(hor, ver) { - return this.expand(this.width * hor - this.width, - this.height * (ver === undefined ? hor : ver) - this.height); - }, - - statics: { - create: function(x, y, width, height) { - return Base.create(Rectangle).set(x, y, width, height); - } - } -}, new function() { - return Base.each([ - ['Top', 'Left'], ['Top', 'Right'], - ['Bottom', 'Left'], ['Bottom', 'Right'], - ['Left', 'Center'], ['Top', 'Center'], - ['Right', 'Center'], ['Bottom', 'Center'] - ], - function(parts, index) { - var part = parts.join(''); - var xFirst = /^[RL]/.test(part); - if (index >= 4) - parts[1] += xFirst ? 'Y' : 'X'; - var x = parts[xFirst ? 0 : 1], - y = parts[xFirst ? 1 : 0], - getX = 'get' + x, - getY = 'get' + y, - setX = 'set' + x, - setY = 'set' + y, - get = 'get' + part, - set = 'set' + part; - this[get] = function() { - return LinkedPoint.create(this, set, - this[getX](), this[getY](), arguments[0]); - }; - this[set] = function(point) { - point = Point.read(arguments); - return this[setX](point.x)[setY](point.y); - }; - }, {}); -}); - -var LinkedRectangle = Rectangle.extend({ - set: function(x, y, width, height, dontNotify) { - this._x = x; - this._y = y; - this._width = width; - this._height = height; - if (!dontNotify) - this._owner[this._setter](this); - return this; - }, - - statics: { - create: function(owner, setter, x, y, width, height) { - var rect = Base.create(LinkedRectangle).set(x, y, width, height, true); - rect._owner = owner; - rect._setter = setter; - return rect; - } - } -}, new function() { - var proto = Rectangle.prototype; - - return Base.each(['x', 'y', 'width', 'height'], function(key) { - var part = Base.capitalize(key); - var internal = '_' + key; - this['get' + part] = function() { - return this[internal]; - }; - - this['set' + part] = function(value) { - this[internal] = value; - if (!this._dontNotify) - this._owner[this._setter](this); - }; - }, Base.each(['Point', 'Size', 'Center', - 'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY', - 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], - function(key) { - var name = 'set' + key; - this[name] = function(value) { - this._dontNotify = true; - proto[name].apply(this, arguments); - delete this._dontNotify; - this._owner[this._setter](this); - return this; - }; - }, {}) - ); -}); - -var Matrix = this.Matrix = Base.extend({ - _type: 'matrix', - - initialize: function(arg) { - var count = arguments.length, - ok = true; - if (count == 6) { - this.set.apply(this, arguments); - } else if (count == 1) { - if (arg instanceof Matrix) { - this.set(arg._a, arg._c, arg._b, arg._d, arg._tx, arg._ty); - } else if (Array.isArray(arg)) { - this.set.apply(this, arg); - } else { - ok = false; - } - } else if (count == 0) { - this.setIdentity(); - } else { - ok = false; - } - if (!ok) - throw new Error('Unsupported matrix parameters'); - }, - - _serialize: function() { - return this.getValues(); - }, - - clone: function() { - return Matrix.create(this._a, this._c, this._b, this._d, - this._tx, this._ty); - }, - - set: function(a, c, b, d, tx, ty) { - this._a = a; - this._c = c; - this._b = b; - this._d = d; - this._tx = tx; - this._ty = ty; - return this; - }, - - setIdentity: function() { - this._a = this._d = 1; - this._c = this._b = this._tx = this._ty = 0; - return this; - }, - - scale: function(scale, center) { - var _scale = Point.read(arguments), - _center = Point.read(arguments); - if (_center) - this.translate(_center); - this._a *= _scale.x; - this._c *= _scale.x; - this._b *= _scale.y; - this._d *= _scale.y; - if (_center) - this.translate(_center.negate()); - return this; - }, - - translate: function(point) { - point = Point.read(arguments); - var x = point.x, - y = point.y; - this._tx += x * this._a + y * this._b; - this._ty += x * this._c + y * this._d; - return this; - }, - - rotate: function(angle, center) { - return this.concatenate( - Matrix.getRotateInstance.apply(Matrix, arguments)); - }, - - shear: function(point, center) { - var _point = Point.read(arguments), - _center = Point.read(arguments); - if (_center) - this.translate(_center); - var a = this._a, - c = this._c; - this._a += _point.y * this._b; - this._c += _point.y * this._d; - this._b += _point.x * a; - this._d += _point.x * c; - if (_center) - this.translate(_center.negate()); - return this; - }, - - toString: function() { - var format = Base.formatFloat; - return '[[' + [format(this._a), format(this._b), - format(this._tx)].join(', ') + '], [' - + [format(this._c), format(this._d), - format(this._ty)].join(', ') + ']]'; - }, - - getValues: function() { - return [ this._a, this._c, this._b, this._d, this._tx, this._ty ]; - }, - - concatenate: function(mx) { - var a = this._a, - b = this._b, - c = this._c, - d = this._d; - this._a = mx._a * a + mx._c * b; - this._b = mx._b * a + mx._d * b; - this._c = mx._a * c + mx._c * d; - this._d = mx._b * c + mx._d * d; - this._tx += mx._tx * a + mx._ty * b; - this._ty += mx._tx * c + mx._ty * d; - return this; - }, - - preConcatenate: function(mx) { - var a = this._a, - b = this._b, - c = this._c, - d = this._d, - tx = this._tx, - ty = this._ty; - this._a = mx._a * a + mx._b * c; - this._b = mx._a * b + mx._b * d; - this._c = mx._c * a + mx._d * c; - this._d = mx._c * b + mx._d * d; - this._tx = mx._a * tx + mx._b * ty + mx._tx; - this._ty = mx._c * tx + mx._d * ty + mx._ty; - return this; - }, - - transform: function( src, srcOff, dst, dstOff, numPts) { - return arguments.length < 5 - ? this._transformPoint(Point.read(arguments)) - : this._transformCoordinates(src, srcOff, dst, dstOff, numPts); - }, - - _transformPoint: function(point, dest, dontNotify) { - var x = point.x, - y = point.y; - if (!dest) - dest = Base.create(Point); - return dest.set( - x * this._a + y * this._b + this._tx, - x * this._c + y * this._d + this._ty, - dontNotify - ); - }, - - _transformCoordinates: function(src, srcOff, dst, dstOff, numPts) { - var i = srcOff, j = dstOff, - srcEnd = srcOff + 2 * numPts; - while (i < srcEnd) { - var x = src[i++]; - var y = src[i++]; - dst[j++] = x * this._a + y * this._b + this._tx; - dst[j++] = x * this._c + y * this._d + this._ty; - } - return dst; - }, - - _transformCorners: function(rect) { - var x1 = rect.x, - y1 = rect.y, - x2 = x1 + rect.width, - y2 = y1 + rect.height, - coords = [ x1, y1, x2, y1, x2, y2, x1, y2 ]; - return this._transformCoordinates(coords, 0, coords, 0, 4); - }, - - _transformBounds: function(bounds, dest, dontNotify) { - var coords = this._transformCorners(bounds), - min = coords.slice(0, 2), - max = coords.slice(0); - for (var i = 2; i < 8; i++) { - var val = coords[i], - j = i & 1; - if (val < min[j]) - min[j] = val; - else if (val > max[j]) - max[j] = val; - } - if (!dest) - dest = Base.create(Rectangle); - return dest.set(min[0], min[1], max[0] - min[0], max[1] - min[1], - dontNotify); - }, - - inverseTransform: function(point) { - return this._inverseTransform(Point.read(arguments)); - }, - - _getDeterminant: function() { - var det = this._a * this._d - this._b * this._c; - return isFinite(det) && !Numerical.isZero(det) - && isFinite(this._tx) && isFinite(this._ty) - ? det : null; - }, - - _inverseTransform: function(point, dest, dontNotify) { - var det = this._getDeterminant(); - if (!det) - return null; - var x = point.x - this._tx, - y = point.y - this._ty; - if (!dest) - dest = Base.create(Point); - return dest.set( - (x * this._d - y * this._b) / det, - (y * this._a - x * this._c) / det, - dontNotify - ); - }, - - getTranslation: function() { - return Point.create(this._tx, this._ty); - }, - - getScaling: function() { - var hor = Math.sqrt(this._a * this._a + this._c * this._c), - ver = Math.sqrt(this._b * this._b + this._d * this._d); - return Point.create(this._a < 0 ? -hor : hor, this._b < 0 ? -ver : ver); - }, - - getRotation: function() { - var angle1 = -Math.atan2(this._b, this._d), - angle2 = Math.atan2(this._c, this._a); - return Math.abs(angle1 - angle2) < 1e-11 - ? angle1 * 180 / Math.PI : undefined; - }, - - equals: function(mx) { - return mx && this._a == mx._a && this._b == mx._b && this._c == mx._c - && this._d == mx._d && this._tx == mx._tx && this._ty == mx._ty; - }, - - isIdentity: function() { - return this._a == 1 && this._c == 0 && this._b == 0 && this._d == 1 - && this._tx == 0 && this._ty == 0; - }, - - isInvertible: function() { - return !!this._getDeterminant(); - }, - - isSingular: function() { - return !this._getDeterminant(); - }, - - createInverse: function() { - var det = this._getDeterminant(); - return det && Matrix.create( - this._d / det, - -this._c / det, - -this._b / det, - this._a / det, - (this._b * this._ty - this._d * this._tx) / det, - (this._c * this._tx - this._a * this._ty) / det); - }, - - createShiftless: function() { - return Matrix.create(this._a, this._c, this._b, this._d, 0, 0); - }, - - setToScale: function(hor, ver) { - return this.set(hor, 0, 0, ver, 0, 0); - }, - - setToTranslation: function(delta) { - delta = Point.read(arguments); - return this.set(1, 0, 0, 1, delta.x, delta.y); - }, - - setToShear: function(hor, ver) { - return this.set(1, ver, hor, 1, 0, 0); - }, - - setToRotation: function(angle, center) { - center = Point.read(arguments, 1); - angle = angle * Math.PI / 180; - var x = center.x, - y = center.y, - cos = Math.cos(angle), - sin = Math.sin(angle); - return this.set(cos, sin, -sin, cos, - x - x * cos + y * sin, - y - x * sin - y * cos); - }, - - applyToContext: function(ctx, reset) { - ctx[reset ? 'setTransform' : 'transform']( - this._a, this._c, this._b, this._d, this._tx, this._ty); - return this; - }, - - statics: { - create: function(a, c, b, d, tx, ty) { - return Base.create(Matrix).set(a, c, b, d, tx, ty); - }, - - getScaleInstance: function(hor, ver) { - var mx = new Matrix(); - return mx.setToScale.apply(mx, arguments); - }, - - getTranslateInstance: function(delta) { - var mx = new Matrix(); - return mx.setToTranslation.apply(mx, arguments); - }, - - getShearInstance: function(hor, ver, center) { - var mx = new Matrix(); - return mx.setToShear.apply(mx, arguments); - }, - - getRotateInstance: function(angle, center) { - var mx = new Matrix(); - return mx.setToRotation.apply(mx, arguments); - } - } -}, new function() { - return Base.each({ - scaleX: '_a', - scaleY: '_d', - translateX: '_tx', - translateY: '_ty', - shearX: '_b', - shearY: '_c' - }, function(prop, name) { - name = Base.capitalize(name); - this['get' + name] = function() { - return this[prop]; - }; - this['set' + name] = function(value) { - this[prop] = value; - }; - }, {}); -}); - -var Line = this.Line = Base.extend({ - initialize: function(point1, point2, infinite) { - var _point1 = Point.read(arguments), - _point2 = Point.read(arguments), - _infinite = Base.read(arguments); - if (_infinite !== undefined) { - this.point = _point1; - this.vector = _point2.subtract(_point1); - this.infinite = _infinite; - } else { - this.point = _point1; - this.vector = _point2; - this.infinite = true; - } - }, - - intersect: function(line) { - var cross = this.vector.cross(line.vector); - if (Numerical.isZero(cross)) - return null; - var v = line.point.subtract(this.point), - t1 = v.cross(line.vector) / cross, - t2 = v.cross(this.vector) / cross; - return (this.infinite || 0 <= t1 && t1 <= 1) - && (line.infinite || 0 <= t2 && t2 <= 1) - ? this.point.add(this.vector.multiply(t1)) : null; - }, - - getSide: function(point) { - var v1 = this.vector, - v2 = point.subtract(this.point), - ccw = v2.cross(v1); - if (ccw === 0) { - ccw = v2.dot(v1); - if (ccw > 0) { - ccw = v2.subtract(v1).dot(v1); - if (ccw < 0) - ccw = 0; - } - } - return ccw < 0 ? -1 : ccw > 0 ? 1 : 0; - }, - - getDistance: function(point) { - var m = this.vector.y / this.vector.x, - b = this.point.y - (m * this.point.x); - var dist = Math.abs(point.y - (m * point.x) - b) / Math.sqrt(m * m + 1); - return this.infinite ? dist : Math.min(dist, - point.getDistance(this.point), - point.getDistance(this.point.add(this.vector))); - } -}); - -var Project = this.Project = PaperScopeItem.extend({ - _list: 'projects', - _reference: 'project', - - initialize: function(view) { - this.base(true); - this.layers = []; - this.symbols = []; - this.activeLayer = new Layer(); - if (view) - this.view = view instanceof View ? view : View.create(view); - this._currentStyle = new PathStyle(); - this._selectedItems = {}; - this._selectedItemCount = 0; - this._drawCount = 0; - }, - - _needsRedraw: function() { - if (this.view) - this.view._redrawNeeded = true; - }, - - remove: function() { - if (!this.base()) - return false; - if (this.view) - this.view.remove(); - return true; - }, - - getCurrentStyle: function() { - return this._currentStyle; - }, - - setCurrentStyle: function(style) { - this._currentStyle.initialize(style); - }, - - getIndex: function() { - return this._index; - }, - - getSelectedItems: function() { - var items = []; - for (var id in this._selectedItems) { - var item = this._selectedItems[id]; - if (item._drawCount === this._drawCount) - items.push(item); - } - return items; - }, - - _updateSelection: function(item) { - if (item._selected) { - this._selectedItemCount++; - this._selectedItems[item._id] = item; - if (item.isInserted()) - item._drawCount = this._drawCount; - } else { - this._selectedItemCount--; - delete this._selectedItems[item._id]; - } - }, - - selectAll: function() { - for (var i = 0, l = this.layers.length; i < l; i++) - this.layers[i].setSelected(true); - }, - - deselectAll: function() { - for (var i in this._selectedItems) - this._selectedItems[i].item.setSelected(false); - }, - - hitTest: function(point, options) { - point = Point.read(arguments); - options = HitResult.getOptions(Base.read(arguments)); - for (var i = this.layers.length - 1; i >= 0; i--) { - var res = this.layers[i].hitTest(point, options); - if (res) return res; - } - return null; - }, - - draw: function(ctx, matrix) { - this._drawCount++; - ctx.save(); - if (!matrix.isIdentity()) - matrix.applyToContext(ctx); - var param = { offset: new Point(0, 0) }; - for (var i = 0, l = this.layers.length; i < l; i++) - Item.draw(this.layers[i], ctx, param); - ctx.restore(); - - if (this._selectedItemCount > 0) { - ctx.save(); - ctx.strokeWidth = 1; - ctx.strokeStyle = ctx.fillStyle = '#009dec'; - var matrices = {}; - function getGlobalMatrix(item, mx, cached) { - var cache = cached && matrices[item._id]; - if (cache) - return cache.clone(); - if (item._parent) - mx = getGlobalMatrix(item._parent, mx, true); - if (!item._matrix.isIdentity()) - mx.concatenate(item._matrix); - if (cached) - matrices[item._id] = mx.clone(); - return mx; - } - for (var id in this._selectedItems) { - var item = this._selectedItems[id]; - if (item._drawCount === this._drawCount) - item.drawSelected(ctx, getGlobalMatrix(item, matrix.clone())); - } - ctx.restore(); - } - } -}); - -var Symbol = this.Symbol = Base.extend({ - initialize: function(item) { - this.project = paper.project; - this.project.symbols.push(this); - this.setDefinition(item); - this._instances = {}; - }, - - _changed: function(flags) { - Base.each(this._instances, function(item) { - item._changed(flags); - }); - }, - - getDefinition: function() { - return this._definition; - }, - - setDefinition: function(item) { - if (item._parentSymbol) - item = item.clone(); - if (this._definition) - delete this._definition._parentSymbol; - this._definition = item; - item.remove(); - item.setSelected(false); - item.setPosition(new Point()); - item._parentSymbol = this; - this._changed(5); - }, - - place: function(position) { - return new PlacedSymbol(this, position); - }, - - clone: function() { - return new Symbol(this._definition.clone()); - } -}); - -var Item = this.Item = Base.extend(Callback, { - _serializeFields: { - name: null, - children: [], - matrix: new Matrix() - }, - - initialize: function(point) { - this._id = ++Item._id; - if (!this._project) - paper.project.activeLayer.addChild(this); - if (!this._style) - this._style = PathStyle.create(this); - this.setStyle(this._project.getCurrentStyle()); - this._matrix = new Matrix(); - if (point) - this._matrix.translate(point); - }, - - _events: new function() { - - var mouseFlags = { - mousedown: { - mousedown: 1, - mousedrag: 1, - click: 1, - doubleclick: 1 - }, - mouseup: { - mouseup: 1, - mousedrag: 1, - click: 1, - doubleclick: 1 - }, - mousemove: { - mousedrag: 1, - mousemove: 1, - mouseenter: 1, - mouseleave: 1 - } - }; - - var mouseEvent = { - install: function(type) { - var counters = this._project.view._eventCounters; - if (counters) { - for (var key in mouseFlags) { - counters[key] = (counters[key] || 0) - + (mouseFlags[key][type] || 0); - } - } - }, - uninstall: function(type) { - var counters = this._project.view._eventCounters; - if (counters) { - for (var key in mouseFlags) - counters[key] -= mouseFlags[key][type] || 0; - } - } - }; - - return Base.each(['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onClick', - 'onDoubleClick', 'onMouseMove', 'onMouseEnter', 'onMouseLeave'], - function(name) { - this[name] = mouseEvent; - }, { - onFrame: { - install: function() { - this._project.view._animateItem(this, true); - }, - uninstall: function() { - this._project.view._animateItem(this, false); - } - }, - - onLoad: {} - } - ); - }, - - _setProperties: function(props) { - if (Base.isPlainObject(props)) - return this.set(props); - }, - - set: function(props) { - if (props) { - for (var key in props) - if (props.hasOwnProperty(key)) - this[key] = props[key]; - } - return this; - }, - - _serialize: function() { - var props = {}, - that = this; - - function serialize(fields) { - for (var key in fields) { - var value = that[key]; - if (!Base.equals(value, fields[key])) - props[key] = Base.serialize(value); - } - } - - serialize(this._serializeFields); - serialize(this._style._defaults); - return [ this._type, props ]; - }, - - _changed: function(flags) { - if (flags & 4) { - delete this._bounds; - delete this._position; - } - if (this._parent - && (flags & (4 | 8))) { - this._parent._clearBoundsCache(); - } - if (flags & 2) { - this._clearBoundsCache(); - } - if (flags & 1) { - this._project._needsRedraw(); - } - if (this._parentSymbol) - this._parentSymbol._changed(flags); - if (this._project._changes) { - var entry = this._project._changesById[this._id]; - if (entry) { - entry.flags |= flags; - } else { - entry = { item: this, flags: flags }; - this._project._changesById[this._id] = entry; - this._project._changes.push(entry); - } - } - }, - - getId: function() { - return this._id; - }, - - getType: function() { - return this._type; - }, - - getName: function() { - return this._name; - }, - - setName: function(name, unique) { - - if (this._name) - this._removeFromNamed(); - if (name && this._parent) { - var children = this._parent._children, - namedChildren = this._parent._namedChildren, - orig = name, - i = 1; - while (unique && children[name]) - name = orig + ' ' + (i++); - (namedChildren[name] = namedChildren[name] || []).push(this); - children[name] = this; - } - this._name = name || undefined; - this._changed(32); - }, - - statics: { - _id: 0 - } -}, Base.each(['locked', 'visible', 'blendMode', 'opacity', 'guide'], - function(name) { - var part = Base.capitalize(name), - name = '_' + name; - this['get' + part] = function() { - return this[name]; - }; - this['set' + part] = function(value) { - if (value != this[name]) { - this[name] = value; - this._changed(name === '_locked' - ? 32 : 33); - } - }; -}, {}), { - - _locked: false, - - _visible: true, - - _blendMode: 'normal', - - _opacity: 1, - - _guide: false, - - applyMatrix: false, - - isSelected: function() { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - if (this._children[i].isSelected()) - return true; - } - return this._selected; - }, - - setSelected: function(selected ) { - if (this._children && !arguments[1]) { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].setSelected(selected); - } else if ((selected = !!selected) != this._selected) { - this._selected = selected; - this._project._updateSelection(this); - this._changed(33); - } - }, - - _selected: false, - - isFullySelected: function() { - if (this._children && this._selected) { - for (var i = 0, l = this._children.length; i < l; i++) - if (!this._children[i].isFullySelected()) - return false; - return true; - } - return this._selected; - }, - - setFullySelected: function(selected) { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].setFullySelected(selected); - } - this.setSelected(selected, true); - }, - - isClipMask: function() { - return this._clipMask; - }, - - setClipMask: function(clipMask) { - if (this._clipMask != (clipMask = !!clipMask)) { - this._clipMask = clipMask; - if (clipMask) { - this.setFillColor(null); - this.setStrokeColor(null); - } - this._changed(33); - if (this._parent) - this._parent._changed(256); - } - }, - - _clipMask: false, - - getPosition: function() { - var pos = this._position - || (this._position = this.getBounds().getCenter(true)); - return arguments[0] ? pos - : LinkedPoint.create(this, 'setPosition', pos.x, pos.y); - }, - - setPosition: function(point) { - this.translate(Point.read(arguments).subtract(this.getPosition(true))); - }, - - getMatrix: function() { - return this._matrix; - }, - - setMatrix: function(matrix) { - this._matrix.initialize(matrix); - this._changed(5); - }, - - isEmpty: function() { - return true; - } -}, Base.each(['getBounds', 'getStrokeBounds', 'getHandleBounds', 'getRoughBounds'], - function(name) { - this[name] = function() { - var getter = this._boundsGetter, - bounds = this._getCachedBounds(typeof getter == 'string' - ? getter : getter && getter[name] || name, arguments[0]); - return name == 'bounds' ? LinkedRectangle.create(this, 'setBounds', - bounds.x, bounds.y, bounds.width, bounds.height) : bounds; - }; - }, -{ - _getCachedBounds: function(getter, matrix, cacheItem) { - var cache = (!matrix || matrix.equals(this._matrix)) && getter; - if (cacheItem && this._parent) { - var id = cacheItem._id, - ref = this._parent._boundsCache - = this._parent._boundsCache || { - ids: {}, - list: [] - }; - if (!ref.ids[id]) { - ref.list.push(cacheItem); - ref.ids[id] = cacheItem; - } - } - if (cache && this._bounds && this._bounds[cache]) - return this._bounds[cache]; - var identity = this._matrix.isIdentity(); - matrix = !matrix || matrix.isIdentity() - ? identity ? null : this._matrix - : identity ? matrix : matrix.clone().concatenate(this._matrix); - var bounds = this._getBounds(getter, matrix, cache ? this : cacheItem); - if (cache) { - if (!this._bounds) - this._bounds = {}; - this._bounds[cache] = bounds.clone(); - } - return bounds; - }, - - _clearBoundsCache: function() { - if (this._boundsCache) { - for (var i = 0, list = this._boundsCache.list, l = list.length; - i < l; i++) { - var item = list[i]; - delete item._bounds; - if (item != this && item._boundsCache) - item._clearBoundsCache(); - } - delete this._boundsCache; - } - }, - - _getBounds: function(getter, matrix, cacheItem) { - var children = this._children; - if (!children || children.length == 0) - return new Rectangle(); - var x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2; - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i]; - if (child._visible && !child.isEmpty()) { - var rect = child._getCachedBounds(getter, matrix, cacheItem); - x1 = Math.min(rect.x, x1); - y1 = Math.min(rect.y, y1); - x2 = Math.max(rect.x + rect.width, x2); - y2 = Math.max(rect.y + rect.height, y2); - } - } - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - setBounds: function(rect) { - rect = Rectangle.read(arguments); - var bounds = this.getBounds(), - matrix = new Matrix(), - center = rect.getCenter(); - matrix.translate(center); - if (rect.width != bounds.width || rect.height != bounds.height) { - matrix.scale( - bounds.width != 0 ? rect.width / bounds.width : 1, - bounds.height != 0 ? rect.height / bounds.height : 1); - } - center = bounds.getCenter(); - matrix.translate(-center.x, -center.y); - this.transform(matrix); - } - -}), { - getProject: function() { - return this._project; - }, - - _setProject: function(project) { - if (this._project != project) { - this._project = project; - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) { - this._children[i]._setProject(project); - } - } - } - }, - - getLayer: function() { - var parent = this; - while (parent = parent._parent) { - if (parent instanceof Layer) - return parent; - } - return null; - }, - - getParent: function() { - return this._parent; - }, - - getChildren: function() { - return this._children; - }, - - setChildren: function(items) { - this.removeChildren(); - this.addChildren(items); - }, - - getFirstChild: function() { - return this._children && this._children[0] || null; - }, - - getLastChild: function() { - return this._children && this._children[this._children.length - 1] - || null; - }, - - getNextSibling: function() { - return this._parent && this._parent._children[this._index + 1] || null; - }, - - getPreviousSibling: function() { - return this._parent && this._parent._children[this._index - 1] || null; - }, - - getIndex: function() { - return this._index; - }, - - isInserted: function() { - return this._parent ? this._parent.isInserted() : false; - }, - - clone: function() { - return this._clone(new this.constructor()); - }, - - _clone: function(copy) { - copy.setStyle(this._style); - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - copy.addChild(this._children[i].clone(), true); - } - var keys = ['_locked', '_visible', '_blendMode', '_opacity', - '_clipMask', '_guide', 'applyMatrix']; - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - if (this.hasOwnProperty(key)) - copy[key] = this[key]; - } - copy._matrix.initialize(this._matrix); - copy.setSelected(this._selected); - if (this._name) - copy.setName(this._name, true); - return copy; - }, - - copyTo: function(itemOrProject) { - var copy = this.clone(); - if (itemOrProject.layers) { - itemOrProject.activeLayer.addChild(copy); - } else { - itemOrProject.addChild(copy); - } - return copy; - }, - - rasterize: function(resolution) { - var bounds = this.getStrokeBounds(), - scale = (resolution || 72) / 72, - canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)), - ctx = canvas.getContext('2d'), - matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y); - matrix.applyToContext(ctx); - this.draw(ctx, {}); - var raster = new Raster(canvas); - raster.setBounds(bounds); - return raster; - }, - - hitTest: function(point, options) { - point = Point.read(arguments); - options = HitResult.getOptions(Base.read(arguments)); - if (!this._children && !this.getRoughBounds() - .expand(options.tolerance)._containsPoint(point)) - return null; - point = this._matrix._inverseTransform(point); - if ((options.center || options.bounds) && - !(this instanceof Layer && !this._parent)) { - var bounds = this.getBounds(), - that = this, - points = ['TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], - res; - function checkBounds(type, part) { - var pt = bounds['get' + part](); - if (point.getDistance(pt) < options.tolerance) - return new HitResult(type, that, - { name: Base.hyphenate(part), point: pt }); - } - if (options.center && (res = checkBounds('center', 'Center'))) - return res; - if (options.bounds) { - for (var i = 0; i < 8; i++) - if (res = checkBounds('bounds', points[i])) - return res; - } - } - - return this._children || !(options.guides && !this._guide - || options.selected && !this._selected) - ? this._hitTest(point, options) : null; - }, - - _hitTest: function(point, options) { - if (this._children) { - for (var i = this._children.length - 1; i >= 0; i--) { - var res = this._children[i].hitTest(point, options); - if (res) return res; - } - } - }, - - addChild: function(item, _cloning) { - return this.insertChild(undefined, item, _cloning); - }, - - insertChild: function(index, item, _cloning) { - if (this._children) { - item._remove(true); - Base.splice(this._children, [item], index, 0); - item._parent = this; - item._setProject(this._project); - if (item._name) - item.setName(item._name); - this._changed(3); - return item; - } - return null; - }, - - addChildren: function(items, _cloning) { - return this.insertChildren(this._children.length, items, _cloning); - }, - - insertChildren: function(index, items, _cloning) { - items = items && Array.prototype.slice.apply(items); - var i = index; - for (var j = 0, l = items && items.length; j < l; j++) { - if (this.insertChild(i, items[j], _cloning)) - i++; - } - return i != index; - }, - - insertAbove: function(item, _cloning) { - var index = item._index; - if (item._parent == this._parent && index < this._index) - index++; - return item._parent.insertChild(index, this, _cloning); - }, - - insertBelow: function(item, _cloning) { - var index = item._index; - if (item._parent == this._parent && index > this._index) - index--; - return item._parent.insertChild(index, this, _cloning); - }, - - sendToBack: function() { - return this._parent.insertChild(0, this); - }, - - bringToFront: function() { - return this._parent.addChild(this); - }, - - appendTop: function(item) { - return this.addChild(item); - }, - - appendBottom: function(item) { - return this.insertChild(0, item); - }, - - moveAbove: function(item) { - return this.insertAbove(item); - }, - - moveBelow: function(item) { - return this.insertBelow(item); - }, - - _removeFromNamed: function() { - var children = this._parent._children, - namedChildren = this._parent._namedChildren, - name = this._name, - namedArray = namedChildren[name], - index = namedArray ? namedArray.indexOf(this) : -1; - if (index == -1) - return; - if (children[name] == this) - delete children[name]; - namedArray.splice(index, 1); - if (namedArray.length) { - children[name] = namedArray[namedArray.length - 1]; - } else { - delete namedChildren[name]; - } - }, - - _remove: function(notify) { - if (this._parent) { - if (this._name) - this._removeFromNamed(); - if (this._index != null) - Base.splice(this._parent._children, null, this._index, 1); - if (notify) - this._parent._changed(3); - this._parent = null; - return true; - } - return false; - }, - - remove: function() { - return this._remove(true); - }, - - removeChildren: function(from, to) { - if (!this._children) - return null; - from = from || 0; - to = Base.pick(to, this._children.length); - var removed = Base.splice(this._children, null, from, to - from); - for (var i = removed.length - 1; i >= 0; i--) - removed[i]._remove(false); - if (removed.length > 0) - this._changed(3); - return removed; - }, - - reverseChildren: function() { - if (this._children) { - this._children.reverse(); - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i]._index = i; - this._changed(3); - } - }, - - isEditable: function() { - var item = this; - while (item) { - if (!item._visible || item._locked) - return false; - item = item._parent; - } - return true; - }, - - _getOrder: function(item) { - function getList(item) { - var list = []; - do { - list.unshift(item); - } while (item = item._parent); - return list; - } - var list1 = getList(this), - list2 = getList(item); - for (var i = 0, l = Math.min(list1.length, list2.length); i < l; i++) { - if (list1[i] != list2[i]) { - return list1[i]._index < list2[i]._index ? 1 : -1; - } - } - return 0; - }, - - hasChildren: function() { - return this._children && this._children.length > 0; - }, - - isAbove: function(item) { - return this._getOrder(item) == -1; - }, - - isBelow: function(item) { - return this._getOrder(item) == 1; - }, - - isParent: function(item) { - return this._parent == item; - }, - - isChild: function(item) { - return item && item._parent == this; - }, - - isDescendant: function(item) { - var parent = this; - while (parent = parent._parent) { - if (parent == item) - return true; - } - return false; - }, - - isAncestor: function(item) { - return item ? item.isDescendant(this) : false; - }, - - isGroupedWith: function(item) { - var parent = this._parent; - while (parent) { - if (parent._parent - && (parent instanceof Group || parent instanceof CompoundPath) - && item.isDescendant(parent)) - return true; - parent = parent._parent; - } - return false; - }, - - scale: function(hor, ver , center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = ver; - ver = hor; - } - return this.transform(new Matrix().scale(hor, ver, - center || this.getPosition(true))); - }, - - translate: function(delta) { - var mx = new Matrix(); - return this.transform(mx.translate.apply(mx, arguments)); - }, - - rotate: function(angle, center) { - return this.transform(new Matrix().rotate(angle, - center || this.getPosition(true))); - }, - - shear: function(hor, ver, center) { - if (arguments.length < 2 || typeof ver === 'object') { - center = ver; - ver = hor; - } - return this.transform(new Matrix().shear(hor, ver, - center || this.getPosition(true))); - }, - - transform: function(matrix ) { - var bounds = this._bounds, - position = this._position; - this._matrix.preConcatenate(matrix); - if (this._transform) - this._transform(matrix); - if ((this.applyMatrix || arguments[1]) - && this._applyMatrix(this._matrix)) - this._matrix.setIdentity(); - this._changed(5); - if (bounds && matrix.getRotation() % 90 === 0) { - for (var key in bounds) { - var rect = bounds[key]; - matrix._transformBounds(rect, rect); - } - var getter = this._boundsGetter, - rect = bounds[getter && getter.getBounds || getter || 'getBounds']; - if (rect) - this._position = rect.getCenter(true); - this._bounds = bounds; - } else if (position) { - this._position = matrix._transformPoint(position, position); - } - return this; - }, - - _applyMatrix: function(matrix) { - if (this._children) { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].transform(matrix, true); - return true; - } - }, - - fitBounds: function(rectangle, fill) { - rectangle = Rectangle.read(arguments); - var bounds = this.getBounds(), - itemRatio = bounds.height / bounds.width, - rectRatio = rectangle.height / rectangle.width, - scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio) - ? rectangle.width / bounds.width - : rectangle.height / bounds.height, - newBounds = new Rectangle(new Point(), - Size.create(bounds.width * scale, bounds.height * scale)); - newBounds.setCenter(rectangle.getCenter()); - this.setBounds(newBounds); - }, - - toString: function() { - return (this.constructor._name || 'Item') + (this._name - ? " '" + this._name + "'" - : ' @' + this._id); - }, - - _setStyles: function(ctx) { - var style = this._style, - width = style._strokeWidth, - join = style._strokeJoin, - cap = style._strokeCap, - limit = style._miterLimit, - fillColor = style._fillColor, - strokeColor = style._strokeColor; - if (width != null) ctx.lineWidth = width; - if (join) ctx.lineJoin = join; - if (cap) ctx.lineCap = cap; - if (limit) ctx.miterLimit = limit; - if (fillColor) ctx.fillStyle = fillColor.getCanvasStyle(ctx); - if (strokeColor) ctx.strokeStyle = strokeColor.getCanvasStyle(ctx); - if (!fillColor || !strokeColor) - ctx.globalAlpha = this._opacity; - }, - - drawSelected: function(ctx, matrix) { - }, - - statics: { - drawSelectedBounds: function(bounds, ctx, matrix) { - var coords = matrix._transformCorners(bounds); - ctx.beginPath(); - for (var i = 0; i < 8; i++) - ctx[i == 0 ? 'moveTo' : 'lineTo'](coords[i], coords[++i]); - ctx.closePath(); - ctx.stroke(); - for (var i = 0; i < 8; i++) { - ctx.beginPath(); - ctx.rect(coords[i] - 2, coords[++i] - 2, 4, 4); - ctx.fill(); - } - }, - - draw: function(item, ctx, param) { - if (!item._visible || item._opacity == 0) - return; - item._drawCount = item._project._drawCount; - var tempCanvas, parentCtx, - itemOffset, prevOffset; - if (item._blendMode !== 'normal' || item._opacity < 1 - && (item._type !== 'path' - || item.getFillColor() && item.getStrokeColor())) { - var bounds = item.getStrokeBounds(); - if (!bounds.width || !bounds.height) - return; - prevOffset = param.offset; - parentCtx = ctx; - itemOffset = param.offset = bounds.getTopLeft().floor(); - tempCanvas = CanvasProvider.getCanvas( - bounds.getSize().ceil().add(Size.create(1, 1))); - ctx = tempCanvas.getContext('2d'); - } - if (!param.clipping) - ctx.save(); - if (tempCanvas) - ctx.translate(-itemOffset.x, -itemOffset.y); - item._matrix.applyToContext(ctx); - item.draw(ctx, param); - if (!param.clipping) - ctx.restore(); - if (tempCanvas) { - param.offset = prevOffset; - if (item._blendMode !== 'normal') { - BlendMode.process(item._blendMode, ctx, parentCtx, - item._opacity, itemOffset.subtract(prevOffset)); - } else { - parentCtx.save(); - parentCtx.globalAlpha = item._opacity; - parentCtx.drawImage(tempCanvas, itemOffset.x, itemOffset.y); - parentCtx.restore(); - } - CanvasProvider.returnCanvas(tempCanvas); - } - } - } -}, Base.each(['down', 'drag', 'up', 'move'], function(name) { - this['removeOn' + Base.capitalize(name)] = function() { - var hash = {}; - hash[name] = true; - return this.removeOn(hash); - }; -}, { - - removeOn: function(obj) { - for (var name in obj) { - if (obj[name]) { - var key = 'mouse' + name, - sets = Tool._removeSets = Tool._removeSets || {}; - sets[key] = sets[key] || {}; - sets[key][this._id] = this; - } - } - return this; - } -})); - -var Group = this.Group = Item.extend({ - _type: 'group', - - initialize: function(arg) { - this.base(); - this._children = []; - this._namedChildren = {}; - if (!this._setProperties(arg)) - this.addChildren(Array.isArray(arg) ? arg : arguments); - }, - - _changed: function(flags) { - Item.prototype._changed.call(this, flags); - if (flags & (2 | 256)) { - delete this._clipItem; - } - }, - - _getClipItem: function() { - if (this._clipItem !== undefined) - return this._clipItem; - for (var i = 0, l = this._children.length; i < l; i++) { - var child = this._children[i]; - if (child._clipMask) - return this._clipItem = child; - } - return this._clipItem = null; - }, - - isClipped: function() { - return !!this._getClipItem(); - }, - - setClipped: function(clipped) { - var child = this.getFirstChild(); - if (child) - child.setClipMask(clipped); - return this; - }, - - isEmpty: function() { - return this._children.length == 0; - }, - - draw: function(ctx, param) { - var clipItem = this._getClipItem(); - if (clipItem) { - param.clipping = true; - Item.draw(clipItem, ctx, param); - delete param.clipping; - } - for (var i = 0, l = this._children.length; i < l; i++) { - var item = this._children[i]; - if (item != clipItem) - Item.draw(item, ctx, param); - } - } -}); - -var Layer = this.Layer = Group.extend({ - _type: 'layer', - initialize: function(items) { - this._project = paper.project; - this._index = this._project.layers.push(this) - 1; - this.base.apply(this, arguments); - this.activate(); - }, - - _remove: function(notify) { - if (this._parent) - return this.base(notify); - if (this._index != null) { - Base.splice(this._project.layers, null, this._index, 1); - this._project._needsRedraw(); - return true; - } - return false; - }, - - getNextSibling: function() { - return this._parent ? this.base() - : this._project.layers[this._index + 1] || null; - }, - - getPreviousSibling: function() { - return this._parent ? this.base() - : this._project.layers[this._index - 1] || null; - }, - - isInserted: function() { - return this._index != null; - }, - - activate: function() { - this._project.activeLayer = this; - } -}, new function () { - function insert(above) { - return function(item) { - if (item instanceof Layer && !item._parent - && this._remove(true)) { - Base.splice(item._project.layers, [this], - item._index + (above ? 1 : 0), 0); - this._setProject(item._project); - return true; - } - return this.base(item); - }; - } - - return { - insertAbove: insert(true), - - insertBelow: insert(false) - }; -}); - -var PlacedItem = this.PlacedItem = Item.extend({ - _boundsGetter: { getBounds: 'getStrokeBounds' }, - - _hitTest: function(point, options, matrix) { - var result = this._symbol._definition._hitTest(point, options, matrix); - if (result) - result.item = this; - return result; - } -}); - -var Raster = this.Raster = PlacedItem.extend({ - _type: 'raster', - _boundsGetter: 'getBounds', - - initialize: function(arg0, arg1) { - this.base(arg1 !== undefined && Point.read(arguments, 1)); - if (!this._setProperties(arg0)) { - if (arg0.getContext) { - this.setCanvas(arg0); - } else if (typeof arg0 === 'string') { - this.setSource(arg0); - } else { - this.setImage(arg0); - } - } - }, - - clone: function() { - var image = this._image; - if (!image) { - image = CanvasProvider.getCanvas(this._size); - image.getContext('2d').drawImage(this._canvas, 0, 0); - } - var copy = new Raster(image); - return this._clone(copy); - }, - - getSize: function() { - return this._size; - }, - - setSize: function() { - var size = Size.read(arguments); - if (!this._size.equals(size)) { - var image = this.getImage(); - this.setCanvas(CanvasProvider.getCanvas(size)); - this.getContext(true).drawImage(image, 0, 0, size.width, size.height); - } - }, - - getWidth: function() { - return this._size.width; - }, - - getHeight: function() { - return this._size.height; - }, - - isEmpty: function() { - return this._size.width == 0 && this._size.height == 0; - }, - - getPpi: function() { - var matrix = this._matrix, - orig = new Point(0, 0).transform(matrix), - u = new Point(1, 0).transform(matrix).subtract(orig), - v = new Point(0, 1).transform(matrix).subtract(orig); - return Size.create( - 72 / u.getLength(), - 72 / v.getLength() - ); - }, - - getContext: function() { - if (!this._context) - this._context = this.getCanvas().getContext('2d'); - if (arguments[0]) - this._changed(129); - return this._context; - }, - - setContext: function(context) { - this._context = context; - }, - - getCanvas: function() { - if (!this._canvas) { - this._canvas = CanvasProvider.getCanvas(this._size); - if (this._image) - this.getContext(true).drawImage(this._image, 0, 0); - } - return this._canvas; - }, - - setCanvas: function(canvas) { - if (this._canvas) - CanvasProvider.returnCanvas(this._canvas); - this._canvas = canvas; - this._size = Size.create(canvas.width, canvas.height); - this._image = null; - this._context = null; - this._changed(5 | 129); - }, - - getImage: function() { - return this._image || this.getCanvas(); - }, - - setImage: function(image) { - if (this._canvas) - CanvasProvider.returnCanvas(this._canvas); - this._image = image; - this._size = Size.create(image.naturalWidth, image.naturalHeight); - this._canvas = null; - this._context = null; - this._changed(5); - }, - - getSource: function() { - return this.getImage().src; - }, - - setSource: function(src) { - var that = this, - image = document.getElementById(src) || new Image(); - DomEvent.add(image, { - load: function() { - that.setImage(image); - that.fire('load'); - if (that._project.view) - that._project.view.draw(true); - } - }); - if (!image.src) - image.src = src; - this.setImage(image); - }, - - getSubImage: function(rect) { - rect = Rectangle.read(arguments); - var canvas = CanvasProvider.getCanvas(rect.getSize()); - canvas.getContext('2d').drawImage(this.getCanvas(), rect.x, rect.y, - canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); - return canvas; - }, - - drawImage: function(image, point) { - point = Point.read(arguments, 1); - this.getContext(true).drawImage(image, point.x, point.y); - }, - - getAverageColor: function(object) { - var bounds, path; - if (!object) { - bounds = this.getBounds(); - } else if (object instanceof PathItem) { - path = object; - bounds = object.getBounds(); - } else if (object.width) { - bounds = new Rectangle(object); - } else if (object.x) { - bounds = Rectangle.create(object.x - 0.5, object.y - 0.5, 1, 1); - } - var sampleSize = 32, - width = Math.min(bounds.width, sampleSize), - height = Math.min(bounds.height, sampleSize); - var ctx = Raster._sampleContext; - if (!ctx) { - ctx = Raster._sampleContext = CanvasProvider.getCanvas( - new Size(sampleSize)).getContext('2d'); - } else { - ctx.clearRect(0, 0, sampleSize, sampleSize); - } - ctx.save(); - ctx.scale(width / bounds.width, height / bounds.height); - ctx.translate(-bounds.x, -bounds.y); - if (path) - path.draw(ctx, { clip: true }); - this._matrix.applyToContext(ctx); - ctx.drawImage(this._canvas || this._image, - -this._size.width / 2, -this._size.height / 2); - ctx.restore(); - var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width), - Math.ceil(height)).data, - channels = [0, 0, 0], - total = 0; - for (var i = 0, l = pixels.length; i < l; i += 4) { - var alpha = pixels[i + 3]; - total += alpha; - alpha /= 255; - channels[0] += pixels[i] * alpha; - channels[1] += pixels[i + 1] * alpha; - channels[2] += pixels[i + 2] * alpha; - } - for (var i = 0; i < 3; i++) - channels[i] /= total; - return total ? Color.read(channels) : null; - }, - - getPixel: function(point) { - point = Point.read(arguments); - var pixels = this.getContext().getImageData(point.x, point.y, 1, 1).data, - channels = new Array(4); - for (var i = 0; i < 4; i++) - channels[i] = pixels[i] / 255; - return RgbColor.read(channels); - }, - - setPixel: function(point, color) { - var _point = Point.read(arguments), - _color = Color.read(arguments); - var ctx = this.getContext(true), - imageData = ctx.createImageData(1, 1), - alpha = color.getAlpha(); - imageData.data[0] = _color.getRed() * 255; - imageData.data[1] = _color.getGreen() * 255; - imageData.data[2] = _color.getBlue() * 255; - imageData.data[3] = alpha != null ? alpha * 255 : 255; - ctx.putImageData(imageData, _point.x, _point.y); - }, - - createData: function(size) { - size = Size.read(arguments); - return this.getContext().createImageData(size.width, size.height); - }, - - getData: function(rect) { - rect = Rectangle.read(arguments); - if (rect.isEmpty()) - rect = new Rectangle(this.getSize()); - return this.getContext().getImageData(rect.x, rect.y, - rect.width, rect.height); - }, - - setData: function(data, point) { - point = Point.read(arguments, 1); - this.getContext(true).putImageData(data, point.x, point.y); - }, - - _getBounds: function(getter, matrix) { - var rect = new Rectangle(this._size).setCenter(0, 0); - return matrix ? matrix._transformBounds(rect) : rect; - }, - - _hitTest: function(point, options) { - if (point.isInside(this._getBounds())) { - var that = this; - return new HitResult('pixel', that, { - offset: point.add(that._size.divide(2)).round(), - color: { - get: function() { - return that.getPixel(this.offset); - } - } - }); - } - }, - - draw: function(ctx, param) { - ctx.drawImage(this._canvas || this._image, - -this._size.width / 2, -this._size.height / 2); - }, - - drawSelected: function(ctx, matrix) { - Item.drawSelectedBounds(new Rectangle(this._size).setCenter(0, 0), ctx, - matrix); - } -}); - -var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend({ - _type: 'placedsymbol', - initialize: function(arg0, arg1) { - this.base(arg1 !== undefined && Point.read(arguments, 1)); - if (!this._setProperties(arg0)) - this.setSymbol(arg0 instanceof Symbol ? arg0 : new Symbol(arg0)); - }, - - getSymbol: function() { - return this._symbol; - }, - - setSymbol: function(symbol) { - if (this._symbol) - delete this._symbol._instances[this._id]; - this._symbol = symbol; - symbol._instances[this._id] = this; - }, - - isEmpty: function() { - return this._symbol._definition.isEmpty(); - }, - - clone: function() { - return this._clone(new PlacedSymbol(this.symbol, this._matrix.clone())); - }, - - _getBounds: function(getter, matrix) { - return this.symbol._definition._getCachedBounds(getter, matrix); - }, - - draw: function(ctx, param) { - Item.draw(this.symbol._definition, ctx, param); - }, - - drawSelected: function(ctx, matrix) { - Item.drawSelectedBounds(this.symbol._definition.getBounds(), ctx, - matrix); - } - -}); - -HitResult = Base.extend({ - initialize: function(type, item, values) { - this.type = type; - this.item = item; - if (values) { - values.enumerable = true; - this.inject(values); - } - }, - - statics: { - getOptions: function(options) { - return options && options._merged ? options : Base.merge({ - type: null, - tolerance: 2, - fill: !options, - stroke: !options, - segments: !options, - handles: false, - ends: false, - center: false, - bounds: false, - guides: false, - selected: false, - _merged: true - }, options); - } - } -}); - -var Segment = this.Segment = Base.extend({ - _type: 'segment', - - initialize: function(arg0, arg1, arg2, arg3, arg4, arg5) { - var count = arguments.length, - createPoint = SegmentPoint.create, - point, handleIn, handleOut; - if (count == 0) { - } else if (count == 1) { - if (arg0.point) { - point = arg0.point; - handleIn = arg0.handleIn; - handleOut = arg0.handleOut; - } else { - point = arg0; - } - } else if (count < 6) { - if (count == 2 && arg1.x === undefined) { - point = [ arg0, arg1 ]; - } else { - point = arg0; - handleIn = arg1; - handleOut = arg2; - } - } else if (count == 6) { - point = [ arg0, arg1 ]; - handleIn = [ arg2, arg3 ]; - handleOut = [ arg4, arg5 ]; - } - createPoint(this, '_point', point); - createPoint(this, '_handleIn', handleIn); - createPoint(this, '_handleOut', handleOut); - }, - - _serialize: function() { - return Base.serialize(this._handleIn.isZero() && this._handleOut.isZero() - ? this._point - : [this._point, this._handleIn, this._handleOut], true); - }, - - _changed: function(point) { - if (!this._path) - return; - var curve = this._path._curves && this.getCurve(), - other; - if (curve) { - curve._changed(); - if (other = (curve[point == this._point - || point == this._handleIn && curve._segment1 == this - ? 'getPrevious' : 'getNext']())) { - other._changed(); - } - } - this._path._changed(5); - }, - - getPoint: function() { - return this._point; - }, - - setPoint: function(point) { - point = Point.read(arguments); - this._point.set(point.x, point.y); - }, - - getHandleIn: function() { - return this._handleIn; - }, - - setHandleIn: function(point) { - point = Point.read(arguments); - this._handleIn.set(point.x, point.y); - }, - - getHandleOut: function() { - return this._handleOut; - }, - - setHandleOut: function(point) { - point = Point.read(arguments); - this._handleOut.set(point.x, point.y); - }, - - isLinear: function() { - return this._handleIn.isZero() && this._handleOut.isZero(); - }, - - _isSelected: function(point) { - var state = this._selectionState; - return point == this._point ? !!(state & 4) - : point == this._handleIn ? !!(state & 1) - : point == this._handleOut ? !!(state & 2) - : false; - }, - - _setSelected: function(point, selected) { - var path = this._path, - selected = !!selected, - state = this._selectionState || 0, - selection = [ - !!(state & 4), - !!(state & 1), - !!(state & 2) - ]; - if (point == this._point) { - if (selected) { - selection[1] = selection[2] = false; - } else { - var previous = this.getPrevious(), - next = this.getNext(); - selection[1] = previous && (previous._point.isSelected() - || previous._handleOut.isSelected()); - selection[2] = next && (next._point.isSelected() - || next._handleIn.isSelected()); - } - selection[0] = selected; - } else { - var index = point == this._handleIn ? 1 : 2; - if (selection[index] != selected) { - if (selected) - selection[0] = false; - selection[index] = selected; - } - } - this._selectionState = (selection[0] ? 4 : 0) - | (selection[1] ? 1 : 0) - | (selection[2] ? 2 : 0); - if (path && state != this._selectionState) { - path._updateSelection(this, state, this._selectionState); - path._changed(33); - } - }, - - isSelected: function() { - return this._isSelected(this._point); - }, - - setSelected: function(selected) { - this._setSelected(this._point, selected); - }, - - getIndex: function() { - return this._index !== undefined ? this._index : null; - }, - - getPath: function() { - return this._path || null; - }, - - getCurve: function() { - if (this._path) { - var index = this._index; - if (!this._path._closed && index == this._path._segments.length - 1) - index--; - return this._path.getCurves()[index] || null; - } - return null; - }, - - getNext: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index + 1] - || this._path._closed && segments[0]) || null; - }, - - getPrevious: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index - 1] - || this._path._closed && segments[segments.length - 1]) || null; - }, - - reverse: function() { - return new Segment(this._point, this._handleOut, this._handleIn); - }, - - remove: function() { - return this._path ? !!this._path.removeSegment(this._index) : false; - }, - - clone: function() { - return new Segment(this._point, this._handleIn, this._handleOut); - }, - - equals: function(segment) { - return segment == this || segment - && this._point.equals(segment._point) - && this._handleIn.equals(segment._handleIn) - && this._handleOut.equals(segment._handleOut); - }, - - toString: function() { - var parts = [ 'point: ' + this._point ]; - if (!this._handleIn.isZero()) - parts.push('handleIn: ' + this._handleIn); - if (!this._handleOut.isZero()) - parts.push('handleOut: ' + this._handleOut); - return '{ ' + parts.join(', ') + ' }'; - }, - - _transformCoordinates: function(matrix, coords, change) { - var point = this._point, - handleIn = !change || !this._handleIn.isZero() - ? this._handleIn : null, - handleOut = !change || !this._handleOut.isZero() - ? this._handleOut : null, - x = point._x, - y = point._y, - i = 2; - coords[0] = x; - coords[1] = y; - if (handleIn) { - coords[i++] = handleIn._x + x; - coords[i++] = handleIn._y + y; - } - if (handleOut) { - coords[i++] = handleOut._x + x; - coords[i++] = handleOut._y + y; - } - if (matrix) { - matrix._transformCoordinates(coords, 0, coords, 0, i / 2); - x = coords[0]; - y = coords[1]; - if (change) { - point._x = x; - point._y = y; - i = 2; - if (handleIn) { - handleIn._x = coords[i++] - x; - handleIn._y = coords[i++] - y; - } - if (handleOut) { - handleOut._x = coords[i++] - x; - handleOut._y = coords[i++] - y; - } - } else { - if (!handleIn) { - coords[i++] = x; - coords[i++] = y; - } - if (!handleOut) { - coords[i++] = x; - coords[i++] = y; - } - } - } - return coords; - } -}); - -var SegmentPoint = Point.extend({ - set: function(x, y) { - this._x = x; - this._y = y; - this._owner._changed(this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner._changed(this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner._changed(this); - }, - - isZero: function() { - return Numerical.isZero(this._x) && Numerical.isZero(this._y); - }, - - setSelected: function(selected) { - this._owner._setSelected(this, selected); - }, - - isSelected: function() { - return this._owner._isSelected(this); - }, - - statics: { - create: function(segment, key, pt) { - var point = Base.create(SegmentPoint), - x, y, selected; - if (!pt) { - x = y = 0; - } else if ((x = pt[0]) !== undefined) { - y = pt[1]; - } else { - if ((x = pt.x) === undefined) { - pt = Point.read(arguments, 2); - x = pt.x; - } - y = pt.y; - selected = pt.selected; - } - point._x = x; - point._y = y; - point._owner = segment; - segment[key] = point; - if (selected) - point.setSelected(true); - return point; - } - } -}); - -var Curve = this.Curve = Base.extend({ - initialize: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { - var count = arguments.length; - if (count == 0) { - this._segment1 = new Segment(); - this._segment2 = new Segment(); - } else if (count == 1) { - this._segment1 = new Segment(arg0.segment1); - this._segment2 = new Segment(arg0.segment2); - } else if (count == 2) { - this._segment1 = new Segment(arg0); - this._segment2 = new Segment(arg1); - } else { - var point1, handle1, handle2, point2; - if (count == 4) { - point1 = arg0; - handle1 = arg1; - handle2 = arg2; - point2 = arg3; - } else if (count == 8) { - point1 = [arg0, arg1]; - point2 = [arg6, arg7]; - handle1 = [arg2 - arg0, arg7 - arg1]; - handle2 = [arg4 - arg6, arg5 - arg7]; - } - this._segment1 = new Segment(point1, null, handle1); - this._segment2 = new Segment(point2, handle2, null); - } - }, - - _changed: function() { - delete this._length; - delete this._bounds; - }, - - getPoint1: function() { - return this._segment1._point; - }, - - setPoint1: function(point) { - point = Point.read(arguments); - this._segment1._point.set(point.x, point.y); - }, - - getPoint2: function() { - return this._segment2._point; - }, - - setPoint2: function(point) { - point = Point.read(arguments); - this._segment2._point.set(point.x, point.y); - }, - - getHandle1: function() { - return this._segment1._handleOut; - }, - - setHandle1: function(point) { - point = Point.read(arguments); - this._segment1._handleOut.set(point.x, point.y); - }, - - getHandle2: function() { - return this._segment2._handleIn; - }, - - setHandle2: function(point) { - point = Point.read(arguments); - this._segment2._handleIn.set(point.x, point.y); - }, - - getSegment1: function() { - return this._segment1; - }, - - getSegment2: function() { - return this._segment2; - }, - - getPath: function() { - return this._path; - }, - - getIndex: function() { - return this._segment1._index; - }, - - getNext: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index + 1] - || this._path._closed && curves[0]) || null; - }, - - getPrevious: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index - 1] - || this._path._closed && curves[curves.length - 1]) || null; - }, - - isSelected: function() { - return this.getHandle1().isSelected() && this.getHandle2().isSelected(); - }, - - setSelected: function(selected) { - this.getHandle1().setSelected(selected); - this.getHandle2().setSelected(selected); - }, - - getValues: function() { - return Curve.getValues(this._segment1, this._segment2); - }, - - getPoints: function() { - var coords = this.getValues(), - points = []; - for (var i = 0; i < 8; i += 2) - points.push(Point.create(coords[i], coords[i + 1])); - return points; - }, - - getLength: function() { - var from = arguments[0], - to = arguments[1], - fullLength = arguments.length == 0 || from == 0 && to == 1; - if (fullLength && this._length != null) - return this._length; - var length = Curve.getLength(this.getValues(), from, to); - if (fullLength) - this._length = length; - return length; - }, - - getPart: function(from, to) { - return new Curve(Curve.getPart(this.getValues(), from, to)); - }, - - isLinear: function() { - return this._segment1._handleOut.isZero() - && this._segment2._handleIn.isZero(); - }, - - getIntersections: function(curve) { - return Curve._addIntersections(this.getValues(), curve.getValues(), - this, []); - }, - - getCrossings: function(point, roots) { - var vals = this.getValues(), - count = Curve.solveCubic(vals, 1, point.y, roots), - crossings = 0; - for (var i = 0; i < count; i++) { - var t = roots[i]; - if (t >= 0 && t < 1 && Curve.evaluate(vals, t, true, 0).x > point.x) { - if (t < 0.00001 - && Curve.evaluate(this.getPrevious().getValues(), 1, true, 1).y - * Curve.evaluate(vals, t, true, 1).y - >= 0.00001) - continue; - crossings++; - } - } - return crossings; - }, - - reverse: function() { - return new Curve(this._segment2.reverse(), this._segment1.reverse()); - }, - - divide: function(parameter) { - var res = null; - if (parameter && parameter.curve === this) - parameter = parameter.parameter; - if (parameter > 0 && parameter < 1) { - var parts = Curve.subdivide(this.getValues(), parameter), - left = parts[0], - right = parts[1], - point1 = this._segment1._point, - point2 = this._segment2._point; - this._segment1._handleOut.set(left[2] - point1._x, - left[3] - point1._y); - this._segment2._handleIn.set(right[4] - point2._x, - right[5] - point2._y); - - var x = left[6], y = left[7], - segment = new Segment(Point.create(x, y), - Point.create(left[4] - x, left[5] - y), - Point.create(right[2] - x, right[3] - y)); - if (this._path) { - if (this._segment1._index > 0 && this._segment2._index == 0) { - this._path.add(segment); - } else { - this._path.insert(this._segment2._index, segment); - } - res = this.getNext(); - } else { - var end = this._segment2; - this._segment2 = segment; - res = new Curve(segment, end); - } - } - return res; - }, - - split: function(parameter) { - return this._path - ? this._path.split(this._segment1._index, parameter) - : null; - }, - - clone: function() { - return new Curve(this._segment1, this._segment2); - }, - - toString: function() { - var parts = [ 'point1: ' + this._segment1._point ]; - if (!this._segment1._handleOut.isZero()) - parts.push('handle1: ' + this._segment1._handleOut); - if (!this._segment2._handleIn.isZero()) - parts.push('handle2: ' + this._segment2._handleIn); - parts.push('point2: ' + this._segment2._point); - return '{ ' + parts.join(', ') + ' }'; - }, - -statics: { - create: function(path, segment1, segment2) { - var curve = Base.create(Curve); - curve._path = path; - curve._segment1 = segment1; - curve._segment2 = segment2; - return curve; - }, - - getValues: function(segment1, segment2) { - var p1 = segment1._point, - h1 = segment1._handleOut, - h2 = segment2._handleIn, - p2 = segment2._point; - return [ - p1._x, p1._y, - p1._x + h1._x, p1._y + h1._y, - p2._x + h2._x, p2._y + h2._y, - p2._x, p2._y - ]; - }, - - evaluate: function(v, offset, isParameter, type) { - var t = isParameter ? offset : Curve.getParameterAt(v, offset, 0), - p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - x, y; - - if (type == 0 && (t == 0 || t == 1)) { - x = t == 0 ? p1x : p2x; - y = t == 0 ? p1y : p2y; - } else { - var tMin = 0.00001; - if (t < tMin && c1x == p1x && c1y == p1y) - t = tMin; - else if (t > 1 - tMin && c2x == p2x && c2y == p2y) - t = 1 - tMin; - var cx = 3 * (c1x - p1x), - bx = 3 * (c2x - c1x) - cx, - ax = p2x - p1x - cx - bx, - - cy = 3 * (c1y - p1y), - by = 3 * (c2y - c1y) - cy, - ay = p2y - p1y - cy - by; - - switch (type) { - case 0: - x = ((ax * t + bx) * t + cx) * t + p1x; - y = ((ay * t + by) * t + cy) * t + p1y; - break; - case 1: - case 2: - x = (3 * ax * t + 2 * bx) * t + cx; - y = (3 * ay * t + 2 * by) * t + cy; - break; - } - } - return type == 2 ? new Point(y, -x) : new Point(x, y); - }, - - subdivide: function(v, t) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7]; - if (t === undefined) - t = 0.5; - var u = 1 - t, - p3x = u * p1x + t * c1x, p3y = u * p1y + t * c1y, - p4x = u * c1x + t * c2x, p4y = u * c1y + t * c2y, - p5x = u * c2x + t * p2x, p5y = u * c2y + t * p2y, - p6x = u * p3x + t * p4x, p6y = u * p3y + t * p4y, - p7x = u * p4x + t * p5x, p7y = u * p4y + t * p5y, - p8x = u * p6x + t * p7x, p8y = u * p6y + t * p7y; - return [ - [p1x, p1y, p3x, p3y, p6x, p6y, p8x, p8y], - [p8x, p8y, p7x, p7y, p5x, p5y, p2x, p2y] - ]; - }, - - solveCubic: function (v, coord, val, roots) { - var p1 = v[coord], - c1 = v[coord + 2], - c2 = v[coord + 4], - p2 = v[coord + 6], - c = 3 * (c1 - p1), - b = 3 * (c2 - c1) - c, - a = p2 - p1 - c - b; - return Numerical.solveCubic(a, b, c, p1 - val, roots, - 0.00001); - }, - - getParameterOf: function(v, x, y) { - if (Math.abs(v[0] - x) < 0.00001 - && Math.abs(v[1] - y) < 0.00001) - return 0; - if (Math.abs(v[6] - x) < 0.00001 - && Math.abs(v[7] - y) < 0.00001) - return 1; - var txs = [], - tys = [], - sx = Curve.solveCubic(v, 0, x, txs), - sy = Curve.solveCubic(v, 1, y, tys), - tx, ty; - for (var cx = 0; sx == -1 || cx < sx;) { - if (sx == -1 || (tx = txs[cx++]) >= 0 && tx <= 1) { - for (var cy = 0; sy == -1 || cy < sy;) { - if (sy == -1 || (ty = tys[cy++]) >= 0 && ty <= 1) { - if (sx == -1) tx = ty; - else if (sy == -1) ty = tx; - if (Math.abs(tx - ty) < 0.00001) - return (tx + ty) * 0.5; - } - } - if (sx == -1) - break; - } - } - return null; - }, - - getPart: function(v, from, to) { - if (from > 0) - v = Curve.subdivide(v, from)[1]; - if (to < 1) - v = Curve.subdivide(v, (to - from) / (1 - from))[0]; - return v; - }, - - isFlatEnough: function(v, tolerance) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - ux = 3 * c1x - 2 * p1x - p2x, - uy = 3 * c1y - 2 * p1y - p2y, - vx = 3 * c2x - 2 * p2x - p1x, - vy = 3 * c2y - 2 * p2y - p1y; - return Math.max(ux * ux, vx * vx) + Math.max(uy * uy, vy * vy) - < 16 * tolerance * tolerance; - }, - - getBounds: function(v) { - var min = v.slice(0, 2), - max = min.slice(0), - roots = new Array(2); - for (var i = 0; i < 2; i++) - Curve._addBounds(v[i], v[i + 2], v[i + 4], v[i + 6], - i, 0, min, max, roots); - return Rectangle.create(min[0], min[1], max[0] - min[0], max[1] - min[1]); - }, - - _addBounds: function(v0, v1, v2, v3, coord, padding, min, max, roots) { - function add(value, padding) { - var left = value - padding, - right = value + padding; - if (left < min[coord]) - min[coord] = left; - if (right > max[coord]) - max[coord] = right; - } - var a = 3 * (v1 - v2) - v0 + v3, - b = 2 * (v0 + v2) - 4 * v1, - c = v1 - v0; - count = Numerical.solveQuadratic(a, b, c, roots, - 0.00001), - tMin = 0.00001, - tMax = 1 - tMin; - add(v3, 0); - for (var j = 0; j < count; j++) { - var t = roots[j], - u = 1 - t; - if (tMin < t && t < tMax) - add(u * u * u * v0 - + 3 * u * u * t * v1 - + 3 * u * t * t * v2 - + t * t * t * v3, - padding); - } - }, - - _addIntersections: function(v1, v2, curve, locations) { - var bounds1 = Curve.getBounds(v1), - bounds2 = Curve.getBounds(v2); - if (bounds1.x + bounds1.width >= bounds2.x - && bounds1.y + bounds1.height >= bounds2.y - && bounds1.x < bounds2.x + bounds2.width - && bounds1.y < bounds2.y + bounds2.height) { - if (Curve.isFlatEnough(v1, 0.00001) - && Curve.isFlatEnough(v2, 0.00001)) { - var point = new Line(v1[0], v1[1], v1[6], v1[7], false) - .intersect(new Line(v2[0], v2[1], v2[6], v2[7], false)); - if (point) - locations.push(new CurveLocation(curve, null, point)); - } else { - var v1s = Curve.subdivide(v1), - v2s = Curve.subdivide(v2); - for (var i = 0; i < 2; i++) - for (var j = 0; j < 2; j++) - this._addIntersections(v1s[i], v2s[j], curve, locations); - } - } - return locations; - } -}}, Base.each(['getBounds', 'getStrokeBounds', 'getHandleBounds', 'getRoughBounds'], - function(name) { - this[name] = function() { - if (!this._bounds) - this._bounds = {}; - var bounds = this._bounds[name]; - if (!bounds) { - bounds = this._bounds[name] = Path[name]( - [this._segment1, this._segment2], false, this._path._style); - } - return bounds.clone(); - }; - }, -{ - -}), Base.each(['getPoint', 'getTangent', 'getNormal'], - function(name, index) { - this[name + 'At'] = function(offset, isParameter) { - return Curve.evaluate(this.getValues(), offset, isParameter, index); - }; - this[name] = function(parameter) { - return Curve.evaluate(this.getValues(), parameter, true, index); - }; - }, -{ - getParameterAt: function(offset, start) { - return Curve.getParameterAt(this.getValues(), offset, - start !== undefined ? start : offset < 0 ? 1 : 0); - }, - - getParameterOf: function(point) { - point = Point.read(arguments); - return Curve.getParameterOf(this.getValues(), point.x, point.y); - }, - - getLocationAt: function(offset, isParameter) { - if (!isParameter) - offset = this.getParameterAt(offset); - return new CurveLocation(this, offset); - }, - - getLocationOf: function(point) { - var t = this.getParameterOf.apply(this, arguments); - return t != null ? new CurveLocation(this, t) : null; - } - -}), -new function() { - - function getLengthIntegrand(v) { - var p1x = v[0], p1y = v[1], - c1x = v[2], c1y = v[3], - c2x = v[4], c2y = v[5], - p2x = v[6], p2y = v[7], - - ax = 9 * (c1x - c2x) + 3 * (p2x - p1x), - bx = 6 * (p1x + c2x) - 12 * c1x, - cx = 3 * (c1x - p1x), - - ay = 9 * (c1y - c2y) + 3 * (p2y - p1y), - by = 6 * (p1y + c2y) - 12 * c1y, - cy = 3 * (c1y - p1y); - - return function(t) { - var dx = (ax * t + bx) * t + cx, - dy = (ay * t + by) * t + cy; - return Math.sqrt(dx * dx + dy * dy); - }; - } - - function getIterations(a, b) { - return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); - } - - return { - statics: true, - - getLength: function(v, a, b) { - if (a === undefined) - a = 0; - if (b === undefined) - b = 1; - if (v[0] == v[2] && v[1] == v[3] && v[6] == v[4] && v[7] == v[5]) { - var dx = v[6] - v[0], - dy = v[7] - v[1]; - return (b - a) * Math.sqrt(dx * dx + dy * dy); - } - var ds = getLengthIntegrand(v); - return Numerical.integrate(ds, a, b, getIterations(a, b)); - }, - - getParameterAt: function(v, offset, start) { - if (offset == 0) - return start; - var forward = offset > 0, - a = forward ? start : 0, - b = forward ? 1 : start, - offset = Math.abs(offset), - ds = getLengthIntegrand(v), - rangeLength = Numerical.integrate(ds, a, b, - getIterations(a, b)); - if (offset >= rangeLength) - return forward ? b : a; - var guess = offset / rangeLength, - length = 0; - function f(t) { - var count = getIterations(start, t); - length += start < t - ? Numerical.integrate(ds, start, t, count) - : -Numerical.integrate(ds, t, start, count); - start = t; - return length - offset; - } - return Numerical.findRoot(f, ds, - forward ? a + guess : b - guess, - a, b, 16, 0.00001); - } - }; -}, new function() { - - var maxDepth = 32, - epsilon = Math.pow(2, -maxDepth - 1); - - var zCubic = [ - [1.0, 0.6, 0.3, 0.1], - [0.4, 0.6, 0.6, 0.4], - [0.1, 0.3, 0.6, 1.0] - ]; - - var xAxis = new Line(new Point(0, 0), new Point(1, 0)); - - function toBezierForm(v, point) { - var n = 3, - degree = 5, - c = [], - d = [], - cd = [], - w = []; - for(var i = 0; i <= n; i++) { - c[i] = v[i].subtract(point); - if (i < n) - d[i] = v[i + 1].subtract(v[i]).multiply(n); - } - - for (var row = 0; row < n; row++) { - cd[row] = []; - for (var column = 0; column <= n; column++) - cd[row][column] = d[row].dot(c[column]); - } - - for (var i = 0; i <= degree; i++) - w[i] = new Point(i / degree, 0); - - for (var k = 0; k <= degree; k++) { - var lb = Math.max(0, k - n + 1), - ub = Math.min(k, n); - for (var i = lb; i <= ub; i++) { - var j = k - i; - w[k].y += cd[j][i] * zCubic[j][i]; - } - } - - return w; - } - - function findRoots(w, depth) { - switch (countCrossings(w)) { - case 0: - return []; - case 1: - if (depth >= maxDepth) - return [0.5 * (w[0].x + w[5].x)]; - if (isFlatEnough(w)) { - var line = new Line(w[0], w[5], true); - return [ Numerical.isZero(line.vector.getLength(true)) - ? line.point.x - : xAxis.intersect(line).x ]; - } - } - - var p = [[]], - left = [], - right = []; - for (var j = 0; j <= 5; j++) - p[0][j] = new Point(w[j]); - - for (var i = 1; i <= 5; i++) { - p[i] = []; - for (var j = 0 ; j <= 5 - i; j++) - p[i][j] = p[i - 1][j].add(p[i - 1][j + 1]).multiply(0.5); - } - for (var j = 0; j <= 5; j++) { - left[j] = p[j][0]; - right[j] = p[5 - j][j]; - } - - return findRoots(left, depth + 1).concat(findRoots(right, depth + 1)); - } - - function countCrossings(v) { - var crossings = 0, - prevSign = null; - for (var i = 0, l = v.length; i < l; i++) { - var sign = v[i].y < 0 ? -1 : 1; - if (prevSign != null && sign != prevSign) - crossings++; - prevSign = sign; - } - return crossings; - } - - function isFlatEnough(v) { - - var n = v.length - 1, - a = v[0].y - v[n].y, - b = v[n].x - v[0].x, - c = v[0].x * v[n].y - v[n].x * v[0].y, - maxAbove = 0, - maxBelow = 0; - for (var i = 1; i < n; i++) { - var val = a * v[i].x + b * v[i].y + c, - dist = val * val; - if (val < 0 && dist > maxBelow) { - maxBelow = dist; - } else if (dist > maxAbove) { - maxAbove = dist; - } - } - return Math.abs((maxAbove + maxBelow) / (2 * a * (a * a + b * b))) - < epsilon; - } - - return { - getNearestLocation: function(point) { - var w = toBezierForm(this.getPoints(), point); - var roots = findRoots(w, 0).concat([0, 1]); - var minDist = Infinity, - minT, - minPoint; - for (var i = 0; i < roots.length; i++) { - var pt = this.getPointAt(roots[i], true), - dist = point.getDistance(pt, true); - if (dist < minDist) { - minDist = dist; - minT = roots[i]; - minPoint = pt; - } - } - return new CurveLocation(this, minT, minPoint, Math.sqrt(minDist)); - }, - - getNearestPoint: function(point) { - return this.getNearestLocation(point).getPoint(); - } - }; -}); - -CurveLocation = Base.extend({ - initialize: function(curve, parameter, point, distance) { - this._curve = curve; - this._segment1 = curve._segment1; - this._segment2 = curve._segment2; - this._parameter = parameter; - this._point = point; - this._distance = distance; - }, - - getSegment: function() { - if (!this._segment) { - var curve = this.getCurve(), - parameter = this.getParameter(); - if (parameter == 0) { - this._segment = curve._segment1; - } else if (parameter == 1) { - this._segment = curve._segment2; - } else if (parameter == null) { - return null; - } else { - this._segment = curve.getLength(0, parameter) - < curve.getLength(parameter, 1) - ? curve._segment1 - : curve._segment2; - } - } - return this._segment; - }, - - getCurve: function() { - if (!this._curve || arguments[0]) { - this._curve = this._segment1.getCurve(); - if (this._curve.getParameterOf(this._point) == null) - this._curve = this._segment2.getPrevious().getCurve(); - } - return this._curve; - }, - - getPath: function() { - var curve = this.getCurve(); - return curve && curve._path; - }, - - getIndex: function() { - var curve = this.getCurve(); - return curve && curve.getIndex(); - }, - - getOffset: function() { - var path = this.getPath(); - return path && path._getOffset(this); - }, - - getCurveOffset: function() { - var curve = this.getCurve(), - parameter = this.getParameter(); - return parameter != null && curve && curve.getLength(0, parameter); - }, - - getParameter: function() { - if ((this._parameter == null || arguments[0]) && this._point) { - var curve = this.getCurve(arguments[0] && this._point); - this._parameter = curve && curve.getParameterOf(this._point); - } - return this._parameter; - }, - - getPoint: function() { - if (!this._point && this._parameter != null) { - var curve = this.getCurve(); - this._point = curve && curve.getPointAt(this._parameter, true); - } - return this._point; - }, - - getTangent: function() { - var parameter = this.getParameter(), - curve = this.getCurve(); - return parameter != null && curve && curve.getTangentAt(parameter, true); - }, - - getNormal: function() { - var parameter = this.getParameter(), - curve = this.getCurve(); - return parameter != null && curve && curve.getNormalAt(parameter, true); - }, - - getDistance: function() { - return this._distance; - }, - - divide: function() { - var curve = this.getCurve(); - return curve && curve.divide(this.getParameter(true)); - }, - - split: function() { - var curve = this.getCurve(); - return curve && curve.split(this.getParameter(true)); - }, - - toString: function() { - var parts = [], - point = this.getPoint(); - if (point) - parts.push('point: ' + point); - var index = this.getIndex(); - if (index != null) - parts.push('index: ' + index); - var parameter = this.getParameter(); - if (parameter != null) - parts.push('parameter: ' + Base.formatFloat(parameter)); - if (this._distance != null) - parts.push('distance: ' + Base.formatFloat(this._distance)); - return '{ ' + parts.join(', ') + ' }'; - } -}); - -var PathItem = this.PathItem = Item.extend({ - - getIntersections: function(path) { - if (!this.getBounds().intersects(path.getBounds())) - return []; - var locations = [], - curves1 = this.getCurves(), - curves2 = path.getCurves(), - length2 = curves2.length, - values2 = []; - for (var i = 0; i < length2; i++) - values2[i] = curves2[i].getValues(); - for (var i = 0, l = curves1.length; i < l; i++) { - var curve = curves1[i], - values1 = curve.getValues(); - for (var j = 0; j < length2; j++) - Curve._addIntersections(values1, values2[j], curve, locations); - } - return locations; - } - -}); - -var Path = this.Path = PathItem.extend({ - _type: 'path', - _serializeFields: { - name: null, - segments: [], - closed: false, - matrix: new Matrix() - }, - - initialize: function(arg) { - this._closed = false; - this._segments = []; - this.base(); - var segments = Array.isArray(arg) - ? typeof arg[0] === 'object' - ? arg - : arguments - : arg && (arg.point !== undefined || arg.x !== undefined) - ? arguments - : null; - this.setSegments(segments || []); - if (!segments) - this._setProperties(arg); - }, - - clone: function() { - var copy = this._clone(new Path(this._segments)); - copy._closed = this._closed; - if (this._clockwise !== undefined) - copy._clockwise = this._clockwise; - return copy; - }, - - _changed: function(flags) { - Item.prototype._changed.call(this, flags); - if (flags & 4) { - delete this._length; - delete this._clockwise; - if (this._curves) { - for (var i = 0, l = this._curves.length; i < l; i++) { - this._curves[i]._changed(5); - } - } - } else if (flags & 8) { - delete this._bounds; - } - }, - - getSegments: function() { - return this._segments; - }, - - setSegments: function(segments) { - this._selectedSegmentState = 0; - this._segments.length = 0; - delete this._curves; - this._add(Segment.readAll(segments)); - }, - - getFirstSegment: function() { - return this._segments[0]; - }, - - getLastSegment: function() { - return this._segments[this._segments.length - 1]; - }, - - getCurves: function() { - var curves = this._curves, - segments = this._segments; - if (!curves) { - var length = this._countCurves(); - curves = this._curves = new Array(length); - for (var i = 0; i < length; i++) - curves[i] = Curve.create(this, segments[i], - segments[i + 1] || segments[0]); - } - if (arguments[0] && !this._closed && this._style._fillColor) { - curves = curves.concat([ - Curve.create(this, segments[segments.length - 1], segments[0]) - ]); - } - return curves; - }, - - getFirstCurve: function() { - return this.getCurves()[0]; - }, - - getLastCurve: function() { - var curves = this.getCurves(); - return curves[curves.length - 1]; - }, - - isClosed: function() { - return this._closed; - }, - - setClosed: function(closed) { - if (this._closed != (closed = !!closed)) { - this._closed = closed; - if (this._curves) { - var length = this._curves.length = this._countCurves(); - if (closed) - this._curves[length - 1] = Curve.create(this, - this._segments[length - 1], this._segments[0]); - } - this._changed(5); - } - }, - - isEmpty: function() { - return this._segments.length === 0; - }, - - isPolygon: function() { - for (var i = 0, l = this._segments.length; i < l; i++) { - if (!this._segments[i].isLinear()) - return false; - } - return true; - }, - - applyMatrix: true, - - _applyMatrix: function(matrix) { - var coords = new Array(6); - for (var i = 0, l = this._segments.length; i < l; i++) { - this._segments[i]._transformCoordinates(matrix, coords, true); - } - var style = this._style, - fillColor = style._fillColor, - strokeColor = style._strokeColor; - if (fillColor && fillColor.transform) - fillColor.transform(matrix); - if (strokeColor && strokeColor.transform) - strokeColor.transform(matrix); - return true; - }, - - _add: function(segs, index) { - var segments = this._segments, - curves = this._curves, - amount = segs.length, - append = index == null, - index = append ? segments.length : index, - fullySelected = this.isFullySelected(); - for (var i = 0; i < amount; i++) { - var segment = segs[i]; - if (segment._path) - segment = segs[i] = segment.clone(); - segment._path = this; - segment._index = index + i; - if (fullySelected) - segment._selectionState = 4; - if (segment._selectionState) - this._updateSelection(segment, 0, segment._selectionState); - } - if (append) { - segments.push.apply(segments, segs); - } else { - segments.splice.apply(segments, [index, 0].concat(segs)); - for (var i = index + amount, l = segments.length; i < l; i++) - segments[i]._index = i; - } - if (curves || segs._curves) { - if (!curves) - curves = this._curves = []; - var from = index > 0 ? index - 1 : index, - start = from, - to = Math.min(from + amount, this._countCurves()); - if (segs._curves) { - curves.splice.apply(curves, [from, 0].concat(segs._curves)); - start += segs._curves.length; - } - for (var i = start; i < to; i++) - curves.splice(i, 0, Base.create(Curve)); - this._adjustCurves(from, to); - } - this._changed(5); - return segs; - }, - - _adjustCurves: function(from, to) { - var segments = this._segments, - curves = this._curves, - curve; - for (var i = from; i < to; i++) { - curve = curves[i]; - curve._path = this; - curve._segment1 = segments[i]; - curve._segment2 = segments[i + 1] || segments[0]; - } - if (curve = curves[this._closed && from === 0 ? segments.length - 1 - : from - 1]) - curve._segment2 = segments[from] || segments[0]; - if (curve = curves[to]) - curve._segment1 = segments[to]; - }, - - _countCurves: function() { - var length = this._segments.length; - return !this._closed && length > 0 ? length - 1 : length; - }, - - add: function(segment1 ) { - return arguments.length > 1 && typeof segment1 !== 'number' - ? this._add(Segment.readAll(arguments)) - : this._add([ Segment.read(arguments) ])[0]; - }, - - insert: function(index, segment1 ) { - return arguments.length > 2 && typeof segment1 !== 'number' - ? this._add(Segment.readAll(arguments, 1), index) - : this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegment: function(segment) { - return this._add([ Segment.read(arguments) ])[0]; - }, - - insertSegment: function(index, segment) { - return this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegments: function(segments) { - return this._add(Segment.readAll(segments)); - }, - - insertSegments: function(index, segments) { - return this._add(Segment.readAll(segments), index); - }, - - removeSegment: function(index) { - return this.removeSegments(index, index + 1)[0] || null; - }, - - removeSegments: function(from, to) { - from = from || 0; - to = Base.pick(to, this._segments.length); - var segments = this._segments, - curves = this._curves, - count = segments.length, - removed = segments.splice(from, to - from), - amount = removed.length; - if (!amount) - return removed; - for (var i = 0; i < amount; i++) { - var segment = removed[i]; - if (segment._selectionState) - this._updateSelection(segment, segment._selectionState, 0); - delete segment._index; - delete segment._path; - } - for (var i = from, l = segments.length; i < l; i++) - segments[i]._index = i; - if (curves) { - var index = to == count + (this._closed ? 1 : 0) ? from - 1 : from, - curves = curves.splice(index, amount); - if (arguments[2]) - removed._curves = curves.slice(1); - this._adjustCurves(index, index); - } - this._changed(5); - return removed; - }, - - isFullySelected: function() { - return this._selected && this._selectedSegmentState - == this._segments.length * 4; - }, - - setFullySelected: function(selected) { - var length = this._segments.length; - this._selectedSegmentState = selected - ? length * 4 : 0; - for (var i = 0; i < length; i++) - this._segments[i]._selectionState = selected - ? 4 : 0; - this.setSelected(selected); - }, - - _updateSelection: function(segment, oldState, newState) { - segment._selectionState = newState; - var total = this._selectedSegmentState += newState - oldState; - if (total > 0) - this.setSelected(true); - }, - - flatten: function(maxDistance) { - var flattener = new PathFlattener(this), - pos = 0, - step = flattener.length / Math.ceil(flattener.length / maxDistance), - end = flattener.length + (this._closed ? -step : step) / 2; - var segments = []; - while (pos <= end) { - segments.push(new Segment(flattener.evaluate(pos, 0))); - pos += step; - } - this.setSegments(segments); - }, - - simplify: function(tolerance) { - if (this._segments.length > 2) { - var fitter = new PathFitter(this, tolerance || 2.5); - this.setSegments(fitter.fit()); - } - }, - - split: function(index, parameter) { - if (parameter === null) - return; - if (arguments.length == 1) { - var arg = index; - if (typeof arg === 'number') - arg = this.getLocationAt(arg); - index = arg.index; - parameter = arg.parameter; - } - if (parameter >= 1) { - index++; - parameter--; - } - var curves = this.getCurves(); - if (index >= 0 && index < curves.length) { - if (parameter > 0) { - curves[index++].divide(parameter); - } - var segs = this.removeSegments(index, this._segments.length, true), - path; - if (this._closed) { - this.setClosed(false); - path = this; - } else if (index > 0) { - path = this._clone(new Path().insertAbove(this, true)); - } - path._add(segs, 0); - this.addSegment(segs[0]); - return path; - } - return null; - }, - - isClockwise: function() { - if (this._clockwise !== undefined) - return this._clockwise; - var sum = 0, - xPre, yPre; - function edge(x, y) { - if (xPre !== undefined) - sum += (xPre - x) * (y + yPre); - xPre = x; - yPre = y; - } - for (var i = 0, l = this._segments.length; i < l; i++) { - var seg1 = this._segments[i], - seg2 = this._segments[i + 1 < l ? i + 1 : 0], - point1 = seg1._point, - handle1 = seg1._handleOut, - handle2 = seg2._handleIn, - point2 = seg2._point; - edge(point1._x, point1._y); - edge(point1._x + handle1._x, point1._y + handle1._y); - edge(point2._x + handle2._x, point2._y + handle2._y); - edge(point2._x, point2._y); - } - return sum > 0; - }, - - setClockwise: function(clockwise) { - if (this.isClockwise() != (clockwise = !!clockwise)) { - this.reverse(); - } - this._clockwise = clockwise; - }, - - reverse: function() { - this._segments.reverse(); - for (var i = 0, l = this._segments.length; i < l; i++) { - var segment = this._segments[i]; - var handleIn = segment._handleIn; - segment._handleIn = segment._handleOut; - segment._handleOut = handleIn; - segment._index = i; - } - if (this._clockwise !== undefined) - this._clockwise = !this._clockwise; - }, - - join: function(path) { - if (path) { - var segments = path._segments, - last1 = this.getLastSegment(), - last2 = path.getLastSegment(); - if (last1._point.equals(last2._point)) - path.reverse(); - var first2 = path.getFirstSegment(); - if (last1._point.equals(first2._point)) { - last1.setHandleOut(first2._handleOut); - this._add(segments.slice(1)); - } else { - var first1 = this.getFirstSegment(); - if (first1._point.equals(first2._point)) - path.reverse(); - last2 = path.getLastSegment(); - if (first1._point.equals(last2._point)) { - first1.setHandleIn(last2._handleIn); - this._add(segments.slice(0, segments.length - 1), 0); - } else { - this._add(segments.slice(0)); - } - } - path.remove(); - var first1 = this.getFirstSegment(); - last1 = this.getLastSegment(); - if (last1._point.equals(first1._point)) { - first1.setHandleIn(last1._handleIn); - last1.remove(); - this.setClosed(true); - } - this._changed(5); - return true; - } - return false; - }, - - reduce: function() { - return this; - }, - - getLength: function() { - if (this._length == null) { - var curves = this.getCurves(); - this._length = 0; - for (var i = 0, l = curves.length; i < l; i++) - this._length += curves[i].getLength(); - } - return this._length; - }, - - _getOffset: function(location) { - var index = location && location.getIndex(); - if (index != null) { - var curves = this.getCurves(), - offset = 0; - for (var i = 0; i < index; i++) - offset += curves[i].getLength(); - var curve = curves[index]; - return offset + curve.getLength(0, location.getParameter()); - } - return null; - }, - - getLocationOf: function(point) { - point = Point.read(arguments); - var curves = this.getCurves(); - for (var i = 0, l = curves.length; i < l; i++) { - var loc = curves[i].getLocationOf(point); - if (loc) - return loc; - } - return null; - }, - - getLocationAt: function(offset, isParameter) { - var curves = this.getCurves(), - length = 0; - if (isParameter) { - var index = ~~offset; - return curves[index].getLocationAt(offset - index, true); - } - for (var i = 0, l = curves.length; i < l; i++) { - var start = length, - curve = curves[i]; - length += curve.getLength(); - if (length >= offset) { - return curve.getLocationAt(offset - start); - } - } - if (offset <= this.getLength()) - return new CurveLocation(curves[curves.length - 1], 1); - return null; - }, - - getPointAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getPoint(); - }, - - getTangentAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getTangent(); - }, - - getNormalAt: function(offset, isParameter) { - var loc = this.getLocationAt(offset, isParameter); - return loc && loc.getNormal(); - }, - - getNearestLocation: function(point) { - var curves = this.getCurves(), - minDist = Infinity, - minLoc = null; - for (var i = 0, l = curves.length; i < l; i++) { - var loc = curves[i].getNearestLocation(point); - if (loc._distance < minDist) { - minDist = loc._distance; - minLoc = loc; - } - } - return minLoc; - }, - - getNearestPoint: function(point) { - return this.getNearestLocation(point).getPoint(); - }, - - contains: function(point) { - point = Point.read(arguments); - if (!this._closed && !this._style._fillColor - || !this.getRoughBounds()._containsPoint(point)) - return false; - var curves = this.getCurves(true), - crossings = 0, - roots = new Array(3); - for (var i = 0, l = curves.length; i < l; i++) - crossings += curves[i].getCrossings(point, roots); - return (crossings & 1) == 1; - }, - - _hitTest: function(point, options) { - var style = this._style, - tolerance = options.tolerance || 0, - radius = (options.stroke && style._strokeColor - ? style._strokeWidth / 2 : 0) + tolerance, - loc, - res; - var coords = [], - that = this; - function checkPoint(seg, pt, name) { - if (point.getDistance(pt) < tolerance) - return new HitResult(name, that, { segment: seg, point: pt }); - } - function checkSegment(seg, ends) { - var point = seg._point; - return (ends || options.segments) - && checkPoint(seg, point, 'segment') - || (!ends && options.handles) && ( - checkPoint(seg, point.add(seg._handleIn), 'handle-in') || - checkPoint(seg, point.add(seg._handleOut), 'handle-out')); - } - if (options.ends && !options.segments && !this._closed) { - if (res = checkSegment(this.getFirstSegment(), true) - || checkSegment(this.getLastSegment(), true)) - return res; - } else if (options.segments || options.handles) { - for (var i = 0, l = this._segments.length; i < l; i++) { - if (res = checkSegment(this._segments[i])) - return res; - } - } - if (options.stroke && radius > 0) - loc = this.getNearestLocation(point); - if (!(loc && loc._distance <= radius) && options.fill - && style._fillColor && this.contains(point)) - return new HitResult('fill', this); - if (!loc && options.stroke && radius > 0) - loc = this.getNearestLocation(point); - if (loc && loc._distance <= radius) - return options.stroke - ? new HitResult('stroke', this, { location: loc }) - : new HitResult('fill', this); - } - -}, new function() { - - function drawHandles(ctx, segments, matrix) { - var coords = new Array(6); - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i]; - segment._transformCoordinates(matrix, coords, false); - var state = segment._selectionState, - selected = state & 4, - pX = coords[0], - pY = coords[1]; - - function drawHandle(index) { - var hX = coords[index], - hY = coords[index + 1]; - if (pX != hX || pY != hY) { - ctx.beginPath(); - ctx.moveTo(pX, pY); - ctx.lineTo(hX, hY); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(hX, hY, 1.75, 0, Math.PI * 2, true); - ctx.fill(); - } - } - - if (selected || (state & 1)) - drawHandle(2); - if (selected || (state & 2)) - drawHandle(4); - ctx.save(); - ctx.beginPath(); - ctx.rect(pX - 2, pY - 2, 4, 4); - ctx.fill(); - if (!selected) { - ctx.beginPath(); - ctx.rect(pX - 1, pY - 1, 2, 2); - ctx.fillStyle = '#ffffff'; - ctx.fill(); - } - ctx.restore(); - } - } - - function drawSegments(ctx, path, matrix) { - var segments = path._segments, - length = segments.length, - coords = new Array(6), - first = true, - curX, curY, - prevX, prevY, - inX, inY, - outX, outY; - - function drawSegment(i) { - var segment = segments[i]; - if (matrix) { - segment._transformCoordinates(matrix, coords, false); - curX = coords[0]; - curY = coords[1]; - } else { - var point = segment._point; - curX = point._x; - curY = point._y; - } - if (first) { - ctx.moveTo(curX, curY); - first = false; - } else { - if (matrix) { - inX = coords[2]; - inY = coords[3]; - } else { - var handle = segment._handleIn; - inX = curX + handle._x; - inY = curY + handle._y; - } - if (inX == curX && inY == curY && outX == prevX && outY == prevY) { - ctx.lineTo(curX, curY); - } else { - ctx.bezierCurveTo(outX, outY, inX, inY, curX, curY); - } - } - prevX = curX; - prevY = curY; - if (matrix) { - outX = coords[4]; - outY = coords[5]; - } else { - var handle = segment._handleOut; - outX = prevX + handle._x; - outY = prevY + handle._y; - } - } - - for (var i = 0; i < length; i++) - drawSegment(i); - if (path._closed && length > 1) - drawSegment(0); - } - - return { - draw: function(ctx, param) { - if (!param.compound) - ctx.beginPath(); - - var style = this._style, - fillColor = style._fillColor, - strokeColor = style._strokeColor, - dashArray = style._dashArray, - hasDash = strokeColor && dashArray && dashArray.length; - - if (param.compound || this._clipMask || fillColor - || strokeColor && !hasDash) { - drawSegments(ctx, this); - } - - if (this._closed) - ctx.closePath(); - - if (this._clipMask) { - ctx.clip(); - } else if (!param.compound && (fillColor || strokeColor)) { - this._setStyles(ctx); - if (fillColor) - ctx.fill(); - if (strokeColor) { - if (hasDash) { - ctx.beginPath(); - var flattener = new PathFlattener(this), - from = style._dashOffset, to, - i = 0; - while (from < flattener.length) { - to = from + dashArray[(i++) % dashArray.length]; - flattener.drawPart(ctx, from, to); - from = to + dashArray[(i++) % dashArray.length]; - } - } - ctx.stroke(); - } - } - }, - - drawSelected: function(ctx, matrix) { - ctx.beginPath(); - drawSegments(ctx, this, matrix); - ctx.stroke(); - drawHandles(ctx, this._segments, matrix); - if (this._selectedSegmentState == 0) { - Item.drawSelectedBounds(this.getBounds(), ctx, matrix); - } - } - }; -}, new function() { - - function getFirstControlPoints(rhs) { - var n = rhs.length, - x = [], - tmp = [], - b = 2; - x[0] = rhs[0] / b; - for (var i = 1; i < n; i++) { - tmp[i] = 1 / b; - b = (i < n - 1 ? 4 : 2) - tmp[i]; - x[i] = (rhs[i] - x[i - 1]) / b; - } - for (var i = 1; i < n; i++) { - x[n - i - 1] -= tmp[n - i] * x[n - i]; - } - return x; - }; - - return { - smooth: function() { - var segments = this._segments, - size = segments.length, - n = size, - overlap; - - if (size <= 2) - return; - - if (this._closed) { - overlap = Math.min(size, 4); - n += Math.min(size, overlap) * 2; - } else { - overlap = 0; - } - var knots = []; - for (var i = 0; i < size; i++) - knots[i + overlap] = segments[i]._point; - if (this._closed) { - for (var i = 0; i < overlap; i++) { - knots[i] = segments[i + size - overlap]._point; - knots[i + size + overlap] = segments[i]._point; - } - } else { - n--; - } - var rhs = []; - - for (var i = 1; i < n - 1; i++) - rhs[i] = 4 * knots[i]._x + 2 * knots[i + 1]._x; - rhs[0] = knots[0]._x + 2 * knots[1]._x; - rhs[n - 1] = 3 * knots[n - 1]._x; - var x = getFirstControlPoints(rhs); - - for (var i = 1; i < n - 1; i++) - rhs[i] = 4 * knots[i]._y + 2 * knots[i + 1]._y; - rhs[0] = knots[0]._y + 2 * knots[1]._y; - rhs[n - 1] = 3 * knots[n - 1]._y; - var y = getFirstControlPoints(rhs); - - if (this._closed) { - for (var i = 0, j = size; i < overlap; i++, j++) { - var f1 = i / overlap, - f2 = 1 - f1, - ie = i + overlap, - je = j + overlap; - x[j] = x[i] * f1 + x[j] * f2; - y[j] = y[i] * f1 + y[j] * f2; - x[je] = x[ie] * f2 + x[je] * f1; - y[je] = y[ie] * f2 + y[je] * f1; - } - n--; - } - var handleIn = null; - for (var i = overlap; i <= n - overlap; i++) { - var segment = segments[i - overlap]; - if (handleIn) - segment.setHandleIn(handleIn.subtract(segment._point)); - if (i < n) { - segment.setHandleOut( - Point.create(x[i], y[i]).subtract(segment._point)); - if (i < n - 1) - handleIn = Point.create( - 2 * knots[i + 1]._x - x[i + 1], - 2 * knots[i + 1]._y - y[i + 1]); - else - handleIn = Point.create( - (knots[n]._x + x[n - 1]) / 2, - (knots[n]._y + y[n - 1]) / 2); - } - } - if (this._closed && handleIn) { - var segment = this._segments[0]; - segment.setHandleIn(handleIn.subtract(segment._point)); - } - } - }; -}, new function() { - function getCurrentSegment(that) { - var segments = that._segments; - if (segments.length == 0) - throw new Error('Use a moveTo() command first'); - return segments[segments.length - 1]; - } - - return { - moveTo: function(point) { - if (this._segments.length === 1) - this.removeSegment(0); - if (!this._segments.length) - this._add([ new Segment(Point.read(arguments)) ]); - }, - - moveBy: function(point) { - throw new Error('moveBy() is unsupported on Path items.'); - }, - - lineTo: function(point) { - this._add([ new Segment(Point.read(arguments)) ]); - }, - - cubicCurveTo: function(handle1, handle2, to) { - var _handle1 = Point.read(arguments), - _handle2 = Point.read(arguments), - _to = Point.read(arguments); - var current = getCurrentSegment(this); - current.setHandleOut(_handle1.subtract(current._point)); - this._add([ new Segment(_to, _handle2.subtract(to)) ]); - }, - - quadraticCurveTo: function(handle, to) { - var _handle = Point.read(arguments), - to = Point.read(arguments); - var current = getCurrentSegment(this)._point; - this.cubicCurveTo( - _handle.add(current.subtract(_handle).multiply(1 / 3)), - _handle.add(to.subtract(_handle).multiply(1 / 3)), - to - ); - }, - - curveTo: function(through, to, parameter) { - var _through = Point.read(arguments), - _to = Point.read(arguments), - t = Base.pick(Base.read(arguments), 0.5), - t1 = 1 - t, - current = getCurrentSegment(this)._point, - handle = _through.subtract(current.multiply(t1 * t1)) - .subtract(_to.multiply(t * t)).divide(2 * t * t1); - if (handle.isNaN()) - throw new Error( - 'Cannot put a curve through points with parameter = ' + t); - this.quadraticCurveTo(handle, _to); - }, - - arcTo: function(to, clockwise ) { - var current = getCurrentSegment(this), - from = current._point, - through, - point = Point.read(arguments), - next = Base.pick(Base.peek(arguments), true); - if (typeof next === 'boolean') { - to = point; - clockwise = next; - var middle = from.add(to).divide(2), - through = middle.add(middle.subtract(from).rotate( - clockwise ? -90 : 90)); - } else { - through = point; - to = Point.read(arguments); - } - var l1 = new Line(from.add(through).divide(2), - through.subtract(from).rotate(90)), - l2 = new Line(through.add(to).divide(2), - to.subtract(through).rotate(90)), - center = l1.intersect(l2), - line = new Line(from, to, true), - throughSide = line.getSide(through); - if (!center) { - if (!throughSide) - return this.lineTo(to); - throw new Error("Cannot put an arc through the given points: " - + [from, through, to]); - } - var vector = from.subtract(center), - radius = vector.getLength(), - extent = vector.getDirectedAngle(to.subtract(center)), - centerSide = line.getSide(center); - if (centerSide == 0) { - extent = throughSide * Math.abs(extent); - } else if (throughSide == centerSide) { - extent -= 360 * (extent < 0 ? -1 : 1); - } - var ext = Math.abs(extent), - count = ext >= 360 ? 4 : Math.ceil(ext / 90), - inc = extent / count, - half = inc * Math.PI / 360, - z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), - segments = []; - for (var i = 0; i <= count; i++) { - var pt = i < count ? center.add(vector) : to; - var out = i < count ? vector.rotate(90).multiply(z) : null; - if (i == 0) { - current.setHandleOut(out); - } else { - segments.push( - new Segment(pt, vector.rotate(-90).multiply(z), out)); - } - vector = vector.rotate(inc); - } - this._add(segments); - }, - - lineBy: function(vector) { - vector = Point.read(arguments); - var current = getCurrentSegment(this); - this.lineTo(current._point.add(vector)); - }, - - curveBy: function(throughVector, toVector, parameter) { - throughVector = Point.read(throughVector); - toVector = Point.read(toVector); - var current = getCurrentSegment(this)._point; - this.curveTo(current.add(throughVector), current.add(toVector), - parameter); - }, - - arcBy: function(throughVector, toVector) { - throughVector = Point.read(throughVector); - toVector = Point.read(toVector); - var current = getCurrentSegment(this)._point; - this.arcBy(current.add(throughVector), current.add(toVector)); - }, - - closePath: function() { - this.setClosed(true); - } - }; -}, { - - _getBounds: function(getter, matrix) { - return Path[getter](this._segments, this._closed, this._style, matrix); - }, - -statics: { - getBounds: function(segments, closed, style, matrix, strokePadding) { - var first = segments[0]; - if (!first) - return new Rectangle(); - var coords = new Array(6), - prevCoords = first._transformCoordinates(matrix, new Array(6), false), - min = prevCoords.slice(0, 2), - max = min.slice(0), - roots = new Array(2); - - function processSegment(segment) { - segment._transformCoordinates(matrix, coords, false); - for (var i = 0; i < 2; i++) { - Curve._addBounds( - prevCoords[i], - prevCoords[i + 4], - coords[i + 2], - coords[i], - i, strokePadding ? strokePadding[i] : 0, min, max, roots); - } - var tmp = prevCoords; - prevCoords = coords; - coords = tmp; - } - - for (var i = 1, l = segments.length; i < l; i++) - processSegment(segments[i]); - if (closed) - processSegment(first); - return Rectangle.create(min[0], min[1], max[0] - min[0], max[1] - min[1]); - }, - - getStrokeBounds: function(segments, closed, style, matrix) { - function getPenPadding(radius, matrix) { - if (!matrix) - return [radius, radius]; - var mx = matrix.createShiftless(), - hor = mx.transform(Point.create(radius, 0)), - ver = mx.transform(Point.create(0, radius)), - phi = hor.getAngleInRadians(), - a = hor.getLength(), - b = ver.getLength(); - var sin = Math.sin(phi), - cos = Math.cos(phi), - tan = Math.tan(phi), - tx = -Math.atan(b * tan / a), - ty = Math.atan(b / (tan * a)); - return [Math.abs(a * Math.cos(tx) * cos - b * Math.sin(tx) * sin), - Math.abs(b * Math.sin(ty) * cos + a * Math.cos(ty) * sin)]; - } - - if (!style._strokeColor || !style._strokeWidth) - return Path.getBounds(segments, closed, style, matrix); - var radius = style._strokeWidth / 2, - padding = getPenPadding(radius, matrix), - bounds = Path.getBounds(segments, closed, style, matrix, padding), - join = style._strokeJoin, - cap = style._strokeCap, - miter = style._miterLimit * style._strokeWidth / 2; - var joinBounds = new Rectangle(new Size(padding).multiply(2)); - - function add(point) { - bounds = bounds.include(matrix - ? matrix._transformPoint(point, point) : point); - } - - function addBevelJoin(curve, t) { - var point = curve.getPointAt(t, true), - normal = curve.getNormalAt(t, true).normalize(radius); - add(point.add(normal)); - add(point.subtract(normal)); - } - - function addJoin(segment, join) { - if (join === 'round' || !segment._handleIn.isZero() - && !segment._handleOut.isZero()) { - bounds = bounds.unite(joinBounds.setCenter(matrix - ? matrix._transformPoint(segment._point) : segment._point)); - } else if (join == 'bevel') { - var curve = segment.getCurve(); - addBevelJoin(curve, 0); - addBevelJoin(curve.getPrevious(), 1); - } else if (join == 'miter') { - var curve2 = segment.getCurve(), - curve1 = curve2.getPrevious(), - point = curve2.getPointAt(0, true), - normal1 = curve1.getNormalAt(1, true).normalize(radius), - normal2 = curve2.getNormalAt(0, true).normalize(radius), - line1 = new Line(point.subtract(normal1), - Point.create(-normal1.y, normal1.x)), - line2 = new Line(point.subtract(normal2), - Point.create(-normal2.y, normal2.x)), - corner = line1.intersect(line2); - if (!corner || point.getDistance(corner) > miter) { - addJoin(segment, 'bevel'); - } else { - add(corner); - } - } - } - - function addCap(segment, cap, t) { - switch (cap) { - case 'round': - return addJoin(segment, cap); - case 'butt': - case 'square': - var curve = segment.getCurve(), - point = curve.getPointAt(t, true), - normal = curve.getNormalAt(t, true).normalize(radius); - if (cap === 'square') - point = point.add(normal.rotate(t == 0 ? -90 : 90)); - add(point.add(normal)); - add(point.subtract(normal)); - break; - } - } - - for (var i = 1, l = segments.length - (closed ? 0 : 1); i < l; i++) - addJoin(segments[i], join); - if (closed) { - addJoin(segments[0], join); - } else { - addCap(segments[0], cap, 0); - addCap(segments[segments.length - 1], cap, 1); - } - return bounds; - }, - - getHandleBounds: function(segments, closed, style, matrix, strokePadding, - joinPadding) { - var coords = new Array(6), - x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2; - strokePadding = strokePadding / 2 || 0; - joinPadding = joinPadding / 2 || 0; - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i]; - segment._transformCoordinates(matrix, coords, false); - for (var j = 0; j < 6; j += 2) { - var padding = j == 0 ? joinPadding : strokePadding, - x = coords[j], - y = coords[j + 1], - xn = x - padding, - xx = x + padding, - yn = y - padding, - yx = y + padding; - if (xn < x1) x1 = xn; - if (xx > x2) x2 = xx; - if (yn < y1) y1 = yn; - if (yx > y2) y2 = yx; - } - } - return Rectangle.create(x1, y1, x2 - x1, y2 - y1); - }, - - getRoughBounds: function(segments, closed, style, matrix) { - var strokeWidth = style._strokeColor ? style._strokeWidth : 0; - return Path.getHandleBounds(segments, closed, style, matrix, - strokeWidth, - style._strokeJoin == 'miter' - ? strokeWidth * style._miterLimit - : strokeWidth); - } -}}); - -Path.inject({ statics: new function() { - - function readRectangle(list) { - var rect; - if (Base.hasNamed(list, 'from')) { - rect = new Rectangle(Point.readNamed(list, 'from'), - Point.readNamed(list, 'to')); - } else if (Base.hasNamed(list, 'size')) { - rect = new Rectangle(Point.readNamed(list, 'point'), - Size.readNamed(list, 'size')); - if (Base.hasNamed(list, 'center')) - rect.setCenter(Point.readNamed(list, 'center')); - } else { - rect = Rectangle.readNamed(list, 'rectangle'); - } - return rect; - } - - function createRectangle() { - var rect = readRectangle(arguments), - left = rect.getLeft(), - top = rect.getTop(), - right = rect.getRight(), - bottom = rect.getBottom(), - path = new Path(arguments._filtered); - path._add([ - new Segment(Point.create(left, bottom)), - new Segment(Point.create(left, top)), - new Segment(Point.create(right, top)), - new Segment(Point.create(right, bottom)) - ]); - path._closed = true; - return path; - } - - var kappa = 2 * (Math.sqrt(2) - 1) / 3; - - var ellipseSegments = [ - new Segment([0, 0.5], [0, kappa ], [0, -kappa]), - new Segment([0.5, 0], [-kappa, 0], [kappa, 0 ]), - new Segment([1, 0.5], [0, -kappa], [0, kappa ]), - new Segment([0.5, 1], [kappa, 0 ], [-kappa, 0]) - ]; - - function createEllipse() { - var rect = readRectangle(arguments), - path = new Path(arguments._filtered), - point = rect.getPoint(true), - size = rect.getSize(true), - segments = new Array(4); - for (var i = 0; i < 4; i++) { - var segment = ellipseSegments[i]; - segments[i] = new Segment( - segment._point.multiply(size).add(point), - segment._handleIn.multiply(size), - segment._handleOut.multiply(size) - ); - } - path._add(segments); - path._closed = true; - return path; - } - - return { - Line: function() { - return new Path( - Point.readNamed(arguments, 'from'), - Point.readNamed(arguments, 'to') - ).set(arguments._filtered); - }, - - Rectangle: createRectangle, - - RoundRectangle: function() { - var rect = readRectangle(arguments), - radius = Size.readNamed(arguments, 'radius'); - if (radius.isZero()) - return createRectangle(rect); - radius = Size.min(radius, rect.getSize(true).divide(2)); - var bl = rect.getBottomLeft(true), - tl = rect.getTopLeft(true), - tr = rect.getTopRight(true), - br = rect.getBottomRight(true), - h = radius.multiply(kappa * 2), - path = new Path(arguments._filtered); - path._add([ - new Segment(bl.add(radius.width, 0), null, [-h.width, 0]), - new Segment(bl.subtract(0, radius.height), [0, h.height], null), - - new Segment(tl.add(0, radius.height), null, [0, -h.height]), - new Segment(tl.add(radius.width, 0), [-h.width, 0], null), - - new Segment(tr.subtract(radius.width, 0), null, [h.width, 0]), - new Segment(tr.add(0, radius.height), [0, -h.height], null), - - new Segment(br.subtract(0, radius.height), null, [0, h.height]), - new Segment(br.subtract(radius.width, 0), [h.width, 0], null) - ]); - path._closed = true; - return path; - }, - - Ellipse: createEllipse, - - Oval: createEllipse, - - Circle: function() { - var center = Point.readNamed(arguments, 'center'), - radius = Base.readNamed(arguments, 'radius'); - return createEllipse(new Rectangle(center.subtract(radius), - Size.create(radius * 2, radius * 2))) - .set(arguments._filtered); - }, - - Arc: function() { - var from = Point.readNamed(arguments, 'from'), - through = Point.readNamed(arguments, 'through'), - to = Point.readNamed(arguments, 'to'), - path = new Path(arguments._filtered); - path.moveTo(from); - path.arcTo(through, to); - return path; - }, - - RegularPolygon: function() { - var center = Point.readNamed(arguments, 'center'), - numSides = Base.readNamed(arguments, 'numSides'), - radius = Base.readNamed(arguments, 'radius'), - path = new Path(arguments._filtered), - step = 360 / numSides, - three = !(numSides % 3), - vector = new Point(0, three ? -radius : radius), - offset = three ? -1 : 0.5, - segments = new Array(numSides); - for (var i = 0; i < numSides; i++) { - segments[i] = new Segment(center.add( - vector.rotate((i + offset) * step))); - } - path._add(segments); - path._closed = true; - return path; - }, - - Star: function() { - var center = Point.readNamed(arguments, 'center'), - numPoints = Base.readNamed(arguments, 'numPoints') * 2, - radius1 = Base.readNamed(arguments, 'radius1'), - radius2 = Base.readNamed(arguments, 'radius2'), - path = new Path(arguments._filtered), - step = 360 / numPoints, - vector = new Point(0, -1), - segments = new Array(numPoints); - for (var i = 0; i < numPoints; i++) { - segments[i] = new Segment(center.add( - vector.rotate(step * i).multiply(i % 2 ? radius2 : radius1))); - } - path._add(segments); - path._closed = true; - return path; - } - }; -}}); - -var CompoundPath = this.CompoundPath = PathItem.extend({ - _type: 'compoundpath', - initialize: function(arg) { - this.base(); - this._children = []; - this._namedChildren = {}; - if (!this._setProperties(arg)) - this.addChildren(Array.isArray(arg) ? arg : arguments); - }, - - insertChild: function(index, item, _cloning) { - if (item._type !== 'path') - return null; - item = this.base(index, item); - if (!_cloning && item && item._clockwise === undefined) - item.setClockwise(item._index == 0); - return item; - }, - - reduce: function() { - if (this._children.length == 1) { - var child = this._children[0]; - child.insertAbove(this); - this.remove(); - return child; - } - return this; - }, - - smooth: function() { - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i].smooth(); - }, - - getCurves: function() { - var curves = []; - for (var i = 0, l = this._children.length; i < l; i++) - curves = curves.concat(this._children[i].getCurves()); - return curves; - }, - - isEmpty: function() { - return this._children.length == 0; - }, - - contains: function(point) { - point = Point.read(arguments); - var count = 0; - for (var i = 0, l = this._children.length; i < l; i++) { - if (this._children[i].contains(point)) - count++; - } - return (count & 1) == 1; - }, - - _hitTest: function(point, options) { - return this.base(point, Base.merge(options, { fill: false })) - || options.fill && this._style._fillColor && this.contains(point) - ? new HitResult('fill', this) - : null; - }, - - draw: function(ctx, param) { - var children = this._children, - style = this._style; - if (children.length == 0) - return; - ctx.beginPath(); - param.compound = true; - for (var i = 0, l = children.length; i < l; i++) - Item.draw(children[i], ctx, param); - param.compound = false; - if (this._clipMask) { - ctx.clip(); - } else { - this._setStyles(ctx); - if (style._fillColor) - ctx.fill(); - if (style._strokeColor) - ctx.stroke(); - } - } -}, new function() { - function getCurrentPath(that) { - if (!that._children.length) - throw new Error('Use a moveTo() command first'); - return that._children[that._children.length - 1]; - } - - var fields = { - moveTo: function(point) { - var path = new Path(); - this.addChild(path); - path.moveTo.apply(path, arguments); - }, - - moveBy: function(point) { - this.moveTo(getCurrentPath(this).getLastSegment()._point.add( - Point.read(arguments))); - }, - - closePath: function() { - getCurrentPath(this).setClosed(true); - } - }; - - Base.each(['lineTo', 'cubicCurveTo', 'quadraticCurveTo', 'curveTo', - 'arcTo', 'lineBy', 'curveBy', 'arcBy'], function(key) { - fields[key] = function() { - var path = getCurrentPath(this); - path[key].apply(path, arguments); - }; - }); - - return fields; -}); - -var PathFlattener = Base.extend({ - initialize: function(path) { - this.curves = []; - this.parts = []; - this.length = 0; - this.index = 0; - - var segments = path._segments, - segment1 = segments[0], - segment2, - that = this; - - function addCurve(segment1, segment2) { - var curve = Curve.getValues(segment1, segment2); - that.curves.push(curve); - that._computeParts(curve, segment1._index, 0, 1); - } - - for (var i = 1, l = segments.length; i < l; i++) { - segment2 = segments[i]; - addCurve(segment1, segment2); - segment1 = segment2; - } - if (path._closed) - addCurve(segment2, segments[0]); - }, - - _computeParts: function(curve, index, minT, maxT) { - if ((maxT - minT) > 1 / 32 && !Curve.isFlatEnough(curve, 0.25)) { - var curves = Curve.subdivide(curve); - var halfT = (minT + maxT) / 2; - this._computeParts(curves[0], index, minT, halfT); - this._computeParts(curves[1], index, halfT, maxT); - } else { - var x = curve[6] - curve[0], - y = curve[7] - curve[1], - dist = Math.sqrt(x * x + y * y); - if (dist > 0.00001) { - this.length += dist; - this.parts.push({ - offset: this.length, - value: maxT, - index: index - }); - } - } - }, - - getParameterAt: function(offset) { - var i, j = this.index; - for (;;) { - i = j; - if (j == 0 || this.parts[--j].offset < offset) - break; - } - for (var l = this.parts.length; i < l; i++) { - var part = this.parts[i]; - if (part.offset >= offset) { - this.index = i; - var prev = this.parts[i - 1]; - var prevVal = prev && prev.index == part.index ? prev.value : 0, - prevLen = prev ? prev.offset : 0; - return { - value: prevVal + (part.value - prevVal) - * (offset - prevLen) / (part.offset - prevLen), - index: part.index - }; - } - } - var part = this.parts[this.parts.length - 1]; - return { - value: 1, - index: part.index - }; - }, - - evaluate: function(offset, type) { - var param = this.getParameterAt(offset); - return Curve.evaluate(this.curves[param.index], param.value, true, type); - }, - - drawPart: function(ctx, from, to) { - from = this.getParameterAt(from); - to = this.getParameterAt(to); - for (var i = from.index; i <= to.index; i++) { - var curve = Curve.getPart(this.curves[i], - i == from.index ? from.value : 0, - i == to.index ? to.value : 1); - if (i == from.index) - ctx.moveTo(curve[0], curve[1]); - ctx.bezierCurveTo.apply(ctx, curve.slice(2)); - } - } -}); - -var PathFitter = Base.extend({ - initialize: function(path, error) { - this.points = []; - var segments = path._segments, - prev; - for (var i = 0, l = segments.length; i < l; i++) { - var point = segments[i].point.clone(); - if (!prev || !prev.equals(point)) { - this.points.push(point); - prev = point; - } - } - this.error = error; - }, - - fit: function() { - this.segments = [new Segment(this.points[0])]; - this.fitCubic(0, this.points.length - 1, - this.points[1].subtract(this.points[0]).normalize(), - this.points[this.points.length - 2].subtract( - this.points[this.points.length - 1]).normalize()); - return this.segments; - }, - - fitCubic: function(first, last, tan1, tan2) { - if (last - first == 1) { - var pt1 = this.points[first], - pt2 = this.points[last], - dist = pt1.getDistance(pt2) / 3; - this.addCurve([pt1, pt1.add(tan1.normalize(dist)), - pt2.add(tan2.normalize(dist)), pt2]); - return; - } - var uPrime = this.chordLengthParameterize(first, last), - maxError = Math.max(this.error, this.error * this.error), - error, - split; - for (var i = 0; i <= 4; i++) { - var curve = this.generateBezier(first, last, uPrime, tan1, tan2); - var max = this.findMaxError(first, last, curve, uPrime); - if (max.error < this.error) { - this.addCurve(curve); - return; - } - split = max.index; - if (max.error >= maxError) - break; - this.reparameterize(first, last, uPrime, curve); - maxError = max.error; - } - var V1 = this.points[split - 1].subtract(this.points[split]), - V2 = this.points[split].subtract(this.points[split + 1]), - tanCenter = V1.add(V2).divide(2).normalize(); - this.fitCubic(first, split, tan1, tanCenter); - this.fitCubic(split, last, tanCenter.negate(), tan2); - }, - - addCurve: function(curve) { - var prev = this.segments[this.segments.length - 1]; - prev.setHandleOut(curve[1].subtract(curve[0])); - this.segments.push( - new Segment(curve[3], curve[2].subtract(curve[3]))); - }, - - generateBezier: function(first, last, uPrime, tan1, tan2) { - var epsilon = 1e-11, - pt1 = this.points[first], - pt2 = this.points[last], - C = [[0, 0], [0, 0]], - X = [0, 0]; - - for (var i = 0, l = last - first + 1; i < l; i++) { - var u = uPrime[i], - t = 1 - u, - b = 3 * u * t, - b0 = t * t * t, - b1 = b * t, - b2 = b * u, - b3 = u * u * u, - a1 = tan1.normalize(b1), - a2 = tan2.normalize(b2), - tmp = this.points[first + i] - .subtract(pt1.multiply(b0 + b1)) - .subtract(pt2.multiply(b2 + b3)); - C[0][0] += a1.dot(a1); - C[0][1] += a1.dot(a2); - C[1][0] = C[0][1]; - C[1][1] += a2.dot(a2); - X[0] += a1.dot(tmp); - X[1] += a2.dot(tmp); - } - - var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1], - alpha1, alpha2; - if (Math.abs(detC0C1) > epsilon) { - var detC0X = C[0][0] * X[1] - C[1][0] * X[0], - detXC1 = X[0] * C[1][1] - X[1] * C[0][1]; - alpha1 = detXC1 / detC0C1; - alpha2 = detC0X / detC0C1; - } else { - var c0 = C[0][0] + C[0][1], - c1 = C[1][0] + C[1][1]; - if (Math.abs(c0) > epsilon) { - alpha1 = alpha2 = X[0] / c0; - } else if (Math.abs(c1) > epsilon) { - alpha1 = alpha2 = X[1] / c1; - } else { - alpha1 = alpha2 = 0; - } - } - - var segLength = pt2.getDistance(pt1); - epsilon *= segLength; - if (alpha1 < epsilon || alpha2 < epsilon) { - alpha1 = alpha2 = segLength / 3; - } - - return [pt1, pt1.add(tan1.normalize(alpha1)), - pt2.add(tan2.normalize(alpha2)), pt2]; - }, - - reparameterize: function(first, last, u, curve) { - for (var i = first; i <= last; i++) { - u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); - } - }, - - findRoot: function(curve, point, u) { - var curve1 = [], - curve2 = []; - for (var i = 0; i <= 2; i++) { - curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3); - } - for (var i = 0; i <= 1; i++) { - curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2); - } - var pt = this.evaluate(3, curve, u), - pt1 = this.evaluate(2, curve1, u), - pt2 = this.evaluate(1, curve2, u), - diff = pt.subtract(point), - df = pt1.dot(pt1) + diff.dot(pt2); - if (Math.abs(df) < 0.00001) - return u; - return u - diff.dot(pt1) / df; - }, - - evaluate: function(degree, curve, t) { - var tmp = curve.slice(); - for (var i = 1; i <= degree; i++) { - for (var j = 0; j <= degree - i; j++) { - tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t)); - } - } - return tmp[0]; - }, - - chordLengthParameterize: function(first, last) { - var u = [0]; - for (var i = first + 1; i <= last; i++) { - u[i - first] = u[i - first - 1] - + this.points[i].getDistance(this.points[i - 1]); - } - for (var i = 1, m = last - first; i <= m; i++) { - u[i] /= u[m]; - } - return u; - }, - - findMaxError: function(first, last, curve, u) { - var index = Math.floor((last - first + 1) / 2), - maxDist = 0; - for (var i = first + 1; i < last; i++) { - var P = this.evaluate(3, curve, u[i - first]); - var v = P.subtract(this.points[i]); - var dist = v.x * v.x + v.y * v.y; - if (dist >= maxDist) { - maxDist = dist; - index = i; - } - } - return { - error: maxDist, - index: index - }; - } -}); - -var TextItem = this.TextItem = Item.extend({ - _boundsGetter: 'getBounds', - - initialize: function(arg) { - this._style = CharacterStyle.create(this); - this._paragraphStyle = ParagraphStyle.create(this); - var point = Point.read(arguments, 0, 0, false, true); - this.base(point); - this.setParagraphStyle(); - this._content = ''; - this._lines = []; - if (!point) - this._setProperties(arg); - }, - - _clone: function(copy) { - copy.setContent(this._content); - copy.setParagraphStyle(this._paragraphStyle); - return this.base(copy); - }, - - getContent: function() { - return this._content; - }, - - setContent: function(content) { - this._content = '' + content; - this._lines = this._content.split(/\r\n|\n|\r/mg); - this._changed(65); - }, - - isEmpty: function() { - return !this._content; - }, - - getCharacterStyle: function() { - return this.getStyle(); - }, - - setCharacterStyle: function(style) { - this.setStyle(style); - } - -}); - -var PointText = this.PointText = TextItem.extend({ - _type: 'pointtext', - - clone: function() { - return this._clone(new PointText()); - }, - - getPoint: function() { - var point = this._matrix.getTranslation(); - return LinkedPoint.create(this, 'setPoint', point.x, point.y); - }, - - setPoint: function(point) { - this.translate(Point.read(arguments).subtract( - this._matrix.getTranslation())); - }, - - draw: function(ctx) { - if (!this._content) - return; - this._setStyles(ctx); - var style = this._style, - leading = this.getLeading(), - lines = this._lines; - ctx.font = style.getFontStyle(); - ctx.textAlign = this.getJustification(); - for (var i = 0, l = lines.length; i < l; i++) { - var line = lines[i]; - if (style._fillColor) - ctx.fillText(line, 0, 0); - if (style._strokeColor) - ctx.strokeText(line, 0, 0); - ctx.translate(0, leading); - } - }, - - drawSelected: function(ctx, matrix) { - Item.drawSelectedBounds(this._getBounds(), ctx, matrix); - } -}, new function() { - var context = null; - - return { - _getBounds: function(getter, matrix) { - if (!context) - context = CanvasProvider.getCanvas( - Size.create(1, 1)).getContext('2d'); - var justification = this.getJustification(), - x = 0; - context.font = this._style.getFontStyle(); - var width = 0; - for (var i = 0, l = this._lines.length; i < l; i++) - width = Math.max(width, context.measureText( - this._lines[i]).width); - if (justification !== 'left') - x -= width / (justification === 'center' ? 2: 1); - var leading = this.getLeading(), - count = this._lines.length, - bounds = Rectangle.create(x, - count ? leading / 4 + (count - 1) * leading : 0, - width, -count * leading); - return matrix ? matrix._transformBounds(bounds, bounds) : bounds; - } - }; -}); - -var SvgStyles = Base.each({ - fillColor: ['fill', 'color'], - strokeColor: ['stroke', 'color'], - strokeWidth: ['stroke-width', 'number'], - strokeCap: ['stroke-linecap', 'string'], - strokeJoin: ['stroke-linejoin', 'string'], - miterLimit: ['stroke-miterlimit', 'number'], - dashArray: ['stroke-dasharray', 'array'], - dashOffset: ['stroke-dashoffset', 'number'] -}, function(entry, key) { - var part = Base.capitalize(key); - this.attributes[entry[0]] = this.properties[key] = { - type: entry[1], - property: key, - attribute: entry[0], - get: 'get' + part, - set: 'set' + part - }; -}, { - properties: {}, - attributes: {} -}); - -new function() { - - var formatFloat = Base.formatFloat; - - function formatPoint(point) { - return formatFloat(point.x) + ',' + formatFloat(point.y); - } - - function setAttributes(svg, attrs) { - for (var key in attrs) { - var val = attrs[key]; - if (typeof val === 'number') - val = formatFloat(val); - svg.setAttribute(key, val); - } - return svg; - } - - function createElement(tag, attrs) { - return setAttributes( - document.createElementNS('http://www.w3.org/2000/svg', tag), attrs); - } - - function getDistance(segments, index1, index2) { - return segments[index1]._point.getDistance(segments[index2]._point); - } - - function getTransform(item, coordinates) { - var matrix = item._matrix, - trans = matrix.getTranslation(), - attrs = {}; - if (coordinates) { - matrix = matrix.createShiftless(); - var point = matrix._inverseTransform(trans); - attrs.x = point.x; - attrs.y = point.y; - trans = null; - } - if (matrix.isIdentity()) - return attrs; - var angle = matrix.getRotation(), - parts = []; - if (angle != null) { - matrix = matrix.clone().scale(1, -1); - if (trans && !trans.isZero()) - parts.push('translate(' + formatPoint(trans) + ')'); - if (angle) - parts.push('rotate(' + formatFloat(angle) + ')'); - var scale = matrix.getScaling(); - if (!Numerical.isZero(scale.x - 1) || !Numerical.isZero(scale.y - 1)) - parts.push('scale(' + formatPoint(scale) +')'); - } else { - parts.push('matrix(' + matrix.getValues().join(',') + ')'); - } - attrs.transform = parts.join(' '); - return attrs; - } - - function getPath(path, segments) { - var parts = [], - style = path._style; - - function addCurve(seg1, seg2, skipLine) { - var point1 = seg1._point, - point2 = seg2._point, - handle1 = seg1._handleOut, - handle2 = seg2._handleIn; - if (handle1.isZero() && handle2.isZero()) { - if (!skipLine) { - parts.push('L' + formatPoint(point2)); - } - } else { - var end = point2.subtract(point1); - parts.push('c' + formatPoint(handle1), - formatPoint(end.add(handle2)), - formatPoint(end)); - } - } - - parts.push('M' + formatPoint(segments[0]._point)); - for (i = 0, l = segments.length - 1; i < l; i++) - addCurve(segments[i], segments[i + 1], false); - if (path._closed && style._strokeColor || style._fillColor) - addCurve(segments[segments.length - 1], segments[0], true); - if (path._closed) - parts.push('z'); - return parts.join(' '); - } - - function determineAngle(path, segments, type, center) { - var topCenter = type === 'rect' - ? segments[1]._point.add(segments[2]._point).divide(2) - : type === 'roundrect' - ? segments[3]._point.add(segments[4]._point).divide(2) - : type === 'circle' || type === 'ellipse' - ? segments[1]._point - : null; - var angle = topCenter && topCenter.subtract(center).getAngle() + 90; - return Numerical.isZero(angle || 0) ? 0 : angle; - } - - function determineType(path, segments) { - function isColinear(i, j) { - var seg1 = segments[i], - seg2 = seg1.getNext(), - seg3 = segments[j], - seg4 = seg3.getNext(); - return seg1._handleOut.isZero() && seg2._handleIn.isZero() - && seg3._handleOut.isZero() && seg4._handleIn.isZero() - && seg2._point.subtract(seg1._point).isColinear( - seg4._point.subtract(seg3._point)); - } - - var kappa = 4 * (Math.sqrt(2) - 1) / 3; - - function isArc(i) { - var segment = segments[i], - next = segment.getNext(), - handle1 = segment._handleOut, - handle2 = next._handleIn; - if (handle1.isOrthogonal(handle2)) { - var from = segment._point, - to = next._point, - corner = new Line(from, handle1).intersect( - new Line(to, handle2)); - return corner && Numerical.isZero(handle1.getLength() / - corner.subtract(from).getLength() - kappa) - && Numerical.isZero(handle2.getLength() / - corner.subtract(to).getLength() - kappa); - } - } - - if (path.isPolygon()) { - return segments.length === 4 && path._closed - && isColinear(0, 2) && isColinear(1, 3) - ? 'rect' - : segments.length === 0 - ? 'empty' - : segments.length >= 3 - ? path._closed ? 'polygon' : 'polyline' - : 'line'; - } else if (path._closed) { - if (segments.length === 8 - && isArc(0) && isArc(2) && isArc(4) && isArc(6) - && isColinear(1, 5) && isColinear(3, 7)) { - return 'roundrect'; - } else if (segments.length === 4 - && isArc(0) && isArc(1) && isArc(2) && isArc(3)) { - return Numerical.isZero(getDistance(segments, 0, 2) - - getDistance(segments, 1, 3)) - ? 'circle' - : 'ellipse'; - } - } - return 'path'; - } - - function exportGroup(group) { - var attrs = getTransform(group), - children = group._children; - attrs.fill = 'none'; - var svg = createElement('g', attrs); - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i].exportSvg(); - if (child) - svg.appendChild(child); - } - return svg; - } - - function exportText(item) { - var attrs = getTransform(item, true), - style = item._style; - if (style._font != null) - attrs['font-family'] = style._font; - if (style._fontSize != null) - attrs['font-size'] = style._fontSize; - var svg = createElement('text', attrs); - svg.textContent = item._content; - return svg; - } - - function exportPath(path) { - var segments = path._segments, - center = path.getPosition(true), - type = determineType(path, segments), - angle = determineAngle(path, segments, type, center), - attrs; - switch (type) { - case 'empty': - return null; - case 'path': - attrs = { - d: getPath(path, segments) - }; - break; - case 'polyline': - case 'polygon': - var parts = []; - for(i = 0, l = segments.length; i < l; i++) - parts.push(formatPoint(segments[i]._point)); - attrs = { - points: parts.join(' ') - }; - break; - case 'rect': - var width = getDistance(segments, 0, 3), - height = getDistance(segments, 0, 1), - point = segments[1]._point.rotate(-angle, center); - attrs = { - x: point.x, - y: point.y, - width: width, - height: height - }; - break; - case 'roundrect': - type = 'rect'; - var width = getDistance(segments, 1, 6), - height = getDistance(segments, 0, 3), - rx = (width - getDistance(segments, 0, 7)) / 2, - ry = (height - getDistance(segments, 1, 2)) / 2, - left = segments[3]._point, - right = segments[4]._point, - point = left.subtract(right.subtract(left).normalize(rx)) - .rotate(-angle, center); - attrs = { - x: point.x, - y: point.y, - width: width, - height: height, - rx: rx, - ry: ry - }; - break; - case'line': - var first = segments[0]._point, - last = segments[segments.length - 1]._point; - attrs = { - x1: first._x, - y1: first._y, - x2: last._x, - y2: last._y - }; - break; - case 'circle': - var radius = getDistance(segments, 0, 2) / 2; - attrs = { - cx: center.x, - cy: center.y, - r: radius - }; - break; - case 'ellipse': - var rx = getDistance(segments, 2, 0) / 2, - ry = getDistance(segments, 3, 1) / 2; - attrs = { - cx: center.x, - cy: center.y, - rx: rx, - ry: ry - }; - break; - } - if (angle) { - attrs.transform = 'rotate(' + formatFloat(angle) + ',' - + formatPoint(center) + ')'; - } - var svg = createElement(type, attrs); - return svg; - } - - var exporters = { - group: exportGroup, - layer: exportGroup, - path: exportPath, - pointtext: exportText - }; - - function applyStyle(item, svg) { - var attrs = {}, - style = item._style, - parent = item.getParent(), - parentStyle = parent && parent._style; - - if (item._name != null) - attrs.id = item._name; - - Base.each(SvgStyles.properties, function(entry) { - var value = style[entry.get](); - if (!parentStyle || !Base.equals(parentStyle[entry.get](), value)) { - if (entry.type === 'color' && value != null && value.getAlpha() < 1) - attrs[entry.attribute + '-opacity'] = value.getAlpha(); - attrs[entry.attribute] = value == null - ? 'none' - : entry.type === 'color' - ? value.toCss(true) - : entry.type === 'array' - ? value.join(',') - : entry.type === 'number' - ? formatFloat(value) - : value; - } - }); - - if (item._opacity != null && item._opacity < 1) - attrs.opacity = item._opacity; - - if (item._visibility != null && !item._visibility) - attrs.visibility = 'hidden'; - - return setAttributes(svg, attrs); - } - - Item.inject({ - exportSvg: function() { - var exporter = exporters[this._type], - svg = exporter && exporter(this, this._type); - return svg && applyStyle(this, svg); - } - }); - - Project.inject({ - exportSvg: function() { - var svg = createElement('svg'), - layers = this.layers; - for (var i = 0, l = layers.length; i < l; i++) - svg.appendChild(layers[i].exportSvg()); - return svg; - } - }); -}; - -new function() { - - function getValue(svg, key, allowNull, index) { - var base = (!allowNull || svg.getAttribute(key) != null) - && svg[key] && svg[key].baseVal; - return base - ? index !== undefined - ? index < base.numberOfItems - ? Base.pick((base = base.getItem(index)).value, base) - : null - : Base.pick(base.value, base) - : null; - } - - function getPoint(svg, x, y, allowNull, index) { - x = getValue(svg, x, allowNull, index); - y = getValue(svg, y, allowNull, index); - return allowNull && x == null && y == null ? null - : Point.create(x || 0, y || 0); - } - - function getSize(svg, w, h, allowNull, index) { - w = getValue(svg, w, allowNull, index); - h = getValue(svg, h, allowNull, index); - return allowNull && w == null && h == null ? null - : Size.create(w || 0, h || 0); - } - - function convertValue(value, type) { - return value === 'none' - ? null - : type === 'number' - ? Base.toFloat(value) - : type === 'array' - ? value.split(/[\s,]+/g).map(parseFloat) - : type === 'color' && getDefinition(value) - || value; - } - - function createClipGroup(item, clip) { - clip.setClipMask(true); - return new Group(clip, item); - } - - function importGroup(svg, type) { - var nodes = svg.childNodes, - compound = type === 'clippath', - group = compound ? new CompoundPath() : new Group(); - - for (var i = 0, l = nodes.length; i < l; i++) { - var child = nodes[i], - item; - if (child.nodeType == 1 && (item = importSvg(child))) { - if (compound && item instanceof CompoundPath) { - group.addChildren(item.removeChildren()); - item.remove(); - } else if (!(item instanceof Symbol)) { - group.addChild(item); - } - } - } - - if (type == 'defs') { - group.remove(); - group = null; - } - return group; - } - - function importPoly(svg, type) { - var path = new Path(), - points = svg.points; - path.moveTo(points.getItem(0)); - for (var i = 1, l = points.numberOfItems; i < l; i++) - path.lineTo(points.getItem(i)); - if (type === 'polygon') - path.closePath(); - return path; - } - - function importPath(svg) { - var path = new Path(), - list = svg.pathSegList, - compoundPath, lastPoint; - for (var i = 0, l = list.numberOfItems; i < l; i++) { - var segment = list.getItem(i), - segType = segment.pathSegType, - isRelative = segType % 2 == 1; - if (segType === 0) - continue; - if (!path.isEmpty()) - lastPoint = path.getLastSegment().getPoint(); - var relative = isRelative && !path.isEmpty() - ? lastPoint - : Point.create(0, 0); - var coord = (segType == 12 - || segType == 13) && 'y' - || (segType == 14 - || segType == 15) && 'x'; - if (coord) - segment[coord] = isRelative ? 0 : lastPoint[coord]; - var point = Point.create(segment.x, segment.y).add(relative); - switch (segType) { - case 1: - path.closePath(); - break; - case 2: - case 3: - if (!path.isEmpty() && !compoundPath) { - compoundPath = new CompoundPath([path]); - } - if (compoundPath) { - path = new Path(); - compoundPath.addChild(path); - } - path.moveTo(point); - break; - case 4: - case 5: - case 12: - case 13: - case 14: - case 15: - path.lineTo(point); - break; - case 6: - case 7: - path.cubicCurveTo( - relative.add(segment.x1, segment.y1), - relative.add(segment.x2, segment.y2), - point - ); - break; - case 8: - case 9: - path.quadraticCurveTo( - relative.add(segment.x1, segment.y1), - point - ); - break; - case 16: - case 17: - var prev = list.getItem(i - 1), - control = lastPoint.add(lastPoint.subtract( - Point.create(prev.x2, prev.y2) - .subtract(prev.x, prev.y) - .add(lastPoint))); - path.cubicCurveTo( - control, - relative.add(segment.x2, segment.y2), - point); - break; - case 18: - case 19: - var control, - j = i; - for (; j >= 0; j--) { - var prev = list.getItem(j); - if (prev.pathSegType === 8 || - prev.pathSegType === 9) { - control = Point.create(prev.x1, prev.y1) - .subtract(prev.x, prev.y) - .add(path._segments[j].getPoint()); - break; - } - } - for (; j < i; ++j) { - var anchor = path._segments[j].getPoint(); - control = anchor.add(anchor.subtract(control)); - } - path.quadraticCurveTo(control, point); - break; - } - } - return compoundPath || path; - } - - function importGradient(svg, type) { - var nodes = svg.childNodes, - stops = []; - for (var i = 0, l = nodes.length; i < l; i++) { - var node = nodes[i]; - if (node.nodeType == 1) - stops.push(applyAttributes(new GradientStop(), node)); - } - var gradient = new Gradient(stops), - isRadial = type == 'radialgradient', - origin, destination, highlight; - if (isRadial) { - gradient.type = 'radial'; - origin = getPoint(svg, 'cx', 'cy'); - destination = origin.add(getValue(svg, 'r'), 0); - highlight = getPoint(svg, 'fx', 'fy', true); - } else { - origin = getPoint(svg, 'x1', 'y1'); - destination = getPoint(svg, 'x2', 'y2'); - } - applyAttributes( - new GradientColor(gradient, origin, destination, highlight), svg); - return null; - } - - var definitions = {}; - function getDefinition(value) { - var match = value.match(/\(#([^)']+)/); - return match && definitions[match[1]]; - } - - var importers = { - // http://www.w3.org/TR/SVG/struct.html#Groups - g: importGroup, - // http://www.w3.org/TR/SVG/struct.html#NewDocument - svg: importGroup, - clippath: importGroup, - // http://www.w3.org/TR/SVG/shapes.html#PolygonElement - polygon: importPoly, - // http://www.w3.org/TR/SVG/shapes.html#PolylineElement - polyline: importPoly, - // http://www.w3.org/TR/SVG/paths.html - path: importPath, - // http://www.w3.org/TR/SVG/pservers.html#LinearGradients - lineargradient: importGradient, - // http://www.w3.org/TR/SVG/pservers.html#RadialGradients - radialgradient: importGradient, - - // http://www.w3.org/TR/SVG/struct.html#ImageElement - image: function (svg) { - var raster = new Raster(getValue(svg, 'href')); - raster.attach('load', function() { - var size = getSize(svg, 'width', 'height'); - this.setSize(size); - // Since x and y start from the top left of an image, add - // half of its size: - this.translate(getPoint(svg, 'x', 'y').add(size.divide(2))); - }); - return raster; - }, - - // http://www.w3.org/TR/SVG/struct.html#SymbolElement - symbol: function(svg, type) { - return new Symbol(applyAttributes(importGroup(svg, type), svg)); - }, - - // http://www.w3.org/TR/SVG/struct.html#DefsElement - defs: importGroup, - - // http://www.w3.org/TR/SVG/struct.html#UseElement - use: function(svg, type) { - // Note the namespaced xlink:href attribute is just called href - // as a property on svg. - // TODO: Should getValue become namespace aware? - var id = (getValue(svg, 'href') || '').substring(1), - definition = definitions[id]; - // Use place if we're dealing with a symbol: - return definition - ? definition instanceof Symbol - ? definition.place() - : definition.clone() - : null; - }, - - circle: function(svg) { - return new Path.Circle(getPoint(svg, 'cx', 'cy'), - getValue(svg, 'r')); - }, - - ellipse: function(svg) { - var center = getPoint(svg, 'cx', 'cy'), - radius = getSize(svg, 'rx', 'ry'); - return new Path.Ellipse(new Rectangle(center.subtract(radius), - center.add(radius))); - }, - - rect: function(svg) { - var point = getPoint(svg, 'x', 'y'), - size = getSize(svg, 'width', 'height'), - radius = getSize(svg, 'rx', 'ry'); - return new Path.RoundRectangle(new Rectangle(point, size), radius); - }, - - line: function(svg) { - return new Path.Line(getPoint(svg, 'x1', 'y1'), - getPoint(svg, 'x2', 'y2')); - }, - - text: function(svg) { - var text = new PointText(getPoint(svg, 'x', 'y', false, 0) - .add(getPoint(svg, 'dx', 'dy', false, 0))); - text.setContent(svg.textContent || ''); - return text; - } - }; - - function applyAttributes(item, svg) { - for (var i = 0, l = svg.style.length; i < l; i++) { - var name = svg.style[i]; - item = applyAttribute(item, svg, name, svg.style[Base.camelize(name)]); - } - for (var i = 0, l = svg.attributes.length; i < l; i++) { - var attr = svg.attributes[i]; - item = applyAttribute(item, svg, attr.name, attr.value); - } - return item; - } - - function applyAttribute(item, svg, name, value) { - if (value == null) - return item; - var entry = SvgStyles.attributes[name]; - if (entry) { - item._style[entry.set](convertValue(value, entry.type)); - } else { - switch (name) { - case 'id': - definitions[value] = item; - if (item.setName) - item.setName(value); - break; - case 'clip-path': - item = createClipGroup(item, - getDefinition(value).clone().reduce()); - break; - case 'gradientTransform': - case 'transform': - var transforms = svg[name].baseVal, - matrix = new Matrix(); - for (var i = 0, l = transforms.numberOfItems; i < l; i++) { - var mx = transforms.getItem(i).matrix; - matrix.concatenate( - new Matrix(mx.a, mx.b, mx.c, mx.d, mx.e, mx.f)); - } - item.transform(matrix); - break; - case 'stop-opacity': - case 'opacity': - var opacity = Base.toFloat(value); - if (name === 'stop-opacity') { - item.color.setAlpha(opacity); - } else { - item.setOpacity(opacity); - } - break; - case 'fill-opacity': - case 'stroke-opacity': - var color = item[name == 'fill-opacity' ? 'getFillColor' - : 'getStrokeColor'](); - if (color) - color.setAlpha(Base.toFloat(value)); - break; - case 'visibility': - item.setVisible(value === 'visible'); - break; - case 'font': - case 'font-family': - case 'font-size': - case 'text-anchor': - applyTextAttribute(item, svg, name, value); - break; - case 'stop-color': - item.setColor(value); - break; - case 'offset': - var percentage = value.match(/(.*)%$/); - item.setRampPoint(percentage ? percentage[1] / 100 : value); - break; - case 'viewBox': - if (item instanceof Symbol) - break; - var values = convertValue(value, 'array'), - rectangle = Rectangle.create.apply(this, values), - size = getSize(svg, 'width', 'height', true), - scale = size ? rectangle.getSize().divide(size) : 1, - offset = rectangle.getPoint(), - matrix = new Matrix().translate(offset).scale(scale); - item.transform(matrix.createInverse()); - if (size) - rectangle.setSize(size); - rectangle.setPoint(0); - item = createClipGroup(item, new Path.Rectangle(rectangle)); - break; - } - } - return item; - } - - function applyTextAttribute(item, svg, name, value) { - if (item instanceof TextItem) { - switch (name) { - case 'font': - var text = document.createElement('span'); - text.style.font = value; - for (var i = 0; i < text.style.length; i++) { - var name = text.style[i]; - item = applyAttribute(item, svg, name, text.style[name]); - } - break; - case 'font-family': - item.setFont(value.split(',')[0].replace(/^\s+|\s+$/g, '')); - break; - case 'font-size': - item.setFontSize(Base.toFloat(value)); - break; - case 'text-anchor': - item.setJustification({ - start: 'left', - middle: 'center', - end: 'right' - }[value]); - break; - } - } else if (item instanceof Group) { - var children = item._children; - for (var i = 0, l = children.length; i < l; i++) { - applyTextAttribute(children[i], svg, name, value); - } - } - } - - function importSvg(svg) { - var type = svg.nodeName.toLowerCase(), - importer = importers[type], - item = importer && importer(svg, type); - return item && applyAttributes(item, svg); - } - - Item.inject({ - importSvg: function(svg) { - return this.addChild(importSvg(svg)); - } - }); - - Project.inject({ - importSvg: function(svg) { - this.activate(); - return importSvg(svg); - } - }); -}; - -var Style = Item.extend({ - initialize: function(style) { - var clone = style instanceof Style; - return Base.each(this._defaults, function(value, key) { - value = style && style[key] || value; - this[key] = value && clone && value.clone - ? value.clone() : value; - }, this); - }, - - _getChildren: function() { - return this._item instanceof Group && this._item._children; - }, - - statics: { - create: function(item) { - var style = Base.create(this); - style._item = item; - return style; - }, - - extend: function(src) { - var styleKey = '_' + src._style, - stylePart = Base.capitalize(src._style), - flags = src._flags || {}, - owner = {}; - - owner['get' + stylePart] = function() { - return this[styleKey]; - }; - - owner['set' + stylePart] = function(style) { - this[styleKey].initialize(style); - }; - - Base.each(src._defaults, function(value, key) { - var isColor = /Color$/.test(key), - part = Base.capitalize(key), - set = 'set' + part, - get = 'get' + part; - src[set] = function(value) { - var children = this._getChildren(); - value = isColor ? Color.read(arguments, 0, 0, true) : value; - if (children) { - for (var i = 0, l = children.length; i < l; i++) - children[i][styleKey][set](value); - } else { - var old = this['_' + key]; - if (!Base.equals(old, value)) { - if (isColor) { - if (old) - delete old._owner; - if (value) { - value._owner = this._item; - } - } - this['_' + key] = value; - if (this._item) - this._item._changed(flags[key] || 17); - } - } - }; - src[get] = function() { - var children = this._getChildren(), - style; - if (!children) - return this['_' + key]; - for (var i = 0, l = children.length; i < l; i++) { - var childStyle = children[i][styleKey][get](); - if (!style) { - style = childStyle; - } else if (!Base.equals(style, childStyle)) { - return undefined; - } - } - return style; - }; - owner[set] = function(value) { - this[styleKey][set](value); - return this; - }; - owner[get] = function() { - return this[styleKey][get](); - }; - }); - src._owner.inject(owner); - return this.base.apply(this, arguments); - } - } -}); - -var PathStyle = this.PathStyle = Style.extend({ - _owner: Item, - _style: 'style', - _defaults: { - fillColor: undefined, - strokeColor: undefined, - strokeWidth: 1, - strokeCap: 'butt', - strokeJoin: 'miter', - miterLimit: 10, - dashOffset: 0, - dashArray: [] - }, - _flags: { - strokeWidth: 25, - strokeCap: 25, - strokeJoin: 25, - miterLimit: 25 - } - -}); - -var ParagraphStyle = this.ParagraphStyle = Style.extend({ - _owner: TextItem, - _style: 'paragraphStyle', - _defaults: { - justification: 'left' - }, - _flags: { - justification: 5 - } - -}); - -var CharacterStyle = this.CharacterStyle = PathStyle.extend({ - _owner: TextItem, - _style: 'style', - _defaults: Base.merge(PathStyle.prototype._defaults, { - fillColor: 'black', - fontSize: 12, - leading: null, - font: 'sans-serif' - }), - _flags: { - fontSize: 5, - leading: 5, - font: 5 - } - -}, { - getLeading: function() { - var leading = this.base(); - return leading != null ? leading : this.getFontSize() * 1.2; - }, - - getFontStyle: function() { - return this._fontSize + 'px ' + this._font; - } -}); - -var Color = this.Color = Base.extend(new function() { - - var components = { - gray: ['gray'], - rgb: ['red', 'green', 'blue'], - hsl: ['hue', 'saturation', 'lightness'], - hsb: ['hue', 'saturation', 'brightness'] - }; - - var colorCache = {}, - colorContext; - - function nameToRgbColor(name) { - var color = colorCache[name]; - if (color) - return color.clone(); - if (!colorContext) { - var canvas = CanvasProvider.getCanvas(Size.create(1, 1)); - colorContext = canvas.getContext('2d'); - colorContext.globalCompositeOperation = 'copy'; - } - colorContext.fillStyle = 'rgba(0,0,0,0)'; - colorContext.fillStyle = name; - colorContext.fillRect(0, 0, 1, 1); - var data = colorContext.getImageData(0, 0, 1, 1).data, - rgb = [data[0] / 255, data[1] / 255, data[2] / 255]; - return (colorCache[name] = RgbColor.read(rgb)).clone(); - } - - function hexToRgbColor(string) { - var hex = string.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); - if (hex.length >= 4) { - var rgb = new Array(3); - for (var i = 0; i < 3; i++) { - var channel = hex[i + 1]; - rgb[i] = parseInt(channel.length == 1 - ? channel + channel : channel, 16) / 255; - } - return RgbColor.read(rgb); - } - } - - var hsbIndices = [ - [0, 3, 1], - [2, 0, 1], - [1, 0, 3], - [1, 2, 0], - [3, 1, 0], - [0, 1, 2] - ]; - - var converters = { - 'rgb-hsb': function(color) { - var r = color._red, - g = color._green, - b = color._blue, - max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - h = delta == 0 ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60, - s = max == 0 ? 0 : delta / max, - v = max; - return new HsbColor(h, s, v, color._alpha); - }, - - 'hsb-rgb': function(color) { - var h = (color._hue / 60) % 6, - s = color._saturation, - b = color._brightness, - i = Math.floor(h), - f = h - i, - i = hsbIndices[i], - v = [ - b, - b * (1 - s), - b * (1 - s * f), - b * (1 - s * (1 - f)) - ]; - return new RgbColor(v[i[0]], v[i[1]], v[i[2]], color._alpha); - }, - - 'rgb-hsl': function(color) { - var r = color._red, - g = color._green, - b = color._blue, - max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - achromatic = delta == 0, - h = achromatic ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60, - l = (max + min) / 2, - s = achromatic ? 0 : l < 0.5 - ? delta / (max + min) - : delta / (2 - max - min); - return new HslColor(h, s, l, color._alpha); - }, - - 'hsl-rgb': function(color) { - var s = color._saturation, - h = color._hue / 360, - l = color._lightness; - if (s == 0) - return new RgbColor(l, l, l, color._alpha); - var t3s = [ h + 1 / 3, h, h - 1 / 3 ], - t2 = l < 0.5 ? l * (1 + s) : l + s - l * s, - t1 = 2 * l - t2, - c = []; - for (var i = 0; i < 3; i++) { - var t3 = t3s[i]; - if (t3 < 0) t3 += 1; - if (t3 > 1) t3 -= 1; - c[i] = 6 * t3 < 1 - ? t1 + (t2 - t1) * 6 * t3 - : 2 * t3 < 1 - ? t2 - : 3 * t3 < 2 - ? t1 + (t2 - t1) * ((2 / 3) - t3) * 6 - : t1; - } - return new RgbColor(c[0], c[1], c[2], color._alpha); - }, - - 'rgb-gray': function(color) { - return new GrayColor(1 - (color._red * 0.2989 + color._green * 0.587 - + color._blue * 0.114), color._alpha); - }, - - 'gray-rgb': function(color) { - var comp = 1 - color._gray; - return new RgbColor(comp, comp, comp, color._alpha); - }, - - 'gray-hsb': function(color) { - return new HsbColor(0, 0, 1 - color._gray, color._alpha); - }, - - 'gray-hsl': function(color) { - return new HslColor(0, 0, 1 - color._gray, color._alpha); - } - }; - - var fields = { - _readNull: true, - _readIndex: true, - - initialize: function(arg) { - var isArray = Array.isArray(arg), - type = this._type, - res; - if (typeof arg === 'object' && !isArray) { - if (!type) { - res = arg.red !== undefined - ? new RgbColor(arg.red, arg.green, arg.blue, arg.alpha) - : arg.gray !== undefined - ? new GrayColor(arg.gray, arg.alpha) - : arg.lightness !== undefined - ? new HslColor(arg.hue, arg.saturation, arg.lightness, - arg.alpha) - : arg.hue !== undefined - ? new HsbColor(arg.hue, arg.saturation, arg.brightness, - arg.alpha) - : new RgbColor(); - if (this._read) - res._read = 1; - } else { - res = Color.read(arguments).convert(type); - if (this._read) - res._read = arguments._read; - } - } else if (typeof arg === 'string') { - var rgbColor = arg.match(/^#[0-9a-f]{3,6}$/i) - ? hexToRgbColor(arg) - : nameToRgbColor(arg); - res = type - ? rgbColor.convert(type) - : rgbColor; - if (this._read) - res._read = 1; - } else { - var components = isArray ? arg - : Array.prototype.slice.call(arguments); - if (!type) { - var ctor = components.length >= 3 - ? RgbColor - : GrayColor; - res = new ctor(components); - } else { - res = Base.each(this._components, - function(name, i) { - var value = components[i]; - this['_' + name] = value !== undefined - ? value : null; - }, - this); - } - if (this._read) - res._read = res._components.length; - } - return res; - }, - - _serialize: function() { - var res = []; - for (var i = 0, l = this._components.length; i < l; i++) { - var component = this._components[i], - value = this['_' + component]; - if (component !== 'alpha' || value != null && value < 1) - res.push(value); - } - return res; - }, - - clone: function() { - var copy = Base.create(this.constructor), - components = this._components; - for (var i = 0, l = components.length; i < l; i++) { - var key = '_' + components[i]; - copy[key] = this[key]; - } - return copy; - }, - - convert: function(type) { - var converter; - return this._type == type - ? this.clone() - : (converter = converters[this._type + '-' + type]) - ? converter(this) - : converters['rgb-' + type]( - converters[this._type + '-rgb'](this)); - }, - - statics: { - extend: function(src) { - if (src._type) { - var comps = components[src._type]; - src._components = comps.concat(['alpha']); - Base.each(comps, function(name) { - var isHue = name === 'hue', - part = Base.capitalize(name), - name = '_' + name; - this['get' + part] = function() { - return this[name]; - }; - this['set' + part] = function(value) { - this[name] = isHue - ? ((value % 360) + 360) % 360 - : Math.min(Math.max(value, 0), 1); - this._changed(); - return this; - }; - }, src); - } - return this.base.apply(this, arguments); - }, - - random: function() { - return new RgbColor(Math.random(), Math.random(), Math.random()); - } - } - }; - - Base.each(components, function(comps, type) { - Base.each(comps, function(component) { - var part = Base.capitalize(component); - fields['get' + part] = function() { - return this.convert(type)[component]; - }; - fields['set' + part] = function(value) { - var color = this.convert(type); - color[component] = value; - color = color.convert(this._type); - for (var i = 0, l = this._components.length; i < l; i++) { - var key = this._components[i]; - this[key] = color[key]; - } - }; - }); - }); - - return fields; -}, { - - _changed: function() { - this._css = null; - if (this._owner) - this._owner._changed(17); - }, - - getType: function() { - return this._type; - }, - - getComponents: function() { - var length = this._components.length; - var comps = new Array(length); - for (var i = 0; i < length; i++) - comps[i] = this['_' + this._components[i]]; - return comps; - }, - - getAlpha: function() { - return this._alpha != null ? this._alpha : 1; - }, - - setAlpha: function(alpha) { - this._alpha = alpha == null ? null : Math.min(Math.max(alpha, 0), 1); - this._changed(); - return this; - }, - - hasAlpha: function() { - return this._alpha != null; - }, - - equals: function(color) { - if (color && color._type === this._type) { - for (var i = 0, l = this._components.length; i < l; i++) { - var component = '_' + this._components[i]; - if (this[component] !== color[component]) - return false; - } - return true; - } - return false; - }, - - toString: function() { - var parts = [], - format = Base.formatFloat; - for (var i = 0, l = this._components.length; i < l; i++) { - var component = this._components[i], - value = this['_' + component]; - if (component === 'alpha' && value == null) - value = 1; - parts.push(component + ': ' + format(value)); - } - return '{ ' + parts.join(', ') + ' }'; - }, - - toCss: function(noAlpha) { - var css = this._css; - if (!css || noAlpha) { - var color = this.convert('rgb'), - alpha = noAlpha ? 1 : color.getAlpha(), - components = [ - Math.round(color._red * 255), - Math.round(color._green * 255), - Math.round(color._blue * 255) - ]; - if (alpha < 1) - components.push(alpha); - var css = (components.length == 4 ? 'rgba(' : 'rgb(') - + components.join(', ') + ')'; - if (!noAlpha) - this._css = css; - } - return css; - }, - - getCanvasStyle: function() { - return this.toCss(); - } - -}); - -var GrayColor = this.GrayColor = Color.extend({ - - _type: 'gray' -}); - -var RgbColor = this.RgbColor = this.RGBColor = Color.extend({ - - _type: 'rgb' -}); - -var HsbColor = this.HsbColor = this.HSBColor = Color.extend({ - - _type: 'hsb' -}); - -var HslColor = this.HslColor = this.HSLColor = Color.extend({ - - _type: 'hsl' -}); - -var GradientColor = this.GradientColor = Color.extend({ - - initialize: function(gradient, origin, destination, hilite) { - this.gradient = gradient || new Gradient(); - this.gradient._addOwner(this); - this.setOrigin(origin); - this.setDestination(destination); - if (hilite) - this.setHilite(hilite); - }, - - clone: function() { - return new GradientColor(this.gradient, this._origin, this._destination, - this._hilite); - }, - - getOrigin: function() { - return this._origin; - }, - - setOrigin: function(origin) { - origin = Point.read(arguments, 0, 0, true); - this._origin = origin; - if (this._destination) - this._radius = this._destination.getDistance(this._origin); - this._changed(); - return this; - }, - - getDestination: function() { - return this._destination; - }, - - setDestination: function(destination) { - destination = Point.read(arguments, 0, 0, true); - this._destination = destination; - this._radius = this._destination.getDistance(this._origin); - this._changed(); - return this; - }, - - getHilite: function() { - return this._hilite; - }, - - setHilite: function(hilite) { - hilite = Point.read(arguments, 0, 0, true); - var vector = hilite.subtract(this._origin); - if (vector.getLength() > this._radius) { - this._hilite = this._origin.add( - vector.normalize(this._radius - 0.1)); - } else { - this._hilite = hilite; - } - this._changed(); - return this; - }, - - getCanvasStyle: function(ctx) { - var gradient; - if (this.gradient.type === 'linear') { - gradient = ctx.createLinearGradient(this._origin.x, this._origin.y, - this._destination.x, this._destination.y); - } else { - var origin = this._hilite || this._origin; - gradient = ctx.createRadialGradient(origin.x, origin.y, - 0, this._origin.x, this._origin.y, this._radius); - } - for (var i = 0, l = this.gradient._stops.length; i < l; i++) { - var stop = this.gradient._stops[i]; - gradient.addColorStop(stop._rampPoint, stop._color.toCss()); - } - return gradient; - }, - - equals: function(color) { - return color == this || color && color._type === this._type - && this.gradient.equals(color.gradient) - && this._origin.equals(color._origin) - && this._destination.equals(color._destination); - }, - - transform: function(matrix) { - matrix._transformPoint(this._origin, this._origin, true); - matrix._transformPoint(this._destination, this._destination, true); - if (this._hilite) - matrix._transformPoint(this._hilite, this._hilite, true); - this._radius = this._destination.getDistance(this._origin); - } -}); - -var Gradient = this.Gradient = Base.extend({ - initialize: function(stops, type) { - this.setStops(stops || ['white', 'black']); - this.type = type || 'linear'; - }, - - _changed: function() { - for (var i = 0, l = this._owners && this._owners.length; i < l; i++) - this._owners[i]._changed(); - }, - - _addOwner: function(color) { - if (!this._owners) - this._owners = []; - this._owners.push(color); - }, - - _removeOwner: function(color) { - var index = this._owners ? this._owners.indexOf(color) : -1; - if (index != -1) { - this._owners.splice(index, 1); - if (this._owners.length == 0) - delete this._owners; - } - }, - - clone: function() { - var stops = []; - for (var i = 0, l = this._stops.length; i < l; i++) - stops[i] = this._stops[i].clone(); - return new Gradient(stops, this.type); - }, - - getStops: function() { - return this._stops; - }, - - setStops: function(stops) { - if (this.stops) { - for (var i = 0, l = this._stops.length; i < l; i++) - delete this._stops[i]._owner; - } - if (stops.length < 2) - throw new Error( - 'Gradient stop list needs to contain at least two stops.'); - this._stops = GradientStop.readAll(stops, 0, true); - for (var i = 0, l = this._stops.length; i < l; i++) { - var stop = this._stops[i]; - stop._owner = this; - if (stop._defaultRamp) - stop.setRampPoint(i / (l - 1)); - } - this._changed(); - return this; - }, - - equals: function(gradient) { - if (gradient.type != this.type) - return false; - if (this._stops.length == gradient._stops.length) { - for (var i = 0, l = this._stops.length; i < l; i++) { - if (!this._stops[i].equals(gradient._stops[i])) - return false; - } - return true; - } - return false; - } -}); - -var GradientStop = this.GradientStop = Base.extend({ - initialize: function(arg0, arg1) { - if (arg0) { - var color, rampPoint; - if (arg1 === undefined && Array.isArray(arg0)) { - color = arg0[0]; - rampPoint = arg0[1]; - } else if (arg0.color) { - color = arg0.color; - rampPoint = arg0.rampPoint; - } else { - color = arg0; - rampPoint = arg1; - } - this.setColor(color); - this.setRampPoint(rampPoint); - } - }, - - clone: function() { - return new GradientStop(this._color.clone(), this._rampPoint); - }, - - _changed: function() { - if (this._owner) - this._owner._changed(17); - }, - - getRampPoint: function() { - return this._rampPoint; - }, - - setRampPoint: function(rampPoint) { - this._defaultRamp = rampPoint == null; - this._rampPoint = rampPoint || 0; - this._changed(); - }, - - getColor: function() { - return this._color; - }, - - setColor: function(color) { - this._color = Color.read(arguments); - if (this._color === color) - this._color = color.clone(); - this._color._owner = this; - this._changed(); - }, - - equals: function(stop) { - return stop == this || stop instanceof GradientStop - && this._color.equals(stop._color) - && this._rampPoint == stop._rampPoint; - } -}); - -var DomElement = new function() { - - var special = /^(checked|value|selected|disabled)$/i, - translated = { text: 'textContent', html: 'innerHTML' }, - unitless = { lineHeight: 1, zoom: 1, zIndex: 1, opacity: 1 }; - - function create(nodes, parent) { - var res = []; - for (var i = 0, l = nodes && nodes.length; i < l;) { - var el = nodes[i++]; - if (typeof el === 'string') { - el = document.createElement(el); - } else if (!el || !el.nodeType) { - continue; - } - if (Base.isPlainObject(nodes[i])) - DomElement.set(el, nodes[i++]); - if (Array.isArray(nodes[i])) - create(nodes[i++], el); - if (parent) - parent.appendChild(el); - res.push(el); - } - return res; - } - - return { - create: function(nodes, parent) { - var isArray = Array.isArray(nodes), - res = create(isArray ? nodes : arguments, isArray ? parent : null); - return res.length == 1 ? res[0] : res; - }, - - find: function(selector, root) { - return (root || document).querySelector(selector); - }, - - findAll: function(selector, root) { - return (root || document).querySelectorAll(selector); - }, - - get: function(el, key) { - return el - ? special.test(key) - ? key === 'value' || typeof el[key] !== 'string' - ? el[key] - : true - : key in translated - ? el[translated[key]] - : el.getAttribute(key) - : null; - }, - - set: function(el, key, value) { - if (typeof key !== 'string') { - for (var name in key) - if (key.hasOwnProperty(name)) - this.set(el, name, key[name]); - } else if (!el || value === undefined) { - return el; - } else if (special.test(key)) { - el[key] = value; - } else if (key in translated) { - el[translated[key]] = value; - } else if (key === 'style') { - this.setStyle(el, value); - } else if (key === 'events') { - DomEvent.add(el, value); - } else { - el.setAttribute(key, value); - } - return el; - }, - - getStyle: function(el, key) { - var style = el.ownerDocument.defaultView.getComputedStyle(el, ''); - return el.style[key] || style && style[key] || null; - }, - - setStyle: function(el, key, value) { - if (typeof key !== 'string') { - for (var name in key) - if (key.hasOwnProperty(name)) - this.setStyle(el, name, key[name]); - } else { - if (/^-?[\d\.]+$/.test(value) && !(key in unitless)) - value += 'px'; - el.style[key] = value; - } - return el; - }, - - hasClass: function(el, cls) { - return new RegExp('\\s*' + cls + '\\s*').test(el.className); - }, - - addClass: function(el, cls) { - el.className = (el.className + ' ' + cls).trim(); - }, - - removeClass: function(el, cls) { - el.className = el.className.replace( - new RegExp('\\s*' + cls + '\\s*'), ' ').trim(); - }, - - remove: function(el) { - if (el.parentNode) - el.parentNode.removeChild(el); - }, - - removeChildren: function(el) { - while (el.firstChild) - el.removeChild(el.firstChild); - }, - - getBounds: function(el, viewport) { - var rect = el.getBoundingClientRect(), - doc = el.ownerDocument, - body = doc.body, - html = doc.documentElement, - x = rect.left - (html.clientLeft || body.clientLeft || 0), - y = rect.top - (html.clientTop || body.clientTop || 0); - if (!viewport) { - var view = doc.defaultView; - x += view.pageXOffset || html.scrollLeft || body.scrollLeft; - y += view.pageYOffset || html.scrollTop || body.scrollTop; - } - return new Rectangle(x, y, rect.width, rect.height); - }, - - getViewportBounds: function(el) { - var doc = el.ownerDocument, - view = doc.defaultView, - html = doc.documentElement; - return Rectangle.create(0, 0, - view.innerWidth || html.clientWidth, - view.innerHeight || html.clientHeight - ); - }, - - getOffset: function(el, viewport) { - return this.getBounds(el, viewport).getPoint(); - }, - - getSize: function(el) { - return this.getBounds(el, true).getSize(); - }, - - isInvisible: function(el) { - return this.getSize(el).equals([0, 0]); - }, - - isInView: function(el) { - return !this.isInvisible(el) && this.getViewportBounds(el).intersects( - this.getBounds(el, true)); - } - }; -}; - -var DomEvent = { - add: function(el, events) { - for (var type in events) { - var func = events[type]; - if (el.addEventListener) { - el.addEventListener(type, func, false); - } else if (el.attachEvent) { - el.attachEvent('on' + type, func.bound = function() { - func.call(el, window.event); - }); - } - } - }, - - remove: function(el, events) { - for (var type in events) { - var func = events[type]; - if (el.removeEventListener) { - el.removeEventListener(type, func, false); - } else if (el.detachEvent) { - el.detachEvent('on' + type, func.bound); - } - } - }, - - getPoint: function(event) { - var pos = event.targetTouches - ? event.targetTouches.length - ? event.targetTouches[0] - : event.changedTouches[0] - : event; - return Point.create( - pos.pageX || pos.clientX + document.documentElement.scrollLeft, - pos.pageY || pos.clientY + document.documentElement.scrollTop - ); - }, - - getTarget: function(event) { - return event.target || event.srcElement; - }, - - getOffset: function(event, target) { - return DomEvent.getPoint(event).subtract(DomElement.getOffset( - target || DomEvent.getTarget(event))); - }, - - preventDefault: function(event) { - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - }, - - stopPropagation: function(event) { - if (event.stopPropagation) { - event.stopPropagation(); - } else { - event.cancelBubble = true; - } - }, - - stop: function(event) { - DomEvent.stopPropagation(event); - DomEvent.preventDefault(event); - } -}; - -DomEvent.requestAnimationFrame = new function() { - var part = 'equestAnimationFrame', - request = window['r' + part] || window['webkitR' + part] - || window['mozR' + part] || window['oR' + part] - || window['msR' + part]; - if (request) { - request(function(time) { - if (time == null) - request = null; - }); - } - - var callbacks = [], - focused = true, - timer; - - DomEvent.add(window, { - focus: function() { - focused = true; - }, - blur: function() { - focused = false; - } - }); - - return function(callback, element) { - if (request) - return request(callback, element); - callbacks.push([callback, element]); - if (timer) - return; - timer = setInterval(function() { - for (var i = callbacks.length - 1; i >= 0; i--) { - var entry = callbacks[i], - func = entry[0], - el = entry[1]; - if (!el || (PaperScript.getAttribute(el, 'keepalive') == 'true' - || focused) && DomElement.isInView(el)) { - callbacks.splice(i, 1); - func(Date.now()); - } - } - }, 1000 / 60); - }; -}; - -var View = this.View = Base.extend(Callback, { - initialize: function(element) { - this._scope = paper; - this._project = paper.project; - this._element = element; - var size; - this._id = element.getAttribute('id'); - if (this._id == null) - element.setAttribute('id', this._id = 'view-' + View._id++); - DomEvent.add(element, this._viewHandlers); - if (PaperScript.hasAttribute(element, 'resize')) { - var offset = DomElement.getOffset(element, true), - that = this; - size = DomElement.getViewportBounds(element) - .getSize().subtract(offset); - this._windowHandlers = { - resize: function(event) { - if (!DomElement.isInvisible(element)) - offset = DomElement.getOffset(element, true); - that.setViewSize(DomElement.getViewportBounds(element) - .getSize().subtract(offset)); - } - }; - DomEvent.add(window, this._windowHandlers); - } else { - size = DomElement.isInvisible(element) - ? Size.create(parseInt(element.getAttribute('width')), - parseInt(element.getAttribute('height'))) - : DomElement.getSize(element); - } - element.width = size.width; - element.height = size.height; - if (PaperScript.hasAttribute(element, 'stats')) { - this._stats = new Stats(); - var stats = this._stats.domElement, - style = stats.style, - offset = DomElement.getOffset(element); - style.position = 'absolute'; - style.left = offset.x + 'px'; - style.top = offset.y + 'px'; - document.body.appendChild(stats); - } - View._views.push(this); - View._viewsById[this._id] = this; - this._viewSize = LinkedSize.create(this, 'setViewSize', - size.width, size.height); - this._matrix = new Matrix(); - this._zoom = 1; - if (!View._focused) - View._focused = this; - this._frameItems = {}; - this._frameItemCount = 0; - }, - - remove: function() { - if (!this._project) - return false; - if (View._focused == this) - View._focused = null; - View._views.splice(View._views.indexOf(this), 1); - delete View._viewsById[this._id]; - if (this._project.view == this) - this._project.view = null; - DomEvent.remove(this._element, this._viewHandlers); - DomEvent.remove(window, this._windowHandlers); - this._element = this._project = null; - this.detach('frame'); - this._frameItems = {}; - return true; - }, - - _events: { - onFrame: { - install: function() { - if (!this._requested) { - this._animate = true; - this._handleFrame(true); - } - }, - - uninstall: function() { - this._animate = false; - } - }, - - onResize: {} - }, - - _animate: false, - _time: 0, - _count: 0, - - _handleFrame: function(request) { - this._requested = false; - if (!this._animate) - return; - paper = this._scope; - if (request) { - this._requested = true; - var that = this; - DomEvent.requestAnimationFrame(function() { - that._handleFrame(true); - }, this._element); - } - var now = Date.now() / 1000, - delta = this._before ? now - this._before : 0; - this._before = now; - this.fire('frame', Base.merge({ - delta: delta, - time: this._time += delta, - count: this._count++ - })); - if (this._stats) - this._stats.update(); - this.draw(true); - }, - - _animateItem: function(item, animate) { - var items = this._frameItems; - if (animate) { - items[item._id] = { - item: item, - time: 0, - count: 0 - }; - if (++this._frameItemCount == 1) - this.attach('frame', this._handleFrameItems); - } else { - delete items[item._id]; - if (--this._frameItemCount == 0) { - this.detach('frame', this._handleFrameItems); - } - } - }, - - _handleFrameItems: function(event) { - for (var i in this._frameItems) { - var entry = this._frameItems[i]; - entry.item.fire('frame', Base.merge(event, { - time: entry.time += event.delta, - count: entry.count++ - })); - } - }, - - _redraw: function() { - this._redrawNeeded = true; - if (this._animate) { - this._handleFrame(); - } else { - this.draw(); - } - }, - - _transform: function(matrix) { - this._matrix.preConcatenate(matrix); - this._bounds = null; - this._inverse = null; - this._redraw(); - }, - - getElement: function() { - return this._element; - }, - - getViewSize: function() { - return this._viewSize; - }, - - setViewSize: function(size) { - size = Size.read(arguments); - var delta = size.subtract(this._viewSize); - if (delta.isZero()) - return; - this._element.width = size.width; - this._element.height = size.height; - this._viewSize.set(size.width, size.height, true); - this._bounds = null; - this._redrawNeeded = true; - this.fire('resize', { - size: size, - delta: delta - }); - this._redraw(); - }, - - getBounds: function() { - if (!this._bounds) - this._bounds = this._getInverse()._transformBounds( - new Rectangle(new Point(), this._viewSize)); - return this._bounds; - }, - - getSize: function() { - return this.getBounds().getSize(); - }, - - getCenter: function() { - return this.getBounds().getCenter(); - }, - - setCenter: function(center) { - this.scrollBy(Point.read(arguments).subtract(this.getCenter())); - }, - - getZoom: function() { - return this._zoom; - }, - - setZoom: function(zoom) { - this._transform(new Matrix().scale(zoom / this._zoom, - this.getCenter())); - this._zoom = zoom; - }, - - isVisible: function() { - return DomElement.isInView(this._element); - }, - - scrollBy: function(point) { - this._transform(new Matrix().translate(Point.read(arguments).negate())); - }, - - projectToView: function(point) { - return this._matrix._transformPoint(Point.read(arguments)); - }, - - viewToProject: function(point) { - return this._getInverse()._transformPoint(Point.read(arguments)); - }, - - _getInverse: function() { - if (!this._inverse) - this._inverse = this._matrix.createInverse(); - return this._inverse; - } - -}, { - statics: { - _views: [], - _viewsById: {}, - _id: 0, - - create: function(element) { - if (typeof element === 'string') - element = document.getElementById(element); - return new CanvasView(element); - } - } -}, new function() { - var tool, - curPoint, - prevFocus, - tempFocus, - dragging = false; - - function getView(event) { - return View._viewsById[DomEvent.getTarget(event).getAttribute('id')]; - } - - function viewToProject(view, event) { - return view.viewToProject(DomEvent.getOffset(event, view._element)); - } - - function updateFocus() { - if (!View._focused || !View._focused.isVisible()) { - for (var i = 0, l = View._views.length; i < l; i++) { - var view = View._views[i]; - if (view && view.isVisible()) { - View._focused = tempFocus = view; - break; - } - } - } - } - - function mousedown(event) { - var view = View._focused = getView(event); - curPoint = viewToProject(view, event); - dragging = true; - if (view._onMouseDown) - view._onMouseDown(event, curPoint); - if (tool = view._scope._tool) - tool._onHandleEvent('mousedown', curPoint, event); - view.draw(true); - } - - function mousemove(event) { - var view; - if (!dragging) { - view = getView(event); - if (view) { - prevFocus = View._focused; - View._focused = tempFocus = view; - } else if (tempFocus && tempFocus == View._focused) { - View._focused = prevFocus; - updateFocus(); - } - } - if (!(view = view || View._focused)) - return; - var point = event && viewToProject(view, event); - if (view._onMouseMove) - view._onMouseMove(event, point); - if (tool = view._scope._tool) { - var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove); - if (dragging && !onlyMove) { - if ((curPoint = point || curPoint) - && tool._onHandleEvent('mousedrag', curPoint, event)) - DomEvent.stop(event); - } else if ((!dragging || onlyMove) - && tool._onHandleEvent('mousemove', point, event)) { - DomEvent.stop(event); - } - } - view.draw(true); - } - - function mouseup(event) { - var view = View._focused; - if (!view || !dragging) - return; - var point = viewToProject(view, event); - curPoint = null; - dragging = false; - if (view._onMouseUp) - view._onMouseUp(event, point); - if (tool && tool._onHandleEvent('mouseup', point, event)) - DomEvent.stop(event); - view.draw(true); - } - - function selectstart(event) { - if (dragging) - DomEvent.stop(event); - } - - DomEvent.add(document, { - mousemove: mousemove, - mouseup: mouseup, - touchmove: mousemove, - touchend: mouseup, - selectstart: selectstart, - scroll: updateFocus - }); - - DomEvent.add(window, { - load: updateFocus - }); - - return { - _viewHandlers: { - mousedown: mousedown, - touchstart: mousedown, - selectstart: selectstart - }, - - statics: { - updateFocus: updateFocus - } - }; -}); - -var CanvasView = View.extend({ - initialize: function(canvas) { - if (!(canvas instanceof HTMLCanvasElement)) { - var size = Size.read(arguments, 1); - if (size.isZero()) - size = Size.create(1024, 768); - canvas = CanvasProvider.getCanvas(size); - } - this._context = canvas.getContext('2d'); - this._eventCounters = {}; - this.base(canvas); - }, - - draw: function(checkRedraw) { - if (checkRedraw && !this._redrawNeeded) - return false; - var ctx = this._context, - size = this._viewSize; - ctx.clearRect(0, 0, size._width + 1, size._height + 1); - this._project.draw(ctx, this._matrix); - this._redrawNeeded = false; - return true; - } -}, new function() { - - var hitOptions = { - fill: true, - stroke: true, - tolerance: 0 - }; - - var downPoint, - lastPoint, - overPoint, - downItem, - lastItem, - overItem, - hasDrag, - doubleClick, - clickTime; - - function callEvent(type, event, point, target, lastPoint, bubble) { - var item = target, - mouseEvent, - called = false; - while (item) { - if (item.responds(type)) { - if (!mouseEvent) - mouseEvent = new MouseEvent(type, event, point, target, - lastPoint ? point.subtract(lastPoint) : null); - called = item.fire(type, mouseEvent) || called; - if (called && (!bubble || mouseEvent._stopped)) - break; - } - item = item.getParent(); - } - return called; - } - - function handleEvent(view, type, event, point, lastPoint) { - if (view._eventCounters[type]) { - var hit = view._project.hitTest(point, hitOptions), - item = hit && hit.item; - if (item) { - if (type == 'mousemove' && item != overItem) - lastPoint = point; - if (type != 'mousemove' || !hasDrag) - callEvent(type, event, point, item, lastPoint); - return item; - } - } - } - - return { - _onMouseDown: function(event, point) { - var item = handleEvent(this, 'mousedown', event, point); - doubleClick = lastItem == item && (Date.now() - clickTime < 300); - downItem = lastItem = item; - downPoint = lastPoint = overPoint = point; - hasDrag = downItem && downItem.responds('mousedrag'); - }, - - _onMouseUp: function(event, point) { - var item = handleEvent(this, 'mouseup', event, point); - if (hasDrag) { - if (lastPoint && !lastPoint.equals(point)) - callEvent('mousedrag', event, point, downItem, lastPoint); - if (item != downItem) { - overPoint = point; - callEvent('mousemove', event, point, item, overPoint); - } - } - if (item == downItem) { - clickTime = Date.now(); - callEvent(doubleClick ? 'doubleclick' : 'click', event, - downPoint, overItem); - doubleClick = false; - } - downItem = null; - hasDrag = false; - }, - - _onMouseMove: function(event, point) { - if (downItem) - callEvent('mousedrag', event, point, downItem, lastPoint); - var item = handleEvent(this, 'mousemove', event, point, overPoint); - lastPoint = overPoint = point; - if (item != overItem) { - callEvent('mouseleave', event, point, overItem); - overItem = item; - callEvent('mouseenter', event, point, item); - } - } - }; -}); - -var Event = this.Event = Base.extend({ - initialize: function(event) { - this.event = event; - }, - - preventDefault: function() { - this._prevented = true; - DomEvent.preventDefault(this.event); - return this; - }, - - stopPropagation: function() { - this._stopped = true; - DomEvent.stopPropagation(this.event); - return this; - }, - - stop: function() { - return this.stopPropagation().preventDefault(); - }, - - getModifiers: function() { - return Key.modifiers; - } -}); - -var KeyEvent = this.KeyEvent = Event.extend({ - initialize: function(down, key, character, event) { - this.base(event); - this.type = down ? 'keydown' : 'keyup'; - this.key = key; - this.character = character; - }, - - toString: function() { - return "{ type: '" + this.type - + "', key: '" + this.key - + "', character: '" + this.character - + "', modifiers: " + this.getModifiers() - + " }"; - } -}); - -var Key = this.Key = new function() { - - var keys = { - 8: 'backspace', - 9: 'tab', - 13: 'enter', - 16: 'shift', - 17: 'control', - 18: 'option', - 19: 'pause', - 20: 'caps-lock', - 27: 'escape', - 32: 'space', - 35: 'end', - 36: 'home', - 37: 'left', - 38: 'up', - 39: 'right', - 40: 'down', - 46: 'delete', - 91: 'command', - 93: 'command', - 224: 'command' - }, - - modifiers = Base.merge({ - shift: false, - control: false, - option: false, - command: false, - capsLock: false, - space: false - }), - - charCodeMap = {}, - keyMap = {}, - downCode; - - function handleKey(down, keyCode, charCode, event) { - var character = String.fromCharCode(charCode), - key = keys[keyCode] || character.toLowerCase(), - type = down ? 'keydown' : 'keyup', - view = View._focused, - scope = view && view.isVisible() && view._scope, - tool = scope && scope._tool; - keyMap[key] = down; - if (tool && tool.responds(type)) { - tool.fire(type, new KeyEvent(down, key, character, event)); - if (view) - view.draw(true); - } - } - - DomEvent.add(document, { - keydown: function(event) { - var code = event.which || event.keyCode; - var key = keys[code], name; - if (key) { - if ((name = Base.camelize(key)) in modifiers) - modifiers[name] = true; - charCodeMap[code] = 0; - handleKey(true, code, null, event); - } else { - downCode = code; - } - }, - - keypress: function(event) { - if (downCode != null) { - var code = event.which || event.keyCode; - charCodeMap[downCode] = code; - handleKey(true, downCode, code, event); - downCode = null; - } - }, - - keyup: function(event) { - var code = event.which || event.keyCode, - key = keys[code], name; - if (key && (name = Base.camelize(key)) in modifiers) - modifiers[name] = false; - if (charCodeMap[code] != null) { - handleKey(false, code, charCodeMap[code], event); - delete charCodeMap[code]; - } - } - }); - - return { - modifiers: modifiers, - - isDown: function(key) { - return !!keyMap[key]; - } - }; -}; - -var MouseEvent = this.MouseEvent = Event.extend({ - initialize: function(type, event, point, target, delta) { - this.base(event); - this.type = type; - this.point = point; - this.target = target; - this.delta = delta; - }, - - toString: function() { - return "{ type: '" + this.type - + "', point: " + this.point - + ', target: ' + this.target - + (this.delta ? ', delta: ' + this.delta : '') - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var Palette = this.Palette = Base.extend(Callback, { - _events: [ 'onChange' ], - - initialize: function(title, components, values) { - var parent = DomElement.find('.palettejs-panel') - || DomElement.find('body').appendChild( - DomElement.create('div', { 'class': 'palettejs-panel' })); - this._element = parent.appendChild( - DomElement.create('table', { 'class': 'palettejs-pane' })), - this._title = title; - if (!values) - values = {}; - for (var name in (this._components = components)) { - var component = components[name]; - if (!(component instanceof Component)) { - if (component.value == null) - component.value = values[name]; - component.name = name; - component = components[name] = new Component(component); - } - this._element.appendChild(component._element); - component._palette = this; - if (values[name] === undefined) - values[name] = component.value; - } - this._values = Base.each(values, function(value, name) { - var component = components[name]; - if (component) { - Base.define(values, name, { - enumerable: true, - configurable: true, - writable: true, - get: function() { - return component._value; - }, - set: function(val) { - component.setValue(val); - } - }); - } - }); - if (window.paper) - paper.palettes.push(this); - }, - - reset: function() { - for (var i in this._components) - this._components[i].reset(); - }, - - remove: function() { - DomElement.remove(this._element); - } -}); - -var Component = this.Component = Base.extend(Callback, { - _events: [ 'onChange', 'onClick' ], - - _types: { - 'boolean': { - type: 'checkbox', - value: 'checked' - }, - - string: { - type: 'text' - }, - - number: { - type: 'number', - number: true - }, - - button: { - type: 'button' - }, - - text: { - tag: 'div', - value: 'text' - }, - - slider: { - type: 'range', - number: true - }, - - list: { - tag: 'select', - - options: function() { - DomElement.removeChildren(this._inputItem); - DomElement.create(Base.each(this._options, function(option) { - this.push('option', { value: option, text: option }); - }, []), this._inputItem); - } - } - }, - - initialize: function(obj) { - this._type = obj.type in this._types - ? obj.type - : 'options' in obj - ? 'list' - : 'onClick' in obj - ? 'button' - : typeof obj.value; - this._info = this._types[this._type] || { type: this._type }; - var that = this, - fireChange = false; - this._inputItem = DomElement.create(this._info.tag || 'input', { - type: this._info.type, - events: { - change: function() { - that.setValue( - DomElement.get(this, that._info.value || 'value')); - if (fireChange) { - that._palette.fire('change', that, that.name, that._value); - that.fire('change', that._value); - } - }, - click: function() { - that.fire('click'); - } - } - }); - this._element = DomElement.create('tr', [ - this._labelItem = DomElement.create('td'), - 'td', [this._inputItem] - ]); - Base.each(obj, function(value, key) { - this[key] = value; - }, this); - this._defaultValue = this._value; - fireChange = true; - }, - - getType: function() { - return this._type; - }, - - getLabel: function() { - return this._label; - }, - - setLabel: function(label) { - this._label = label; - DomElement.set(this._labelItem, 'text', label + ':'); - }, - - getOptions: function() { - return this._options; - }, - - setOptions: function(options) { - this._options = options; - if (this._info.options) - this._info.options.call(this); - }, - - getValue: function() { - return this._value; - }, - - setValue: function(value) { - var key = this._info.value || 'value'; - DomElement.set(this._inputItem, key, value); - value = DomElement.get(this._inputItem, key); - this._value = this._info.number ? Base.toFloat(value) : value; - }, - - getRange: function() { - return [Base.toFloat(DomElement.get(this._inputItem, 'min')), - Base.toFloat(DomElement.get(this._inputItem, 'max'))]; - }, - - setRange: function(min, max) { - var range = Array.isArray(min) ? min : [min, max]; - DomElement.set(this._inputItem, { min: range[0], max: range[1] }); - }, - - getMin: function() { - return this.getRange()[0]; - }, - - setMin: function(min) { - this.setRange(min, this.getMax()); - }, - - getMax: function() { - return this.getRange()[1]; - }, - - setMax: function(max) { - this.setRange(this.getMin(), max); - }, - - getStep: function() { - return Base.toFloat(DomElement.get(this._inputItem, 'step')); - }, - - setStep: function(step) { - DomElement.set(this._inputItem, 'step', step); - }, - - reset: function() { - this.setValue(this._defaultValue); - } -}); - -var ToolEvent = this.ToolEvent = Event.extend({ - _item: null, - - initialize: function(tool, type, event) { - this.tool = tool; - this.type = type; - this.event = event; - }, - - _choosePoint: function(point, toolPoint) { - return point ? point : toolPoint ? toolPoint.clone() : null; - }, - - getPoint: function() { - return this._choosePoint(this._point, this.tool._point); - }, - - setPoint: function(point) { - this._point = point; - }, - - getLastPoint: function() { - return this._choosePoint(this._lastPoint, this.tool._lastPoint); - }, - - setLastPoint: function(lastPoint) { - this._lastPoint = lastPoint; - }, - - getDownPoint: function() { - return this._choosePoint(this._downPoint, this.tool._downPoint); - }, - - setDownPoint: function(downPoint) { - this._downPoint = downPoint; - }, - - getMiddlePoint: function() { - if (!this._middlePoint && this.tool._lastPoint) { - return this.tool._point.add(this.tool._lastPoint).divide(2); - } - return this.middlePoint; - }, - - setMiddlePoint: function(middlePoint) { - this._middlePoint = middlePoint; - }, - - getDelta: function() { - return !this._delta && this.tool._lastPoint - ? this.tool._point.subtract(this.tool._lastPoint) - : this._delta; - }, - - setDelta: function(delta) { - this._delta = delta; - }, - - getCount: function() { - return /^mouse(down|up)$/.test(this.type) - ? this.tool._downCount - : this.tool._count; - }, - - setCount: function(count) { - this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count'] - = count; - }, - - getItem: function() { - if (!this._item) { - var result = this.tool._scope.project.hitTest(this.getPoint()); - if (result) { - var item = result.item, - parent = item._parent; - while ((parent instanceof Group && !(parent instanceof Layer)) - || parent instanceof CompoundPath) { - item = parent; - parent = parent._parent; - } - this._item = item; - } - } - return this._item; - }, - setItem: function(item) { - this._item = item; - }, - - toString: function() { - return '{ type: ' + this.type - + ', point: ' + this.getPoint() - + ', count: ' + this.getCount() - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var Tool = this.Tool = PaperScopeItem.extend({ - _list: 'tools', - _reference: '_tool', - _events: [ 'onActivate', 'onDeactivate', 'onEditOptions', - 'onMouseDown', 'onMouseUp', 'onMouseDrag', 'onMouseMove', - 'onKeyDown', 'onKeyUp' ], - - initialize: function() { - this.base(); - this._firstMove = true; - this._count = 0; - this._downCount = 0; - }, - - getMinDistance: function() { - return this._minDistance; - }, - - setMinDistance: function(minDistance) { - this._minDistance = minDistance; - if (this._minDistance != null && this._maxDistance != null - && this._minDistance > this._maxDistance) { - this._maxDistance = this._minDistance; - } - }, - - getMaxDistance: function() { - return this._maxDistance; - }, - - setMaxDistance: function(maxDistance) { - this._maxDistance = maxDistance; - if (this._minDistance != null && this._maxDistance != null - && this._maxDistance < this._minDistance) { - this._minDistance = maxDistance; - } - }, - - getFixedDistance: function() { - return this._minDistance == this._maxDistance - ? this._minDistance : null; - }, - - setFixedDistance: function(distance) { - this._minDistance = distance; - this._maxDistance = distance; - }, - - _updateEvent: function(type, pt, minDistance, maxDistance, start, - needsChange, matchMaxDistance) { - if (!start) { - if (minDistance != null || maxDistance != null) { - var minDist = minDistance != null ? minDistance : 0, - vector = pt.subtract(this._point), - distance = vector.getLength(); - if (distance < minDist) - return false; - var maxDist = maxDistance != null ? maxDistance : 0; - if (maxDist != 0) { - if (distance > maxDist) { - pt = this._point.add(vector.normalize(maxDist)); - } else if (matchMaxDistance) { - return false; - } - } - } - if (needsChange && pt.equals(this._point)) - return false; - } - this._lastPoint = start && type == 'mousemove' ? pt : this._point; - this._point = pt; - switch (type) { - case 'mousedown': - this._lastPoint = this._downPoint; - this._downPoint = this._point; - this._downCount++; - break; - case 'mouseup': - this._lastPoint = this._downPoint; - break; - } - this._count = start ? 0 : this._count + 1; - return true; - }, - - _onHandleEvent: function(type, pt, event) { - paper = this._scope; - var sets = Tool._removeSets; - if (sets) { - if (type === 'mouseup') - sets.mousedrag = null; - var set = sets[type]; - if (set) { - for (var id in set) { - var item = set[id]; - for (var key in sets) { - var other = sets[key]; - if (other && other != set && other[item._id]) - delete other[item._id]; - } - item.remove(); - } - sets[type] = null; - } - } - var called = false; - switch (type) { - case 'mousedown': - this._updateEvent(type, pt, null, null, true, false, false); - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - break; - case 'mousedrag': - var needsChange = false, - matchMaxDistance = false; - while (this._updateEvent(type, pt, this.minDistance, - this.maxDistance, false, needsChange, matchMaxDistance)) { - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - needsChange = true; - matchMaxDistance = true; - } - break; - case 'mouseup': - if ((this._point.x != pt.x || this._point.y != pt.y) - && this._updateEvent('mousedrag', pt, this.minDistance, - this.maxDistance, false, false, false)) { - if (this.responds('mousedrag')) - called = this.fire('mousedrag', - new ToolEvent(this, type, event)); - } - this._updateEvent(type, pt, null, this.maxDistance, false, - false, false); - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - this._updateEvent(type, pt, null, null, true, false, false); - this._firstMove = true; - break; - case 'mousemove': - while (this._updateEvent(type, pt, this.minDistance, - this.maxDistance, this._firstMove, true, false)) { - if (this.responds(type)) - called = this.fire(type, new ToolEvent(this, type, event)); - this._firstMove = false; - } - break; - } - return called; - } - -}); - -var CanvasProvider = { - canvases: [], - getCanvas: function(size) { - if (this.canvases.length) { - var canvas = this.canvases.pop(); - if ((canvas.width != size.width) - || (canvas.height != size.height)) { - canvas.width = size.width; - canvas.height = size.height; - } else { - canvas.getContext('2d').clearRect(0, 0, - size.width + 1, size.height + 1); - } - return canvas; - } else { - var canvas = document.createElement('canvas'); - canvas.width = size.width; - canvas.height = size.height; - return canvas; - } - }, - - returnCanvas: function(canvas) { - this.canvases.push(canvas); - } -}; - -var Numerical = new function() { - - var abscissas = [ - [ 0.5773502691896257645091488], - [0,0.7745966692414833770358531], - [ 0.3399810435848562648026658,0.8611363115940525752239465], - [0,0.5384693101056830910363144,0.9061798459386639927976269], - [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016], - [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897], - [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609], - [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762], - [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640], - [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380], - [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491], - [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294], - [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973], - [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657], - [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542] - ]; - - var weights = [ - [1], - [0.8888888888888888888888889,0.5555555555555555555555556], - [0.6521451548625461426269361,0.3478548451374538573730639], - [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640], - [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961], - [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114], - [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314], - [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922], - [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688], - [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537], - [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160], - [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216], - [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329], - [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284], - [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806] - ]; - - var abs = Math.abs, - sqrt = Math.sqrt, - pow = Math.pow, - cos = Math.cos, - PI = Math.PI; - - function cbrt(x) { - return x > 0 ? pow(x, 1 / 3) : x < 0 ? -pow(-x, 1 / 3) : 0; - } - - return { - TOLERANCE: 10e-6, - EPSILON: 10e-12, - - isZero: function(val) { - return Math.abs(val) <= this.EPSILON; - }, - - integrate: function(f, a, b, n) { - var x = abscissas[n - 2], - w = weights[n - 2], - A = 0.5 * (b - a), - B = A + a, - i = 0, - m = (n + 1) >> 1, - sum = n & 1 ? w[i++] * f(B) : 0; - while (i < m) { - var Ax = A * x[i]; - sum += w[i++] * (f(B + Ax) + f(B - Ax)); - } - return A * sum; - }, - - findRoot: function(f, df, x, a, b, n, tolerance) { - for (var i = 0; i < n; i++) { - var fx = f(x), - dx = fx / df(x); - if (abs(dx) < tolerance) - return x; - var nx = x - dx; - if (fx > 0) { - b = x; - x = nx <= a ? 0.5 * (a + b) : nx; - } else { - a = x; - x = nx >= b ? 0.5 * (a + b) : nx; - } - } - }, - - solveQuadratic: function(a, b, c, roots, tolerance) { - if (abs(a) < tolerance) { - if (abs(b) >= tolerance) { - roots[0] = -c / b; - return 1; - } - return abs(c) < tolerance ? -1 : 0; - } - var q = b * b - 4 * a * c; - if (q < 0) - return 0; - q = sqrt(q); - a *= 2; - var n = 0; - roots[n++] = (-b - q) / a; - if (q > 0) - roots[n++] = (-b + q) / a; - return n; - }, - - solveCubic: function(a, b, c, d, roots, tolerance) { - if (abs(a) < tolerance) - return Numerical.solveQuadratic(b, c, d, roots, tolerance); - b /= a; - c /= a; - d /= a; - var bb = b * b, - p = 1 / 3 * (-1 / 3 * bb + c), - q = 1 / 2 * (2 / 27 * b * bb - 1 / 3 * b * c + d), - ppp = p * p * p, - D = q * q + ppp; - b /= 3; - if (abs(D) < tolerance) { - if (abs(q) < tolerance) { - roots[0] = - b; - return 1; - } else { - var u = cbrt(-q); - roots[0] = 2 * u - b; - roots[1] = - u - b; - return 2; - } - } else if (D < 0) { - var phi = 1 / 3 * Math.acos(-q / sqrt(-ppp)); - var t = 2 * sqrt(-p); - roots[0] = t * cos(phi) - b; - roots[1] = - t * cos(phi + PI / 3) - b; - roots[2] = - t * cos(phi - PI / 3) - b; - return 3; - } else { - D = sqrt(D); - roots[0] = cbrt(D - q) - cbrt(D + q) - b; - return 1; - } - } - }; -}; - -var BlendMode = { - process: function(blendMode, srcContext, dstContext, alpha, offset) { - var srcCanvas = srcContext.canvas, - dstData = dstContext.getImageData(offset.x, offset.y, - srcCanvas.width, srcCanvas.height), - dst = dstData.data, - src = srcContext.getImageData(0, 0, - srcCanvas.width, srcCanvas.height).data, - min = Math.min, - max = Math.max, - abs = Math.abs, - sr, sg, sb, sa, - br, bg, bb, ba, - dr, dg, db; - - function getLum(r, g, b) { - return 0.2989 * r + 0.587 * g + 0.114 * b; - } - - function setLum(r, g, b, l) { - var d = l - getLum(r, g, b); - dr = r + d; - dg = g + d; - db = b + d; - var l = getLum(dr, dg, db), - mn = min(dr, dg, db), - mx = max(dr, dg, db); - if (mn < 0) { - var lmn = l - mn; - dr = l + (dr - l) * l / lmn; - dg = l + (dg - l) * l / lmn; - db = l + (db - l) * l / lmn; - } - if (mx > 255) { - var ln = 255 - l, mxl = mx - l; - dr = l + (dr - l) * ln / mxl; - dg = l + (dg - l) * ln / mxl; - db = l + (db - l) * ln / mxl; - } - } - - function getSat(r, g, b) { - return max(r, g, b) - min(r, g, b); - } - - function setSat(r, g, b, s) { - var col = [r, g, b], - mx = max(r, g, b), - mn = min(r, g, b), - md; - mn = mn == r ? 0 : mn == g ? 1 : 2; - mx = mx == r ? 0 : mx == g ? 1 : 2; - md = min(mn, mx) == 0 ? max(mn, mx) == 1 ? 2 : 1 : 0; - if (col[mx] > col[mn]) { - col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]); - col[mx] = s; - } else { - col[md] = col[mx] = 0; - } - col[mn] = 0; - dr = col[0]; - dg = col[1]; - db = col[2]; - } - - var modes = { - multiply: function() { - dr = br * sr / 255; - dg = bg * sg / 255; - db = bb * sb / 255; - }, - - screen: function() { - dr = 255 - (255 - br) * (255 - sr) / 255; - dg = 255 - (255 - bg) * (255 - sg) / 255; - db = 255 - (255 - bb) * (255 - sb) / 255; - }, - - overlay: function() { - dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255; - dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255; - db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255; - }, - - 'soft-light': function() { - var t = sr * br / 255; - dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255; - t = sg * bg / 255; - dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255; - t = sb * bb / 255; - db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255; - }, - - 'hard-light': function() { - dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255; - dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255; - db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255; - }, - - 'color-dodge': function() { - dr = sr == 255 ? sr : min(255, br * 255 / (255 - sr)); - dg = sg == 255 ? sg : min(255, bg * 255 / (255 - sg)); - db = sb == 255 ? sb : min(255, bb * 255 / (255 - sb)); - }, - - 'color-burn': function() { - dr = sr == 0 ? 0 : max(255 - ((255 - br) * 255) / sr, 0); - dg = sg == 0 ? 0 : max(255 - ((255 - bg) * 255) / sg, 0); - db = sb == 0 ? 0 : max(255 - ((255 - bb) * 255) / sb, 0); - }, - - darken: function() { - dr = br < sr ? br : sr; - dg = bg < sg ? bg : sg; - db = bb < sb ? bb : sb; - }, - - lighten: function() { - dr = br > sr ? br : sr; - dg = bg > sg ? bg : sg; - db = bb > sb ? bb : sb; - }, - - difference: function() { - dr = br - sr; - if (dr < 0) - dr = -dr; - dg = bg - sg; - if (dg < 0) - dg = -dg; - db = bb - sb; - if (db < 0) - db = -db; - }, - - exclusion: function() { - dr = br + sr * (255 - br - br) / 255; - dg = bg + sg * (255 - bg - bg) / 255; - db = bb + sb * (255 - bb - bb) / 255; - }, - - hue: function() { - setSat(sr, sg, sb, getSat(br, bg, bb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - saturation: function() { - setSat(br, bg, bb, getSat(sr, sg, sb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - luminosity: function() { - setLum(br, bg, bb, getLum(sr, sg, sb)); - }, - - color: function() { - setLum(sr, sg, sb, getLum(br, bg, bb)); - }, - - add: function() { - dr = min(br + sr, 255); - dg = min(bg + sg, 255); - db = min(bb + sb, 255); - }, - - subtract: function() { - dr = max(br - sr, 0); - dg = max(bg - sg, 0); - db = max(bb - sb, 0); - }, - - average: function() { - dr = (br + sr) / 2; - dg = (bg + sg) / 2; - db = (bb + sb) / 2; - }, - - negation: function() { - dr = 255 - abs(255 - sr - br); - dg = 255 - abs(255 - sg - bg); - db = 255 - abs(255 - sb - bb); - } - }; - - var process = modes[blendMode]; - if (!process) - return; - - for (var i = 0, l = dst.length; i < l; i += 4) { - sr = src[i]; - br = dst[i]; - sg = src[i + 1]; - bg = dst[i + 1]; - sb = src[i + 2]; - bb = dst[i + 2]; - sa = src[i + 3]; - ba = dst[i + 3]; - process(); - var a1 = sa * alpha / 255, - a2 = 1 - a1; - dst[i] = a1 * dr + a2 * br; - dst[i + 1] = a1 * dg + a2 * bg; - dst[i + 2] = a1 * db + a2 * bb; - dst[i + 3] = sa * alpha + a2 * ba; - } - dstContext.putImageData(dstData, offset.x, offset.y); - } -}; - -(function(e){"use strict";function r(e,r){throw"number"==typeof e&&(e=Br(nr,e)),r+=" ("+e.line+":"+e.column+")",new SyntaxError(r)}function t(e){function r(e){if(1==e.length)return t+="return str === "+JSON.stringify(e[0])+";";t+="switch(str){";for(var r=0;e.length>r;++r)t+="case "+JSON.stringify(e[r])+":";t+="return true}return false;"}e=e.split(" ");var t="",n=[];e:for(var a=0;e.length>a;++a){for(var o=0;n.length>o;++o)if(n[o][0].length==e[a].length){n[o].push(e[a]);continue e}n.push([e[a]])}if(n.length>3){n.sort(function(e,r){return r.length-e.length}),t+="switch(str.length){";for(var a=0;n.length>a;++a){var i=n[a];t+="case "+i[0].length+":",r(i)}t+="}"}else r(e);return Function("str",t)}function n(e){return 65>e?36===e:91>e?!0:97>e?95===e:123>e?!0:e>=170&&zt.test(String.fromCharCode(e))}function a(e){return 48>e?36===e:58>e?!0:65>e?!1:91>e?!0:97>e?95===e:123>e?!0:e>=170&&Nt.test(String.fromCharCode(e))}function o(){Jt.lastIndex=yr;var e=Jt.exec(nr);return e?e.index+e[0].length:nr.length+1}function i(){for(;ir>=gr;)++br,yr=gr,gr=o();return{line:br,column:ir-yr}}function s(){br=1,ir=yr=0,gr=o(),hr=!0,vr=null,f()}function u(e,r){ur=ir,tr.locations&&(lr=i()),fr=e,f(),pr=r,mr=vr,hr=e.beforeExpr}function c(){var e=nr.indexOf("*/",ir+=2);-1===e&&r(ir-2,"Unterminated comment"),tr.trackComments&&(vr||(vr=[])).push(nr.slice(ir,e)),ir=e+2}function l(){for(var e=ir,r=nr.charCodeAt(ir+=2);ar>ir&&10!==r&&13!==r&&8232!==r&&8329!==r;)++ir,r=nr.charCodeAt(ir);tr.trackComments&&(vr||(vr=[])).push(nr.slice(e,ir))}function f(){for(vr=null;ar>ir;){var e=nr.charCodeAt(ir);if(47===e){var r=nr.charCodeAt(ir+1);if(42===r)c();else{if(47!==r)break;l()}}else if(14>e&&e>8)++ir;else if(32===e||160===e)++ir;else{if(!(e>=5760&&Mt.test(String.fromCharCode(e))))break;++ir}}}function p(e){if(sr=ir,tr.locations&&(cr=i()),dr=vr,e)return m();if(ir>=ar)return u(qr);var t=nr.charCodeAt(ir);if(n(t)||92===t)return x();var a=nr.charCodeAt(ir+1);switch(t){case 46:return a>=48&&57>=a?b(String.fromCharCode(t)):(++ir,u(vt));case 40:return++ir,u(ft);case 41:return++ir,u(pt);case 59:return++ir,u(mt);case 44:return++ir,u(dt);case 91:return++ir,u(st);case 93:return++ir,u(ut);case 123:return++ir,u(ct);case 125:return++ir,u(lt);case 58:return++ir,u(ht);case 63:return++ir,u(bt);case 48:if(120===a||88===a)return v();case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return b(String.fromCharCode(t));case 34:case 39:return y(t);case 47:return hr?(++ir,m()):61===a?d(kt,2):d(yt,1);case 37:case 42:return 61===a?d(kt,2):d(Ft,1);case 124:case 38:return a===t?d(124===t?Ct:At,2):61===a?d(kt,2):d(124===t?St:Ut,1);case 94:return 61===a?d(kt,2):d(It,1);case 43:case 45:return a===t?d(wt,2):61===a?d(kt,2):d(xt,1);case 60:case 62:var o=1;return a===t?(o=62===t&&62===nr.charCodeAt(ir+2)?3:2,61===nr.charCodeAt(ir+o)?d(kt,o+1):d(Vt,o)):(61===a&&(o=61===nr.charCodeAt(ir+2)?3:2),d(Lt,o));case 61:case 33:return 61===a?d(Bt,61===nr.charCodeAt(ir+2)?3:2):d(61===t?gt:Et,1);case 126:return d(Et,1)}var s=String.fromCharCode(t);return"\\"===s||zt.test(s)?x():(r(ir,"Unexpected character '"+s+"'"),void 0)}function d(e,r){var t=nr.slice(ir,ir+r);ir+=r,u(e,t)}function m(){for(var e,t,n="",a=ir;;){ir>=ar&&r(a,"Unterminated regular expression");var o=nr.charAt(ir);if(Wt.test(o)&&r(a,"Unterminated regular expression"),e)e=!1;else{if("["===o)t=!0;else if("]"===o&&t)t=!1;else if("/"===o&&!t)break;e="\\"===o}++ir}var n=nr.slice(a,ir);++ir;var i=k();return i&&!/^[gmsiy]*$/.test(i)&&r(a,"Invalid regexp flag"),u(Vr,RegExp(n,i))}function h(e,r){for(var t=ir,n=0;;){var a,o=nr.charCodeAt(ir);if(a=o>=97?o-97+10:o>=65?o-65+10:o>=48&&57>=o?o-48:1/0,a>=e)break;++ir,n=n*e+a}return ir===t||null!=r&&ir-t!==r?null:n}function v(){ir+=2;var e=h(16);return null==e&&r(sr+2,"Expected hexadecimal number"),n(nr.charCodeAt(ir))&&r(ir,"Identifier directly after number"),u(Lr,e)}function b(e){var t=ir,a="."===e;if(a||null!=h(10)||r(t,"Invalid number"),a||"."===nr.charAt(ir)){var o=nr.charAt(++ir);("-"===o||"+"===o)&&++ir,null===h(10)&&"."===e&&r(t,"Invalid number"),a=!0}if(/e/i.test(nr.charAt(ir))){var o=nr.charAt(++ir);("-"===o||"+"===o)&&++ir,null===h(10)&&r(t,"Invalid number"),a=!0}n(nr.charCodeAt(ir))&&r(ir,"Identifier directly after number");var i,s=nr.slice(t,ir);return a?i=parseFloat(s):"0"!==e||1===s.length?i=parseInt(s,10):/[89]/.test(s)||Ar?r(t,"Invalid number"):i=parseInt(s,8),u(Lr,i)}function y(e){ir++;for(var t=[];;){ir>=ar&&r(sr,"Unterminated string constant");var n=nr.charCodeAt(ir);if(n===e)return++ir,u(Fr,String.fromCharCode.apply(null,t));if(92===n){n=nr.charCodeAt(++ir);var a=/^[0-7]+/.exec(nr.slice(ir,ir+3));for(a&&(a=a[0]);a&&parseInt(a,8)>255;)a=a.slice(0,a.length-1);if("0"===a&&(a=null),++ir,a)Ar&&r(ir-2,"Octal literal in strict mode"),t.push(parseInt(a,8)),ir+=a.length-1;else switch(n){case 110:t.push(10);break;case 114:t.push(13);break;case 120:t.push(g(2));break;case 117:t.push(g(4));break;case 85:t.push(g(8));break;case 116:t.push(9);break;case 98:t.push(8);break;case 118:t.push(11);break;case 102:t.push(12);break;case 48:t.push(0);break;case 13:10===nr.charCodeAt(ir)&&++ir;case 10:break;default:t.push(n)}}else(13===n||10===n||8232===n||8329===n)&&r(sr,"Unterminated string constant"),92!==n&&t.push(n),++ir}}function g(e){var t=h(16,e);return null===t&&r(sr,"Bad character escape sequence"),t}function k(){Sr=!1;for(var e,t=!0,o=ir;;){var i=nr.charCodeAt(ir);if(a(i))Sr&&(e+=nr.charAt(ir)),++ir;else{if(92!==i)break;Sr||(e=nr.slice(o,ir)),Sr=!0,117!=nr.charCodeAt(++ir)&&r(ir,"Expecting Unicode escape sequence \\uXXXX"),++ir;var s=g(4),u=String.fromCharCode(s);u||r(ir-1,"Invalid Unicode escape"),(t?n(s):a(s))||r(ir-4,"Invalid Unicode escape"),e+=u}t=!1}return Sr?e:nr.slice(o,ir)}function x(){var e=k(),t=Rr;return Sr||(Tt(e)?t=it[e]:(tr.forbidReserved&&(3===tr.ecmaVersion?Rt:qt)(e)||Ar&&Dt(e))&&r(sr,"The keyword '"+e+"' is reserved")),u(t,e)}function w(){kr=sr,xr=ur,wr=lr,p()}function E(e){Ar=e,ir=xr,f(),p()}function C(){var e={type:null,start:sr,end:null};return tr.trackComments&&dr&&(e.commentsBefore=dr,dr=null),tr.locations&&(e.loc={start:cr,end:null,source:or}),tr.ranges&&(e.range=[sr,0]),e}function A(e){var r={type:null,start:e.start};return e.commentsBefore&&(r.commentsBefore=e.commentsBefore,e.commentsBefore=null),tr.locations&&(r.loc={start:e.loc.start,end:null,source:e.loc.source}),tr.ranges&&(r.range=[e.range[0],0]),r}function S(e,r){return e.type=r,e.end=xr,tr.trackComments&&(mr?(e.commentsAfter=mr,mr=null):Ir&&Ir.end===xr&&Ir.commentsAfter&&(e.commentsAfter=Ir.commentsAfter,Ir.commentsAfter=null),Ir=e),tr.locations&&(e.loc.end=wr),tr.ranges&&(e.range[1]=xr),e}function I(e){return tr.ecmaVersion>=5&&"ExpressionStatement"===e.type&&"Literal"===e.expression.type&&"use strict"===e.expression.value}function U(e){return fr===e?(w(),!0):void 0}function B(){return!tr.strictSemicolons&&(fr===qr||fr===lt||Wt.test(nr.slice(xr,sr)))}function L(){U(mt)||B()||F()}function V(e){fr===e?w():F()}function F(){r(sr,"Unexpected token")}function R(e){"Identifier"!==e.type&&"MemberExpression"!==e.type&&r(e.start,"Assigning to rvalue"),Ar&&"Identifier"===e.type&&Ot(e.name)&&r(e.start,"Assigning to "+e.name+" in strict mode")}function q(e){s(),kr=xr=ir,tr.locations&&(wr=i()),Er=Ar=null,Cr=[],p();var r=e||C(),t=!0;for(e||(r.body=[]);fr!==qr;){var n=D();r.body.push(n),t&&I(n)&&E(!0),t=!1}return S(r,"Program")}function D(){fr===yt&&p(!0);var e=fr,t=C();switch(e){case Dr:case Mr:w();var n=e===Dr;U(mt)||B()?t.label=null:fr!==Rr?F():(t.label=rr(),L());for(var a=0;Cr.length>a;++a){var o=Cr[a];if(null==t.label||o.name===t.label.name){if(null!=o.kind&&(n||"loop"===o.kind))break;if(t.label&&n)break}}return a===Cr.length&&r(t.start,"Unsyntactic "+e.keyword),S(t,n?"BreakStatement":"ContinueStatement");case jr:return w(),S(t,"DebuggerStatement");case zr:return w(),Cr.push(Pt),t.body=D(),Cr.pop(),V(Zr),t.test=O(),L(),S(t,"DoWhileStatement");case Jr:if(w(),Cr.push(Pt),V(ft),fr===mt)return M(t,null);if(fr===Yr){var i=C();return w(),X(i,!0),1===i.declarations.length&&U(ot)?j(t,i):M(t,i)}var i=z(!1,!0);return U(ot)?(R(i),j(t,i)):M(t,i);case Pr:return w(),_(t,!0);case $r:return w(),t.test=O(),t.consequent=D(),t.alternate=U(Nr)?D():null,S(t,"IfStatement");case Gr:return Er||r(sr,"'return' outside of function"),w(),U(mt)||B()?t.argument=null:(t.argument=z(),L()),S(t,"ReturnStatement");case Hr:w(),t.discriminant=O(),t.cases=[],V(ct),Cr.push($t);for(var s,u;fr!=lt;)if(fr===Or||fr===Xr){var c=fr===Or;s&&S(s,"SwitchCase"),t.cases.push(s=C()),s.consequent=[],w(),c?s.test=z():(u&&r(kr,"Multiple default clauses"),u=!0,s.test=null),V(ht)}else s||F(),s.consequent.push(D());return s&&S(s,"SwitchCase"),w(),Cr.pop(),S(t,"SwitchStatement");case Kr:return w(),Wt.test(nr.slice(xr,sr))&&r(xr,"Illegal newline after throw"),t.argument=z(),S(t,"ThrowStatement");case Qr:for(w(),t.block=T(),t.handlers=[];fr===Tr;){var l=C();w(),V(ft),l.param=rr(),Ar&&Ot(l.param.name)&&r(l.param.start,"Binding "+l.param.name+" in strict mode"),V(pt),l.guard=null,l.body=T(),t.handlers.push(S(l,"CatchClause"))}return t.finalizer=U(Wr)?T():null,t.handlers.length||t.finalizer||r(t.start,"Missing catch or finally clause"),S(t,"TryStatement");case Yr:return w(),t=X(t),L(),t;case Zr:return w(),t.test=O(),Cr.push(Pt),t.body=D(),Cr.pop(),S(t,"WhileStatement");case _r:return Ar&&r(sr,"'with' in strict mode"),w(),t.object=O(),t.body=D(),S(t,"WithStatement");case ct:return T();case mt:return w(),S(t,"EmptyStatement");default:var f=pr,d=z();if(e===Rr&&"Identifier"===d.type&&U(ht)){for(var a=0;Cr.length>a;++a)Cr[a].name===f&&r(d.start,"Label '"+f+"' is already declared");var m=fr.isLoop?"loop":fr===Hr?"switch":null;return Cr.push({name:f,kind:m}),t.body=D(),t.label=d,S(t,"LabeledStatement")}return t.expression=d,L(),S(t,"ExpressionStatement")}}function O(){V(ft);var e=z();return V(pt),e}function T(){var e,r=C(),t=!0,n=!1;for(r.body=[],V(ct);!U(lt);){var a=D();r.body.push(a),t&&I(a)&&(e=n,E(n=!0)),t=!1}return n&&!e&&E(!1),S(r,"BlockStatement")}function M(e,r){return e.init=r,V(mt),e.test=fr===mt?null:z(),V(mt),e.update=fr===pt?null:z(),V(pt),e.body=D(),Cr.pop(),S(e,"ForStatement")}function j(e,r){return e.left=r,e.right=z(),V(pt),e.body=D(),Cr.pop(),S(e,"ForInStatement")}function X(e,t){for(e.declarations=[],e.kind="var";;){var n=C();if(n.id=rr(),Ar&&Ot(n.id.name)&&r(n.id.start,"Binding "+n.id.name+" in strict mode"),n.init=U(gt)?z(!0,t):null,e.declarations.push(S(n,"VariableDeclarator")),!U(dt))break}return S(e,"VariableDeclaration")}function z(e,r){var t=N(r);if(!e&&fr===dt){var n=A(t);for(n.expressions=[t];U(dt);)n.expressions.push(N(r));return S(n,"SequenceExpression")}return t}function N(e){var r=W(e);if(fr.isAssign){var t=A(r);return t.operator=pr,t.left=r,w(),t.right=N(e),R(r),S(t,"AssignmentExpression")}return r}function W(e){var r=J(e);if(U(bt)){var t=A(r);return t.test=r,t.consequent=z(!0),V(ht),t.alternate=z(!0,e),S(t,"ConditionalExpression")}return r}function J(e){return P($(e),-1,e)}function P(e,r,t){var n=fr.binop;if(null!=n&&(!t||fr!==ot)&&n>r){var a=A(e);a.left=e,a.operator=pr,w(),a.right=P($(t),n,t);var a=S(a,/&&|\|\|/.test(a.operator)?"LogicalExpression":"BinaryExpression");return P(a,r,t)}return e}function $(e){if(fr.prefix){var t=C(),n=fr.isUpdate;return t.operator=pr,t.prefix=!0,w(),t.argument=$(e),n?R(t.argument):Ar&&"delete"===t.operator&&"Identifier"===t.argument.type&&r(t.start,"Deleting local variable in strict mode"),S(t,n?"UpdateExpression":"UnaryExpression")}for(var a=G();fr.postfix&&!B();){var t=A(a);t.operator=pr,t.prefix=!1,t.argument=a,R(a),w(),a=S(t,"UpdateExpression")}return a}function G(){return H(K())}function H(e,r){if(U(vt)){var t=A(e);return t.object=e,t.property=rr(!0),t.computed=!1,H(S(t,"MemberExpression"),r)}if(U(st)){var t=A(e);return t.object=e,t.property=z(),t.computed=!0,V(ut),H(S(t,"MemberExpression"),r)}if(!r&&U(ft)){var t=A(e);return t.callee=e,t.arguments=er(pt,!1),H(S(t,"CallExpression"),r)}return e}function K(){switch(fr){case rt:var e=C();return w(),S(e,"ThisExpression");case Rr:return rr();case Lr:case Fr:case Vr:var e=C();return e.value=pr,e.raw=nr.slice(sr,ur),w(),S(e,"Literal");case tt:case nt:case at:var e=C();return e.value=fr.atomValue,w(),S(e,"Literal");case ft:var r=cr,t=sr;w();var n=z();return n.start=t,n.end=ur,tr.locations&&(n.loc.start=r,n.loc.end=lr),tr.ranges&&(n.range=[t,ur]),V(pt),n;case st:var e=C();return w(),e.elements=er(ut,!0,!0),S(e,"ArrayExpression");case ct:return Y();case Pr:var e=C();return w(),_(e,!1);case et:return Q();default:F()}}function Q(){var e=C();return w(),e.callee=H(K(!1),!0),e.arguments=U(ft)?er(pt,!1):[],S(e,"NewExpression")}function Y(){var e=C(),t=!0,n=!1;for(e.properties=[],w();!U(lt);){if(t)t=!1;else if(V(dt),tr.allowTrailingCommas&&U(lt))break;var a,o={key:Z()},i=!1;if(U(ht)?(o.value=z(!0),a=o.kind="init"):tr.ecmaVersion>=5&&"Identifier"===o.key.type&&("get"===o.key.name||"set"===o.key.name)?(i=n=!0,a=o.kind=o.key.name,o.key=Z(),!fr===ft&&F(),o.value=_(C(),!1)):F(),"Identifier"===o.key.type&&(Ar||n))for(var s=0;e.properties.length>s;++s){var u=e.properties[s];if(u.key.name===o.key.name){var c=a==u.kind||i&&"init"===u.kind||"init"===a&&("get"===u.kind||"set"===u.kind);c&&!Ar&&"init"===a&&"init"===u.kind&&(c=!1),c&&r(o.key.start,"Redefinition of property")}}e.properties.push(o)}return S(e,"ObjectExpression")}function Z(){return fr===Lr||fr===Fr?K():rr(!0)}function _(e,t){fr===Rr?e.id=rr():t?F():e.id=null,e.params=[];var n=!0;for(V(ft);!U(pt);)n?n=!1:V(dt),e.params.push(rr());var a=Er,o=Cr;if(Er=!0,Cr=[],e.body=T(!0),Er=a,Cr=o,Ar||e.body.body.length&&I(e.body.body[0]))for(var i=e.id?-1:0;e.params.length>i;++i){var s=0>i?e.id:e.params[i];if((Dt(s.name)||Ot(s.name))&&r(s.start,"Defining '"+s.name+"' in strict mode"),i>=0)for(var u=0;i>u;++u)s.name===e.params[u].name&&r(s.start,"Argument name clash in strict mode")}return S(e,t?"FunctionDeclaration":"FunctionExpression")}function er(e,r,t){for(var n=[],a=!0;!U(e);){if(a)a=!1;else if(V(dt),r&&tr.allowTrailingCommas&&U(e))break;t&&fr===dt?n.push(null):n.push(z(!0))}return n}function rr(e){var r=C();return r.name=fr===Rr?pr:e&&!tr.forbidReserved&&fr.keyword||F(),w(),S(r,"Identifier")}e.version="0.0.1";var tr,nr,ar,or;e.parse=function(e,r){nr=e+"",ar=nr.length,tr=r||{};for(var t in Ur)tr.hasOwnProperty(t)||(tr[t]=Ur[t]);return or=tr.sourceFile||null,q(tr.program)};var ir,sr,ur,cr,lr,fr,pr,dr,mr,hr,vr,br,yr,gr,kr,xr,wr,Er,Cr,Ar,Sr,Ir,Ur=e.defaultOptions={ecmaVersion:5,strictSemicolons:!1,allowTrailingCommas:!0,forbidReserved:!1,trackComments:!1,locations:!1,ranges:!1,program:null,sourceFile:null},Br=e.getLineInfo=function(e,r){for(var t=1,n=0;;){Jt.lastIndex=n;var a=Jt.exec(e);if(!(a&&r>a.index))break;++t,n=a.index+a[0].length}return{line:t,column:r-n}},Lr={type:"num"},Vr={type:"regexp"},Fr={type:"string"},Rr={type:"name"},qr={type:"eof"},Dr={keyword:"break"},Or={keyword:"case",beforeExpr:!0},Tr={keyword:"catch"},Mr={keyword:"continue"},jr={keyword:"debugger"},Xr={keyword:"default"},zr={keyword:"do",isLoop:!0},Nr={keyword:"else",beforeExpr:!0},Wr={keyword:"finally"},Jr={keyword:"for",isLoop:!0},Pr={keyword:"function"},$r={keyword:"if"},Gr={keyword:"return",beforeExpr:!0},Hr={keyword:"switch"},Kr={keyword:"throw",beforeExpr:!0},Qr={keyword:"try"},Yr={keyword:"var"},Zr={keyword:"while",isLoop:!0},_r={keyword:"with"},et={keyword:"new",beforeExpr:!0},rt={keyword:"this"},tt={keyword:"null",atomValue:null},nt={keyword:"true",atomValue:!0},at={keyword:"false",atomValue:!1},ot={keyword:"in",binop:7,beforeExpr:!0},it={"break":Dr,"case":Or,"catch":Tr,"continue":Mr,"debugger":jr,"default":Xr,"do":zr,"else":Nr,"finally":Wr,"for":Jr,"function":Pr,"if":$r,"return":Gr,"switch":Hr,"throw":Kr,"try":Qr,"var":Yr,"while":Zr,"with":_r,"null":tt,"true":nt,"false":at,"new":et,"in":ot,"instanceof":{keyword:"instanceof",binop:7},"this":rt,"typeof":{keyword:"typeof",prefix:!0},"void":{keyword:"void",prefix:!0},"delete":{keyword:"delete",prefix:!0}},st={type:"[",beforeExpr:!0},ut={type:"]"},ct={type:"{",beforeExpr:!0},lt={type:"}"},ft={type:"(",beforeExpr:!0},pt={type:")"},dt={type:",",beforeExpr:!0},mt={type:";",beforeExpr:!0},ht={type:":",beforeExpr:!0},vt={type:"."},bt={type:"?",beforeExpr:!0},yt={binop:10,beforeExpr:!0},gt={isAssign:!0,beforeExpr:!0},kt={isAssign:!0,beforeExpr:!0},xt={binop:9,prefix:!0,beforeExpr:!0},wt={postfix:!0,prefix:!0,isUpdate:!0},Et={prefix:!0,beforeExpr:!0},Ct={binop:1,beforeExpr:!0},At={binop:2,beforeExpr:!0},St={binop:3,beforeExpr:!0},It={binop:4,beforeExpr:!0},Ut={binop:5,beforeExpr:!0},Bt={binop:6,beforeExpr:!0},Lt={binop:7,beforeExpr:!0},Vt={binop:8,beforeExpr:!0},Ft={binop:10,beforeExpr:!0},Rt=t("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"),qt=t("class enum extends super const export import"),Dt=t("implements interface let package private protected public static yield"),Ot=t("eval arguments"),Tt=t("break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"),Mt=/[\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/,jt="\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",Xt="\u0371-\u0374\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f",zt=RegExp("["+jt+"]"),Nt=RegExp("["+jt+Xt+"]"),Wt=/[\n\r\u2028\u2029]/,Jt=/\r\n|[\n\r\u2028\u2029]/g,Pt={kind:"loop"},$t={kind:"switch"}})("undefined"==typeof exports?window.acorn={}:exports); - -var PaperScript = this.PaperScript = new function() { - - var binaryOperators = { - '+': 'add', - '-': 'subtract', - '*': 'multiply', - '/': 'divide', - '%': 'modulo', - '==': 'equals', - '!=': 'equals' - }; - - var unaryOperators = { - '-': 'negate', - '+': null - }; - - function _$_(left, operator, right) { - var handler = binaryOperators[operator]; - if (left && left[handler]) { - var res = left[handler](right); - return operator === '!=' ? !res : res; - } - switch (operator) { - case '+': return left + right; - case '-': return left - right; - case '*': return left * right; - case '/': return left / right; - case '%': return left % right; - case '==': return left == right; - case '!=': return left != right; - } - } - - function $_(operator, value) { - var handler = unaryOperators[operator]; - if (handler && value && value[handler]) - return value[handler](); - switch (operator) { - case '+': return +value; - case '-': return -value; - } - } - - function compile(code) { - - var insertions = []; - - function getOffset(offset) { - var start = offset; - for (var i = 0, l = insertions.length; i < l; i++) { - var insertion = insertions[i]; - if (insertion[0] >= offset) - break; - offset += insertion[1]; - } - return offset; - } - - function getCode(node) { - return code.substring(getOffset(node.range[0]), - getOffset(node.range[1])); - } - - function replaceCode(node, str) { - var start = getOffset(node.range[0]), - end = getOffset(node.range[1]); - var insert = 0; - for (var i = insertions.length - 1; i >= 0; i--) { - if (start > insertions[i][0]) { - insert = i + 1; - break; - } - } - insertions.splice(insert, 0, [start, str.length - end + start]); - code = code.substring(0, start) + str + code.substring(end); - } - - function walkAst(node) { - for (var key in node) { - if (key === 'range') - continue; - var value = node[key]; - if (Array.isArray(value)) { - for (var i = 0, l = value.length; i < l; i++) - walkAst(value[i]); - } else if (Base.isPlainObject(value)) { - walkAst(value); - } - } - switch (node && node.type) { - case 'BinaryExpression': - if (node.operator in binaryOperators - && node.left.type !== 'Literal') { - var left = getCode(node.left), - right = getCode(node.right); - replaceCode(node, '_$_(' + left + ', "' + node.operator - + '", ' + right + ')'); - } - break; - case 'AssignmentExpression': - if (/^.=$/.test(node.operator) - && node.left.type !== 'Literal') { - var left = getCode(node.left), - right = getCode(node.right); - replaceCode(node, left + ' = _$_(' + left + ', "' - + node.operator[0] + '", ' + right + ')'); - } - break; - case 'UpdateExpression': - if (!node.prefix) { - var arg = getCode(node.argument); - replaceCode(node, arg + ' = _$_(' + arg + ', "' - + node.operator[0] + '", 1)'); - } - break; - case 'UnaryExpression': - if (node.operator in unaryOperators - && node.argument.type !== 'Literal') { - var arg = getCode(node.argument); - replaceCode(node, '$_("' + node.operator + '", ' - + arg + ')'); - } - break; - } - } - walkAst(acorn.parse(code, { ranges: true })); - return code; - } - - function evaluate(code, scope) { - paper = scope; - var view = scope.project && scope.project.view, - res; - with (scope) { - (function() { - var onActivate, onDeactivate, onEditOptions, - onMouseDown, onMouseUp, onMouseDrag, onMouseMove, - onKeyDown, onKeyUp, onFrame, onResize; - res = eval(compile(code)); - if (/on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)) { - Base.each(Tool.prototype._events, function(key) { - var value = eval(key); - if (value) { - scope.getTool()[key] = value; - } - }); - } - if (view) { - view.setOnResize(onResize); - view.fire('resize', { - size: view.size, - delta: new Point() - }); - view.setOnFrame(onFrame); - view.draw(); - } - }).call(scope); - } - return res; - } - - function request(url, scope) { - var xhr = new (window.ActiveXObject || XMLHttpRequest)( - 'Microsoft.XMLHTTP'); - xhr.open('GET', url, true); - if (xhr.overrideMimeType) - xhr.overrideMimeType('text/plain'); - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - return evaluate(xhr.responseText, scope); - } - }; - return xhr.send(null); - } - - function load() { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, l = scripts.length; i < l; i++) { - var script = scripts[i]; - if (/^text\/(?:x-|)paperscript$/.test(script.type) - && !script.getAttribute('data-paper-ignore')) { - var scope = new PaperScope(script); - scope.setup(PaperScript.getAttribute(script, 'canvas')); - if (script.src) { - request(script.src, scope); - } else { - evaluate(script.innerHTML, scope); - } - script.setAttribute('data-paper-ignore', true); - } - } - } - - DomEvent.add(window, { load: load }); - - function handleAttribute(name) { - name += 'Attribute'; - return function(el, attr) { - return el[name](attr) || el[name]('data-paper-' + attr); - }; - } - - return { - compile: compile, - evaluate: evaluate, - load: load, - getAttribute: handleAttribute('get'), - hasAttribute: handleAttribute('has') - }; - -}; - -this.load = PaperScript.load; - -Base.each(this, function(val, key) { - if (val && val.prototype instanceof Base) { - val._name = key; - } -}); - -this.enumerable = true; -return new (PaperScope.inject(this)); -}; +// For more information on building the library please refer to the +// 'Building the Library' section of README.md: +// https://github.com/paperjs/paper.js#building-the-library