1 /*! |
1 /*! |
2 * Paper.js v0.9.22 - The Swiss Army Knife of Vector Graphics Scripting. |
2 * Paper.js v0.9.24 - The Swiss Army Knife of Vector Graphics Scripting. |
3 * http://paperjs.org/ |
3 * http://paperjs.org/ |
4 * |
4 * |
5 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey |
5 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey |
6 * http://scratchdisk.com/ & http://jonathanpuckey.com/ |
6 * http://scratchdisk.com/ & http://jonathanpuckey.com/ |
7 * |
7 * |
8 * Distributed under the MIT license. See LICENSE file for details. |
8 * Distributed under the MIT license. See LICENSE file for details. |
9 * |
9 * |
10 * All rights reserved. |
10 * All rights reserved. |
11 * |
11 * |
12 * Date: Sat Feb 28 19:20:48 2015 +0100 |
12 * Date: Fri Aug 21 16:39:41 2015 +0200 |
13 * |
13 * |
14 *** |
14 *** |
15 * |
15 * |
16 * Straps.js - Class inheritance library with support for bean-style accessors |
16 * Straps.js - Class inheritance library with support for bean-style accessors |
17 * |
17 * |
159 return this; |
159 return this; |
160 }, |
160 }, |
161 |
161 |
162 extend: function() { |
162 extend: function() { |
163 var base = this, |
163 var base = this, |
164 ctor; |
164 ctor, |
|
165 proto; |
165 for (var i = 0, l = arguments.length; i < l; i++) |
166 for (var i = 0, l = arguments.length; i < l; i++) |
166 if (ctor = arguments[i].initialize) |
167 if (ctor = arguments[i].initialize) |
167 break; |
168 break; |
168 ctor = ctor || function() { |
169 ctor = ctor || function() { |
169 base.apply(this, arguments); |
170 base.apply(this, arguments); |
170 }; |
171 }; |
171 ctor.prototype = create(this.prototype); |
172 proto = ctor.prototype = create(this.prototype); |
172 ctor.base = base; |
173 define(proto, 'constructor', |
173 define(ctor.prototype, 'constructor', |
|
174 { value: ctor, writable: true, configurable: true }); |
174 { value: ctor, writable: true, configurable: true }); |
175 inject(ctor, this, true); |
175 inject(ctor, this, true); |
176 return arguments.length ? this.inject.apply(ctor, arguments) : ctor; |
176 if (arguments.length) |
|
177 this.inject.apply(ctor, arguments); |
|
178 ctor.base = base; |
|
179 return ctor; |
177 } |
180 } |
178 }, true).inject({ |
181 }, true).inject({ |
179 inject: function() { |
182 inject: function() { |
180 for (var i = 0, l = arguments.length; i < l; i++) { |
183 for (var i = 0, l = arguments.length; i < l; i++) { |
181 var src = arguments[i]; |
184 var src = arguments[i]; |
257 return Base.serialize(this); |
260 return Base.serialize(this); |
258 }, |
261 }, |
259 |
262 |
260 _set: function(props, exclude, dontCheck) { |
263 _set: function(props, exclude, dontCheck) { |
261 if (props && (dontCheck || Base.isPlainObject(props))) { |
264 if (props && (dontCheck || Base.isPlainObject(props))) { |
262 var orig = props._filtering || props; |
265 var keys = Object.keys(props._filtering || props); |
263 for (var key in orig) { |
266 for (var i = 0, l = keys.length; i < l; i++) { |
264 if (orig.hasOwnProperty(key) && !(exclude && exclude[key])) { |
267 var key = keys[i]; |
|
268 if (!(exclude && exclude[key])) { |
265 var value = props[key]; |
269 var value = props[key]; |
266 if (value !== undefined) |
270 if (value !== undefined) |
267 this[key] = value; |
271 this[key] = value; |
268 } |
272 } |
269 } |
273 } |
284 Base.exports[name] = res; |
288 Base.exports[name] = res; |
285 return res; |
289 return res; |
286 }, |
290 }, |
287 |
291 |
288 equals: function(obj1, obj2) { |
292 equals: function(obj1, obj2) { |
289 function checkKeys(o1, o2) { |
|
290 for (var i in o1) |
|
291 if (o1.hasOwnProperty(i) && !o2.hasOwnProperty(i)) |
|
292 return false; |
|
293 return true; |
|
294 } |
|
295 if (obj1 === obj2) |
293 if (obj1 === obj2) |
296 return true; |
294 return true; |
297 if (obj1 && obj1.equals) |
295 if (obj1 && obj1.equals) |
298 return obj1.equals(obj2); |
296 return obj1.equals(obj2); |
299 if (obj2 && obj2.equals) |
297 if (obj2 && obj2.equals) |
300 return obj2.equals(obj1); |
298 return obj2.equals(obj1); |
301 if (Array.isArray(obj1) && Array.isArray(obj2)) { |
299 if (obj1 && obj2 |
302 if (obj1.length !== obj2.length) |
300 && typeof obj1 === 'object' && typeof obj2 === 'object') { |
303 return false; |
301 if (Array.isArray(obj1) && Array.isArray(obj2)) { |
304 for (var i = 0, l = obj1.length; i < l; i++) { |
302 var length = obj1.length; |
305 if (!Base.equals(obj1[i], obj2[i])) |
303 if (length !== obj2.length) |
306 return false; |
304 return false; |
307 } |
305 while (length--) { |
308 return true; |
306 if (!Base.equals(obj1[length], obj2[length])) |
309 } |
307 return false; |
310 if (obj1 && typeof obj1 === 'object' |
308 } |
311 && obj2 && typeof obj2 === 'object') { |
309 } else { |
312 if (!checkKeys(obj1, obj2) || !checkKeys(obj2, obj1)) |
310 var keys = Object.keys(obj1), |
313 return false; |
311 length = keys.length; |
314 for (var i in obj1) { |
312 if (length !== Object.keys(obj2).length) |
315 if (obj1.hasOwnProperty(i) |
|
316 && !Base.equals(obj1[i], obj2[i])) |
|
317 return false; |
313 return false; |
|
314 while (length--) { |
|
315 var key = keys[length]; |
|
316 if (!(obj2.hasOwnProperty(key) |
|
317 && Base.equals(obj1[key], obj2[key]))) |
|
318 return false; |
|
319 } |
318 } |
320 } |
319 return true; |
321 return true; |
320 } |
322 } |
321 return false; |
323 return false; |
322 }, |
324 }, |
441 dictionary); |
443 dictionary); |
442 if (compact) |
444 if (compact) |
443 res._compact = true; |
445 res._compact = true; |
444 } else if (Base.isPlainObject(obj)) { |
446 } else if (Base.isPlainObject(obj)) { |
445 res = {}; |
447 res = {}; |
446 for (var i in obj) |
448 var keys = Object.keys(obj); |
447 if (obj.hasOwnProperty(i)) |
449 for (var i = 0, l = keys.length; i < l; i++) { |
448 res[i] = Base.serialize(obj[i], options, compact, |
450 var key = keys[i]; |
449 dictionary); |
451 res[key] = Base.serialize(obj[key], options, compact, |
|
452 dictionary); |
|
453 } |
450 } else if (typeof obj === 'number') { |
454 } else if (typeof obj === 'number') { |
451 res = options.formatter.number(obj, options.precision); |
455 res = options.formatter.number(obj, options.precision); |
452 } else { |
456 } else { |
453 res = obj; |
457 res = obj; |
454 } |
458 } |
455 return root && dictionary.length > 0 |
459 return root && dictionary.length > 0 |
456 ? [['dictionary', dictionary.definitions], res] |
460 ? [['dictionary', dictionary.definitions], res] |
457 : res; |
461 : res; |
458 }, |
462 }, |
459 |
463 |
460 deserialize: function(json, create, _data) { |
464 deserialize: function(json, create, _data, _isDictionary) { |
461 var res = json, |
465 var res = json, |
462 isRoot = !_data; |
466 isRoot = !_data; |
463 _data = _data || {}; |
467 _data = _data || {}; |
464 if (Array.isArray(json)) { |
468 if (Array.isArray(json)) { |
465 var type = json[0], |
469 var type = json[0], |
466 isDictionary = type === 'dictionary'; |
470 isDictionary = type === 'dictionary'; |
467 if (!isDictionary) { |
471 if (json.length == 1 && /^#/.test(type)) |
468 if (_data.dictionary && json.length == 1 && /^#/.test(type)) |
472 return _data.dictionary[type]; |
469 return _data.dictionary[type]; |
473 type = Base.exports[type]; |
470 type = Base.exports[type]; |
|
471 } |
|
472 res = []; |
474 res = []; |
|
475 if (_isDictionary) |
|
476 _data.dictionary = res; |
473 for (var i = type ? 1 : 0, l = json.length; i < l; i++) |
477 for (var i = type ? 1 : 0, l = json.length; i < l; i++) |
474 res.push(Base.deserialize(json[i], create, _data)); |
478 res.push(Base.deserialize(json[i], create, _data, |
475 if (isDictionary) { |
479 isDictionary)); |
476 _data.dictionary = res[0]; |
480 if (type) { |
477 } else if (type) { |
|
478 var args = res; |
481 var args = res; |
479 if (create) { |
482 if (create) { |
480 res = create(type, args); |
483 res = create(type, args); |
481 } else { |
484 } else { |
482 res = Base.create(type.prototype); |
485 res = Base.create(type.prototype); |
483 type.apply(res, args); |
486 type.apply(res, args); |
484 } |
487 } |
485 } |
488 } |
486 } else if (Base.isPlainObject(json)) { |
489 } else if (Base.isPlainObject(json)) { |
487 res = {}; |
490 res = {}; |
|
491 if (_isDictionary) |
|
492 _data.dictionary = res; |
488 for (var key in json) |
493 for (var key in json) |
489 res[key] = Base.deserialize(json[key], create, _data); |
494 res[key] = Base.deserialize(json[key], create, _data); |
490 } |
495 } |
491 return isRoot && json && json.length && json[0][0] === 'dictionary' |
496 return isRoot && json && json.length && json[0][0] === 'dictionary' |
492 ? res[1] |
497 ? res[1] |
568 if (typeof type !== 'string') { |
573 if (typeof type !== 'string') { |
569 Base.each(type, function(value, key) { |
574 Base.each(type, function(value, key) { |
570 this.on(key, value); |
575 this.on(key, value); |
571 }, this); |
576 }, this); |
572 } else { |
577 } else { |
573 var entry = this._eventTypes[type]; |
578 var types = this._eventTypes, |
574 if (entry) { |
579 entry = types && types[type], |
575 var handlers = this._callbacks = this._callbacks || {}; |
580 handlers = this._callbacks = this._callbacks || {}; |
576 handlers = handlers[type] = handlers[type] || []; |
581 handlers = handlers[type] = handlers[type] || []; |
577 if (handlers.indexOf(func) === -1) { |
582 if (handlers.indexOf(func) === -1) { |
578 handlers.push(func); |
583 handlers.push(func); |
579 if (entry.install && handlers.length == 1) |
584 if (entry && entry.install && handlers.length == 1) |
580 entry.install.call(this, type); |
585 entry.install.call(this, type); |
581 } |
|
582 } |
586 } |
583 } |
587 } |
584 return this; |
588 return this; |
585 }, |
589 }, |
586 |
590 |
589 Base.each(type, function(value, key) { |
593 Base.each(type, function(value, key) { |
590 this.off(key, value); |
594 this.off(key, value); |
591 }, this); |
595 }, this); |
592 return; |
596 return; |
593 } |
597 } |
594 var entry = this._eventTypes[type], |
598 var types = this._eventTypes, |
|
599 entry = types && types[type], |
595 handlers = this._callbacks && this._callbacks[type], |
600 handlers = this._callbacks && this._callbacks[type], |
596 index; |
601 index; |
597 if (entry && handlers) { |
602 if (handlers) { |
598 if (!func || (index = handlers.indexOf(func)) !== -1 |
603 if (!func || (index = handlers.indexOf(func)) !== -1 |
599 && handlers.length === 1) { |
604 && handlers.length === 1) { |
600 if (entry.uninstall) |
605 if (entry && entry.uninstall) |
601 entry.uninstall.call(this, type); |
606 entry.uninstall.call(this, type); |
602 delete this._callbacks[type]; |
607 delete this._callbacks[type]; |
603 } else if (index !== -1) { |
608 } else if (index !== -1) { |
604 handlers.splice(index, 1); |
609 handlers.splice(index, 1); |
605 } |
610 } |
617 emit: function(type, event) { |
622 emit: function(type, event) { |
618 var handlers = this._callbacks && this._callbacks[type]; |
623 var handlers = this._callbacks && this._callbacks[type]; |
619 if (!handlers) |
624 if (!handlers) |
620 return false; |
625 return false; |
621 var args = [].slice.call(arguments, 1); |
626 var args = [].slice.call(arguments, 1); |
|
627 handlers = handlers.slice(); |
622 for (var i = 0, l = handlers.length; i < l; i++) { |
628 for (var i = 0, l = handlers.length; i < l; i++) { |
623 if (handlers[i].apply(this, args) === false |
629 if (handlers[i].apply(this, args) === false) { |
624 && event && event.stop) { |
630 if (event && event.stop) |
625 event.stop(); |
631 event.stop(); |
626 break; |
632 break; |
627 } |
633 } |
628 } |
634 } |
629 return true; |
635 return true; |
630 }, |
636 }, |
640 _installEvents: function(install) { |
646 _installEvents: function(install) { |
641 var handlers = this._callbacks, |
647 var handlers = this._callbacks, |
642 key = install ? 'install' : 'uninstall'; |
648 key = install ? 'install' : 'uninstall'; |
643 for (var type in handlers) { |
649 for (var type in handlers) { |
644 if (handlers[type].length > 0) { |
650 if (handlers[type].length > 0) { |
645 var entry = this._eventTypes[type], |
651 var types = this._eventTypes, |
646 func = entry[key]; |
652 entry = types && types[type], |
|
653 func = entry && entry[key]; |
647 if (func) |
654 if (func) |
648 func.call(this, type); |
655 func.call(this, type); |
649 } |
656 } |
650 } |
657 } |
651 }, |
658 }, |
706 }; |
713 }; |
707 CanvasProvider.release(ctx); |
714 CanvasProvider.release(ctx); |
708 } |
715 } |
709 |
716 |
710 if (!this.browser) { |
717 if (!this.browser) { |
711 var browser = proto.browser = {}; |
718 var agent = navigator.userAgent.toLowerCase(), |
712 navigator.userAgent.toLowerCase().replace( |
719 platform = (/(win)/.exec(agent) |
|
720 || /(mac)/.exec(agent) |
|
721 || /(linux)/.exec(agent) |
|
722 || [])[0], |
|
723 browser = proto.browser = { platform: platform }; |
|
724 if (platform) |
|
725 browser[platform] = true; |
|
726 agent.replace( |
713 /(opera|chrome|safari|webkit|firefox|msie|trident|atom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:([.\d]+))?/g, |
727 /(opera|chrome|safari|webkit|firefox|msie|trident|atom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:([.\d]+))?/g, |
714 function(all, n, v1, v2, rv) { |
728 function(all, n, v1, v2, rv) { |
715 if (!browser.chrome) { |
729 if (!browser.chrome) { |
716 var v = n === 'opera' ? v2 : v1; |
730 var v = n === 'opera' ? v2 : v1; |
717 if (n === 'trident') { |
731 if (n === 'trident') { |
967 x1, x2 = Infinity, |
981 x1, x2 = Infinity, |
968 B = b, |
982 B = b, |
969 D; |
983 D; |
970 b /= 2; |
984 b /= 2; |
971 D = b * b - a * c; |
985 D = b * b - a * c; |
972 if (abs(D) < MACHINE_EPSILON) { |
986 if (D !== 0 && abs(D) < MACHINE_EPSILON) { |
973 var pow = Math.pow, |
987 var gmC = pow(abs(a * b * c), 1 / 3); |
974 gmC = pow(abs(a*b*c), 1/3); |
|
975 if (gmC < 1e-8) { |
988 if (gmC < 1e-8) { |
976 /* |
|
977 * we multiply with a factor to normalize the |
|
978 * coefficients. The factor is just the nearest exponent |
|
979 * of 10, big enough to raise all the coefficients to |
|
980 * nearly [-1, +1] range. |
|
981 */ |
|
982 var mult = pow(10, abs( |
989 var mult = pow(10, abs( |
983 Math.floor(Math.log(gmC) * Math.LOG10E))); |
990 Math.floor(Math.log(gmC) * Math.LOG10E))); |
984 if (!isFinite(mult)) |
991 if (!isFinite(mult)) |
985 mult = 0; |
992 mult = 0; |
986 a *= mult; |
993 a *= mult; |
987 b *= mult; |
994 b *= mult; |
988 c *= mult; |
995 c *= mult; |
989 D = b * b - a * c; |
996 D = b * b - a * c; |
990 } |
997 } |
991 } |
998 } |
992 if (abs(a) < MACHINE_EPSILON) { |
999 if (abs(a) < EPSILON) { |
993 if (abs(B) < MACHINE_EPSILON) |
1000 if (abs(B) < EPSILON) |
994 return abs(c) < MACHINE_EPSILON ? -1 : 0; |
1001 return abs(c) < EPSILON ? -1 : 0; |
995 x1 = -c / B; |
1002 x1 = -c / B; |
996 } else { |
1003 } else { |
997 if (D >= -MACHINE_EPSILON) { |
1004 if (D >= -MACHINE_EPSILON) { |
998 D = D < 0 ? 0 : D; |
1005 D = D < 0 ? 0 : D; |
999 var R = sqrt(D); |
1006 var R = sqrt(D); |
1282 |
1307 |
1283 isClose: function(point, tolerance) { |
1308 isClose: function(point, tolerance) { |
1284 return this.getDistance(point) < tolerance; |
1309 return this.getDistance(point) < tolerance; |
1285 }, |
1310 }, |
1286 |
1311 |
1287 isColinear: function(point) { |
1312 isCollinear: function(point) { |
1288 return Math.abs(this.cross(point)) < 1e-12; |
1313 return Math.abs(this.cross(point)) < 0.000001; |
1289 }, |
1314 }, |
|
1315 |
|
1316 isColinear: '#isCollinear', |
1290 |
1317 |
1291 isOrthogonal: function(point) { |
1318 isOrthogonal: function(point) { |
1292 return Math.abs(this.dot(point)) < 1e-12; |
1319 return Math.abs(this.dot(point)) < 0.000001; |
1293 }, |
1320 }, |
1294 |
1321 |
1295 isZero: function() { |
1322 isZero: function() { |
1296 return Numerical.isZero(this.x) && Numerical.isZero(this.y); |
1323 return Numerical.isZero(this.x) && Numerical.isZero(this.y); |
1297 }, |
1324 }, |
2733 var hasProps = props && Base.isPlainObject(props), |
2760 var hasProps = props && Base.isPlainObject(props), |
2734 internal = hasProps && props.internal === true, |
2761 internal = hasProps && props.internal === true, |
2735 matrix = this._matrix = new Matrix(), |
2762 matrix = this._matrix = new Matrix(), |
2736 project = hasProps && props.project || paper.project; |
2763 project = hasProps && props.project || paper.project; |
2737 if (!internal) |
2764 if (!internal) |
2738 this._id = Item._id = (Item._id || 0) + 1; |
2765 this._id = UID.get(); |
2739 this._applyMatrix = this._canApplyMatrix && paper.settings.applyMatrix; |
2766 this._applyMatrix = this._canApplyMatrix && paper.settings.applyMatrix; |
2740 if (point) |
2767 if (point) |
2741 matrix.translate(point); |
2768 matrix.translate(point); |
2742 matrix._owner = this; |
2769 matrix._owner = this; |
2743 this._style = new Style(project._currentStyle, this, project); |
2770 this._style = new Style(project._currentStyle, this, project); |
3044 } |
3072 } |
3045 return pivot; |
3073 return pivot; |
3046 }, |
3074 }, |
3047 |
3075 |
3048 setPivot: function() { |
3076 setPivot: function() { |
3049 this._pivot = Point.read(arguments); |
3077 this._pivot = Point.read(arguments, 0, { clone: true, readNull: true }); |
3050 this._position = undefined; |
3078 this._position = undefined; |
3051 }, |
3079 }, |
3052 |
3080 |
3053 _pivot: null, |
3081 _pivot: null, |
3054 |
|
3055 getRegistration: '#getPivot', |
|
3056 setRegistration: '#setPivot' |
|
3057 }, Base.each(['bounds', 'strokeBounds', 'handleBounds', 'roughBounds', |
3082 }, Base.each(['bounds', 'strokeBounds', 'handleBounds', 'roughBounds', |
3058 'internalBounds', 'internalRoughBounds'], |
3083 'internalBounds', 'internalRoughBounds'], |
3059 function(key) { |
3084 function(key) { |
3060 var getter = 'get' + Base.capitalize(key), |
3085 var getter = 'get' + Base.capitalize(key), |
3061 match = key.match(/^internal(.*)$/), |
3086 match = key.match(/^internal(.*)$/), |
3118 |
3144 |
3119 _getCachedBounds: function(getter, matrix, cacheItem, internalGetter) { |
3145 _getCachedBounds: function(getter, matrix, cacheItem, internalGetter) { |
3120 matrix = matrix && matrix.orNullIfIdentity(); |
3146 matrix = matrix && matrix.orNullIfIdentity(); |
3121 var _matrix = internalGetter ? null : this._matrix.orNullIfIdentity(), |
3147 var _matrix = internalGetter ? null : this._matrix.orNullIfIdentity(), |
3122 cache = (!matrix || matrix.equals(_matrix)) && getter; |
3148 cache = (!matrix || matrix.equals(_matrix)) && getter; |
3123 var cacheParent = this._parent || this._parentSymbol; |
3149 Item._updateBoundsCache(this._parent || this._parentSymbol, cacheItem); |
3124 if (cacheParent) { |
|
3125 var id = cacheItem._id, |
|
3126 ref = cacheParent._boundsCache = cacheParent._boundsCache || { |
|
3127 ids: {}, |
|
3128 list: [] |
|
3129 }; |
|
3130 if (!ref.ids[id]) { |
|
3131 ref.list.push(cacheItem); |
|
3132 ref.ids[id] = cacheItem; |
|
3133 } |
|
3134 } |
|
3135 if (cache && this._bounds && this._bounds[cache]) |
3150 if (cache && this._bounds && this._bounds[cache]) |
3136 return this._bounds[cache].clone(); |
3151 return this._bounds[cache].clone(); |
3137 var bounds = this._getBounds(internalGetter || getter, |
3152 var bounds = this._getBounds(internalGetter || getter, |
3138 matrix || _matrix, cacheItem); |
3153 matrix || _matrix, cacheItem); |
3139 if (cache) { |
3154 if (cache) { |
3144 } |
3159 } |
3145 return bounds; |
3160 return bounds; |
3146 }, |
3161 }, |
3147 |
3162 |
3148 statics: { |
3163 statics: { |
|
3164 _updateBoundsCache: function(parent, item) { |
|
3165 if (parent) { |
|
3166 var id = item._id, |
|
3167 ref = parent._boundsCache = parent._boundsCache || { |
|
3168 ids: {}, |
|
3169 list: [] |
|
3170 }; |
|
3171 if (!ref.ids[id]) { |
|
3172 ref.list.push(item); |
|
3173 ref.ids[id] = item; |
|
3174 } |
|
3175 } |
|
3176 }, |
|
3177 |
3149 _clearBoundsCache: function(item) { |
3178 _clearBoundsCache: function(item) { |
3150 var cache = item._boundsCache; |
3179 var cache = item._boundsCache; |
3151 if (cache) { |
3180 if (cache) { |
3152 item._bounds = item._position = item._boundsCache = undefined; |
3181 item._bounds = item._position = item._boundsCache = undefined; |
3153 for (var i = 0, list = cache.list, l = list.length; i < l; i++) { |
3182 for (var i = 0, list = cache.list, l = list.length; i < l; i++){ |
3154 var other = list[i]; |
3183 var other = list[i]; |
3155 if (other !== item) { |
3184 if (other !== item) { |
3156 other._bounds = other._position = undefined; |
3185 other._bounds = other._position = undefined; |
3157 if (other._boundsCache) |
3186 if (other._boundsCache) |
3158 Item._clearBoundsCache(other); |
3187 Item._clearBoundsCache(other); |
3338 |
3368 |
3339 clone: function(insert) { |
3369 clone: function(insert) { |
3340 return this._clone(new this.constructor(Item.NO_INSERT), insert); |
3370 return this._clone(new this.constructor(Item.NO_INSERT), insert); |
3341 }, |
3371 }, |
3342 |
3372 |
3343 _clone: function(copy, insert) { |
3373 _clone: function(copy, insert, includeMatrix) { |
|
3374 var keys = ['_locked', '_visible', '_blendMode', '_opacity', |
|
3375 '_clipMask', '_guide'], |
|
3376 children = this._children; |
3344 copy.setStyle(this._style); |
3377 copy.setStyle(this._style); |
3345 if (this._children) { |
3378 for (var i = 0, l = children && children.length; i < l; i++) { |
3346 for (var i = 0, l = this._children.length; i < l; i++) |
3379 copy.addChild(children[i].clone(false), true); |
3347 copy.addChild(this._children[i].clone(false), true); |
3380 } |
3348 } |
|
3349 if (insert || insert === undefined) |
|
3350 copy.insertAbove(this); |
|
3351 var keys = ['_locked', '_visible', '_blendMode', '_opacity', |
|
3352 '_clipMask', '_guide', '_applyMatrix']; |
|
3353 for (var i = 0, l = keys.length; i < l; i++) { |
3381 for (var i = 0, l = keys.length; i < l; i++) { |
3354 var key = keys[i]; |
3382 var key = keys[i]; |
3355 if (this.hasOwnProperty(key)) |
3383 if (this.hasOwnProperty(key)) |
3356 copy[key] = this[key]; |
3384 copy[key] = this[key]; |
3357 } |
3385 } |
3358 copy._matrix.initialize(this._matrix); |
3386 if (includeMatrix !== false) |
|
3387 copy._matrix.initialize(this._matrix); |
|
3388 copy.setApplyMatrix(this._applyMatrix); |
|
3389 copy.setPivot(this._pivot); |
|
3390 copy.setSelected(this._selected); |
3359 copy._data = this._data ? Base.clone(this._data) : null; |
3391 copy._data = this._data ? Base.clone(this._data) : null; |
3360 copy.setSelected(this._selected); |
3392 if (insert || insert === undefined) |
|
3393 copy.insertAbove(this); |
3361 if (this._name) |
3394 if (this._name) |
3362 copy.setName(this._name, true); |
3395 copy.setName(this._name, true); |
3363 return copy; |
3396 return copy; |
3364 }, |
3397 }, |
3365 |
3398 |
3557 }, |
3593 }, |
3558 |
3594 |
3559 statics: { |
3595 statics: { |
3560 _getItems: function _getItems(children, match, matrix, param, |
3596 _getItems: function _getItems(children, match, matrix, param, |
3561 firstOnly) { |
3597 firstOnly) { |
3562 if (!param) { |
3598 if (!param && typeof match === 'object') { |
3563 var overlapping = match.overlapping, |
3599 var overlapping = match.overlapping, |
3564 inside = match.inside, |
3600 inside = match.inside, |
3565 bounds = overlapping || inside, |
3601 bounds = overlapping || inside, |
3566 rect = bounds && Rectangle.read([bounds]); |
3602 rect = bounds && Rectangle.read([bounds]); |
3567 param = { |
3603 param = { |
3568 items: [], |
3604 items: [], |
3569 inside: rect, |
3605 inside: !!inside, |
3570 overlapping: overlapping && new Path.Rectangle({ |
3606 overlapping: !!overlapping, |
|
3607 rect: rect, |
|
3608 path: overlapping && new Path.Rectangle({ |
3571 rectangle: rect, |
3609 rectangle: rect, |
3572 insert: false |
3610 insert: false |
3573 }) |
3611 }) |
3574 }; |
3612 }; |
3575 if (bounds) |
3613 if (bounds) |
3576 match = Base.set({}, match, |
3614 match = Base.set({}, match, |
3577 { inside: true, overlapping: true }); |
3615 { inside: true, overlapping: true }); |
3578 } |
3616 } |
3579 var items = param.items, |
3617 var items = param && param.items, |
3580 inside = param.inside, |
3618 rect = param && param.rect; |
3581 overlapping = param.overlapping; |
3619 matrix = rect && (matrix || new Matrix()); |
3582 matrix = inside && (matrix || new Matrix()); |
|
3583 for (var i = 0, l = children && children.length; i < l; i++) { |
3620 for (var i = 0, l = children && children.length; i < l; i++) { |
3584 var child = children[i], |
3621 var child = children[i], |
3585 childMatrix = matrix && matrix.chain(child._matrix), |
3622 childMatrix = matrix && matrix.chain(child._matrix), |
3586 add = true; |
3623 add = true; |
3587 if (inside) { |
3624 if (rect) { |
3588 var bounds = child.getBounds(childMatrix); |
3625 var bounds = child.getBounds(childMatrix); |
3589 if (!inside.intersects(bounds)) |
3626 if (!rect.intersects(bounds)) |
3590 continue; |
3627 continue; |
3591 if (!(inside && inside.contains(bounds)) && !(overlapping |
3628 if (!(param.inside && rect.contains(bounds)) |
3592 && overlapping.intersects(child, childMatrix))) |
3629 && !(param.overlapping && (bounds.contains(rect) |
|
3630 || param.path.intersects(child, childMatrix)))) |
3593 add = false; |
3631 add = false; |
3594 } |
3632 } |
3595 if (add && child.matches(match)) { |
3633 if (add && child.matches(match)) { |
3596 items.push(child); |
3634 items.push(child); |
3597 if (firstOnly) |
3635 if (firstOnly) |
4064 direct = normalBlend && opacity === 1 |
4102 direct = normalBlend && opacity === 1 |
4065 || param.dontStart |
4103 || param.dontStart |
4066 || param.clip |
4104 || param.clip |
4067 || (nativeBlend || normalBlend && opacity < 1) |
4105 || (nativeBlend || normalBlend && opacity < 1) |
4068 && this._canComposite(), |
4106 && this._canComposite(), |
4069 pixelRatio = param.pixelRatio, |
4107 pixelRatio = param.pixelRatio || 1, |
4070 mainCtx, itemOffset, prevOffset; |
4108 mainCtx, itemOffset, prevOffset; |
4071 if (!direct) { |
4109 if (!direct) { |
4072 var bounds = this.getStrokeBounds(getViewMatrix(globalMatrix)); |
4110 var bounds = this.getStrokeBounds(getViewMatrix(globalMatrix)); |
4073 if (!bounds.width || !bounds.height) |
4111 if (!bounds.width || !bounds.height) |
4074 return; |
4112 return; |
4420 isEmpty: function() { |
4458 isEmpty: function() { |
4421 return false; |
4459 return false; |
4422 }, |
4460 }, |
4423 |
4461 |
4424 toPath: function(insert) { |
4462 toPath: function(insert) { |
4425 var path = new Path[Base.capitalize(this._type)]({ |
4463 var path = this._clone(new Path[Base.capitalize(this._type)]({ |
4426 center: new Point(), |
4464 center: new Point(), |
4427 size: this._size, |
4465 size: this._size, |
4428 radius: this._radius, |
4466 radius: this._radius, |
4429 insert: false |
4467 insert: false |
4430 }); |
4468 }), insert); |
4431 path.setStyle(this._style); |
4469 if (paper.settings.applyMatrix) |
4432 path.transform(this._matrix); |
4470 path.setApplyMatrix(true); |
4433 if (insert || insert === undefined) |
|
4434 path.insertAbove(this); |
|
4435 return path; |
4471 return path; |
4436 }, |
4472 }, |
4437 |
4473 |
4438 _draw: function(ctx, param, strokeMatrix) { |
4474 _draw: function(ctx, param, strokeMatrix) { |
4439 var style = this._style, |
4475 var style = this._style, |
4453 var rx = isCircle ? radius : radius.width, |
4489 var rx = isCircle ? radius : radius.width, |
4454 ry = isCircle ? radius : radius.height, |
4490 ry = isCircle ? radius : radius.height, |
4455 size = this._size, |
4491 size = this._size, |
4456 width = size.width, |
4492 width = size.width, |
4457 height = size.height; |
4493 height = size.height; |
4458 if (untransformed && type === 'rect' && rx === 0 && ry === 0) { |
4494 if (untransformed && type === 'rectangle' && rx === 0 && ry === 0) { |
4459 ctx.rect(-width / 2, -height / 2, width, height); |
4495 ctx.rect(-width / 2, -height / 2, width, height); |
4460 } else { |
4496 } else { |
4461 var x = width / 2, |
4497 var x = width / 2, |
4462 y = height / 2, |
4498 y = height / 2, |
4463 kappa = 1 - 0.5522847498307936, |
4499 kappa = 1 - 0.5522847498307936, |
4645 _applyMatrix: false, |
4681 _applyMatrix: false, |
4646 _canApplyMatrix: false, |
4682 _canApplyMatrix: false, |
4647 _boundsGetter: 'getBounds', |
4683 _boundsGetter: 'getBounds', |
4648 _boundsSelected: true, |
4684 _boundsSelected: true, |
4649 _serializeFields: { |
4685 _serializeFields: { |
|
4686 crossOrigin: null, |
4650 source: null |
4687 source: null |
4651 }, |
4688 }, |
4652 |
4689 |
4653 initialize: function Raster(object, position) { |
4690 initialize: function Raster(object, position) { |
4654 if (!this._initialize(object, |
4691 if (!this._initialize(object, |
4678 } else if (canvas) { |
4715 } else if (canvas) { |
4679 var copyCanvas = CanvasProvider.getCanvas(this._size); |
4716 var copyCanvas = CanvasProvider.getCanvas(this._size); |
4680 copyCanvas.getContext('2d').drawImage(canvas, 0, 0); |
4717 copyCanvas.getContext('2d').drawImage(canvas, 0, 0); |
4681 copy.setImage(copyCanvas); |
4718 copy.setImage(copyCanvas); |
4682 } |
4719 } |
|
4720 copy._crossOrigin = this._crossOrigin; |
4683 return this._clone(copy, insert); |
4721 return this._clone(copy, insert); |
4684 }, |
4722 }, |
4685 |
4723 |
4686 getSize: function() { |
4724 getSize: function() { |
4687 var size = this._size; |
4725 var size = this._size; |
4809 that.emit('load'); |
4848 that.emit('load'); |
4810 view.update(); |
4849 view.update(); |
4811 } |
4850 } |
4812 } |
4851 } |
4813 |
4852 |
4814 image = document.getElementById(src) || new Image(); |
4853 image = document.getElementById(src) || new Image(); |
4815 |
4854 if (crossOrigin) |
|
4855 image.crossOrigin = crossOrigin; |
4816 if (image.naturalWidth && image.naturalHeight) { |
4856 if (image.naturalWidth && image.naturalHeight) { |
4817 setTimeout(loaded, 0); |
4857 setTimeout(loaded, 0); |
4818 } else { |
4858 } else { |
4819 DomEvent.add(image, { |
4859 DomEvent.add(image, { load: loaded }); |
4820 load: loaded |
|
4821 }); |
|
4822 if (!image.src) |
4860 if (!image.src) |
4823 image.src = src; |
4861 image.src = src; |
4824 } |
4862 } |
4825 this.setImage(image); |
4863 this.setImage(image); |
|
4864 }, |
|
4865 |
|
4866 getCrossOrigin: function() { |
|
4867 return this._image && this._image.crossOrigin || this._crossOrigin || ''; |
|
4868 }, |
|
4869 |
|
4870 setCrossOrigin: function(crossOrigin) { |
|
4871 this._crossOrigin = crossOrigin; |
|
4872 if (this._image) |
|
4873 this._image.crossOrigin = crossOrigin; |
4826 }, |
4874 }, |
4827 |
4875 |
4828 getElement: function() { |
4876 getElement: function() { |
4829 return this._canvas || this._loaded && this._image; |
4877 return this._canvas || this._loaded && this._image; |
4830 } |
4878 } |
5107 new SegmentPoint(handleIn, this, '_handleIn'); |
5155 new SegmentPoint(handleIn, this, '_handleIn'); |
5108 new SegmentPoint(handleOut, this, '_handleOut'); |
5156 new SegmentPoint(handleOut, this, '_handleOut'); |
5109 }, |
5157 }, |
5110 |
5158 |
5111 _serialize: function(options) { |
5159 _serialize: function(options) { |
5112 return Base.serialize(this.isLinear() ? this._point |
5160 return Base.serialize(this.isStraight() ? this._point |
5113 : [this._point, this._handleIn, this._handleOut], |
5161 : [this._point, this._handleIn, this._handleOut], |
5114 options, true); |
5162 options, true); |
5115 }, |
5163 }, |
5116 |
5164 |
5117 _changed: function(point) { |
5165 _changed: function(point) { |
5158 setHandleOut: function() { |
5206 setHandleOut: function() { |
5159 var point = Point.read(arguments); |
5207 var point = Point.read(arguments); |
5160 this._handleOut.set(point.x, point.y); |
5208 this._handleOut.set(point.x, point.y); |
5161 }, |
5209 }, |
5162 |
5210 |
|
5211 hasHandles: function() { |
|
5212 return !this.isStraight(); |
|
5213 }, |
|
5214 |
|
5215 isStraight: function() { |
|
5216 return this._handleIn.isZero() && this._handleOut.isZero(); |
|
5217 }, |
|
5218 |
5163 isLinear: function() { |
5219 isLinear: function() { |
5164 return this._handleIn.isZero() && this._handleOut.isZero(); |
5220 return Segment.isLinear(this, this.getNext()); |
5165 }, |
5221 }, |
5166 |
5222 |
5167 setLinear: function(linear) { |
5223 isCollinear: function(segment) { |
5168 if (linear) { |
5224 return Segment.isCollinear(this, this.getNext(), |
5169 this._handleIn.set(0, 0); |
5225 segment, segment.getNext()); |
5170 this._handleOut.set(0, 0); |
5226 }, |
5171 } else { |
5227 |
5172 } |
5228 isColinear: '#isCollinear', |
5173 }, |
|
5174 |
|
5175 isColinear: function(segment) { |
|
5176 var next1 = this.getNext(), |
|
5177 next2 = segment.getNext(); |
|
5178 return this._handleOut.isZero() && next1._handleIn.isZero() |
|
5179 && segment._handleOut.isZero() && next2._handleIn.isZero() |
|
5180 && next1._point.subtract(this._point).isColinear( |
|
5181 next2._point.subtract(segment._point)); |
|
5182 }, |
|
5183 |
5229 |
5184 isOrthogonal: function() { |
5230 isOrthogonal: function() { |
5185 var prev = this.getPrevious(), |
5231 return Segment.isOrthogonal(this.getPrevious(), this, this.getNext()); |
5186 next = this.getNext(); |
5232 }, |
5187 return prev._handleOut.isZero() && this._handleIn.isZero() |
5233 |
5188 && this._handleOut.isZero() && next._handleIn.isZero() |
5234 isOrthogonalArc: function() { |
5189 && this._point.subtract(prev._point).isOrthogonal( |
5235 return Segment.isOrthogonalArc(this, this.getNext()); |
5190 next._point.subtract(this._point)); |
5236 }, |
5191 }, |
5237 |
5192 |
5238 isArc: '#isOrthogonalArc', |
5193 isArc: function() { |
|
5194 var next = this.getNext(), |
|
5195 handle1 = this._handleOut, |
|
5196 handle2 = next._handleIn, |
|
5197 kappa = 0.5522847498307936; |
|
5198 if (handle1.isOrthogonal(handle2)) { |
|
5199 var from = this._point, |
|
5200 to = next._point, |
|
5201 corner = new Line(from, handle1, true).intersect( |
|
5202 new Line(to, handle2, true), true); |
|
5203 return corner && Numerical.isZero(handle1.getLength() / |
|
5204 corner.subtract(from).getLength() - kappa) |
|
5205 && Numerical.isZero(handle2.getLength() / |
|
5206 corner.subtract(to).getLength() - kappa); |
|
5207 } |
|
5208 return false; |
|
5209 }, |
|
5210 |
5239 |
5211 _selectionState: 0, |
5240 _selectionState: 0, |
5212 |
5241 |
5213 isSelected: function(_point) { |
5242 isSelected: function(_point) { |
5214 var state = this._selectionState; |
5243 var state = this._selectionState; |
5359 coords[i++] = y; |
5388 coords[i++] = y; |
5360 } |
5389 } |
5361 } |
5390 } |
5362 } |
5391 } |
5363 return coords; |
5392 return coords; |
|
5393 }, |
|
5394 |
|
5395 statics: { |
|
5396 |
|
5397 isLinear: function(seg1, seg2) { |
|
5398 var l = seg2._point.subtract(seg1._point); |
|
5399 return l.isCollinear(seg1._handleOut) |
|
5400 && l.isCollinear(seg2._handleIn); |
|
5401 }, |
|
5402 |
|
5403 isCollinear: function(seg1, seg2, seg3, seg4) { |
|
5404 return seg1._handleOut.isZero() && seg2._handleIn.isZero() |
|
5405 && seg3._handleOut.isZero() && seg4._handleIn.isZero() |
|
5406 && seg2._point.subtract(seg1._point).isCollinear( |
|
5407 seg4._point.subtract(seg3._point)); |
|
5408 }, |
|
5409 |
|
5410 isOrthogonal: function(seg1, seg2, seg3) { |
|
5411 return seg1._handleOut.isZero() && seg2._handleIn.isZero() |
|
5412 && seg2._handleOut.isZero() && seg3._handleIn.isZero() |
|
5413 && seg2._point.subtract(seg1._point).isOrthogonal( |
|
5414 seg3._point.subtract(seg2._point)); |
|
5415 }, |
|
5416 |
|
5417 isOrthogonalArc: function(seg1, seg2) { |
|
5418 var handle1 = seg1._handleOut, |
|
5419 handle2 = seg2._handleIn, |
|
5420 kappa = 0.5522847498307936; |
|
5421 if (handle1.isOrthogonal(handle2)) { |
|
5422 var pt1 = seg1._point, |
|
5423 pt2 = seg2._point, |
|
5424 corner = new Line(pt1, handle1, true).intersect( |
|
5425 new Line(pt2, handle2, true), true); |
|
5426 return corner && Numerical.isZero(handle1.getLength() / |
|
5427 corner.subtract(pt1).getLength() - kappa) |
|
5428 && Numerical.isZero(handle2.getLength() / |
|
5429 corner.subtract(pt2).getLength() - kappa); |
|
5430 } |
|
5431 return false; |
|
5432 }, |
5364 } |
5433 } |
5365 }); |
5434 }); |
5366 |
5435 |
5367 var SegmentPoint = Point.extend({ |
5436 var SegmentPoint = Point.extend({ |
5368 initialize: function SegmentPoint(point, owner, key) { |
5437 initialize: function SegmentPoint(point, owner, key) { |
5584 |
5653 |
5585 getPartLength: function(from, to) { |
5654 getPartLength: function(from, to) { |
5586 return Curve.getLength(this.getValues(), from, to); |
5655 return Curve.getLength(this.getValues(), from, to); |
5587 }, |
5656 }, |
5588 |
5657 |
|
5658 hasHandles: function() { |
|
5659 return !this._segment1._handleOut.isZero() |
|
5660 || !this._segment2._handleIn.isZero(); |
|
5661 }, |
|
5662 |
5589 isLinear: function() { |
5663 isLinear: function() { |
5590 return this._segment1._handleOut.isZero() |
5664 return Segment.isLinear(this._segment1, this._segment2); |
5591 && this._segment2._handleIn.isZero(); |
5665 }, |
|
5666 |
|
5667 isCollinear: function(curve) { |
|
5668 return Ssegment.isCollinear(this._segment1, this._segment2, |
|
5669 curve._segment1, curve._segment2); |
|
5670 }, |
|
5671 |
|
5672 isOrthogonalArc: function() { |
|
5673 return Segment.isOrthogonalArc(this._segment1, this._segment2); |
5592 }, |
5674 }, |
5593 |
5675 |
5594 getIntersections: function(curve) { |
5676 getIntersections: function(curve) { |
5595 return Curve.filterIntersections(Curve.getIntersections( |
5677 return Curve.filterIntersections(Curve.getIntersections( |
5596 this.getValues(), curve.getValues(), this, curve, [])); |
5678 this.getValues(), curve.getValues(), this, curve, [])); |
5694 p2._x, p2._y |
5776 p2._x, p2._y |
5695 ]; |
5777 ]; |
5696 if (matrix) |
5778 if (matrix) |
5697 matrix._transformCoordinates(values, values, 4); |
5779 matrix._transformCoordinates(values, values, 4); |
5698 return values; |
5780 return values; |
5699 }, |
|
5700 |
|
5701 evaluate: function(v, t, type) { |
|
5702 var p1x = v[0], p1y = v[1], |
|
5703 c1x = v[2], c1y = v[3], |
|
5704 c2x = v[4], c2y = v[5], |
|
5705 p2x = v[6], p2y = v[7], |
|
5706 tolerance = 0.000001, |
|
5707 x, y; |
|
5708 |
|
5709 if (type === 0 && (t < tolerance || t > 1 - tolerance)) { |
|
5710 var isZero = t < tolerance; |
|
5711 x = isZero ? p1x : p2x; |
|
5712 y = isZero ? p1y : p2y; |
|
5713 } else { |
|
5714 var cx = 3 * (c1x - p1x), |
|
5715 bx = 3 * (c2x - c1x) - cx, |
|
5716 ax = p2x - p1x - cx - bx, |
|
5717 |
|
5718 cy = 3 * (c1y - p1y), |
|
5719 by = 3 * (c2y - c1y) - cy, |
|
5720 ay = p2y - p1y - cy - by; |
|
5721 if (type === 0) { |
|
5722 x = ((ax * t + bx) * t + cx) * t + p1x; |
|
5723 y = ((ay * t + by) * t + cy) * t + p1y; |
|
5724 } else { |
|
5725 if (t < tolerance && c1x === p1x && c1y === p1y |
|
5726 || t > 1 - tolerance && c2x === p2x && c2y === p2y) { |
|
5727 x = c2x - c1x; |
|
5728 y = c2y - c1y; |
|
5729 } else if (t < tolerance) { |
|
5730 x = cx; |
|
5731 y = cy; |
|
5732 } else if (t > 1 - tolerance) { |
|
5733 x = 3 * (p2x - c2x); |
|
5734 y = 3 * (p2y - c2y); |
|
5735 } else { |
|
5736 x = (3 * ax * t + 2 * bx) * t + cx; |
|
5737 y = (3 * ay * t + 2 * by) * t + cy; |
|
5738 } |
|
5739 if (type === 3) { |
|
5740 var x2 = 6 * ax * t + 2 * bx, |
|
5741 y2 = 6 * ay * t + 2 * by; |
|
5742 return (x * y2 - y * x2) / Math.pow(x * x + y * y, 3 / 2); |
|
5743 } |
|
5744 } |
|
5745 } |
|
5746 return type === 2 ? new Point(y, -x) : new Point(x, y); |
|
5747 }, |
5781 }, |
5748 |
5782 |
5749 subdivide: function(v, t) { |
5783 subdivide: function(v, t) { |
5750 var p1x = v[0], p1y = v[1], |
5784 var p1x = v[0], p1y = v[1], |
5751 c1x = v[2], c1y = v[3], |
5785 c1x = v[2], c1y = v[3], |
5771 c1 = v[coord + 2], |
5805 c1 = v[coord + 2], |
5772 c2 = v[coord + 4], |
5806 c2 = v[coord + 4], |
5773 p2 = v[coord + 6], |
5807 p2 = v[coord + 6], |
5774 c = 3 * (c1 - p1), |
5808 c = 3 * (c1 - p1), |
5775 b = 3 * (c2 - c1) - c, |
5809 b = 3 * (c2 - c1) - c, |
5776 a = p2 - p1 - c - b, |
5810 a = p2 - p1 - c - b; |
5777 isZero = Numerical.isZero; |
|
5778 if (isZero(a) && isZero(b)) |
|
5779 a = b = 0; |
|
5780 return Numerical.solveCubic(a, b, c, p1 - val, roots, min, max); |
5811 return Numerical.solveCubic(a, b, c, p1 - val, roots, min, max); |
5781 }, |
5812 }, |
5782 |
5813 |
5783 getParameterOf: function(v, x, y) { |
5814 getParameterOf: function(v, x, y) { |
5784 var tolerance = 0.000001; |
5815 var tolerance = 0.000001; |
5789 var txs = [], |
5820 var txs = [], |
5790 tys = [], |
5821 tys = [], |
5791 sx = Curve.solveCubic(v, 0, x, txs, 0, 1), |
5822 sx = Curve.solveCubic(v, 0, x, txs, 0, 1), |
5792 sy = Curve.solveCubic(v, 1, y, tys, 0, 1), |
5823 sy = Curve.solveCubic(v, 1, y, tys, 0, 1), |
5793 tx, ty; |
5824 tx, ty; |
5794 for (var cx = 0; sx == -1 || cx < sx;) { |
5825 for (var cx = 0; sx === -1 || cx < sx;) { |
5795 if (sx == -1 || (tx = txs[cx++]) >= 0 && tx <= 1) { |
5826 if (sx === -1 || (tx = txs[cx++]) > 0 && tx < 1) { |
5796 for (var cy = 0; sy == -1 || cy < sy;) { |
5827 for (var cy = 0; sy === -1 || cy < sy;) { |
5797 if (sy == -1 || (ty = tys[cy++]) >= 0 && ty <= 1) { |
5828 if (sy === -1 || (ty = tys[cy++]) > 0 && ty < 1) { |
5798 if (sx == -1) tx = ty; |
5829 if (sx === -1) { |
5799 else if (sy == -1) ty = tx; |
5830 tx = ty; |
|
5831 } else if (sy === -1) { |
|
5832 ty = tx; |
|
5833 } |
5800 if (Math.abs(tx - ty) < tolerance) |
5834 if (Math.abs(tx - ty) < tolerance) |
5801 return (tx + ty) * 0.5; |
5835 return (tx + ty) * 0.5; |
5802 } |
5836 } |
5803 } |
5837 } |
5804 if (sx == -1) |
5838 if (sx === -1) |
5805 break; |
5839 break; |
5806 } |
5840 } |
5807 } |
5841 } |
5808 return null; |
5842 return null; |
5809 }, |
5843 }, |
5814 if (to < 1) |
5848 if (to < 1) |
5815 v = Curve.subdivide(v, (to - from) / (1 - from))[0]; |
5849 v = Curve.subdivide(v, (to - from) / (1 - from))[0]; |
5816 return v; |
5850 return v; |
5817 }, |
5851 }, |
5818 |
5852 |
|
5853 hasHandles: function(v) { |
|
5854 var isZero = Numerical.isZero; |
|
5855 return !(isZero(v[0] - v[2]) && isZero(v[1] - v[3]) |
|
5856 && isZero(v[4] - v[6]) && isZero(v[5] - v[7])); |
|
5857 }, |
|
5858 |
5819 isLinear: function(v) { |
5859 isLinear: function(v) { |
5820 var isZero = Numerical.isZero; |
5860 var p1x = v[0], p1y = v[1], |
5821 return isZero(v[0] - v[2]) && isZero(v[1] - v[3]) |
5861 p2x = v[6], p2y = v[7], |
5822 && isZero(v[4] - v[6]) && isZero(v[5] - v[7]); |
5862 l = new Point(p2x - p1x, p2y - p1y); |
|
5863 return l.isCollinear(new Point(v[2] - p1x, v[3] - p1y)) |
|
5864 && l.isCollinear(new Point(v[4] - p2x, v[5] - p2y)); |
5823 }, |
5865 }, |
5824 |
5866 |
5825 isFlatEnough: function(v, tolerance) { |
5867 isFlatEnough: function(v, tolerance) { |
5826 var p1x = v[0], p1y = v[1], |
5868 var p1x = v[0], p1y = v[1], |
5827 c1x = v[2], c1y = v[3], |
5869 c1x = v[2], c1y = v[3], |
5904 return bounds.clone(); |
5947 return bounds.clone(); |
5905 }; |
5948 }; |
5906 }, |
5949 }, |
5907 { |
5950 { |
5908 |
5951 |
5909 }), Base.each(['getPoint', 'getTangent', 'getNormal', 'getCurvature'], |
5952 }), { |
5910 function(name, index) { |
|
5911 this[name + 'At'] = function(offset, isParameter) { |
|
5912 var values = this.getValues(); |
|
5913 return Curve.evaluate(values, isParameter |
|
5914 ? offset : Curve.getParameterAt(values, offset, 0), index); |
|
5915 }; |
|
5916 this[name] = function(parameter) { |
|
5917 return Curve.evaluate(this.getValues(), parameter, index); |
|
5918 }; |
|
5919 }, |
|
5920 { |
|
5921 beans: false, |
5953 beans: false, |
5922 |
5954 |
5923 getParameterAt: function(offset, start) { |
5955 getParameterAt: function(offset, start) { |
5924 return Curve.getParameterAt(this.getValues(), offset, start); |
5956 return Curve.getParameterAt(this.getValues(), offset, start); |
5925 }, |
5957 }, |
5928 var point = Point.read(arguments); |
5960 var point = Point.read(arguments); |
5929 return Curve.getParameterOf(this.getValues(), point.x, point.y); |
5961 return Curve.getParameterOf(this.getValues(), point.x, point.y); |
5930 }, |
5962 }, |
5931 |
5963 |
5932 getLocationAt: function(offset, isParameter) { |
5964 getLocationAt: function(offset, isParameter) { |
5933 if (!isParameter) |
5965 var t = isParameter ? offset : this.getParameterAt(offset); |
5934 offset = this.getParameterAt(offset); |
5966 return t != null && t >= 0 && t <= 1 |
5935 return offset >= 0 && offset <= 1 && new CurveLocation(this, offset); |
5967 ? new CurveLocation(this, t) |
|
5968 : null; |
5936 }, |
5969 }, |
5937 |
5970 |
5938 getLocationOf: function() { |
5971 getLocationOf: function() { |
5939 return this.getLocationAt(this.getParameterOf(Point.read(arguments)), |
5972 return this.getLocationAt(this.getParameterOf(Point.read(arguments)), |
5940 true); |
5973 true); |
5970 var step = 1 / (count * 2); |
6002 var step = 1 / (count * 2); |
5971 while (step > 0.000001) { |
6003 while (step > 0.000001) { |
5972 if (!refine(minT - step) && !refine(minT + step)) |
6004 if (!refine(minT - step) && !refine(minT + step)) |
5973 step /= 2; |
6005 step /= 2; |
5974 } |
6006 } |
5975 var pt = Curve.evaluate(values, minT, 0); |
6007 var pt = Curve.getPoint(values, minT); |
5976 return new CurveLocation(this, minT, pt, null, null, null, |
6008 return new CurveLocation(this, minT, pt, null, null, null, |
5977 point.getDistance(pt)); |
6009 point.getDistance(pt)); |
5978 }, |
6010 }, |
5979 |
6011 |
5980 getNearestPoint: function() { |
6012 getNearestPoint: function() { |
5981 return this.getNearestLocation.apply(this, arguments).getPoint(); |
6013 return this.getNearestLocation.apply(this, arguments).getPoint(); |
5982 } |
6014 } |
5983 |
6015 |
5984 }), |
6016 }, |
|
6017 new function() { |
|
6018 var methods = ['getPoint', 'getTangent', 'getNormal', 'getWeightedTangent', |
|
6019 'getWeightedNormal', 'getCurvature']; |
|
6020 return Base.each(methods, |
|
6021 function(name) { |
|
6022 this[name + 'At'] = function(offset, isParameter) { |
|
6023 var values = this.getValues(); |
|
6024 return Curve[name](values, isParameter ? offset |
|
6025 : Curve.getParameterAt(values, offset, 0)); |
|
6026 }; |
|
6027 }, { |
|
6028 statics: { |
|
6029 evaluateMethods: methods |
|
6030 } |
|
6031 }) |
|
6032 }, |
5985 new function() { |
6033 new function() { |
5986 |
6034 |
5987 function getLengthIntegrand(v) { |
6035 function getLengthIntegrand(v) { |
5988 var p1x = v[0], p1y = v[1], |
6036 var p1x = v[0], p1y = v[1], |
5989 c1x = v[2], c1y = v[3], |
6037 c1x = v[2], c1y = v[3], |
6005 }; |
6053 }; |
6006 } |
6054 } |
6007 |
6055 |
6008 function getIterations(a, b) { |
6056 function getIterations(a, b) { |
6009 return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); |
6057 return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); |
|
6058 } |
|
6059 |
|
6060 function evaluate(v, t, type, normalized) { |
|
6061 if (t == null || t < 0 || t > 1) |
|
6062 return null; |
|
6063 var p1x = v[0], p1y = v[1], |
|
6064 c1x = v[2], c1y = v[3], |
|
6065 c2x = v[4], c2y = v[5], |
|
6066 p2x = v[6], p2y = v[7], |
|
6067 tolerance = 0.000001, |
|
6068 x, y; |
|
6069 |
|
6070 if (type === 0 && (t < tolerance || t > 1 - tolerance)) { |
|
6071 var isZero = t < tolerance; |
|
6072 x = isZero ? p1x : p2x; |
|
6073 y = isZero ? p1y : p2y; |
|
6074 } else { |
|
6075 var cx = 3 * (c1x - p1x), |
|
6076 bx = 3 * (c2x - c1x) - cx, |
|
6077 ax = p2x - p1x - cx - bx, |
|
6078 |
|
6079 cy = 3 * (c1y - p1y), |
|
6080 by = 3 * (c2y - c1y) - cy, |
|
6081 ay = p2y - p1y - cy - by; |
|
6082 if (type === 0) { |
|
6083 x = ((ax * t + bx) * t + cx) * t + p1x; |
|
6084 y = ((ay * t + by) * t + cy) * t + p1y; |
|
6085 } else { |
|
6086 if (t < tolerance) { |
|
6087 x = cx; |
|
6088 y = cy; |
|
6089 } else if (t > 1 - tolerance) { |
|
6090 x = 3 * (p2x - c2x); |
|
6091 y = 3 * (p2y - c2y); |
|
6092 } else { |
|
6093 x = (3 * ax * t + 2 * bx) * t + cx; |
|
6094 y = (3 * ay * t + 2 * by) * t + cy; |
|
6095 } |
|
6096 if (normalized) { |
|
6097 if (x === 0 && y === 0 |
|
6098 && (t < tolerance || t > 1 - tolerance)) { |
|
6099 x = c2x - c1x; |
|
6100 y = c2y - c1y; |
|
6101 } |
|
6102 var len = Math.sqrt(x * x + y * y); |
|
6103 x /= len; |
|
6104 y /= len; |
|
6105 } |
|
6106 if (type === 3) { |
|
6107 var x2 = 6 * ax * t + 2 * bx, |
|
6108 y2 = 6 * ay * t + 2 * by, |
|
6109 d = Math.pow(x * x + y * y, 3 / 2); |
|
6110 x = d !== 0 ? (x * y2 - y * x2) / d : 0; |
|
6111 y = 0; |
|
6112 } |
|
6113 } |
|
6114 } |
|
6115 return type === 2 ? new Point(y, -x) : new Point(x, y); |
6010 } |
6116 } |
6011 |
6117 |
6012 return { |
6118 return { |
6013 statics: true, |
6119 statics: true, |
6014 |
6120 |
6032 getParameterAt: function(v, offset, start) { |
6138 getParameterAt: function(v, offset, start) { |
6033 if (start === undefined) |
6139 if (start === undefined) |
6034 start = offset < 0 ? 1 : 0 |
6140 start = offset < 0 ? 1 : 0 |
6035 if (offset === 0) |
6141 if (offset === 0) |
6036 return start; |
6142 return start; |
6037 var forward = offset > 0, |
6143 var tolerance = 0.000001, |
|
6144 abs = Math.abs, |
|
6145 forward = offset > 0, |
6038 a = forward ? start : 0, |
6146 a = forward ? start : 0, |
6039 b = forward ? 1 : start, |
6147 b = forward ? 1 : start, |
6040 ds = getLengthIntegrand(v), |
6148 ds = getLengthIntegrand(v), |
6041 rangeLength = Numerical.integrate(ds, a, b, |
6149 rangeLength = Numerical.integrate(ds, a, b, |
6042 getIterations(a, b)); |
6150 getIterations(a, b)); |
6043 if (Math.abs(offset) >= rangeLength) |
6151 if (abs(offset - rangeLength) < tolerance) { |
6044 return forward ? b : a; |
6152 return forward ? b : a; |
|
6153 } else if (abs(offset) > rangeLength) { |
|
6154 return null; |
|
6155 } |
6045 var guess = offset / rangeLength, |
6156 var guess = offset / rangeLength, |
6046 length = 0; |
6157 length = 0; |
6047 function f(t) { |
6158 function f(t) { |
6048 length += Numerical.integrate(ds, start, t, |
6159 length += Numerical.integrate(ds, start, t, |
6049 getIterations(start, t)); |
6160 getIterations(start, t)); |
6050 start = t; |
6161 start = t; |
6051 return length - offset; |
6162 return length - offset; |
6052 } |
6163 } |
6053 return Numerical.findRoot(f, ds, start + guess, a, b, 16, |
6164 return Numerical.findRoot(f, ds, start + guess, a, b, 16, |
6054 0.000001); |
6165 tolerance); |
|
6166 }, |
|
6167 |
|
6168 getPoint: function(v, t) { |
|
6169 return evaluate(v, t, 0, false); |
|
6170 }, |
|
6171 |
|
6172 getTangent: function(v, t) { |
|
6173 return evaluate(v, t, 1, true); |
|
6174 }, |
|
6175 |
|
6176 getWeightedTangent: function(v, t) { |
|
6177 return evaluate(v, t, 1, false); |
|
6178 }, |
|
6179 |
|
6180 getNormal: function(v, t) { |
|
6181 return evaluate(v, t, 2, true); |
|
6182 }, |
|
6183 |
|
6184 getWeightedNormal: function(v, t) { |
|
6185 return evaluate(v, t, 2, false); |
|
6186 }, |
|
6187 |
|
6188 getCurvature: function(v, t) { |
|
6189 return evaluate(v, t, 3, false).x; |
6055 } |
6190 } |
6056 }; |
6191 }; |
6057 }, new function() { |
6192 }, new function() { |
6058 function addLocation(locations, include, curve1, t1, point1, curve2, t2, |
6193 function addLocation(locations, include, curve1, t1, point1, curve2, t2, |
6059 point2) { |
6194 point2) { |
6077 dp0 = getSignedDistance(q0x, q0y, q3x, q3y, v1[0], v1[1]), |
6212 dp0 = getSignedDistance(q0x, q0y, q3x, q3y, v1[0], v1[1]), |
6078 dp1 = getSignedDistance(q0x, q0y, q3x, q3y, v1[2], v1[3]), |
6213 dp1 = getSignedDistance(q0x, q0y, q3x, q3y, v1[2], v1[3]), |
6079 dp2 = getSignedDistance(q0x, q0y, q3x, q3y, v1[4], v1[5]), |
6214 dp2 = getSignedDistance(q0x, q0y, q3x, q3y, v1[4], v1[5]), |
6080 dp3 = getSignedDistance(q0x, q0y, q3x, q3y, v1[6], v1[7]), |
6215 dp3 = getSignedDistance(q0x, q0y, q3x, q3y, v1[6], v1[7]), |
6081 tMinNew, tMaxNew, tDiff; |
6216 tMinNew, tMaxNew, tDiff; |
6082 if (q0x === q3x && uMax - uMin <= tolerance && recursion > 3) { |
6217 if (q0x === q3x && uMax - uMin < tolerance && recursion > 3) { |
6083 tMaxNew = tMinNew = (tMax + tMin) / 2; |
6218 tMaxNew = tMinNew = (tMax + tMin) / 2; |
6084 tDiff = 0; |
6219 tDiff = 0; |
6085 } else { |
6220 } else { |
6086 var hull = getConvexHull(dp0, dp1, dp2, dp3), |
6221 var hull = getConvexHull(dp0, dp1, dp2, dp3), |
6087 top = hull[0], |
6222 top = hull[0], |
6121 } else if (Math.max(uMax - uMin, tMaxNew - tMinNew) < tolerance) { |
6256 } else if (Math.max(uMax - uMin, tMaxNew - tMinNew) < tolerance) { |
6122 var t1 = tMinNew + (tMaxNew - tMinNew) / 2, |
6257 var t1 = tMinNew + (tMaxNew - tMinNew) / 2, |
6123 t2 = uMin + (uMax - uMin) / 2; |
6258 t2 = uMin + (uMax - uMin) / 2; |
6124 if (reverse) { |
6259 if (reverse) { |
6125 addLocation(locations, include, |
6260 addLocation(locations, include, |
6126 curve2, t2, Curve.evaluate(v2, t2, 0), |
6261 curve2, t2, Curve.getPoint(v2, t2), |
6127 curve1, t1, Curve.evaluate(v1, t1, 0)); |
6262 curve1, t1, Curve.getPoint(v1, t1)); |
6128 } else { |
6263 } else { |
6129 addLocation(locations, include, |
6264 addLocation(locations, include, |
6130 curve1, t1, Curve.evaluate(v1, t1, 0), |
6265 curve1, t1, Curve.getPoint(v1, t1), |
6131 curve2, t2, Curve.evaluate(v2, t2, 0)); |
6266 curve2, t2, Curve.getPoint(v2, t2)); |
6132 } |
6267 } |
6133 } else if (tDiff > 0) { |
6268 } else if (tDiff > 0) { |
6134 addCurveIntersections(v2, v1, curve2, curve1, locations, include, |
6269 addCurveIntersections(v2, v1, curve2, curve1, locations, include, |
6135 uMin, uMax, tMinNew, tMaxNew, tDiff, !reverse, ++recursion); |
6270 uMin, uMax, tMinNew, tMaxNew, tDiff, !reverse, ++recursion); |
6136 } |
6271 } |
6217 } |
6352 } |
6218 var roots = [], |
6353 var roots = [], |
6219 count = Curve.solveCubic(rvc, 1, 0, roots, 0, 1); |
6354 count = Curve.solveCubic(rvc, 1, 0, roots, 0, 1); |
6220 for (var i = 0; i < count; i++) { |
6355 for (var i = 0; i < count; i++) { |
6221 var tc = roots[i], |
6356 var tc = roots[i], |
6222 x = Curve.evaluate(rvc, tc, 0).x; |
6357 x = Curve.getPoint(rvc, tc).x; |
6223 if (x >= 0 && x <= rlx2) { |
6358 if (x >= 0 && x <= rlx2) { |
6224 var tl = Curve.getParameterOf(rvl, x, 0), |
6359 var tl = Curve.getParameterOf(rvl, x, 0), |
6225 t1 = flip ? tl : tc, |
6360 t1 = flip ? tl : tc, |
6226 t2 = flip ? tc : tl; |
6361 t2 = flip ? tc : tl; |
6227 addLocation(locations, include, |
6362 addLocation(locations, include, |
6228 curve1, t1, Curve.evaluate(v1, t1, 0), |
6363 curve1, t1, Curve.getPoint(v1, t1), |
6229 curve2, t2, Curve.evaluate(v2, t2, 0)); |
6364 curve2, t2, Curve.getPoint(v2, t2)); |
6230 } |
6365 } |
6231 } |
6366 } |
6232 } |
6367 } |
6233 |
6368 |
6234 function addLineIntersection(v1, v2, curve1, curve2, locations, include) { |
6369 function addLineIntersection(v1, v2, curve1, curve2, locations, include) { |
6320 _class: 'CurveLocation', |
6455 _class: 'CurveLocation', |
6321 beans: true, |
6456 beans: true, |
6322 |
6457 |
6323 initialize: function CurveLocation(curve, parameter, point, _curve2, |
6458 initialize: function CurveLocation(curve, parameter, point, _curve2, |
6324 _parameter2, _point2, _distance) { |
6459 _parameter2, _point2, _distance) { |
6325 this._id = CurveLocation._id = (CurveLocation._id || 0) + 1; |
6460 this._id = UID.get(CurveLocation); |
|
6461 var path = curve._path; |
|
6462 this._version = path ? path._version : 0; |
6326 this._curve = curve; |
6463 this._curve = curve; |
6327 this._segment1 = curve._segment1; |
|
6328 this._segment2 = curve._segment2; |
|
6329 this._parameter = parameter; |
6464 this._parameter = parameter; |
6330 this._point = point; |
6465 this._point = point || curve.getPointAt(parameter, true); |
6331 this._curve2 = _curve2; |
6466 this._curve2 = _curve2; |
6332 this._parameter2 = _parameter2; |
6467 this._parameter2 = _parameter2; |
6333 this._point2 = _point2; |
6468 this._point2 = _point2; |
6334 this._distance = _distance; |
6469 this._distance = _distance; |
|
6470 this._segment1 = curve._segment1; |
|
6471 this._segment2 = curve._segment2; |
6335 }, |
6472 }, |
6336 |
6473 |
6337 getSegment: function(_preferFirst) { |
6474 getSegment: function(_preferFirst) { |
6338 if (!this._segment) { |
6475 if (!this._segment) { |
6339 var curve = this.getCurve(), |
6476 var curve = this.getCurve(), |
6352 } |
6489 } |
6353 } |
6490 } |
6354 return this._segment; |
6491 return this._segment; |
6355 }, |
6492 }, |
6356 |
6493 |
6357 getCurve: function(_uncached) { |
6494 getCurve: function() { |
6358 if (!this._curve || _uncached) { |
6495 var curve = this._curve, |
6359 this._curve = this._segment1.getCurve(); |
6496 path = curve && curve._path; |
6360 if (this._curve.getParameterOf(this._point) == null) |
6497 if (path && path._version !== this._version) { |
6361 this._curve = this._segment2.getPrevious().getCurve(); |
6498 curve = null; |
6362 } |
6499 this._parameter = null; |
6363 return this._curve; |
6500 } |
6364 }, |
6501 if (!curve) { |
6365 |
6502 curve = this._segment1.getCurve(); |
6366 getIntersection: function() { |
6503 if (curve.getParameterOf(this._point) == null) |
6367 var intersection = this._intersection; |
6504 curve = this._segment2.getPrevious().getCurve(); |
6368 if (!intersection && this._curve2) { |
6505 this._curve = curve; |
6369 var param = this._parameter2; |
6506 path = curve._path; |
6370 this._intersection = intersection = new CurveLocation( |
6507 this._version = path ? path._version : 0; |
6371 this._curve2, param, this._point2 || this._point, this); |
6508 } |
6372 intersection._intersection = this; |
6509 return curve; |
6373 } |
|
6374 return intersection; |
|
6375 }, |
6510 }, |
6376 |
6511 |
6377 getPath: function() { |
6512 getPath: function() { |
6378 var curve = this.getCurve(); |
6513 var curve = this.getCurve(); |
6379 return curve && curve._path; |
6514 return curve && curve._path; |
6380 }, |
6515 }, |
6381 |
6516 |
6382 getIndex: function() { |
6517 getIndex: function() { |
6383 var curve = this.getCurve(); |
6518 var curve = this.getCurve(); |
6384 return curve && curve.getIndex(); |
6519 return curve && curve.getIndex(); |
|
6520 }, |
|
6521 |
|
6522 getParameter: function() { |
|
6523 var curve = this.getCurve(), |
|
6524 parameter = this._parameter; |
|
6525 return curve && parameter == null |
|
6526 ? this._parameter = curve.getParameterOf(this._point) |
|
6527 : parameter; |
|
6528 }, |
|
6529 |
|
6530 getPoint: function() { |
|
6531 return this._point; |
6385 }, |
6532 }, |
6386 |
6533 |
6387 getOffset: function() { |
6534 getOffset: function() { |
6388 var path = this.getPath(); |
6535 var path = this.getPath(); |
6389 return path ? path._getOffset(this) : this.getCurveOffset(); |
6536 return path ? path._getOffset(this) : this.getCurveOffset(); |
6393 var curve = this.getCurve(), |
6540 var curve = this.getCurve(), |
6394 parameter = this.getParameter(); |
6541 parameter = this.getParameter(); |
6395 return parameter != null && curve && curve.getPartLength(0, parameter); |
6542 return parameter != null && curve && curve.getPartLength(0, parameter); |
6396 }, |
6543 }, |
6397 |
6544 |
6398 getParameter: function(_uncached) { |
6545 getIntersection: function() { |
6399 if ((this._parameter == null || _uncached) && this._point) { |
6546 var intersection = this._intersection; |
6400 var curve = this.getCurve(_uncached); |
6547 if (!intersection && this._curve2) { |
6401 this._parameter = curve && curve.getParameterOf(this._point); |
6548 this._intersection = intersection = new CurveLocation(this._curve2, |
6402 } |
6549 this._parameter2, this._point2 || this._point, this); |
6403 return this._parameter; |
6550 intersection._intersection = this; |
6404 }, |
6551 } |
6405 |
6552 return intersection; |
6406 getPoint: function(_uncached) { |
|
6407 if ((!this._point || _uncached) && this._parameter != null) { |
|
6408 var curve = this.getCurve(_uncached); |
|
6409 this._point = curve && curve.getPointAt(this._parameter, true); |
|
6410 } |
|
6411 return this._point; |
|
6412 }, |
6553 }, |
6413 |
6554 |
6414 getDistance: function() { |
6555 getDistance: function() { |
6415 return this._distance; |
6556 return this._distance; |
6416 }, |
6557 }, |
6417 |
6558 |
6418 divide: function() { |
6559 divide: function() { |
6419 var curve = this.getCurve(true); |
6560 var curve = this.getCurve(); |
6420 return curve && curve.divide(this.getParameter(true), true); |
6561 return curve && curve.divide(this.getParameter(), true); |
6421 }, |
6562 }, |
6422 |
6563 |
6423 split: function() { |
6564 split: function() { |
6424 var curve = this.getCurve(true); |
6565 var curve = this.getCurve(); |
6425 return curve && curve.split(this.getParameter(true), true); |
6566 return curve && curve.split(this.getParameter(), true); |
6426 }, |
6567 }, |
6427 |
6568 |
6428 equals: function(loc) { |
6569 equals: function(loc) { |
6429 var abs = Math.abs, |
6570 var abs = Math.abs, |
6430 tolerance = 0.000001; |
6571 tolerance = 0.000001; |
6431 return this === loc |
6572 return this === loc |
6432 || loc |
6573 || loc instanceof CurveLocation |
6433 && this._curve === loc._curve |
6574 && this.getCurve() === loc.getCurve() |
|
6575 && abs(this.getParameter() - loc.getParameter()) < tolerance |
6434 && this._curve2 === loc._curve2 |
6576 && this._curve2 === loc._curve2 |
6435 && abs(this._parameter - loc._parameter) <= tolerance |
6577 && abs(this._parameter2 - loc._parameter2) < tolerance |
6436 && abs(this._parameter2 - loc._parameter2) <= tolerance |
|
6437 || false; |
6578 || false; |
6438 }, |
6579 }, |
6439 |
6580 |
6440 toString: function() { |
6581 toString: function() { |
6441 var parts = [], |
6582 var parts = [], |
6451 parts.push('parameter: ' + f.number(parameter)); |
6592 parts.push('parameter: ' + f.number(parameter)); |
6452 if (this._distance != null) |
6593 if (this._distance != null) |
6453 parts.push('distance: ' + f.number(this._distance)); |
6594 parts.push('distance: ' + f.number(this._distance)); |
6454 return '{ ' + parts.join(', ') + ' }'; |
6595 return '{ ' + parts.join(', ') + ' }'; |
6455 } |
6596 } |
6456 }, Base.each(['getTangent', 'getNormal', 'getCurvature'], function(name) { |
6597 }, Base.each(Curve.evaluateMethods, function(name) { |
6457 var get = name + 'At'; |
6598 if (name !== 'getPoint') { |
6458 this[name] = function() { |
6599 var get = name + 'At'; |
6459 var parameter = this.getParameter(), |
6600 this[name] = function() { |
6460 curve = this.getCurve(); |
6601 var parameter = this.getParameter(), |
6461 return parameter != null && curve && curve[get](parameter, true); |
6602 curve = this.getCurve(); |
6462 }; |
6603 return parameter != null && curve && curve[get](parameter, true); |
|
6604 }; |
|
6605 } |
6463 }, {})); |
6606 }, {})); |
6464 |
6607 |
6465 var PathItem = Item.extend({ |
6608 var PathItem = Item.extend({ |
6466 _class: 'PathItem', |
6609 _class: 'PathItem', |
6467 |
6610 |
6697 if (flags & 8) { |
6839 if (flags & 8) { |
6698 var parent = this._parent; |
6840 var parent = this._parent; |
6699 if (parent) |
6841 if (parent) |
6700 parent._currentPath = undefined; |
6842 parent._currentPath = undefined; |
6701 this._length = this._clockwise = undefined; |
6843 this._length = this._clockwise = undefined; |
6702 if (this._curves && !(flags & 16)) { |
6844 if (flags & 16) { |
6703 for (var i = 0, l = this._curves.length; i < l; i++) |
6845 this._version++; |
|
6846 } else if (this._curves) { |
|
6847 for (var i = 0, l = this._curves.length; i < l; i++) |
6704 this._curves[i]._changed(); |
6848 this._curves[i]._changed(); |
6705 } |
6849 } |
6706 this._monoCurves = undefined; |
6850 this._monoCurves = undefined; |
6707 } else if (flags & 32) { |
6851 } else if (flags & 32) { |
6708 this._bounds = undefined; |
6852 this._bounds = undefined; |
6831 |
6975 |
6832 isEmpty: function() { |
6976 isEmpty: function() { |
6833 return this._segments.length === 0; |
6977 return this._segments.length === 0; |
6834 }, |
6978 }, |
6835 |
6979 |
6836 isPolygon: function() { |
6980 isLinear: function() { |
6837 for (var i = 0, l = this._segments.length; i < l; i++) { |
6981 var segments = this._segments; |
6838 if (!this._segments[i].isLinear()) |
6982 for (var i = 0, l = segments.length; i < l; i++) { |
|
6983 if (!segments[i].isLinear()) |
6839 return false; |
6984 return false; |
6840 } |
6985 } |
6841 return true; |
6986 return true; |
|
6987 }, |
|
6988 |
|
6989 hasHandles: function() { |
|
6990 var segments = this._segments; |
|
6991 for (var i = 0, l = segments.length; i < l; i++) { |
|
6992 if (segments[i].hasHandles()) |
|
6993 return true; |
|
6994 } |
|
6995 return false; |
6842 }, |
6996 }, |
6843 |
6997 |
6844 _transformContent: function(matrix) { |
6998 _transformContent: function(matrix) { |
6845 var coords = new Array(6); |
6999 var coords = new Array(6); |
6846 for (var i = 0, l = this._segments.length; i < l; i++) |
7000 for (var i = 0, l = this._segments.length; i < l; i++) |
7173 type, |
7327 type, |
7174 size, |
7328 size, |
7175 radius, |
7329 radius, |
7176 topCenter; |
7330 topCenter; |
7177 |
7331 |
7178 function isColinear(i, j) { |
7332 function isCollinear(i, j) { |
7179 return segments[i].isColinear(segments[j]); |
7333 return segments[i].isCollinear(segments[j]); |
7180 } |
7334 } |
7181 |
7335 |
7182 function isOrthogonal(i) { |
7336 function isOrthogonal(i) { |
7183 return segments[i].isOrthogonal(); |
7337 return segments[i].isOrthogonal(); |
7184 } |
7338 } |
7185 |
7339 |
7186 function isArc(i) { |
7340 function isArc(i) { |
7187 return segments[i].isArc(); |
7341 return segments[i].isOrthogonalArc(); |
7188 } |
7342 } |
7189 |
7343 |
7190 function getDistance(i, j) { |
7344 function getDistance(i, j) { |
7191 return segments[i]._point.getDistance(segments[j]._point); |
7345 return segments[i]._point.getDistance(segments[j]._point); |
7192 } |
7346 } |
7193 |
7347 |
7194 if (this.isPolygon() && segments.length === 4 |
7348 if (!this.hasHandles() && segments.length === 4 |
7195 && isColinear(0, 2) && isColinear(1, 3) && isOrthogonal(1)) { |
7349 && isCollinear(0, 2) && isCollinear(1, 3) && isOrthogonal(1)) { |
7196 type = Shape.Rectangle; |
7350 type = Shape.Rectangle; |
7197 size = new Size(getDistance(0, 3), getDistance(0, 1)); |
7351 size = new Size(getDistance(0, 3), getDistance(0, 1)); |
7198 topCenter = segments[1]._point.add(segments[2]._point).divide(2); |
7352 topCenter = segments[1]._point.add(segments[2]._point).divide(2); |
7199 } else if (segments.length === 8 && isArc(0) && isArc(2) && isArc(4) |
7353 } else if (segments.length === 8 && isArc(0) && isArc(2) && isArc(4) |
7200 && isArc(6) && isColinear(1, 5) && isColinear(3, 7)) { |
7354 && isArc(6) && isCollinear(1, 5) && isCollinear(3, 7)) { |
7201 type = Shape.Rectangle; |
7355 type = Shape.Rectangle; |
7202 size = new Size(getDistance(1, 6), getDistance(0, 3)); |
7356 size = new Size(getDistance(1, 6), getDistance(0, 3)); |
7203 radius = size.subtract(new Size(getDistance(0, 7), |
7357 radius = size.subtract(new Size(getDistance(0, 7), |
7204 getDistance(1, 2))).divide(2); |
7358 getDistance(1, 2))).divide(2); |
7205 topCenter = segments[3]._point.add(segments[4]._point).divide(2); |
7359 topCenter = segments[3]._point.add(segments[4]._point).divide(2); |
7398 |
7549 |
7399 getLocationAt: function(offset, isParameter) { |
7550 getLocationAt: function(offset, isParameter) { |
7400 var curves = this.getCurves(), |
7551 var curves = this.getCurves(), |
7401 length = 0; |
7552 length = 0; |
7402 if (isParameter) { |
7553 if (isParameter) { |
7403 var index = ~~offset; |
7554 var index = ~~offset, |
7404 return curves[index].getLocationAt(offset - index, true); |
7555 curve = curves[index]; |
|
7556 return curve ? curve.getLocationAt(offset - index, true) : null; |
7405 } |
7557 } |
7406 for (var i = 0, l = curves.length; i < l; i++) { |
7558 for (var i = 0, l = curves.length; i < l; i++) { |
7407 var start = length, |
7559 var start = length, |
7408 curve = curves[i]; |
7560 curve = curves[i]; |
7409 length += curve.getLength(); |
7561 length += curve.getLength(); |
7987 |
8139 |
7988 function addJoin(segment, join) { |
8140 function addJoin(segment, join) { |
7989 var handleIn = segment._handleIn, |
8141 var handleIn = segment._handleIn, |
7990 handleOut = segment._handleOut; |
8142 handleOut = segment._handleOut; |
7991 if (join === 'round' || !handleIn.isZero() && !handleOut.isZero() |
8143 if (join === 'round' || !handleIn.isZero() && !handleOut.isZero() |
7992 && handleIn.isColinear(handleOut)) { |
8144 && handleIn.isCollinear(handleOut)) { |
7993 addRound(segment); |
8145 addRound(segment); |
7994 } else { |
8146 } else { |
7995 Path._addBevelJoin(segment, join, radius, miterLimit, add); |
8147 Path._addBevelJoin(segment, join, radius, miterLimit, add); |
7996 } |
8148 } |
7997 } |
8149 } |
8066 }, |
8218 }, |
8067 |
8219 |
8068 _addSquareCap: function(segment, cap, radius, addPoint, area) { |
8220 _addSquareCap: function(segment, cap, radius, addPoint, area) { |
8069 var point = segment._point, |
8221 var point = segment._point, |
8070 loc = segment.getLocation(), |
8222 loc = segment.getLocation(), |
8071 normal = loc.getNormal().normalize(radius); |
8223 normal = loc.getNormal().multiply(radius); |
8072 if (area) { |
8224 if (area) { |
8073 addPoint(point.subtract(normal)); |
8225 addPoint(point.subtract(normal)); |
8074 addPoint(point.add(normal)); |
8226 addPoint(point.add(normal)); |
8075 } |
8227 } |
8076 if (cap === 'square') |
8228 if (cap === 'square') |
8520 totalLength += length; |
8672 totalLength += length; |
8521 segment = segment.getNext(); |
8673 segment = segment.getNext(); |
8522 } while (segment && !segment._intersection && segment !== startSeg); |
8674 } while (segment && !segment._intersection && segment !== startSeg); |
8523 for (var j = 0; j < 3; j++) { |
8675 for (var j = 0; j < 3; j++) { |
8524 var length = totalLength * (j + 1) / 4; |
8676 var length = totalLength * (j + 1) / 4; |
8525 for (k = 0, m = chain.length; k < m; k++) { |
8677 for (var k = 0, m = chain.length; k < m; k++) { |
8526 var node = chain[k], |
8678 var node = chain[k], |
8527 curveLength = node.length; |
8679 curveLength = node.length; |
8528 if (length <= curveLength) { |
8680 if (length <= curveLength) { |
8529 if (length <= tolerance |
8681 if (length < tolerance |
8530 || curveLength - length <= tolerance) |
8682 || curveLength - length < tolerance) |
8531 length = curveLength / 2; |
8683 length = curveLength / 2; |
8532 var curve = node.segment.getCurve(), |
8684 var curve = node.segment.getCurve(), |
8533 pt = curve.getPointAt(length), |
8685 pt = curve.getPointAt(length), |
8534 hor = curve.isLinear() && Math.abs(curve |
8686 hor = curve.isLinear() && Math.abs(curve |
8535 .getTangentAt(0.5, true).y) <= tolerance, |
8687 .getTangentAt(0.5, true).y) < tolerance, |
8536 path = curve._path; |
8688 path = curve._path; |
8537 if (path._parent instanceof CompoundPath) |
8689 if (path._parent instanceof CompoundPath) |
8538 path = path._parent; |
8690 path = path._parent; |
8539 windingSum += operation === 'subtract' && _path2 |
8691 windingSum += operation === 'subtract' && _path2 |
8540 && (path === _path1 && _path2._getWinding(pt, hor) |
8692 && (path === _path1 && _path2._getWinding(pt, hor) |
8623 yAfter = py + tolerance; |
8775 yAfter = py + tolerance; |
8624 for (var i = 0, l = curves.length; i < l; i++) { |
8776 for (var i = 0, l = curves.length; i < l; i++) { |
8625 var values = curves[i].values; |
8777 var values = curves[i].values; |
8626 if (Curve.solveCubic(values, 0, px, roots, 0, 1) > 0) { |
8778 if (Curve.solveCubic(values, 0, px, roots, 0, 1) > 0) { |
8627 for (var j = roots.length - 1; j >= 0; j--) { |
8779 for (var j = roots.length - 1; j >= 0; j--) { |
8628 var y = Curve.evaluate(values, roots[j], 0).y; |
8780 var y = Curve.getPoint(values, roots[j]).y; |
8629 if (y < yBefore && y > yTop) { |
8781 if (y < yBefore && y > yTop) { |
8630 yTop = y; |
8782 yTop = y; |
8631 } else if (y > yAfter && y < yBottom) { |
8783 } else if (y > yAfter && y < yBottom) { |
8632 yBottom = y; |
8784 yBottom = y; |
8633 } |
8785 } |
8641 if (yBottom < Infinity) |
8793 if (yBottom < Infinity) |
8642 windRight = getWinding(new Point(px, yBottom), curves); |
8794 windRight = getWinding(new Point(px, yBottom), curves); |
8643 } else { |
8795 } else { |
8644 var xBefore = px - tolerance, |
8796 var xBefore = px - tolerance, |
8645 xAfter = px + tolerance; |
8797 xAfter = px + tolerance; |
|
8798 var startCounted = false, |
|
8799 prevCurve, |
|
8800 prevT; |
8646 for (var i = 0, l = curves.length; i < l; i++) { |
8801 for (var i = 0, l = curves.length; i < l; i++) { |
8647 var curve = curves[i], |
8802 var curve = curves[i], |
8648 values = curve.values, |
8803 values = curve.values, |
8649 winding = curve.winding, |
8804 winding = curve.winding; |
8650 prevT, |
|
8651 prevX; |
|
8652 if (winding && (winding === 1 |
8805 if (winding && (winding === 1 |
8653 && py >= values[1] && py <= values[7] |
8806 && py >= values[1] && py <= values[7] |
8654 || py >= values[7] && py <= values[1]) |
8807 || py >= values[7] && py <= values[1]) |
8655 && Curve.solveCubic(values, 1, py, roots, 0, 1) === 1) { |
8808 && Curve.solveCubic(values, 1, py, roots, 0, 1) === 1) { |
8656 var t = roots[0], |
8809 var t = roots[0]; |
8657 x = Curve.evaluate(values, t, 0).x, |
8810 if (!( |
8658 slope = Curve.evaluate(values, t, 1).y; |
8811 t > tMax && startCounted && curve.next !== curves[i + 1] |
8659 if (!(t > tMax |
8812 || t < tMin && prevT > tMax |
8660 && (i === l - 1 || curve.next !== curves[i + 1]) |
8813 && curve.previous === prevCurve)) { |
8661 && abs(Curve.evaluate(curve.next.values, 0, 0).x -x) |
8814 var x = Curve.getPoint(values, t).x, |
8662 <= tolerance |
8815 slope = Curve.getTangent(values, t).y, |
8663 || i > 0 && curve.previous === curves[i - 1] |
8816 counted = false; |
8664 && abs(prevX - x) < tolerance |
|
8665 && prevT > tMax && t < tMin)) { |
|
8666 if (Numerical.isZero(slope) && !Curve.isLinear(values) |
8817 if (Numerical.isZero(slope) && !Curve.isLinear(values) |
8667 || t < tMin && slope * Curve.evaluate( |
8818 || t < tMin && slope * Curve.getTangent( |
8668 curve.previous.values, 1, 1).y < 0 |
8819 curve.previous.values, 1).y < 0 |
8669 || t > tMax && slope * Curve.evaluate( |
8820 || t > tMax && slope * Curve.getTangent( |
8670 curve.next.values, 0, 1).y < 0) { |
8821 curve.next.values, 0).y < 0) { |
8671 if (testContains && x >= xBefore && x <= xAfter) { |
8822 if (testContains && x >= xBefore && x <= xAfter) { |
8672 ++windLeft; |
8823 ++windLeft; |
8673 ++windRight; |
8824 ++windRight; |
|
8825 counted = true; |
8674 } |
8826 } |
8675 } else if (x <= xBefore) { |
8827 } else if (x <= xBefore) { |
8676 windLeft += winding; |
8828 windLeft += winding; |
|
8829 counted = true; |
8677 } else if (x >= xAfter) { |
8830 } else if (x >= xAfter) { |
8678 windRight += winding; |
8831 windRight += winding; |
|
8832 counted = true; |
8679 } |
8833 } |
|
8834 if (curve.previous !== curves[i - 1]) |
|
8835 startCounted = t < tMin && counted; |
8680 } |
8836 } |
|
8837 prevCurve = curve; |
8681 prevT = t; |
8838 prevT = t; |
8682 prevX = x; |
|
8683 } |
8839 } |
8684 } |
8840 } |
8685 } |
8841 } |
8686 return Math.max(abs(windLeft), abs(windRight)); |
8842 return Math.max(abs(windLeft), abs(windRight)); |
8687 } |
8843 } |
8887 if ((curves[i].winding === 1 |
9043 if ((curves[i].winding === 1 |
8888 && y >= values[1] && y <= values[7] |
9044 && y >= values[1] && y <= values[7] |
8889 || y >= values[7] && y <= values[1]) |
9045 || y >= values[7] && y <= values[1]) |
8890 && Curve.solveCubic(values, 1, y, roots, 0, 1) > 0) { |
9046 && Curve.solveCubic(values, 1, y, roots, 0, 1) > 0) { |
8891 for (var j = roots.length - 1; j >= 0; j--) |
9047 for (var j = roots.length - 1; j >= 0; j--) |
8892 xIntercepts.push(Curve.evaluate(values, roots[j], 0).x); |
9048 xIntercepts.push(Curve.getPoint(values, roots[j]).x); |
8893 } |
9049 } |
8894 if (xIntercepts.length > 1) |
9050 if (xIntercepts.length > 1) |
8895 break; |
9051 break; |
8896 } |
9052 } |
8897 point.x = (xIntercepts[0] + xIntercepts[1]) / 2; |
9053 point.x = (xIntercepts[0] + xIntercepts[1]) / 2; |
9015 value: 1, |
9171 value: 1, |
9016 index: part.index |
9172 index: part.index |
9017 }; |
9173 }; |
9018 }, |
9174 }, |
9019 |
9175 |
9020 evaluate: function(offset, type) { |
|
9021 var param = this.getParameterAt(offset); |
|
9022 return Curve.evaluate(this.curves[param.index], param.value, type); |
|
9023 }, |
|
9024 |
|
9025 drawPart: function(ctx, from, to) { |
9176 drawPart: function(ctx, from, to) { |
9026 from = this.getParameterAt(from); |
9177 from = this.getParameterAt(from); |
9027 to = this.getParameterAt(to); |
9178 to = this.getParameterAt(to); |
9028 for (var i = from.index; i <= to.index; i++) { |
9179 for (var i = from.index; i <= to.index; i++) { |
9029 var curve = Curve.getPart(this.curves[i], |
9180 var curve = Curve.getPart(this.curves[i], |
9032 if (i == from.index) |
9183 if (i == from.index) |
9033 ctx.moveTo(curve[0], curve[1]); |
9184 ctx.moveTo(curve[0], curve[1]); |
9034 ctx.bezierCurveTo.apply(ctx, curve.slice(2)); |
9185 ctx.bezierCurveTo.apply(ctx, curve.slice(2)); |
9035 } |
9186 } |
9036 } |
9187 } |
9037 }, Base.each(['getPoint', 'getTangent', 'getNormal', 'getCurvature'], |
9188 }, Base.each(Curve.evaluateMethods, |
9038 function(name, index) { |
9189 function(name) { |
9039 this[name + 'At'] = function(offset) { |
9190 this[name + 'At'] = function(offset, weighted) { |
9040 return this.evaluate(offset, index); |
9191 var param = this.getParameterAt(offset); |
|
9192 return Curve[name](this.curves[param.index], param.value, weighted); |
9041 }; |
9193 }; |
9042 }, {}) |
9194 }, {}) |
9043 ); |
9195 ); |
9044 |
9196 |
9045 var PathFitter = Base.extend({ |
9197 var PathFitter = Base.extend({ |
9091 pt2.add(tan2.normalize(dist)), pt2]); |
9243 pt2.add(tan2.normalize(dist)), pt2]); |
9092 return; |
9244 return; |
9093 } |
9245 } |
9094 var uPrime = this.chordLengthParameterize(first, last), |
9246 var uPrime = this.chordLengthParameterize(first, last), |
9095 maxError = Math.max(this.error, this.error * this.error), |
9247 maxError = Math.max(this.error, this.error * this.error), |
9096 split; |
9248 split, |
|
9249 parametersInOrder = true; |
9097 for (var i = 0; i <= 4; i++) { |
9250 for (var i = 0; i <= 4; i++) { |
9098 var curve = this.generateBezier(first, last, uPrime, tan1, tan2); |
9251 var curve = this.generateBezier(first, last, uPrime, tan1, tan2); |
9099 var max = this.findMaxError(first, last, curve, uPrime); |
9252 var max = this.findMaxError(first, last, curve, uPrime); |
9100 if (max.error < this.error) { |
9253 if (max.error < this.error && parametersInOrder) { |
9101 this.addCurve(curve); |
9254 this.addCurve(curve); |
9102 return; |
9255 return; |
9103 } |
9256 } |
9104 split = max.index; |
9257 split = max.index; |
9105 if (max.error >= maxError) |
9258 if (max.error >= maxError) |
9106 break; |
9259 break; |
9107 this.reparameterize(first, last, uPrime, curve); |
9260 parametersInOrder = this.reparameterize(first, last, uPrime, curve); |
9108 maxError = max.error; |
9261 maxError = max.error; |
9109 } |
9262 } |
9110 var V1 = this.points[split - 1].subtract(this.points[split]), |
9263 var V1 = this.points[split - 1].subtract(this.points[split]), |
9111 V2 = this.points[split].subtract(this.points[split + 1]), |
9264 V2 = this.points[split].subtract(this.points[split + 1]), |
9112 tanCenter = V1.add(V2).divide(2).normalize(); |
9265 tanCenter = V1.add(V2).divide(2).normalize(); |
9166 } else { |
9319 } else { |
9167 alpha1 = alpha2 = 0; |
9320 alpha1 = alpha2 = 0; |
9168 } |
9321 } |
9169 } |
9322 } |
9170 |
9323 |
9171 var segLength = pt2.getDistance(pt1); |
9324 var segLength = pt2.getDistance(pt1), |
9172 epsilon *= segLength; |
9325 eps = epsilon * segLength, |
9173 if (alpha1 < epsilon || alpha2 < epsilon) { |
9326 handle1, |
|
9327 handle2; |
|
9328 if (alpha1 < eps || alpha2 < eps) { |
9174 alpha1 = alpha2 = segLength / 3; |
9329 alpha1 = alpha2 = segLength / 3; |
9175 } |
9330 } else { |
9176 |
9331 var line = pt2.subtract(pt1); |
9177 return [pt1, pt1.add(tan1.normalize(alpha1)), |
9332 handle1 = tan1.normalize(alpha1); |
9178 pt2.add(tan2.normalize(alpha2)), pt2]; |
9333 handle2 = tan2.normalize(alpha2); |
|
9334 if (handle1.dot(line) - handle2.dot(line) > segLength * segLength) { |
|
9335 alpha1 = alpha2 = segLength / 3; |
|
9336 handle1 = handle2 = null; |
|
9337 } |
|
9338 } |
|
9339 |
|
9340 return [pt1, pt1.add(handle1 || tan1.normalize(alpha1)), |
|
9341 pt2.add(handle2 || tan2.normalize(alpha2)), pt2]; |
9179 }, |
9342 }, |
9180 |
9343 |
9181 reparameterize: function(first, last, u, curve) { |
9344 reparameterize: function(first, last, u, curve) { |
9182 for (var i = first; i <= last; i++) { |
9345 for (var i = first; i <= last; i++) { |
9183 u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); |
9346 u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); |
9184 } |
9347 } |
|
9348 for (var i = 1, l = u.length; i < l; i++) { |
|
9349 if (u[i] <= u[i - 1]) |
|
9350 return false; |
|
9351 } |
|
9352 return true; |
9185 }, |
9353 }, |
9186 |
9354 |
9187 findRoot: function(curve, point, u) { |
9355 findRoot: function(curve, point, u) { |
9188 var curve1 = [], |
9356 var curve1 = [], |
9189 curve2 = []; |
9357 curve2 = []; |
9264 |
9432 |
9265 _equals: function(item) { |
9433 _equals: function(item) { |
9266 return this._content === item._content; |
9434 return this._content === item._content; |
9267 }, |
9435 }, |
9268 |
9436 |
9269 _clone: function _clone(copy, insert) { |
9437 _clone: function _clone(copy, insert, includeMatrix) { |
9270 copy.setContent(this._content); |
9438 copy.setContent(this._content); |
9271 return _clone.base.call(this, copy, insert); |
9439 return _clone.base.call(this, copy, insert, includeMatrix); |
9272 }, |
9440 }, |
9273 |
9441 |
9274 getContent: function() { |
9442 getContent: function() { |
9275 return this._content; |
9443 return this._content; |
9276 }, |
9444 }, |
9657 } |
9822 } |
9658 if (this.__read && type) |
9823 if (this.__read && type) |
9659 read = 1; |
9824 read = 1; |
9660 } |
9825 } |
9661 this._type = type || 'rgb'; |
9826 this._type = type || 'rgb'; |
9662 if (type === 'gradient') |
9827 this._id = UID.get(Color); |
9663 this._id = Color._id = (Color._id || 0) + 1; |
|
9664 if (!components) { |
9828 if (!components) { |
9665 this._components = components = []; |
9829 this._components = components = []; |
9666 var parsers = componentParsers[this._type]; |
9830 var parsers = componentParsers[this._type]; |
9667 for (var i = 0, l = parsers.length; i < l; i++) { |
9831 for (var i = 0, l = parsers.length; i < l; i++) { |
9668 var value = parsers[i].call(this, values && values[i]); |
9832 var value = parsers[i].call(this, values && values[i]); |
9895 |
10059 |
9896 var Gradient = Base.extend({ |
10060 var Gradient = Base.extend({ |
9897 _class: 'Gradient', |
10061 _class: 'Gradient', |
9898 |
10062 |
9899 initialize: function Gradient(stops, radial) { |
10063 initialize: function Gradient(stops, radial) { |
9900 this._id = Gradient._id = (Gradient._id || 0) + 1; |
10064 this._id = UID.get(); |
9901 if (stops && this._set(stops)) |
10065 if (stops && this._set(stops)) |
9902 stops = radial = null; |
10066 stops = radial = null; |
9903 if (!this._stops) |
10067 if (!this._stops) |
9904 this.setStops(stops || ['white', 'black']); |
10068 this.setStops(stops || ['white', 'black']); |
9905 if (this._radial == null) |
10069 if (this._radial == null) |
10898 this._context.scale(pixelRatio, pixelRatio); |
11062 this._context.scale(pixelRatio, pixelRatio); |
10899 } |
11063 } |
10900 }, |
11064 }, |
10901 |
11065 |
10902 getPixelSize: function(size) { |
11066 getPixelSize: function(size) { |
10903 var ctx = this._context, |
11067 var browser = paper.browser, |
10904 prevFont = ctx.font; |
11068 pixels; |
10905 ctx.font = size + ' serif'; |
11069 if (browser && browser.firefox) { |
10906 size = parseFloat(ctx.font); |
11070 var parent = this._element.parentNode, |
10907 ctx.font = prevFont; |
11071 temp = document.createElement('div'); |
10908 return size; |
11072 temp.style.fontSize = size; |
|
11073 parent.appendChild(temp); |
|
11074 pixels = parseFloat(DomElement.getStyles(temp).fontSize); |
|
11075 parent.removeChild(temp); |
|
11076 } else { |
|
11077 var ctx = this._context, |
|
11078 prevFont = ctx.font; |
|
11079 ctx.font = size + ' serif'; |
|
11080 pixels = parseFloat(ctx.font); |
|
11081 ctx.font = prevFont; |
|
11082 } |
|
11083 return pixels; |
10909 }, |
11084 }, |
10910 |
11085 |
10911 getTextWidth: function(font, lines) { |
11086 getTextWidth: function(font, lines) { |
10912 var ctx = this._context, |
11087 var ctx = this._context, |
10913 prevFont = ctx.font, |
11088 prevFont = ctx.font, |
10917 width = Math.max(width, ctx.measureText(lines[i]).width); |
11092 width = Math.max(width, ctx.measureText(lines[i]).width); |
10918 ctx.font = prevFont; |
11093 ctx.font = prevFont; |
10919 return width; |
11094 return width; |
10920 }, |
11095 }, |
10921 |
11096 |
10922 update: function() { |
11097 update: function(force) { |
10923 var project = this._project; |
11098 var project = this._project; |
10924 if (!project || !project._needsUpdate) |
11099 if (!project || !force && !project._needsUpdate) |
10925 return false; |
11100 return false; |
10926 var ctx = this._context, |
11101 var ctx = this._context, |
10927 size = this._viewSize; |
11102 size = this._viewSize; |
10928 ctx.clearRect(0, 0, size.width + 1, size.height + 1); |
11103 ctx.clearRect(0, 0, size.width + 1, size.height + 1); |
10929 project.draw(ctx, this._matrix, this._pixelRatio); |
11104 project.draw(ctx, this._matrix, this._pixelRatio); |
11135 view = View._focused, |
11311 view = View._focused, |
11136 scope = view && view.isVisible() && view._scope, |
11312 scope = view && view.isVisible() && view._scope, |
11137 tool = scope && scope.tool, |
11313 tool = scope && scope.tool, |
11138 name; |
11314 name; |
11139 keyMap[key] = down; |
11315 keyMap[key] = down; |
11140 if (specialKey && (name = Base.camelize(specialKey)) in modifiers) |
|
11141 modifiers[name] = down; |
|
11142 if (down) { |
11316 if (down) { |
11143 charCodeMap[keyCode] = charCode; |
11317 charCodeMap[keyCode] = charCode; |
11144 } else { |
11318 } else { |
11145 delete charCodeMap[keyCode]; |
11319 delete charCodeMap[keyCode]; |
|
11320 } |
|
11321 if (specialKey && (name = Base.camelize(specialKey)) in modifiers) { |
|
11322 modifiers[name] = down; |
|
11323 var browser = paper.browser; |
|
11324 if (name === 'command' && browser && browser.mac) { |
|
11325 if (down) { |
|
11326 commandFixMap = {}; |
|
11327 } else { |
|
11328 for (var code in commandFixMap) { |
|
11329 if (code in charCodeMap) |
|
11330 handleKey(false, code, commandFixMap[code], event); |
|
11331 } |
|
11332 commandFixMap = null; |
|
11333 } |
|
11334 } |
|
11335 } else if (down && commandFixMap) { |
|
11336 commandFixMap[keyCode] = charCode; |
11146 } |
11337 } |
11147 if (tool && tool.responds(type)) { |
11338 if (tool && tool.responds(type)) { |
11148 paper = scope; |
11339 paper = scope; |
11149 tool.emit(type, new KeyEvent(down, key, character, event)); |
11340 tool.emit(type, new KeyEvent(down, key, character, event)); |
11150 if (view) |
11341 if (view) |
11334 return this._minDistance; |
11525 return this._minDistance; |
11335 }, |
11526 }, |
11336 |
11527 |
11337 setMinDistance: function(minDistance) { |
11528 setMinDistance: function(minDistance) { |
11338 this._minDistance = minDistance; |
11529 this._minDistance = minDistance; |
11339 if (this._minDistance != null && this._maxDistance != null |
11530 if (minDistance != null && this._maxDistance != null |
11340 && this._minDistance > this._maxDistance) { |
11531 && minDistance > this._maxDistance) { |
11341 this._maxDistance = this._minDistance; |
11532 this._maxDistance = minDistance; |
11342 } |
11533 } |
11343 }, |
11534 }, |
11344 |
11535 |
11345 getMaxDistance: function() { |
11536 getMaxDistance: function() { |
11346 return this._maxDistance; |
11537 return this._maxDistance; |
11347 }, |
11538 }, |
11348 |
11539 |
11349 setMaxDistance: function(maxDistance) { |
11540 setMaxDistance: function(maxDistance) { |
11350 this._maxDistance = maxDistance; |
11541 this._maxDistance = maxDistance; |
11351 if (this._minDistance != null && this._maxDistance != null |
11542 if (this._minDistance != null && maxDistance != null |
11352 && this._maxDistance < this._minDistance) { |
11543 && maxDistance < this._minDistance) { |
11353 this._minDistance = maxDistance; |
11544 this._minDistance = maxDistance; |
11354 } |
11545 } |
11355 }, |
11546 }, |
11356 |
11547 |
11357 getFixedDistance: function() { |
11548 getFixedDistance: function() { |
11371 var minDist = minDistance != null ? minDistance : 0, |
11562 var minDist = minDistance != null ? minDistance : 0, |
11372 vector = point.subtract(this._point), |
11563 vector = point.subtract(this._point), |
11373 distance = vector.getLength(); |
11564 distance = vector.getLength(); |
11374 if (distance < minDist) |
11565 if (distance < minDist) |
11375 return false; |
11566 return false; |
11376 var maxDist = maxDistance != null ? maxDistance : 0; |
11567 if (maxDistance != null && maxDistance != 0) { |
11377 if (maxDist != 0) { |
11568 if (distance > maxDistance) { |
11378 if (distance > maxDist) { |
11569 point = this._point.add(vector.normalize(maxDistance)); |
11379 point = this._point.add(vector.normalize(maxDist)); |
|
11380 } else if (matchMaxDistance) { |
11570 } else if (matchMaxDistance) { |
11381 return false; |
11571 return false; |
11382 } |
11572 } |
11383 } |
11573 } |
11384 } |
11574 } |
11468 } |
11658 } |
11469 |
11659 |
11470 }); |
11660 }); |
11471 |
11661 |
11472 var Http = { |
11662 var Http = { |
11473 request: function(method, url, callback) { |
11663 request: function(method, url, callback, async) { |
|
11664 async = (async === undefined) ? true : async; |
11474 var xhr = new (window.ActiveXObject || XMLHttpRequest)( |
11665 var xhr = new (window.ActiveXObject || XMLHttpRequest)( |
11475 'Microsoft.XMLHTTP'); |
11666 'Microsoft.XMLHTTP'); |
11476 xhr.open(method.toUpperCase(), url, true); |
11667 xhr.open(method.toUpperCase(), url, async); |
11477 if ('overrideMimeType' in xhr) |
11668 if ('overrideMimeType' in xhr) |
11478 xhr.overrideMimeType('text/plain'); |
11669 xhr.overrideMimeType('text/plain'); |
11479 xhr.onreadystatechange = function() { |
11670 xhr.onreadystatechange = function() { |
11480 if (xhr.readyState === 4) { |
11671 if (xhr.readyState === 4) { |
11481 var status = xhr.status; |
11672 var status = xhr.status; |
11902 } |
12093 } |
11903 } |
12094 } |
11904 return node; |
12095 return node; |
11905 } |
12096 } |
11906 |
12097 |
11907 function exportRaster(item) { |
12098 function exportRaster(item, options) { |
11908 var attrs = getTransform(item._matrix, true), |
12099 var attrs = getTransform(item._matrix, true), |
11909 size = item.getSize(); |
12100 size = item.getSize(), |
|
12101 image = item.getImage(); |
11910 attrs.x -= size.width / 2; |
12102 attrs.x -= size.width / 2; |
11911 attrs.y -= size.height / 2; |
12103 attrs.y -= size.height / 2; |
11912 attrs.width = size.width; |
12104 attrs.width = size.width; |
11913 attrs.height = size.height; |
12105 attrs.height = size.height; |
11914 attrs.href = item.toDataURL(); |
12106 attrs.href = options.embedImages === false && image && image.src |
|
12107 || item.toDataURL(); |
11915 return createElement('image', attrs); |
12108 return createElement('image', attrs); |
11916 } |
12109 } |
11917 |
12110 |
11918 function exportPath(item, options) { |
12111 function exportPath(item, options) { |
11919 if (options.matchShapes) { |
12112 var matchShapes = options.matchShapes; |
|
12113 if (matchShapes) { |
11920 var shape = item.toShape(false); |
12114 var shape = item.toShape(false); |
11921 if (shape) |
12115 if (shape) |
11922 return exportShape(shape, options); |
12116 return exportShape(shape, options); |
11923 } |
12117 } |
11924 var segments = item._segments, |
12118 var segments = item._segments, |
11925 type, |
12119 type, |
11926 attrs = getTransform(item._matrix); |
12120 attrs = getTransform(item._matrix); |
11927 if (segments.length === 0) |
12121 if (segments.length === 0) |
11928 return null; |
12122 return null; |
11929 if (item.isPolygon()) { |
12123 if (matchShapes && !item.hasHandles()) { |
11930 if (segments.length >= 3) { |
12124 if (segments.length >= 3) { |
11931 type = item._closed ? 'polygon' : 'polyline'; |
12125 type = item._closed ? 'polygon' : 'polyline'; |
11932 var parts = []; |
12126 var parts = []; |
11933 for(i = 0, l = segments.length; i < l; i++) |
12127 for(var i = 0, l = segments.length; i < l; i++) |
11934 parts.push(formatter.point(segments[i]._point)); |
12128 parts.push(formatter.point(segments[i]._point)); |
11935 attrs.points = parts.join(' '); |
12129 attrs.points = parts.join(' '); |
11936 } else { |
12130 } else { |
11937 type = 'line'; |
12131 type = 'line'; |
11938 var first = segments[0]._point, |
12132 var first = segments[0]._point, |
12268 children = []; |
12462 children = []; |
12269 if (!isClip) { |
12463 if (!isClip) { |
12270 item = applyAttributes(item, node, isRoot); |
12464 item = applyAttributes(item, node, isRoot); |
12271 project._currentStyle = item._style.clone(); |
12465 project._currentStyle = item._style.clone(); |
12272 } |
12466 } |
|
12467 if (isRoot) { |
|
12468 var defs = node.querySelectorAll('defs'); |
|
12469 for (var i = 0, l = defs.length; i < l; i++) { |
|
12470 importSVG(defs[i], options, false); |
|
12471 } |
|
12472 } |
12273 for (var i = 0, l = nodes.length; i < l; i++) { |
12473 for (var i = 0, l = nodes.length; i < l; i++) { |
12274 var childNode = nodes[i], |
12474 var childNode = nodes[i], |
12275 child; |
12475 child; |
12276 if (childNode.nodeType === 1 |
12476 if (childNode.nodeType === 1 |
|
12477 && childNode.nodeName.toLowerCase() !== 'defs' |
12277 && (child = importSVG(childNode, options, false)) |
12478 && (child = importSVG(childNode, options, false)) |
12278 && !(child instanceof Symbol)) |
12479 && !(child instanceof Symbol)) |
12279 children.push(child); |
12480 children.push(child); |
12280 } |
12481 } |
12281 item.addChildren(children); |
12482 item.addChildren(children); |
12471 : 'getStrokeColor'](); |
12672 : 'getStrokeColor'](); |
12472 if (color) |
12673 if (color) |
12473 color.setAlpha(parseFloat(value)); |
12674 color.setAlpha(parseFloat(value)); |
12474 } |
12675 } |
12475 |
12676 |
12476 var attributes = Base.each(SVGStyles, function(entry) { |
12677 var attributes = Base.set(Base.each(SVGStyles, function(entry) { |
12477 this[entry.attribute] = function(item, value) { |
12678 this[entry.attribute] = function(item, value) { |
12478 item[entry.set](convertValue(value, entry.type, entry.fromSVG)); |
12679 item[entry.set](convertValue(value, entry.type, entry.fromSVG)); |
12479 if (entry.type === 'color' && item instanceof Shape) { |
12680 if (entry.type === 'color' && item instanceof Shape) { |
12480 var color = item[entry.get](); |
12681 var color = item[entry.get](); |
12481 if (color) |
12682 if (color) |
12482 color.transform(new Matrix().translate( |
12683 color.transform(new Matrix().translate( |
12483 item.getPosition(true).negate())); |
12684 item.getPosition(true).negate())); |
12484 } |
12685 } |
12485 }; |
12686 }; |
12486 }, { |
12687 }, {}), { |
12487 id: function(item, value) { |
12688 id: function(item, value) { |
12488 definitions[value] = item; |
12689 definitions[value] = item; |
12489 if (item.setName) |
12690 if (item.setName) |
12490 item.setName(value); |
12691 item.setName(value); |
12491 }, |
12692 }, |
12825 || parentType === 'BinaryExpression' |
13026 || parentType === 'BinaryExpression' |
12826 && /^[=!<>]/.test(parent.operator) |
13027 && /^[=!<>]/.test(parent.operator) |
12827 || parentType === 'MemberExpression' && parent.computed |
13028 || parentType === 'MemberExpression' && parent.computed |
12828 )) { |
13029 )) { |
12829 if (node.type === 'UpdateExpression') { |
13030 if (node.type === 'UpdateExpression') { |
12830 var arg = getCode(node.argument); |
13031 var arg = getCode(node.argument), |
12831 var str = arg + ' = __$__(' + arg |
13032 exp = '__$__(' + arg + ', "' + node.operator[0] |
12832 + ', "' + node.operator[0] + '", 1)'; |
13033 + '", 1)', |
|
13034 str = arg + ' = ' + exp; |
12833 if (!node.prefix |
13035 if (!node.prefix |
12834 && (parentType === 'AssignmentExpression' |
13036 && (parentType === 'AssignmentExpression' |
12835 || parentType === 'VariableDeclarator')) |
13037 || parentType === 'VariableDeclarator')) { |
|
13038 if (getCode(parent.left || parent.id) === arg) |
|
13039 str = exp; |
12836 str = arg + '; ' + str; |
13040 str = arg + '; ' + str; |
|
13041 } |
12837 replaceCode(node, str); |
13042 replaceCode(node, str); |
12838 } else { |
13043 } else { |
12839 if (/^.=$/.test(node.operator) |
13044 if (/^.=$/.test(node.operator) |
12840 && node.left.type !== 'Literal') { |
13045 && node.left.type !== 'Literal') { |
12841 var left = getCode(node.left), |
13046 var left = getCode(node.left), |
12956 function loadScript(script) { |
13161 function loadScript(script) { |
12957 if (/^text\/(?:x-|)paperscript$/.test(script.type) |
13162 if (/^text\/(?:x-|)paperscript$/.test(script.type) |
12958 && PaperScope.getAttribute(script, 'ignore') !== 'true') { |
13163 && PaperScope.getAttribute(script, 'ignore') !== 'true') { |
12959 var canvasId = PaperScope.getAttribute(script, 'canvas'), |
13164 var canvasId = PaperScope.getAttribute(script, 'canvas'), |
12960 canvas = document.getElementById(canvasId), |
13165 canvas = document.getElementById(canvasId), |
12961 src = script.src, |
13166 src = script.src || script.getAttribute('data-src'), |
|
13167 async = PaperScope.hasAttribute(script, 'async'), |
12962 scopeAttribute = 'data-paper-scope'; |
13168 scopeAttribute = 'data-paper-scope'; |
12963 if (!canvas) |
13169 if (!canvas) |
12964 throw new Error('Unable to find canvas with id "' |
13170 throw new Error('Unable to find canvas with id "' |
12965 + canvasId + '"'); |
13171 + canvasId + '"'); |
12966 var scope = PaperScope.get(canvas.getAttribute(scopeAttribute)) |
13172 var scope = PaperScope.get(canvas.getAttribute(scopeAttribute)) |
12967 || new PaperScope().setup(canvas); |
13173 || new PaperScope().setup(canvas); |
12968 canvas.setAttribute(scopeAttribute, scope._id); |
13174 canvas.setAttribute(scopeAttribute, scope._id); |
12969 if (src) { |
13175 if (src) { |
12970 Http.request('get', src, function(code) { |
13176 Http.request('get', src, function(code) { |
12971 execute(code, scope, src); |
13177 execute(code, scope, src); |
12972 }); |
13178 }, async); |
12973 } else { |
13179 } else { |
12974 execute(script.innerHTML, scope, script.baseURI); |
13180 execute(script.innerHTML, scope, script.baseURI); |
12975 } |
13181 } |
12976 script.setAttribute('data-paper-ignore', 'true'); |
13182 script.setAttribute('data-paper-ignore', 'true'); |
12977 return scope; |
13183 return scope; |