paper 0.12.20 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/README.md +29 -13
  3. package/dist/docs/assets/js/paper.js +788 -365
  4. package/dist/docs/classes/Color.html +63 -47
  5. package/dist/docs/classes/CompoundPath.html +162 -59
  6. package/dist/docs/classes/Curve.html +9 -7
  7. package/dist/docs/classes/CurveLocation.html +1 -1
  8. package/dist/docs/classes/Event.html +1 -1
  9. package/dist/docs/classes/Gradient.html +1 -1
  10. package/dist/docs/classes/GradientStop.html +1 -1
  11. package/dist/docs/classes/Group.html +63 -24
  12. package/dist/docs/classes/HitResult.html +1 -1
  13. package/dist/docs/classes/Item.html +63 -24
  14. package/dist/docs/classes/Key.html +1 -1
  15. package/dist/docs/classes/KeyEvent.html +1 -1
  16. package/dist/docs/classes/Layer.html +63 -24
  17. package/dist/docs/classes/Matrix.html +1 -1
  18. package/dist/docs/classes/MouseEvent.html +1 -1
  19. package/dist/docs/classes/PaperScope.html +87 -1
  20. package/dist/docs/classes/PaperScript.html +1 -1
  21. package/dist/docs/classes/Path.html +174 -68
  22. package/dist/docs/classes/PathItem.html +280 -177
  23. package/dist/docs/classes/Point.html +143 -21
  24. package/dist/docs/classes/PointText.html +94 -24
  25. package/dist/docs/classes/Project.html +14 -8
  26. package/dist/docs/classes/Raster.html +93 -35
  27. package/dist/docs/classes/Rectangle.html +12 -11
  28. package/dist/docs/classes/Segment.html +1 -1
  29. package/dist/docs/classes/Shape.html +63 -24
  30. package/dist/docs/classes/Size.html +81 -21
  31. package/dist/docs/classes/Style.html +34 -2
  32. package/dist/docs/classes/SymbolDefinition.html +1 -1
  33. package/dist/docs/classes/SymbolItem.html +64 -25
  34. package/dist/docs/classes/TextItem.html +94 -24
  35. package/dist/docs/classes/Tool.html +2 -1
  36. package/dist/docs/classes/ToolEvent.html +27 -1
  37. package/dist/docs/classes/Tween.html +1 -1
  38. package/dist/docs/classes/View.html +203 -10
  39. package/dist/docs/classes/global.html +1 -1
  40. package/dist/docs/classes/index.html +2 -2
  41. package/dist/docs/index.html +1 -1
  42. package/dist/node/canvas.js +1 -1
  43. package/dist/node/self.js +4 -3
  44. package/dist/paper-core.js +769 -354
  45. package/dist/paper-core.min.js +3 -3
  46. package/dist/paper-full.js +788 -365
  47. package/dist/paper-full.min.js +3 -3
  48. package/dist/paper.d.ts +324 -73
  49. package/examples/Rasters/Smoothing.html +1 -1
  50. package/package.json +1 -8
  51. package/dist/node/xml.js +0 -40
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Paper.js v0.12.20 - The Swiss Army Knife of Vector Graphics Scripting.
2
+ * Paper.js v0.13.0 - The Swiss Army Knife of Vector Graphics Scripting.
3
3
  * http://paperjs.org/
4
4
  *
5
5
  * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * All rights reserved.
11
11
  *
12
- * Date: Sun Oct 18 17:04:58 2026 +0200
12
+ * Date: Mon Oct 19 15:31:53 2026 +0200
13
13
  *
14
14
  ***
15
15
  *
@@ -36,6 +36,9 @@ self = self || require('./node/self.js');
36
36
  var window = self.window,
37
37
  document = self.document;
38
38
 
39
+ if (window && !document.createElement('canvas').getContext('2d'))
40
+ window = null;
41
+
39
42
  var Base = new function() {
40
43
  var hidden = /^(statics|enumerable|beans|preserve)$/,
41
44
  array = [],
@@ -821,7 +824,7 @@ var PaperScope = Base.extend({
821
824
  }
822
825
  },
823
826
 
824
- version: "0.12.20",
827
+ version: "0.13.0",
825
828
 
826
829
  getView: function() {
827
830
  var project = this.project;
@@ -1646,6 +1649,16 @@ var Point = Base.extend({
1646
1649
  );
1647
1650
  },
1648
1651
 
1652
+ clamp: function() {
1653
+ var args = arguments,
1654
+ min = Point.read(args),
1655
+ max = Point.read(args);
1656
+ return new Point(
1657
+ Numerical.clamp(this.x, min.x, max.x),
1658
+ Numerical.clamp(this.y, min.y, max.y)
1659
+ );
1660
+ },
1661
+
1649
1662
  statics: {
1650
1663
  min: function() {
1651
1664
  var args = arguments,
@@ -1927,10 +1940,11 @@ var Rectangle = Base.extend({
1927
1940
  arg0.width || 0, arg0.height || 0);
1928
1941
  read = 1;
1929
1942
  } else if (arg0.from === undefined && arg0.to === undefined) {
1930
- this._set(0, 0, 0, 0);
1931
- if (Base.readSupported(args, this)) {
1943
+ var builder = new RectangleBuilder();
1944
+ if (Base.readSupported(args, builder)) {
1932
1945
  read = 1;
1933
1946
  }
1947
+ this._set(builder.x, builder.y, builder.width, builder.height);
1934
1948
  }
1935
1949
  }
1936
1950
  if (read === undefined) {
@@ -2025,24 +2039,10 @@ var Rectangle = Base.extend({
2025
2039
  return new ctor(this.width, this.height, this, 'setSize');
2026
2040
  },
2027
2041
 
2028
- _fw: 1,
2029
- _fh: 1,
2030
-
2031
2042
  setSize: function() {
2032
- var size = Size.read(arguments),
2033
- sx = this._sx,
2034
- sy = this._sy,
2035
- w = size.width,
2036
- h = size.height;
2037
- if (sx) {
2038
- this.x += (this.width - w) * sx;
2039
- }
2040
- if (sy) {
2041
- this.y += (this.height - h) * sy;
2042
- }
2043
- this.width = w;
2044
- this.height = h;
2045
- this._fw = this._fh = 1;
2043
+ var size = Size.read(arguments);
2044
+ this.width = size.width;
2045
+ this.height = size.height;
2046
2046
  },
2047
2047
 
2048
2048
  getLeft: function() {
@@ -2050,12 +2050,8 @@ var Rectangle = Base.extend({
2050
2050
  },
2051
2051
 
2052
2052
  setLeft: function(left) {
2053
- if (!this._fw) {
2054
- var amount = left - this.x;
2055
- this.width -= this._sx === 0.5 ? amount * 2 : amount;
2056
- }
2053
+ this.width -= left - this.x;
2057
2054
  this.x = left;
2058
- this._sx = this._fw = 0;
2059
2055
  },
2060
2056
 
2061
2057
  getTop: function() {
@@ -2063,12 +2059,8 @@ var Rectangle = Base.extend({
2063
2059
  },
2064
2060
 
2065
2061
  setTop: function(top) {
2066
- if (!this._fh) {
2067
- var amount = top - this.y;
2068
- this.height -= this._sy === 0.5 ? amount * 2 : amount;
2069
- }
2062
+ this.height -= top - this.y;
2070
2063
  this.y = top;
2071
- this._sy = this._fh = 0;
2072
2064
  },
2073
2065
 
2074
2066
  getRight: function() {
@@ -2076,13 +2068,7 @@ var Rectangle = Base.extend({
2076
2068
  },
2077
2069
 
2078
2070
  setRight: function(right) {
2079
- if (!this._fw) {
2080
- var amount = right - this.x;
2081
- this.width = this._sx === 0.5 ? amount * 2 : amount;
2082
- }
2083
- this.x = right - this.width;
2084
- this._sx = 1;
2085
- this._fw = 0;
2071
+ this.width = right - this.x;
2086
2072
  },
2087
2073
 
2088
2074
  getBottom: function() {
@@ -2090,13 +2076,7 @@ var Rectangle = Base.extend({
2090
2076
  },
2091
2077
 
2092
2078
  setBottom: function(bottom) {
2093
- if (!this._fh) {
2094
- var amount = bottom - this.y;
2095
- this.height = this._sy === 0.5 ? amount * 2 : amount;
2096
- }
2097
- this.y = bottom - this.height;
2098
- this._sy = 1;
2099
- this._fh = 0;
2079
+ this.height = bottom - this.y;
2100
2080
  },
2101
2081
 
2102
2082
  getCenterX: function() {
@@ -2104,16 +2084,7 @@ var Rectangle = Base.extend({
2104
2084
  },
2105
2085
 
2106
2086
  setCenterX: function(x) {
2107
- if (this._fw || this._sx === 0.5) {
2108
- this.x = x - this.width / 2;
2109
- } else {
2110
- if (this._sx) {
2111
- this.x += (x - this.x) * 2 * this._sx;
2112
- }
2113
- this.width = (x - this.x) * 2;
2114
- }
2115
- this._sx = 0.5;
2116
- this._fw = 0;
2087
+ this.x = x - this.width / 2;
2117
2088
  },
2118
2089
 
2119
2090
  getCenterY: function() {
@@ -2121,16 +2092,7 @@ var Rectangle = Base.extend({
2121
2092
  },
2122
2093
 
2123
2094
  setCenterY: function(y) {
2124
- if (this._fh || this._sy === 0.5) {
2125
- this.y = y - this.height / 2;
2126
- } else {
2127
- if (this._sy) {
2128
- this.y += (y - this.y) * 2 * this._sy;
2129
- }
2130
- this.height = (y - this.y) * 2;
2131
- }
2132
- this._sy = 0.5;
2133
- this._fh = 0;
2095
+ this.y = y - this.height / 2;
2134
2096
  },
2135
2097
 
2136
2098
  getCenter: function(_dontLink) {
@@ -2316,6 +2278,94 @@ new function() {
2316
2278
  );
2317
2279
  });
2318
2280
 
2281
+ var RectangleBuilder = Rectangle.extend({
2282
+ beans: true,
2283
+
2284
+ _fw: 1,
2285
+ _fh: 1,
2286
+
2287
+ setSize: function() {
2288
+ var size = Size.read(arguments),
2289
+ sx = this._sx,
2290
+ sy = this._sy,
2291
+ w = size.width,
2292
+ h = size.height;
2293
+ if (sx) {
2294
+ this.x += (this.width - w) * sx;
2295
+ }
2296
+ if (sy) {
2297
+ this.y += (this.height - h) * sy;
2298
+ }
2299
+ this.width = w;
2300
+ this.height = h;
2301
+ this._fw = this._fh = 1;
2302
+ },
2303
+
2304
+ setLeft: function(left) {
2305
+ if (!this._fw) {
2306
+ var amount = left - this.x;
2307
+ this.width -= this._sx === 0.5 ? amount * 2 : amount;
2308
+ }
2309
+ this.x = left;
2310
+ this._sx = this._fw = 0;
2311
+ },
2312
+
2313
+ setTop: function(top) {
2314
+ if (!this._fh) {
2315
+ var amount = top - this.y;
2316
+ this.height -= this._sy === 0.5 ? amount * 2 : amount;
2317
+ }
2318
+ this.y = top;
2319
+ this._sy = this._fh = 0;
2320
+ },
2321
+
2322
+ setRight: function(right) {
2323
+ if (!this._fw) {
2324
+ var amount = right - this.x;
2325
+ this.width = this._sx === 0.5 ? amount * 2 : amount;
2326
+ }
2327
+ this.x = right - this.width;
2328
+ this._sx = 1;
2329
+ this._fw = 0;
2330
+ },
2331
+
2332
+ setBottom: function(bottom) {
2333
+ if (!this._fh) {
2334
+ var amount = bottom - this.y;
2335
+ this.height = this._sy === 0.5 ? amount * 2 : amount;
2336
+ }
2337
+ this.y = bottom - this.height;
2338
+ this._sy = 1;
2339
+ this._fh = 0;
2340
+ },
2341
+
2342
+ setCenterX: function(x) {
2343
+ if (this._fw || this._sx === 0.5) {
2344
+ this.x = x - this.width / 2;
2345
+ } else {
2346
+ if (this._sx) {
2347
+ this.x += (x - this.x) * 2 * this._sx;
2348
+ }
2349
+ this.width = (x - this.x) * 2;
2350
+ }
2351
+ this._sx = 0.5;
2352
+ this._fw = 0;
2353
+ },
2354
+
2355
+ setCenterY: function(y) {
2356
+ if (this._fh || this._sy === 0.5) {
2357
+ this.y = y - this.height / 2;
2358
+ } else {
2359
+ if (this._sy) {
2360
+ this.y += (y - this.y) * 2 * this._sy;
2361
+ }
2362
+ this.height = (y - this.y) * 2;
2363
+ }
2364
+ this._sy = 0.5;
2365
+ this._fh = 0;
2366
+ }
2367
+ });
2368
+
2319
2369
  var Matrix = Base.extend({
2320
2370
  _class: 'Matrix',
2321
2371
 
@@ -2867,8 +2917,10 @@ var Line = Base.extend({
2867
2917
  : vy === 0 ? (vx < 0 ? y - py : py - y)
2868
2918
  : ((x - px) * vy - (y - py) * vx) / (
2869
2919
  vy > vx
2870
- ? vy * Math.sqrt(1 + (vx * vx) / (vy * vy))
2871
- : vx * Math.sqrt(1 + (vy * vy) / (vx * vx))
2920
+ ? Math.abs(vy)
2921
+ * Math.sqrt(1 + (vx * vx) / (vy * vy))
2922
+ : Math.abs(vx)
2923
+ * Math.sqrt(1 + (vy * vy) / (vx * vx))
2872
2924
  );
2873
2925
  },
2874
2926
 
@@ -3005,10 +3057,10 @@ var Project = PaperScopeItem.extend({
3005
3057
  return items;
3006
3058
  },
3007
3059
 
3008
- _updateSelection: function(item) {
3060
+ _updateSelection: function(item, remove) {
3009
3061
  var id = item._id,
3010
3062
  selectionItems = this._selectionItems;
3011
- if (item._selection) {
3063
+ if (item._selection && !remove && item.isInserted()) {
3012
3064
  if (selectionItems[id] !== item) {
3013
3065
  this._selectionCount++;
3014
3066
  selectionItems[id] = item;
@@ -3117,7 +3169,7 @@ var Project = PaperScopeItem.extend({
3117
3169
 
3118
3170
  if (this._selectionCount > 0) {
3119
3171
  ctx.save();
3120
- ctx.strokeWidth = 1;
3172
+ ctx.lineWidth = 1;
3121
3173
  var items = this._selectionItems,
3122
3174
  size = this._scope.settings.handleSize,
3123
3175
  version = this._updateVersion;
@@ -3180,11 +3232,13 @@ new function() {
3180
3232
  function(name) {
3181
3233
  this._events[name] = {
3182
3234
  install: function(type) {
3183
- this.getView()._countItemEvent(type, 1);
3235
+ if (this.isInserted())
3236
+ this.getView()._countItemEvent(type, 1);
3184
3237
  },
3185
3238
 
3186
3239
  uninstall: function(type) {
3187
- this.getView()._countItemEvent(type, -1);
3240
+ if (this.isInserted())
3241
+ this.getView()._countItemEvent(type, -1);
3188
3242
  }
3189
3243
  };
3190
3244
  }, {
@@ -3493,8 +3547,8 @@ new function() {
3493
3547
  bounds = this.getBounds();
3494
3548
  }
3495
3549
  matrix.scale(
3496
- bounds.width !== 0 ? rect.width / bounds.width : 0,
3497
- bounds.height !== 0 ? rect.height / bounds.height : 0);
3550
+ bounds.width !== 0 ? rect.width / bounds.width : 1,
3551
+ bounds.height !== 0 ? rect.height / bounds.height : 1);
3498
3552
  }
3499
3553
  center = bounds.getCenter();
3500
3554
  matrix.translate(-center.x, -center.y);
@@ -3518,14 +3572,18 @@ new function() {
3518
3572
  },
3519
3573
 
3520
3574
  _getCachedBounds: function(matrix, options, noInternal) {
3521
- matrix = matrix && matrix._orNullIfIdentity();
3522
3575
  var internal = options.internal && !noInternal,
3523
3576
  cacheItem = options.cacheItem,
3524
- _matrix = internal ? null : this._matrix._orNullIfIdentity(),
3525
- cacheKey = cacheItem && (!matrix || matrix.equals(_matrix))
3577
+ _matrix = internal ? null : this._matrix._orNullIfIdentity();
3578
+ matrix = matrix ? matrix._orNullIfIdentity() : _matrix;
3579
+ var cacheKey = cacheItem && (matrix ? matrix.equals(_matrix) : !_matrix)
3526
3580
  && this._getBoundsCacheKey(options, internal),
3581
+ isIntermediate = cacheKey && cacheItem !== this
3582
+ && (this._children || this._definition),
3527
3583
  bounds = this._bounds;
3528
3584
  Item._updateBoundsCache(this._parent || this._symbol, cacheItem);
3585
+ if (isIntermediate)
3586
+ Item._updateBoundsCache(this, cacheItem);
3529
3587
  if (cacheKey && bounds && cacheKey in bounds) {
3530
3588
  var cached = bounds[cacheKey];
3531
3589
  return {
@@ -3533,7 +3591,9 @@ new function() {
3533
3591
  nonscaling: cached.nonscaling
3534
3592
  };
3535
3593
  }
3536
- var res = this._getBounds(matrix || _matrix, options),
3594
+ var res = this._getBounds(matrix, isIntermediate
3595
+ ? Base.set({}, options, { cacheItem: this })
3596
+ : options),
3537
3597
  rect = res.rect || res,
3538
3598
  style = this._style,
3539
3599
  nonscaling = res.nonscaling || style.hasStroke()
@@ -3697,27 +3757,14 @@ new function() {
3697
3757
  },
3698
3758
 
3699
3759
  getGlobalMatrix: function(_dontClone) {
3700
- var matrix = this._globalMatrix;
3701
- if (matrix) {
3702
- var parent = this._parent;
3703
- var parents = [];
3704
- while (parent) {
3705
- if (!parent._globalMatrix) {
3706
- matrix = null;
3707
- for (var i = 0, l = parents.length; i < l; i++) {
3708
- parents[i]._globalMatrix = null;
3709
- }
3710
- break;
3711
- }
3712
- parents.push(parent);
3713
- parent = parent._parent;
3714
- }
3715
- }
3716
- if (!matrix) {
3760
+ var parent = this._parent,
3761
+ parentMatrix = parent && parent.getGlobalMatrix(true),
3762
+ matrix = this._globalMatrix;
3763
+ if (!matrix || this._parentGlobalMatrix !== parentMatrix) {
3717
3764
  matrix = this._globalMatrix = this._matrix.clone();
3718
- var parent = this._parent;
3719
- if (parent)
3720
- matrix.prepend(parent.getGlobalMatrix(true));
3765
+ if (parentMatrix)
3766
+ matrix.prepend(parentMatrix);
3767
+ this._parentGlobalMatrix = parentMatrix;
3721
3768
  }
3722
3769
  return _dontClone ? matrix : matrix.clone();
3723
3770
  },
@@ -3744,13 +3791,10 @@ new function() {
3744
3791
 
3745
3792
  _setProject: function(project, installEvents) {
3746
3793
  if (this._project !== project) {
3747
- if (this._project)
3748
- this._installEvents(false);
3749
3794
  this._project = project;
3750
3795
  var children = this._children;
3751
3796
  for (var i = 0, l = children && children.length; i < l; i++)
3752
3797
  children[i]._setProject(project);
3753
- installEvents = true;
3754
3798
  }
3755
3799
  if (installEvents)
3756
3800
  this._installEvents(true);
@@ -3762,6 +3806,8 @@ new function() {
3762
3806
 
3763
3807
  _installEvents: function _installEvents(install) {
3764
3808
  _installEvents.base.call(this, install);
3809
+ if (this._selection)
3810
+ this._project._updateSelection(this, !install);
3765
3811
  var children = this._children;
3766
3812
  for (var i = 0, l = children && children.length; i < l; i++)
3767
3813
  children[i]._installEvents(install);
@@ -3849,7 +3895,8 @@ new function() {
3849
3895
  var copy = new this.constructor(Item.NO_INSERT),
3850
3896
  children = this._children,
3851
3897
  insert = Base.pick(options ? options.insert : undefined,
3852
- options === undefined || options === true),
3898
+ typeof options === 'boolean' ? options
3899
+ : paper.settings.insertItems),
3853
3900
  deep = Base.pick(options ? options.deep : undefined, true);
3854
3901
  if (children)
3855
3902
  copy.copyAttributes(this);
@@ -3937,7 +3984,7 @@ new function() {
3937
3984
  .translate(topLeft.add(boundsSize.divide(2)))
3938
3985
  .scale(1 / scale)
3939
3986
  );
3940
- if (insert === undefined || insert) {
3987
+ if (Base.pick(insert, paper.settings.insertItems)) {
3941
3988
  raster.insertAbove(this);
3942
3989
  }
3943
3990
  return raster;
@@ -3970,6 +4017,7 @@ new function() {
3970
4017
  _asPathItem: function() {
3971
4018
  return new Path.Rectangle({
3972
4019
  rectangle: this.getInternalBounds(),
4020
+ applyMatrix: false,
3973
4021
  matrix: this._matrix,
3974
4022
  insert: false,
3975
4023
  });
@@ -4033,14 +4081,16 @@ new function() {
4033
4081
  }
4034
4082
 
4035
4083
  var matrix = this._matrix,
4084
+ pointMatrix = parentViewMatrix ? matrix : this.getGlobalMatrix(),
4036
4085
  viewMatrix = parentViewMatrix
4037
4086
  ? parentViewMatrix.appended(matrix)
4038
- : this.getGlobalMatrix().prepend(this.getView()._matrix),
4087
+ : pointMatrix.prepended(this.getView()._matrix),
4039
4088
  tolerance = Math.max(options.tolerance, 1e-12),
4040
4089
  tolerancePadding = options._tolerancePadding = new Size(
4041
- Path._getStrokePadding(tolerance,
4042
- matrix._shiftless().invert()));
4043
- point = matrix._inverseTransform(point);
4090
+ Path._getStrokePadding(tolerance, viewMatrix
4091
+ .prepended(this.getView()._matrix.inverted())
4092
+ ._shiftless().invert()));
4093
+ point = pointMatrix._inverseTransform(point);
4044
4094
  if (!point || !this._children &&
4045
4095
  !this.getBounds({ internal: true, stroke: true, handle: true })
4046
4096
  .expand(tolerancePadding.multiply(2))._containsPoint(point)) {
@@ -4105,7 +4155,7 @@ new function() {
4105
4155
  || null;
4106
4156
  }
4107
4157
  if (res && res.point) {
4108
- res.point = matrix.transform(res.point);
4158
+ res.point = pointMatrix.transform(res.point);
4109
4159
  }
4110
4160
  return res;
4111
4161
  },
@@ -4185,7 +4235,7 @@ new function() {
4185
4235
  rect = bounds && Rectangle.read([bounds]);
4186
4236
  param = {
4187
4237
  items: [],
4188
- recursive: obj && obj.recursive !== false,
4238
+ recursive: !obj || obj.recursive !== false,
4189
4239
  inside: !!inside,
4190
4240
  overlapping: !!overlapping,
4191
4241
  rect: rect,
@@ -4379,13 +4429,13 @@ new function() {
4379
4429
  if (owner) {
4380
4430
  if (this._name)
4381
4431
  this._removeNamed();
4432
+ this._installEvents(false);
4382
4433
  if (index != null) {
4383
4434
  if (project._activeLayer === this)
4384
4435
  project._activeLayer = this.getNextSibling()
4385
4436
  || this.getPreviousSibling();
4386
4437
  Base.splice(owner._children, null, index, 1);
4387
4438
  }
4388
- this._installEvents(false);
4389
4439
  if (notifySelf && project._changes)
4390
4440
  this._changed(5);
4391
4441
  if (notifyParent)
@@ -4644,30 +4694,46 @@ new function() {
4644
4694
  return this._matrix._transformPoint(Point.read(arguments));
4645
4695
  },
4646
4696
 
4647
- fitBounds: function(rectangle, fill) {
4697
+ fitBounds: function(rectangle, fit) {
4648
4698
  rectangle = Rectangle.read(arguments);
4649
- fill = Base.read(arguments);
4699
+ fit = Base.read(arguments);
4700
+ if (fit === true)
4701
+ fit = 'cover';
4650
4702
  var bounds = this.getBounds(),
4651
- itemRatio = bounds.height / bounds.width,
4652
- rectRatio = rectangle.height / rectangle.width,
4653
- scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio)
4654
- ? rectangle.width / bounds.width
4655
- : rectangle.height / bounds.height,
4656
- newBounds = new Rectangle(new Point(),
4657
- new Size(bounds.width * scale, bounds.height * scale));
4658
- newBounds.setCenter(rectangle.getCenter());
4659
- this.setBounds(newBounds);
4703
+ hor = rectangle.width / bounds.width,
4704
+ ver = rectangle.height / bounds.height,
4705
+ size;
4706
+
4707
+ function isScaling(ratio) {
4708
+ return ratio > 0 && isFinite(ratio);
4709
+ }
4710
+
4711
+ if (fit === 'fill') {
4712
+ size = new Size(
4713
+ isScaling(hor) ? rectangle.width : bounds.width,
4714
+ isScaling(ver) ? rectangle.height : bounds.height);
4715
+ } else {
4716
+ var ratios = [hor, ver].filter(isScaling),
4717
+ scale = !ratios.length ? 1
4718
+ : fit === 'cover' ? Math.max.apply(Math, ratios)
4719
+ : Math.min.apply(Math, ratios);
4720
+ size = bounds.getSize().multiply(scale);
4721
+ }
4722
+ this.setBounds(new Rectangle(new Point(), size)
4723
+ .setCenter(rectangle.getCenter()));
4660
4724
  }
4661
4725
  }), {
4662
4726
 
4663
- _setStyles: function(ctx, param, viewMatrix) {
4727
+ _setStyles: function(ctx, param, viewMatrix, strokeMatrix) {
4664
4728
  var style = this._style,
4665
4729
  matrix = this._matrix;
4666
4730
  if (style.hasFill()) {
4667
- ctx.fillStyle = style.getFillColor().toCanvasStyle(ctx, matrix);
4731
+ ctx.fillStyle = style.getFillColor().toCanvasStyle(ctx, matrix,
4732
+ strokeMatrix);
4668
4733
  }
4669
4734
  if (style.hasStroke()) {
4670
- ctx.strokeStyle = style.getStrokeColor().toCanvasStyle(ctx, matrix);
4735
+ ctx.strokeStyle = style.getStrokeColor().toCanvasStyle(ctx,
4736
+ matrix, strokeMatrix);
4671
4737
  ctx.lineWidth = style.getStrokeWidth();
4672
4738
  var strokeJoin = style.getStrokeJoin(),
4673
4739
  strokeCap = style.getStrokeCap(),
@@ -4712,7 +4778,8 @@ new function() {
4712
4778
  var matrices = param.matrices,
4713
4779
  viewMatrix = param.viewMatrix,
4714
4780
  matrix = this._matrix,
4715
- globalMatrix = matrices[matrices.length - 1].appended(matrix);
4781
+ parentMatrix = matrices[matrices.length - 1],
4782
+ globalMatrix = parentMatrix.appended(matrix);
4716
4783
  if (!globalMatrix.isInvertible())
4717
4784
  return;
4718
4785
 
@@ -4722,6 +4789,7 @@ new function() {
4722
4789
  matrices.push(globalMatrix);
4723
4790
  if (param.updateMatrix) {
4724
4791
  this._globalMatrix = globalMatrix;
4792
+ this._parentGlobalMatrix = this._parent && parentMatrix;
4725
4793
  }
4726
4794
 
4727
4795
  var blendMode = this._blendMode,
@@ -4736,8 +4804,23 @@ new function() {
4736
4804
  pixelRatio = param.pixelRatio || 1,
4737
4805
  mainCtx, itemOffset, prevOffset;
4738
4806
  if (!direct) {
4739
- var bounds = this.getStrokeBounds(viewMatrix);
4740
- if (!bounds.width || !bounds.height) {
4807
+ var bounds = this.getStrokeBounds(viewMatrix),
4808
+ style = this._style;
4809
+ if (style.getShadowColor(true)) {
4810
+ var mx = viewMatrix._shiftless(),
4811
+ blur = mx.transform(
4812
+ new Point(style.getShadowBlur(true), 0)),
4813
+ offset = mx.transform(style.getShadowOffset(true));
4814
+ bounds = bounds.unite(
4815
+ new Rectangle(bounds.getPoint().add(offset),
4816
+ bounds.getSize()).expand(blur.getLength() * 3));
4817
+ }
4818
+ var canvas = ctx.canvas;
4819
+ bounds = bounds.intersect(
4820
+ new Rectangle(new Point(param.offset),
4821
+ new Size(canvas.width, canvas.height)
4822
+ .divide(pixelRatio)));
4823
+ if (bounds.width <= 0 || bounds.height <= 0) {
4741
4824
  matrices.pop();
4742
4825
  return;
4743
4826
  }
@@ -4763,11 +4846,16 @@ new function() {
4763
4846
  } else if (transform) {
4764
4847
  ctx.translate(-itemOffset.x, -itemOffset.y);
4765
4848
  }
4766
- if (transform) {
4767
- (direct ? matrix : viewMatrix).applyToContext(ctx);
4768
- }
4769
4849
  if (clip) {
4770
- param.clipItem.draw(ctx, param.extend({ clip: true }));
4850
+ (param.viewMatrix ? param.viewMatrix.appended(parentMatrix)
4851
+ : parentMatrix).applyToContext(ctx);
4852
+ param.clipItem.draw(ctx, param.extend({
4853
+ clip: true,
4854
+ matrices: matrices.slice(0, -1)
4855
+ }));
4856
+ matrix.applyToContext(ctx);
4857
+ } else if (transform) {
4858
+ (direct ? matrix : viewMatrix).applyToContext(ctx);
4771
4859
  }
4772
4860
  if (strokeMatrix) {
4773
4861
  ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
@@ -4811,7 +4899,7 @@ new function() {
4811
4899
  if (!this._drawSelected)
4812
4900
  itemSelected = false;
4813
4901
  if ((itemSelected || boundsSelected || positionSelected)
4814
- && this._isUpdated(updateVersion)) {
4902
+ && this._isUpdated(updateVersion) && this.isInserted()) {
4815
4903
  var layer,
4816
4904
  color = this.getSelectedColor(true) || (layer = this.getLayer())
4817
4905
  && layer.getSelectedColor(true),
@@ -4982,10 +5070,21 @@ var Group = Item.extend({
4982
5070
  clipItem);
4983
5071
  },
4984
5072
 
5073
+ _hitTestSelf: function(point, options, viewMatrix) {
5074
+ if (options.match || options.class || options.type || options.all) {
5075
+ var res = this._hitTestChildren(point, options.extend({
5076
+ all: null, match: null, class: null, type: null
5077
+ }), viewMatrix);
5078
+ if (res)
5079
+ res.item = this;
5080
+ return res;
5081
+ }
5082
+ },
5083
+
4985
5084
  _draw: function(ctx, param) {
4986
5085
  var clip = param.clip,
4987
- clipItem = !clip && this._getClipItem();
4988
- param = param.extend({ clipItem: clipItem, clip: false });
5086
+ clipItem = this._getClipItem();
5087
+ param = param.extend({ clipItem: !clip && clipItem, clip: false });
4989
5088
  if (clip) {
4990
5089
  ctx.beginPath();
4991
5090
  param.dontStart = param.dontFinish = true;
@@ -5034,6 +5133,7 @@ var Shape = Item.extend({
5034
5133
  size: null,
5035
5134
  radius: null
5036
5135
  },
5136
+ _prioritize: ['type'],
5037
5137
 
5038
5138
  initialize: function Shape(props, point) {
5039
5139
  this._initialize(props, point);
@@ -5131,16 +5231,10 @@ var Shape = Item.extend({
5131
5231
  },
5132
5232
 
5133
5233
  toPath: function(insert) {
5134
- var path = new Path[Base.capitalize(this._type)]({
5135
- center: new Point(),
5136
- size: this._size,
5137
- radius: this._radius,
5138
- insert: false
5139
- });
5140
- path.copyAttributes(this);
5234
+ var path = this._asPathItem();
5141
5235
  if (paper.settings.applyMatrix)
5142
5236
  path.setApplyMatrix(true);
5143
- if (insert === undefined || insert)
5237
+ if (Base.pick(insert, paper.settings.insertItems))
5144
5238
  path.insertAbove(this);
5145
5239
  return path;
5146
5240
  },
@@ -5148,7 +5242,14 @@ var Shape = Item.extend({
5148
5242
  toShape: '#clone',
5149
5243
 
5150
5244
  _asPathItem: function() {
5151
- return this.toPath(false);
5245
+ var path = new Path[Base.capitalize(this._type)]({
5246
+ center: new Point(),
5247
+ size: this._size,
5248
+ radius: this._radius,
5249
+ insert: false
5250
+ });
5251
+ path.copyAttributes(this);
5252
+ return path;
5152
5253
  },
5153
5254
 
5154
5255
  _draw: function(ctx, param, viewMatrix, strokeMatrix) {
@@ -5215,7 +5316,7 @@ var Shape = Item.extend({
5215
5316
  ctx.closePath();
5216
5317
  }
5217
5318
  if (!dontPaint && (hasFill || hasStroke)) {
5218
- this._setStyles(ctx, param, viewMatrix);
5319
+ this._setStyles(ctx, param, viewMatrix, strokeMatrix);
5219
5320
  if (hasFill) {
5220
5321
  ctx.fill(style.getFillRule());
5221
5322
  ctx.shadowColor = 'rgba(0,0,0,0)';
@@ -5230,12 +5331,25 @@ var Shape = Item.extend({
5230
5331
  },
5231
5332
 
5232
5333
  _getBounds: function(matrix, options) {
5233
- var rect = new Rectangle(this._size).setCenter(0, 0),
5334
+ var size = this._size,
5335
+ rect = new Rectangle(size).setCenter(0, 0),
5234
5336
  style = this._style,
5235
5337
  strokeWidth = options.stroke && style.hasStroke()
5236
5338
  && style.getStrokeWidth();
5237
- if (matrix)
5238
- rect = matrix._transformBounds(rect);
5339
+ if (matrix) {
5340
+ if (this._type === 'rectangle') {
5341
+ rect = matrix._transformBounds(rect);
5342
+ } else {
5343
+ var rx = size.width / 2,
5344
+ ry = size.height / 2,
5345
+ dx = Math.sqrt(Math.pow(matrix._a * rx, 2)
5346
+ + Math.pow(matrix._c * ry, 2)),
5347
+ dy = Math.sqrt(Math.pow(matrix._b * rx, 2)
5348
+ + Math.pow(matrix._d * ry, 2));
5349
+ rect = new Rectangle(matrix._tx - dx, matrix._ty - dy,
5350
+ 2 * dx, 2 * dy);
5351
+ }
5352
+ }
5239
5353
  return strokeWidth
5240
5354
  ? rect.expand(Path._getStrokePadding(strokeWidth,
5241
5355
  this._getStrokeMatrix(matrix, options)))
@@ -5777,7 +5891,12 @@ var Raster = Item.extend({
5777
5891
 
5778
5892
  _draw: function(ctx, param, viewMatrix) {
5779
5893
  var element = this.getElement();
5780
- if (element && element.width > 0 && element.height > 0) {
5894
+ if (param.dontFinish || param.clip) {
5895
+ var rect = this.getInternalBounds();
5896
+ if (!param.dontStart)
5897
+ ctx.beginPath();
5898
+ ctx.rect(rect.x, rect.y, rect.width, rect.height);
5899
+ } else if (element && element.width > 0 && element.height > 0) {
5781
5900
  ctx.globalAlpha = Numerical.clamp(this._opacity, 0, 1);
5782
5901
 
5783
5902
  this._setStyles(ctx, param, viewMatrix);
@@ -5846,7 +5965,9 @@ var SymbolItem = Item.extend({
5846
5965
  },
5847
5966
 
5848
5967
  _hitTestSelf: function(point, options, viewMatrix) {
5849
- var opts = options.extend({ all: false });
5968
+ var opts = options.extend({
5969
+ all: false, match: null, class: null, type: null
5970
+ });
5850
5971
  var res = this._definition._item._hitTest(point, opts, viewMatrix);
5851
5972
  if (res)
5852
5973
  res.item = this;
@@ -5854,7 +5975,7 @@ var SymbolItem = Item.extend({
5854
5975
  },
5855
5976
 
5856
5977
  _draw: function(ctx, param) {
5857
- this._definition._item.draw(ctx, param);
5978
+ this._definition._item.draw(ctx, param.extend({ updateMatrix: false }));
5858
5979
  }
5859
5980
 
5860
5981
  });
@@ -6886,7 +7007,7 @@ statics: {
6886
7007
  }
6887
7008
  }
6888
7009
  }}, Base.each(
6889
- ['getBounds', 'getStrokeBounds', 'getHandleBounds'],
7010
+ ['getBounds', 'getStrokeBounds'],
6890
7011
  function(name) {
6891
7012
  this[name] = function() {
6892
7013
  if (!this._bounds)
@@ -6901,6 +7022,15 @@ statics: {
6901
7022
  },
6902
7023
  {
6903
7024
 
7025
+ getHandleBounds: function() {
7026
+ var v = this.getValues(),
7027
+ x1 = Math.min(v[0], v[2], v[4], v[6]),
7028
+ y1 = Math.min(v[1], v[3], v[5], v[7]),
7029
+ x2 = Math.max(v[0], v[2], v[4], v[6]),
7030
+ y2 = Math.max(v[1], v[3], v[5], v[7]);
7031
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
7032
+ },
7033
+
6904
7034
  }), Base.each({
6905
7035
  isStraight: function(p1, h1, h2, p2) {
6906
7036
  if (h1.isZero() && h2.isZero()) {
@@ -7693,8 +7823,8 @@ new function() {
7693
7823
  den = 2 * ax * ty - 2 * ay * tx,
7694
7824
  times = [];
7695
7825
  if (Math.abs(den) < Numerical.CURVETIME_EPSILON) {
7696
- var num = ax * cy - ay * cx,
7697
- den = ax * by - ay * bx;
7826
+ var num = cx * ty - cy * tx,
7827
+ den = bx * ty - by * tx;
7698
7828
  if (den != 0) {
7699
7829
  var t = -num / den;
7700
7830
  if (t >= 0 && t <= 1) times.push(t);
@@ -8143,7 +8273,12 @@ var PathItem = Item.extend({
8143
8273
  previous,
8144
8274
  control,
8145
8275
  current = new Point(),
8146
- start = new Point();
8276
+ start = new Point(),
8277
+ number = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)(?:[eE][+-]?\\d+)?)',
8278
+ numbers = new RegExp(number, 'g'),
8279
+ flag = '([01])',
8280
+ arcs = new RegExp([number, number, number, flag, flag, number,
8281
+ number].join('[\\s,]*'), 'g');
8147
8282
 
8148
8283
  function getCoord(index, coord) {
8149
8284
  var val = +coords[index];
@@ -8165,7 +8300,7 @@ var PathItem = Item.extend({
8165
8300
  var part = parts[i],
8166
8301
  command = part[0],
8167
8302
  lower = command.toLowerCase();
8168
- coords = part.match(/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g);
8303
+ coords = part.match(numbers);
8169
8304
  var length = coords && coords.length;
8170
8305
  relative = command === lower;
8171
8306
  if (previous === 'z' && !/[mz]/.test(lower))
@@ -8230,10 +8365,10 @@ var PathItem = Item.extend({
8230
8365
  }
8231
8366
  break;
8232
8367
  case 'a':
8233
- for (var j = 0; j < length; j += 7) {
8234
- this.arcTo(current = getPoint(j + 5),
8235
- new Size(+coords[j], +coords[j + 1]),
8236
- +coords[j + 2], +coords[j + 4], +coords[j + 3]);
8368
+ while (coords = arcs.exec(part)) {
8369
+ this.arcTo(current = getPoint(6),
8370
+ new Size(+coords[1], +coords[2]),
8371
+ +coords[3], +coords[5], +coords[4]);
8237
8372
  }
8238
8373
  break;
8239
8374
  case 'z':
@@ -8667,6 +8802,9 @@ var Path = PathItem.extend({
8667
8802
  removeSegments: function(start, end, _includeCurves) {
8668
8803
  start = start || 0;
8669
8804
  end = Base.pick(end, this._segments.length);
8805
+ if (start > end && this._closed)
8806
+ return this.removeSegments(start).concat(
8807
+ this.removeSegments(0, end));
8670
8808
  var segments = this._segments,
8671
8809
  curves = this._curves,
8672
8810
  count = segments.length,
@@ -8795,7 +8933,7 @@ var Path = PathItem.extend({
8795
8933
  time = 0;
8796
8934
  }
8797
8935
  var curves = this.getCurves();
8798
- if (index >= 0 && index < curves.length) {
8936
+ if (loc && index < curves.length) {
8799
8937
  if (time >= tMin) {
8800
8938
  curves[index++].divideAtTime(time);
8801
8939
  }
@@ -9107,7 +9245,7 @@ var Path = PathItem.extend({
9107
9245
  shape.copyAttributes(this, true);
9108
9246
  shape._matrix.prepend(this._matrix);
9109
9247
  shape.rotate(topCenter.subtract(center).getAngle() + 90);
9110
- if (insert === undefined || insert)
9248
+ if (Base.pick(insert, paper.settings.insertItems))
9111
9249
  shape.insertAbove(this);
9112
9250
  return shape;
9113
9251
  }
@@ -9248,7 +9386,7 @@ var Path = PathItem.extend({
9248
9386
  Path._addBevelJoin(segment, join, strokeRadius,
9249
9387
  miterLimit, null, strokeMatrix, addToArea, true);
9250
9388
  }
9251
- } else if (cap === 'square') {
9389
+ } else {
9252
9390
  Path._addSquareCap(segment, cap, strokeRadius, null,
9253
9391
  strokeMatrix, addToArea, true);
9254
9392
  }
@@ -9501,7 +9639,7 @@ new function() {
9501
9639
  }
9502
9640
 
9503
9641
  if (!dontPaint && (hasFill || hasStroke)) {
9504
- this._setStyles(ctx, param, viewMatrix);
9642
+ this._setStyles(ctx, param, viewMatrix, strokeMatrix);
9505
9643
  if (hasFill) {
9506
9644
  ctx.fill(style.getFillRule());
9507
9645
  ctx.shadowColor = 'rgba(0,0,0,0)';
@@ -9881,18 +10019,12 @@ statics: {
9881
10019
  _getStrokePadding: function(radius, matrix) {
9882
10020
  if (!matrix)
9883
10021
  return [radius, radius];
9884
- var hor = new Point(radius, 0).transform(matrix),
9885
- ver = new Point(0, radius).transform(matrix),
9886
- phi = hor.getAngleInRadians(),
9887
- a = hor.getLength(),
9888
- b = ver.getLength();
9889
- var sin = Math.sin(phi),
9890
- cos = Math.cos(phi),
9891
- tan = Math.tan(phi),
9892
- tx = Math.atan2(b * tan, a),
9893
- ty = Math.atan2(b, tan * a);
9894
- return [Math.abs(a * Math.cos(tx) * cos + b * Math.sin(tx) * sin),
9895
- Math.abs(b * Math.sin(ty) * cos + a * Math.cos(ty) * sin)];
10022
+ var a = matrix._a,
10023
+ b = matrix._b,
10024
+ c = matrix._c,
10025
+ d = matrix._d;
10026
+ return [radius * Math.sqrt(a * a + c * c),
10027
+ radius * Math.sqrt(b * b + d * d)];
9896
10028
  },
9897
10029
 
9898
10030
  _addBevelJoin: function(segment, join, radius, miterLimit, matrix,
@@ -9900,44 +10032,42 @@ statics: {
9900
10032
  var curve2 = segment.getCurve(),
9901
10033
  curve1 = curve2.getPrevious(),
9902
10034
  point = curve2.getPoint1().transform(matrix),
9903
- normal1 = curve1.getNormalAtTime(1).multiply(radius)
9904
- .transform(strokeMatrix),
9905
- normal2 = curve2.getNormalAtTime(0).multiply(radius)
9906
- .transform(strokeMatrix),
9907
- angle = normal1.getDirectedAngle(normal2);
10035
+ normal1 = curve1.getNormalAtTime(1).multiply(radius),
10036
+ normal2 = curve2.getNormalAtTime(0).multiply(radius),
10037
+ angle = normal1.getDirectedAngle(normal2);
9908
10038
  if (angle < 0 || angle >= 180) {
9909
10039
  normal1 = normal1.negate();
9910
10040
  normal2 = normal2.negate();
9911
10041
  }
9912
10042
  if (isArea)
9913
10043
  addPoint(point);
9914
- addPoint(point.add(normal1));
10044
+ addPoint(point.add(normal1.transform(strokeMatrix)));
9915
10045
  if (join === 'miter') {
9916
- var corner = new Line(point.add(normal1),
10046
+ var corner = new Line(normal1,
9917
10047
  new Point(-normal1.y, normal1.x), true
9918
- ).intersect(new Line(point.add(normal2),
10048
+ ).intersect(new Line(normal2,
9919
10049
  new Point(-normal2.y, normal2.x), true
9920
10050
  ), true);
9921
- if (corner && point.getDistance(corner) <= miterLimit * radius) {
9922
- addPoint(corner);
10051
+ if (corner && corner.getLength() <= miterLimit * radius) {
10052
+ addPoint(point.add(corner.transform(strokeMatrix)));
9923
10053
  }
9924
10054
  }
9925
- addPoint(point.add(normal2));
10055
+ addPoint(point.add(normal2.transform(strokeMatrix)));
9926
10056
  },
9927
10057
 
9928
10058
  _addSquareCap: function(segment, cap, radius, matrix, strokeMatrix,
9929
10059
  addPoint, isArea) {
9930
10060
  var point = segment._point.transform(matrix),
9931
10061
  loc = segment.getLocation(),
9932
- normal = loc.getNormal()
9933
- .multiply(loc.getTime() === 0 ? radius : -radius)
9934
- .transform(strokeMatrix);
10062
+ vector = loc.getNormal()
10063
+ .multiply(loc.getTime() === 0 ? radius : -radius),
10064
+ normal = vector.transform(strokeMatrix);
9935
10065
  if (cap === 'square') {
9936
10066
  if (isArea) {
9937
10067
  addPoint(point.subtract(normal));
9938
10068
  addPoint(point.add(normal));
9939
10069
  }
9940
- point = point.add(normal.rotate(-90));
10070
+ point = point.add(vector.rotate(-90).transform(strokeMatrix));
9941
10071
  }
9942
10072
  addPoint(point.add(normal));
9943
10073
  addPoint(point.subtract(normal));
@@ -9999,14 +10129,14 @@ Path.inject({ statics: new function() {
9999
10129
 
10000
10130
  function createPath(segments, closed, args) {
10001
10131
  var props = Base.getNamed(args),
10002
- path = new Path(props && (
10003
- props.insert == true ? Item.INSERT
10004
- : props.insert == false ? Item.NO_INSERT
10005
- : null
10006
- ));
10132
+ path = new Path(props && {
10133
+ insert: props.insert,
10134
+ project: props.project,
10135
+ parent: props.parent
10136
+ });
10007
10137
  path._add(segments);
10008
10138
  path._closed = closed;
10009
- return path.set(props, Item.INSERT);
10139
+ return path.set(props, { insert: true, project: true, parent: true });
10010
10140
  }
10011
10141
 
10012
10142
  function createEllipse(center, radius, args) {
@@ -10275,7 +10405,7 @@ var CompoundPath = PathItem.extend({
10275
10405
  children[i].draw(ctx, param, strokeMatrix);
10276
10406
 
10277
10407
  if (!param.clip) {
10278
- this._setStyles(ctx, param, viewMatrix);
10408
+ this._setStyles(ctx, param, viewMatrix, strokeMatrix);
10279
10409
  var style = this._style;
10280
10410
  if (style.hasFill()) {
10281
10411
  ctx.fill(style.getFillRule());
@@ -10388,7 +10518,7 @@ PathItem.inject(new function() {
10388
10518
  var result = new CompoundPath(Item.NO_INSERT);
10389
10519
  result.addChildren(paths, true);
10390
10520
  result = result.reduce({ simplify: simplify });
10391
- if (!(options && options.insert == false)) {
10521
+ if (Base.pick(options && options.insert, paper.settings.insertItems)) {
10392
10522
  result.insertAbove(path2 && path1.isSibling(path2)
10393
10523
  && path1.getIndex() < path2.getIndex() ? path2 : path1);
10394
10524
  }
@@ -10403,7 +10533,7 @@ PathItem.inject(new function() {
10403
10533
  function traceBoolean(path1, path2, operation, options) {
10404
10534
  if (options && (options.trace == false || options.stroke) &&
10405
10535
  /^(subtract|intersect)$/.test(operation))
10406
- return splitBoolean(path1, path2, operation);
10536
+ return splitBoolean(path1, path2, operation, options);
10407
10537
  var _path1 = preparePath(path1, true),
10408
10538
  _path2 = path2 && path1 !== path2 && preparePath(path2, true),
10409
10539
  operator = operators[operation];
@@ -10483,7 +10613,7 @@ PathItem.inject(new function() {
10483
10613
  return createResult(paths, true, path1, path2, options);
10484
10614
  }
10485
10615
 
10486
- function splitBoolean(path1, path2, operation) {
10616
+ function splitBoolean(path1, path2, operation, options) {
10487
10617
  var _path1 = preparePath(path1),
10488
10618
  _path2 = preparePath(path2),
10489
10619
  crossings = _path1.getIntersections(_path2, filterIntersection),
@@ -10510,7 +10640,7 @@ PathItem.inject(new function() {
10510
10640
  }
10511
10641
  }
10512
10642
  addPath(_path1);
10513
- return createResult(paths, false, path1, path2);
10643
+ return createResult(paths, false, path1, path2, options);
10514
10644
  }
10515
10645
 
10516
10646
  function linkIntersections(from, to) {
@@ -11097,7 +11227,7 @@ PathItem.inject(new function() {
11097
11227
 
11098
11228
  divide: function(path, options) {
11099
11229
  return options && (options.trace == false || options.stroke)
11100
- ? splitBoolean(this, path, 'divide')
11230
+ ? splitBoolean(this, path, 'divide', options)
11101
11231
  : createResult([
11102
11232
  this.subtract(path, options),
11103
11233
  this.intersect(path, options)
@@ -11565,7 +11695,7 @@ var TextItem = Item.extend({
11565
11695
  _serializeFields: {
11566
11696
  content: null
11567
11697
  },
11568
- _boundsOptions: { stroke: false, handle: false },
11698
+ _boundsOptions: { handle: false },
11569
11699
 
11570
11700
  initialize: function TextItem(arg) {
11571
11701
  this._content = '';
@@ -11622,27 +11752,33 @@ var PointText = TextItem.extend({
11622
11752
  },
11623
11753
 
11624
11754
  _draw: function(ctx, param, viewMatrix) {
11625
- if (!this._content)
11626
- return;
11627
- this._setStyles(ctx, param, viewMatrix);
11628
- var lines = this._lines,
11629
- style = this._style,
11630
- hasFill = style.hasFill(),
11631
- hasStroke = style.hasStroke(),
11632
- leading = style.getLeading(),
11633
- shadowColor = ctx.shadowColor;
11634
- ctx.font = style.getFontStyle();
11635
- ctx.textAlign = style.getJustification();
11636
- for (var i = 0, l = lines.length; i < l; i++) {
11637
- ctx.shadowColor = shadowColor;
11638
- var line = lines[i];
11639
- if (hasFill) {
11640
- ctx.fillText(line, 0, 0);
11641
- ctx.shadowColor = 'rgba(0,0,0,0)';
11755
+ if (param.dontFinish || param.clip) {
11756
+ var rect = this.getInternalBounds();
11757
+ if (!param.dontStart)
11758
+ ctx.beginPath();
11759
+ ctx.rect(rect.x, rect.y, rect.width, rect.height);
11760
+ } else if (this._content) {
11761
+ this._setStyles(ctx, param, viewMatrix);
11762
+ var lines = this._lines,
11763
+ style = this._style,
11764
+ hasFill = style.hasFill(),
11765
+ hasStroke = style.hasStroke(),
11766
+ leading = style.getLeading(),
11767
+ shadowColor = ctx.shadowColor;
11768
+ ctx.font = style.getFontStyle();
11769
+ ctx.textAlign = style.getJustification();
11770
+ ctx.letterSpacing = style.getTrackingStyle();
11771
+ for (var i = 0, l = lines.length; i < l; i++) {
11772
+ ctx.shadowColor = shadowColor;
11773
+ var line = lines[i];
11774
+ if (hasFill) {
11775
+ ctx.fillText(line, 0, 0);
11776
+ ctx.shadowColor = 'rgba(0,0,0,0)';
11777
+ }
11778
+ if (hasStroke)
11779
+ ctx.strokeText(line, 0, 0);
11780
+ ctx.translate(0, leading);
11642
11781
  }
11643
- if (hasStroke)
11644
- ctx.strokeText(line, 0, 0);
11645
- ctx.translate(0, leading);
11646
11782
  }
11647
11783
  },
11648
11784
 
@@ -11652,14 +11788,28 @@ var PointText = TextItem.extend({
11652
11788
  numLines = lines.length,
11653
11789
  justification = style.getJustification(),
11654
11790
  leading = style.getLeading(),
11655
- width = this.getView().getTextWidth(style.getFontStyle(), lines),
11791
+ width = this.getView().getTextWidth(style.getFontStyle(), lines,
11792
+ style.getTrackingStyle()),
11656
11793
  x = 0;
11657
11794
  if (justification !== 'left')
11658
11795
  x -= width / (justification === 'center' ? 2: 1);
11659
11796
  var rect = new Rectangle(x,
11660
11797
  numLines ? - 0.75 * leading : 0,
11661
11798
  width, numLines * leading);
11799
+ if (options.stroke && style.hasStroke())
11800
+ rect = rect.expand(style.getStrokeWidth());
11662
11801
  return matrix ? matrix._transformBounds(rect, rect) : rect;
11802
+ },
11803
+
11804
+ _hitTestSelf: function(point, options) {
11805
+ if (options.fill && this.hasFill()) {
11806
+ var bounds = this.getInternalBounds(),
11807
+ closest = point.clamp(bounds.getTopLeft(true),
11808
+ bounds.getBottomRight(true));
11809
+ if (point.subtract(closest).divide(options._tolerancePadding)
11810
+ .getLength() <= 1)
11811
+ return new HitResult('fill', this);
11812
+ }
11663
11813
  }
11664
11814
  });
11665
11815
 
@@ -11720,13 +11870,14 @@ var Color = Base.extend(new function() {
11720
11870
  } else {
11721
11871
  var color = namedColors[string];
11722
11872
  if (!color) {
11723
- if (window) {
11724
- if (!colorCtx) {
11725
- colorCtx = CanvasProvider.getContext(1, 1, {
11726
- willReadFrequently: true
11727
- });
11873
+ if (!colorCtx) {
11874
+ colorCtx = CanvasProvider.getContext(1, 1, {
11875
+ willReadFrequently: true
11876
+ });
11877
+ if (colorCtx)
11728
11878
  colorCtx.globalCompositeOperation = 'copy';
11729
- }
11879
+ }
11880
+ if (colorCtx) {
11730
11881
  colorCtx.fillStyle = 'rgba(0,0,0,0)';
11731
11882
  colorCtx.fillStyle = string;
11732
11883
  colorCtx.fillRect(0, 0, 1, 1);
@@ -12133,8 +12284,9 @@ var Color = Base.extend(new function() {
12133
12284
  + components.join(',') + ')';
12134
12285
  },
12135
12286
 
12136
- toCanvasStyle: function(ctx, matrix) {
12137
- if (this._canvasStyle)
12287
+ toCanvasStyle: function(ctx, matrix, strokeMatrix) {
12288
+ var isCacheable = !(this._type === 'gradient' && strokeMatrix);
12289
+ if (this._canvasStyle && isCacheable)
12138
12290
  return this._canvasStyle;
12139
12291
  if (this._type !== 'gradient')
12140
12292
  return this._canvasStyle = this.toCSS();
@@ -12152,6 +12304,12 @@ var Color = Base.extend(new function() {
12152
12304
  if (highlight)
12153
12305
  highlight = inverse._transformPoint(highlight);
12154
12306
  }
12307
+ if (strokeMatrix) {
12308
+ origin = strokeMatrix._transformPoint(origin);
12309
+ destination = strokeMatrix._transformPoint(destination);
12310
+ if (highlight)
12311
+ highlight = strokeMatrix._transformPoint(highlight);
12312
+ }
12155
12313
  if (gradient._radial) {
12156
12314
  var radius = destination.getDistance(origin);
12157
12315
  if (highlight) {
@@ -12173,7 +12331,9 @@ var Color = Base.extend(new function() {
12173
12331
  offset == null ? i / (l - 1) : offset,
12174
12332
  stop._color.toCanvasStyle());
12175
12333
  }
12176
- return this._canvasStyle = canvasGradient;
12334
+ if (isCacheable)
12335
+ this._canvasStyle = canvasGradient;
12336
+ return canvasGradient;
12177
12337
  },
12178
12338
 
12179
12339
  transform: function(matrix) {
@@ -12437,6 +12597,7 @@ var Style = Base.extend(new function() {
12437
12597
  fontWeight: 'normal',
12438
12598
  fontSize: 12,
12439
12599
  leading: null,
12600
+ tracking: 0,
12440
12601
  justification: 'left'
12441
12602
  }),
12442
12603
  textDefaults = Base.set({}, groupDefaults, {
@@ -12453,6 +12614,7 @@ var Style = Base.extend(new function() {
12453
12614
  fontSize: 9,
12454
12615
  font: 9,
12455
12616
  leading: 9,
12617
+ tracking: 9,
12456
12618
  justification: 9
12457
12619
  },
12458
12620
  item = {
@@ -12497,7 +12659,7 @@ var Style = Base.extend(new function() {
12497
12659
  var old = this._values[key];
12498
12660
  if (old !== value) {
12499
12661
  if (isColor) {
12500
- if (old) {
12662
+ if (old && old.constructor === Color) {
12501
12663
  Color._setOwner(old, null);
12502
12664
  old._canvasStyle = null;
12503
12665
  }
@@ -12643,6 +12805,10 @@ var Style = Base.extend(new function() {
12643
12805
  + this.getFontFamily();
12644
12806
  },
12645
12807
 
12808
+ getTrackingStyle: function() {
12809
+ return this.getTracking() / 1000 + 'em';
12810
+ },
12811
+
12646
12812
  getFont: '#getFontFamily',
12647
12813
  setFont: '#setFontFamily',
12648
12814
 
@@ -12719,6 +12885,18 @@ var DomElement = new function() {
12719
12885
  return DomElement.getBounds(el, true).getSize();
12720
12886
  },
12721
12887
 
12888
+ getInsets: function(el, start) {
12889
+ var style = DomElement.getStyles(el);
12890
+ function get(side) {
12891
+ return parseFloat(style['padding' + side])
12892
+ + parseFloat(style['border' + side + 'Width']);
12893
+ }
12894
+ return start
12895
+ ? new Size(get('Left'), get('Top'))
12896
+ : new Size(get('Left') + get('Right'),
12897
+ get('Top') + get('Bottom'));
12898
+ },
12899
+
12722
12900
  isInvisible: function(el) {
12723
12901
  return DomElement.getSize(el).equals(new Size(0, 0));
12724
12902
  },
@@ -12777,12 +12955,20 @@ var DomEvent = {
12777
12955
  }
12778
12956
  },
12779
12957
 
12780
- getPoint: function(event) {
12781
- var pos = event.targetTouches
12782
- ? event.targetTouches.length
12783
- ? event.targetTouches[0]
12784
- : event.changedTouches[0]
12785
- : event;
12958
+ getPoint: function(event, target) {
12959
+ function find(touches) {
12960
+ for (var i = 0, l = touches.length; i < l; i++) {
12961
+ if (touches[i].target === target)
12962
+ return touches[i];
12963
+ }
12964
+ }
12965
+
12966
+ var touches = event.targetTouches,
12967
+ pos = event;
12968
+ if (touches) {
12969
+ pos = find(event.touches) || find(event.changedTouches)
12970
+ || (touches.length ? touches[0] : event.changedTouches[0]);
12971
+ }
12786
12972
  return new Point(
12787
12973
  pos.pageX || pos.clientX + document.documentElement.scrollLeft,
12788
12974
  pos.pageY || pos.clientY + document.documentElement.scrollTop
@@ -12798,8 +12984,9 @@ var DomEvent = {
12798
12984
  },
12799
12985
 
12800
12986
  getOffset: function(event, target) {
12801
- return DomEvent.getPoint(event).subtract(DomElement.getOffset(
12802
- target || DomEvent.getTarget(event)));
12987
+ target = target || DomEvent.getTarget(event);
12988
+ return DomEvent.getPoint(event, target).subtract(
12989
+ DomElement.getOffset(target));
12803
12990
  }
12804
12991
  };
12805
12992
 
@@ -12845,7 +13032,7 @@ var View = Base.extend(Emitter, {
12845
13032
  var size = DomElement.getSize(element);
12846
13033
  return size.isNaN() || size.isZero()
12847
13034
  ? new Size(getSize('width'), getSize('height'))
12848
- : size;
13035
+ : size.subtract(DomElement.getInsets(element));
12849
13036
  }
12850
13037
 
12851
13038
  var size;
@@ -12958,7 +13145,7 @@ var View = Base.extend(Emitter, {
12958
13145
  this.requestUpdate();
12959
13146
  },
12960
13147
 
12961
- update: function() {
13148
+ update: function(force) {
12962
13149
  },
12963
13150
 
12964
13151
  draw: function() {
@@ -13046,6 +13233,10 @@ var View = Base.extend(Emitter, {
13046
13233
  return this._element;
13047
13234
  },
13048
13235
 
13236
+ getProject: function() {
13237
+ return this._project;
13238
+ },
13239
+
13049
13240
  getPixelRatio: function() {
13050
13241
  return this._pixelRatio;
13051
13242
  },
@@ -13151,12 +13342,14 @@ var View = Base.extend(Emitter, {
13151
13342
 
13152
13343
  getZoom: function() {
13153
13344
  var scaling = this._decompose().scaling;
13154
- return (scaling.x + scaling.y) / 2;
13345
+ return (Math.abs(scaling.x) + Math.abs(scaling.y)) / 2;
13155
13346
  },
13156
13347
 
13157
13348
  setZoom: function(zoom) {
13158
- this.transform(new Matrix().scale(zoom / this.getZoom(),
13159
- this.getCenter()));
13349
+ if (zoom > 0 && isFinite(zoom)) {
13350
+ this.transform(new Matrix().scale(zoom / this.getZoom(),
13351
+ this.getCenter()));
13352
+ }
13160
13353
  },
13161
13354
 
13162
13355
  getRotation: function() {
@@ -13166,7 +13359,8 @@ var View = Base.extend(Emitter, {
13166
13359
  setRotation: function(rotation) {
13167
13360
  var current = this.getRotation();
13168
13361
  if (current != null && rotation != null) {
13169
- this.rotate(rotation - current);
13362
+ this._matrix.prepend(new Matrix().rotate(rotation - current,
13363
+ this.projectToView(this.getCenter())));
13170
13364
  }
13171
13365
  },
13172
13366
 
@@ -13196,6 +13390,31 @@ var View = Base.extend(Emitter, {
13196
13390
  this._matrix.append(matrix);
13197
13391
  },
13198
13392
 
13393
+ fitBounds: function(rectangle, fit) {
13394
+ rectangle = Rectangle.read(arguments);
13395
+ fit = Base.read(arguments);
13396
+ var matrix = this._matrix,
13397
+ size = this._viewSize,
13398
+ bounds = matrix._transformBounds(rectangle),
13399
+ scaleX = new Point(matrix._a, matrix._c).getLength(),
13400
+ scaleY = new Point(matrix._b, matrix._d).getLength(),
13401
+ ratios = [
13402
+ size.width / bounds.width * scaleX,
13403
+ size.height / bounds.height * scaleY
13404
+ ].filter(function(ratio) {
13405
+ return ratio > 0 && isFinite(ratio);
13406
+ });
13407
+ this.setCenter(rectangle.getCenter());
13408
+ if (ratios.length) {
13409
+ var amount = fit === 'cover'
13410
+ ? Math.max.apply(Math, ratios)
13411
+ : Math.min.apply(Math, ratios);
13412
+ matrix.prepend(new Matrix().scale(
13413
+ new Point(amount / scaleX, amount / scaleY),
13414
+ size.divide(2)));
13415
+ }
13416
+ },
13417
+
13199
13418
  scrollBy: function() {
13200
13419
  this.translate(Point.read(arguments).negate());
13201
13420
  }
@@ -13210,7 +13429,17 @@ var View = Base.extend(Emitter, {
13210
13429
  },
13211
13430
 
13212
13431
  getEventPoint: function(event) {
13213
- return this.viewToProject(DomEvent.getOffset(event, this._element));
13432
+ var element = this._element,
13433
+ offset = DomEvent.getOffset(event, element),
13434
+ size = DomElement.getSize(element);
13435
+ if (!size.isZero()) {
13436
+ var cssSize = new Size(element.offsetWidth, element.offsetHeight);
13437
+ offset = offset.multiply(cssSize.divide(size))
13438
+ .subtract(DomElement.getInsets(element, true))
13439
+ .multiply(this.getViewSize().divide(
13440
+ cssSize.subtract(DomElement.getInsets(element))));
13441
+ }
13442
+ return this.viewToProject(offset);
13214
13443
  },
13215
13444
 
13216
13445
  }, {
@@ -13280,16 +13509,8 @@ new function() {
13280
13509
  mouseout: function(event) {
13281
13510
  var view = View._focused,
13282
13511
  target = DomEvent.getRelatedTarget(event);
13283
- if (view && (!target || target.nodeName === 'HTML')) {
13284
- var offset = DomEvent.getOffset(event, view._element),
13285
- x = offset.x,
13286
- abs = Math.abs,
13287
- ax = abs(x),
13288
- max = 1 << 25,
13289
- diff = ax - max;
13290
- offset.x = abs(diff) < ax ? diff * (x < 0 ? -1 : 1) : x;
13291
- handleMouseMove(view, event, view.viewToProject(offset));
13292
- }
13512
+ if (view && (!target || target.nodeName === 'HTML'))
13513
+ handleMouseMove(view, event);
13293
13514
  },
13294
13515
 
13295
13516
  scroll: updateFocus
@@ -13484,9 +13705,12 @@ new function() {
13484
13705
  if (mouse.down && inView || mouse.up && downPoint) {
13485
13706
  emitMouseEvents(this, hitItem, type, event, point, downPoint);
13486
13707
  if (mouse.down) {
13487
- dblClick = hitItem === clickItem
13488
- && (Date.now() - clickTime < 300);
13708
+ var time = Date.now();
13709
+ dblClick = !dblClick && hitItem === clickItem
13710
+ && time - clickTime < 300
13711
+ && point.getDistance(downPoint) < 3;
13489
13712
  downItem = clickItem = hitItem;
13713
+ clickTime = time;
13490
13714
  if (!prevented && hitItem) {
13491
13715
  var item = hitItem;
13492
13716
  while (item && !item.responds('mousedrag'))
@@ -13497,10 +13721,8 @@ new function() {
13497
13721
  downPoint = point;
13498
13722
  } else if (mouse.up) {
13499
13723
  if (!prevented && hitItem === downItem) {
13500
- clickTime = Date.now();
13501
13724
  emitMouseEvents(this, hitItem, dblClick ? 'doubleclick'
13502
13725
  : 'click', event, point, downPoint);
13503
- dblClick = false;
13504
13726
  }
13505
13727
  downItem = dragItem = null;
13506
13728
  }
@@ -13602,9 +13824,13 @@ var CanvasView = View.extend({
13602
13824
  var element = this._element,
13603
13825
  ctx = this._context;
13604
13826
  if (!PaperScope.hasAttribute(element, 'resize')) {
13605
- var style = element.style;
13606
- style.width = width + 'px';
13607
- style.height = height + 'px';
13827
+ var style = element.style,
13828
+ insets = DomElement.getStyles(element).boxSizing
13829
+ === 'border-box'
13830
+ ? DomElement.getInsets(element)
13831
+ : new Size();
13832
+ style.width = (width + insets.width) + 'px';
13833
+ style.height = (height + insets.height) + 'px';
13608
13834
  }
13609
13835
  ctx.restore();
13610
13836
  ctx.save();
@@ -13631,19 +13857,22 @@ var CanvasView = View.extend({
13631
13857
  return pixels;
13632
13858
  },
13633
13859
 
13634
- getTextWidth: function(font, lines) {
13860
+ getTextWidth: function(font, lines, letterSpacing) {
13635
13861
  var ctx = this._context,
13636
13862
  prevFont = ctx.font,
13863
+ prevLetterSpacing = ctx.letterSpacing,
13637
13864
  width = 0;
13638
13865
  ctx.font = font;
13866
+ ctx.letterSpacing = letterSpacing;
13639
13867
  for (var i = 0, l = lines.length; i < l; i++)
13640
13868
  width = Math.max(width, ctx.measureText(lines[i]).width);
13641
13869
  ctx.font = prevFont;
13870
+ ctx.letterSpacing = prevLetterSpacing;
13642
13871
  return width;
13643
13872
  },
13644
13873
 
13645
- update: function() {
13646
- if (!this._needsUpdate)
13874
+ update: function(force) {
13875
+ if (!this._needsUpdate && !force)
13647
13876
  return false;
13648
13877
  var project = this._project,
13649
13878
  ctx = this._context,
@@ -13714,6 +13943,7 @@ var Key = new function() {
13714
13943
  var keyLookup = {
13715
13944
  '\t': 'tab',
13716
13945
  ' ': 'space',
13946
+ '\xA0': 'space',
13717
13947
  '\b': 'backspace',
13718
13948
  '\x7f': 'delete',
13719
13949
  'Spacebar': 'space',
@@ -13768,6 +13998,7 @@ var Key = new function() {
13768
13998
  }
13769
13999
 
13770
14000
  function handleKey(down, key, character, event) {
14001
+ View.updateFocus();
13771
14002
  var type = down ? 'keydown' : 'keyup',
13772
14003
  view = View._focused,
13773
14004
  name;
@@ -13802,11 +14033,9 @@ var Key = new function() {
13802
14033
 
13803
14034
  DomEvent.add(document, {
13804
14035
  keydown: function(event) {
13805
- var key = getKey(event),
13806
- agent = paper && paper.agent;
13807
- if (key.length > 1 || agent && (agent.chrome && (event.altKey
13808
- || agent.mac && event.metaKey
13809
- || !agent.mac && event.ctrlKey))) {
14036
+ var key = getKey(event);
14037
+ if (key.length > 1 || event.ctrlKey || event.altKey
14038
+ || event.metaKey) {
13810
14039
  handleKey(true, key,
13811
14040
  charLookup[key] || (key.length > 1 ? '' : key), event);
13812
14041
  } else {
@@ -14140,6 +14369,48 @@ var Tween = Base.extend(Emitter, {
14140
14369
  return t < 0.5
14141
14370
  ? 16 * t * t * t * t * t
14142
14371
  : 1 + 16 * (--t) * t * t * t * t;
14372
+ },
14373
+
14374
+ easeInSine: function(t) {
14375
+ return 1 - Math.cos(t * Math.PI / 2);
14376
+ },
14377
+
14378
+ easeOutSine: function(t) {
14379
+ return Math.sin(t * Math.PI / 2);
14380
+ },
14381
+
14382
+ easeInOutSine: function(t) {
14383
+ return (1 - Math.cos(t * Math.PI)) / 2;
14384
+ },
14385
+
14386
+ easeInExpo: function(t) {
14387
+ return t === 0 ? 0 : Math.pow(2, 10 * t - 10);
14388
+ },
14389
+
14390
+ easeOutExpo: function(t) {
14391
+ return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
14392
+ },
14393
+
14394
+ easeInOutExpo: function(t) {
14395
+ return t === 0 || t === 1
14396
+ ? t
14397
+ : t < 0.5
14398
+ ? Math.pow(2, 20 * t - 10) / 2
14399
+ : 1 - Math.pow(2, 10 - 20 * t) / 2;
14400
+ },
14401
+
14402
+ easeInCirc: function(t) {
14403
+ return 1 - Math.sqrt(1 - t * t);
14404
+ },
14405
+
14406
+ easeOutCirc: function(t) {
14407
+ return Math.sqrt(1 - (--t) * t);
14408
+ },
14409
+
14410
+ easeInOutCirc: function(t) {
14411
+ return t < 0.5
14412
+ ? (1 - Math.sqrt(1 - 4 * t * t)) / 2
14413
+ : (1 + Math.sqrt(1 - 4 * (--t) * t)) / 2;
14143
14414
  }
14144
14415
  })
14145
14416
  },
@@ -14360,7 +14631,7 @@ var CanvasProvider = Base.exports.CanvasProvider = {
14360
14631
  canvases: [],
14361
14632
 
14362
14633
  getCanvas: function(width, height, options) {
14363
- if (!window)
14634
+ if (!window && !self.OffscreenCanvas)
14364
14635
  return null;
14365
14636
  var canvas,
14366
14637
  clear = true;
@@ -14371,7 +14642,9 @@ var CanvasProvider = Base.exports.CanvasProvider = {
14371
14642
  if (this.canvases.length) {
14372
14643
  canvas = this.canvases.pop();
14373
14644
  } else {
14374
- canvas = document.createElement('canvas');
14645
+ canvas = window
14646
+ ? document.createElement('canvas')
14647
+ : new self.OffscreenCanvas(width, height);
14375
14648
  clear = false;
14376
14649
  }
14377
14650
  var ctx = canvas.getContext('2d', options || {});
@@ -14575,6 +14848,12 @@ var BlendMode = new function() {
14575
14848
  db = (bb + sb) / 2;
14576
14849
  },
14577
14850
 
14851
+ 'pin-light': function() {
14852
+ dr = sr < 128 ? min(br, 2 * sr) : max(br, 2 * sr - 255);
14853
+ dg = sg < 128 ? min(bg, 2 * sg) : max(bg, 2 * sg - 255);
14854
+ db = sb < 128 ? min(bb, 2 * sb) : max(bb, 2 * sb - 255);
14855
+ },
14856
+
14578
14857
  negation: function() {
14579
14858
  dr = 255 - abs(255 - sr - br);
14580
14859
  dg = 255 - abs(255 - sg - bg);
@@ -14673,7 +14952,8 @@ var SvgElement = new function() {
14673
14952
  function get(node, name) {
14674
14953
  var namespace = attributeNamespace[name],
14675
14954
  value = namespace
14676
- ? node.getAttributeNS(namespace, name)
14955
+ ? node.getAttribute(name)
14956
+ || node.getAttributeNS(namespace, name)
14677
14957
  : node.getAttribute(name);
14678
14958
  return value === 'null' ? null : value;
14679
14959
  }
@@ -14726,6 +15006,7 @@ var SvgStyles = Base.each({
14726
15006
  fontFamily: ['font-family', 'string'],
14727
15007
  fontWeight: ['font-weight', 'string'],
14728
15008
  fontSize: ['font-size', 'number'],
15009
+ tracking: ['letter-spacing', 'tracking'],
14729
15010
  justification: ['text-anchor', 'lookup', {
14730
15011
  left: 'start',
14731
15012
  center: 'middle',
@@ -14751,7 +15032,8 @@ var SvgStyles = Base.each({
14751
15032
  }, {});
14752
15033
 
14753
15034
  new function() {
14754
- var formatter;
15035
+ var formatter,
15036
+ parentStyles;
14755
15037
 
14756
15038
  function getTransform(matrix, coordinates, center) {
14757
15039
  var attrs = new Base(),
@@ -14800,34 +15082,72 @@ new function() {
14800
15082
  var node = SvgElement.create('g', attrs, formatter);
14801
15083
  for (var i = 0, l = children.length; i < l; i++) {
14802
15084
  var child = children[i];
14803
- var childNode = exportSVG(child, options);
14804
- if (childNode) {
14805
- if (child.isClipMask()) {
14806
- var clip = SvgElement.create('clipPath');
14807
- clip.appendChild(childNode);
14808
- setDefinition(child, clip, 'clip');
14809
- SvgElement.set(node, {
14810
- 'clip-path': 'url(#' + clip.id + ')'
14811
- });
14812
- } else {
15085
+ if (child.isClipMask()) {
15086
+ var clip = exportClip(child, options);
15087
+ setDefinition(child, clip, 'clip', options);
15088
+ SvgElement.set(node, {
15089
+ 'clip-path': 'url(#' + clip.id + ')'
15090
+ });
15091
+ } else {
15092
+ var childNode = exportSVG(child, options);
15093
+ if (childNode)
14813
15094
  node.appendChild(childNode);
14814
- }
14815
15095
  }
14816
15096
  }
14817
15097
  return node;
14818
15098
  }
14819
15099
 
15100
+ function exportClip(item, options) {
15101
+ var clip = SvgElement.create('clipPath');
15102
+
15103
+ function addItem(item) {
15104
+ if (item instanceof Group) {
15105
+ var children = item._children;
15106
+ for (var i = 0, l = children.length; i < l; i++) {
15107
+ if (!children[i]._clipMask)
15108
+ addItem(children[i]);
15109
+ }
15110
+ } else {
15111
+ var node = exportSVG(item, options);
15112
+ if (node)
15113
+ clip.appendChild(node);
15114
+ }
15115
+ }
15116
+
15117
+ if (item instanceof Group) {
15118
+ item = item.clone({ insert: false });
15119
+ item.matrix.apply(true, true);
15120
+ }
15121
+ addItem(item);
15122
+ return clip;
15123
+ }
15124
+
14820
15125
  function exportRaster(item, options) {
14821
15126
  var attrs = getTransform(item._matrix, true),
14822
15127
  size = item.getSize(),
14823
- image = item.getImage();
15128
+ image = item.getImage(),
15129
+ href = options.embedImages == false && image && image.src
15130
+ || item.toDataURL();
14824
15131
  attrs.x -= size.width / 2;
14825
15132
  attrs.y -= size.height / 2;
14826
- attrs.width = size.width;
14827
- attrs.height = size.height;
14828
- attrs.href = options.embedImages == false && image && image.src
14829
- || item.toDataURL();
14830
- return SvgElement.create('image', attrs, formatter);
15133
+ if (options.reuseImages) {
15134
+ var node = getDefinition(href, 'image');
15135
+ if (!node) {
15136
+ node = SvgElement.create('image', {
15137
+ width: size.width,
15138
+ height: size.height,
15139
+ href: href
15140
+ }, formatter);
15141
+ setDefinition(href, node, 'image', options);
15142
+ }
15143
+ attrs.href = '#' + node.id;
15144
+ return SvgElement.create('use', attrs, formatter);
15145
+ } else {
15146
+ attrs.width = size.width;
15147
+ attrs.height = size.height;
15148
+ attrs.href = href;
15149
+ return SvgElement.create('image', attrs, formatter);
15150
+ }
14831
15151
  }
14832
15152
 
14833
15153
  function exportPath(item, options) {
@@ -14913,7 +15233,7 @@ new function() {
14913
15233
  viewBox: formatter.rectangle(bounds)
14914
15234
  });
14915
15235
  node.appendChild(exportSVG(definitionItem, options));
14916
- setDefinition(definition, node, 'symbol');
15236
+ setDefinition(definition, node, 'symbol', options);
14917
15237
  }
14918
15238
  attrs.href = '#' + node.id;
14919
15239
  attrs.x += bounds.x;
@@ -14924,7 +15244,7 @@ new function() {
14924
15244
  return SvgElement.create('use', attrs, formatter);
14925
15245
  }
14926
15246
 
14927
- function exportGradient(color) {
15247
+ function exportGradient(color, options) {
14928
15248
  var gradientNode = getDefinition(color, 'color');
14929
15249
  if (!gradientNode) {
14930
15250
  var gradient = color.getGradient(),
@@ -14970,15 +15290,28 @@ new function() {
14970
15290
  gradientNode.appendChild(
14971
15291
  SvgElement.create('stop', attrs, formatter));
14972
15292
  }
14973
- setDefinition(color, gradientNode, 'color');
15293
+ setDefinition(color, gradientNode, 'color', options);
14974
15294
  }
14975
15295
  return 'url(#' + gradientNode.id + ')';
14976
15296
  }
14977
15297
 
14978
15298
  function exportText(item) {
14979
- var node = SvgElement.create('text', getTransform(item._matrix, true),
14980
- formatter);
14981
- node.textContent = item._content;
15299
+ var attrs = getTransform(item._matrix, true),
15300
+ node = SvgElement.create('text', attrs, formatter),
15301
+ lines = item._lines;
15302
+ if (lines.length > 1) {
15303
+ var leading = item._style.getLeading();
15304
+ for (var i = 0, l = lines.length; i < l; i++) {
15305
+ var span = SvgElement.create('tspan', {
15306
+ x: attrs.x,
15307
+ y: attrs.y + i * leading
15308
+ }, formatter);
15309
+ span.textContent = lines[i];
15310
+ node.appendChild(span);
15311
+ }
15312
+ } else {
15313
+ node.textContent = item._content;
15314
+ }
14982
15315
  return node;
14983
15316
  }
14984
15317
 
@@ -14996,6 +15329,8 @@ new function() {
14996
15329
  function applyStyle(item, node, options, isRoot) {
14997
15330
  var attrs = {},
14998
15331
  parent = !isRoot && item.getParent(),
15332
+ parentStyle = parent && (parentStyles[parent._id] =
15333
+ parentStyles[parent._id] || {}),
14999
15334
  style = [];
15000
15335
 
15001
15336
  if (item._name != null)
@@ -15005,10 +15340,12 @@ new function() {
15005
15340
  var get = entry.get,
15006
15341
  type = entry.type,
15007
15342
  value = item[get]();
15008
- if (entry.exportFilter
15343
+ if (parent && !(get in parentStyle))
15344
+ parentStyle[get] = parent[get]();
15345
+ if (value !== undefined && (entry.exportFilter
15009
15346
  ? entry.exportFilter(item, value)
15010
15347
  : options.reduceAttributes == false
15011
- || !parent || !Base.equals(parent[get](), value)) {
15348
+ || !parent || !Base.equals(parentStyle[get], value))) {
15012
15349
  if (type === 'color' && value != null) {
15013
15350
  var alpha = value.getAlpha();
15014
15351
  if (alpha < 1)
@@ -15019,10 +15356,11 @@ new function() {
15019
15356
  } else {
15020
15357
  attrs[entry.attribute] = value == null ? 'none'
15021
15358
  : type === 'color' ? value.gradient
15022
- ? exportGradient(value, item)
15359
+ ? exportGradient(value, options)
15023
15360
  : value.toCSS(true)
15024
15361
  : type === 'array' ? value.join(',')
15025
15362
  : type === 'lookup' ? entry.toSVG[value]
15363
+ : type === 'tracking' ? value && value / 1000 + 'em'
15026
15364
  : value;
15027
15365
  }
15028
15366
  }
@@ -15044,16 +15382,20 @@ new function() {
15044
15382
  function getDefinition(item, type) {
15045
15383
  if (!definitions)
15046
15384
  definitions = { ids: {}, svgs: {} };
15047
- return item && definitions.svgs[type + '-'
15048
- + (item._id || item.__id || (item.__id = UID.get('svg')))];
15385
+ return item && definitions.svgs[getDefinitionKey(item, type)];
15049
15386
  }
15050
15387
 
15051
- function setDefinition(item, node, type) {
15388
+ function setDefinition(item, node, type, options) {
15052
15389
  if (!definitions)
15053
15390
  getDefinition();
15054
15391
  var typeId = definitions.ids[type] = (definitions.ids[type] || 0) + 1;
15055
- node.id = type + '-' + typeId;
15056
- definitions.svgs[type + '-' + (item._id || item.__id)] = node;
15392
+ node.id = (options.idPrefix || '') + type + '-' + typeId;
15393
+ definitions.svgs[getDefinitionKey(item, type)] = node;
15394
+ }
15395
+
15396
+ function getDefinitionKey(item, type) {
15397
+ return type + '-' + (typeof item === 'string' ? item
15398
+ : item._id || item.__id || (item.__id = UID.get('svg')));
15057
15399
  }
15058
15400
 
15059
15401
  function exportDefinitions(node, options) {
@@ -15074,6 +15416,7 @@ new function() {
15074
15416
  }
15075
15417
  definitions = null;
15076
15418
  }
15419
+ parentStyles = null;
15077
15420
  return options.asString
15078
15421
  ? new self.XMLSerializer().serializeToString(svg)
15079
15422
  : svg;
@@ -15097,6 +15440,7 @@ new function() {
15097
15440
  if (!options)
15098
15441
  options = {};
15099
15442
  formatter = new Formatter(options.precision);
15443
+ parentStyles = {};
15100
15444
  return options;
15101
15445
  }
15102
15446
 
@@ -15149,7 +15493,14 @@ new function() {
15149
15493
  new function() {
15150
15494
 
15151
15495
  var definitions = {},
15152
- rootSize;
15496
+ rootSize,
15497
+ units = { 'in': 96, pt: 96 / 72, pc: 96 / 6, cm: 96 / 2.54,
15498
+ mm: 96 / 25.4 };
15499
+
15500
+ function parseLength(value) {
15501
+ var unit = /(in|pt|pc|cm|mm)\s*$/.exec(value);
15502
+ return parseFloat(value) * (unit ? units[unit[1]] : 1);
15503
+ }
15153
15504
 
15154
15505
  function getValue(node, name, isString, allowNull, allowPercent,
15155
15506
  defaultValue) {
@@ -15160,7 +15511,7 @@ new function() {
15160
15511
  : isString ? '' : 0
15161
15512
  : isString
15162
15513
  ? value
15163
- : parseFloat(value);
15514
+ : parseLength(value);
15164
15515
  return /%\s*$/.test(value)
15165
15516
  ? (res / 100) * (allowPercent ? 1
15166
15517
  : rootSize[/x|^width/.test(name) ? 'width' : 'height'])
@@ -15181,12 +15532,12 @@ new function() {
15181
15532
  : new Size(w, h);
15182
15533
  }
15183
15534
 
15184
- function convertValue(value, type, lookup) {
15535
+ function convertValue(value, type, lookup, options) {
15185
15536
  return value === 'none' ? null
15186
- : type === 'number' ? parseFloat(value)
15537
+ : type === 'number' ? parseLength(value)
15187
15538
  : type === 'array' ?
15188
- value ? value.split(/[\s,]+/g).map(parseFloat) : []
15189
- : type === 'color' ? getDefinition(value) || value
15539
+ value ? value.split(/[\s,]+/g).map(parseLength) : []
15540
+ : type === 'color' ? getDefinition(value, options) || value
15190
15541
  : type === 'lookup' ? lookup[value]
15191
15542
  : value;
15192
15543
  }
@@ -15198,11 +15549,17 @@ new function() {
15198
15549
  item = new Group(),
15199
15550
  project = item._project,
15200
15551
  currentStyle = project._currentStyle,
15552
+ parentSize = rootSize,
15201
15553
  children = [];
15202
15554
  if (!isClip && !isDefs) {
15203
- item = applyAttributes(item, node, isRoot);
15555
+ item = applyAttributes(item, node, options, isRoot);
15204
15556
  project._currentStyle = item._style.clone();
15205
15557
  }
15558
+ if (type === 'svg' && !isRoot) {
15559
+ rootSize = new Size(
15560
+ getValue(node, 'width', false, false, false, '100%'),
15561
+ getValue(node, 'height', false, false, false, '100%'));
15562
+ }
15206
15563
  if (isRoot) {
15207
15564
  var defs = node.querySelectorAll('defs');
15208
15565
  for (var i = 0, l = defs.length; i < l; i++) {
@@ -15220,8 +15577,9 @@ new function() {
15220
15577
  }
15221
15578
  item.addChildren(children);
15222
15579
  if (isClip)
15223
- item = applyAttributes(item.reduce(), node, isRoot);
15580
+ item = applyAttributes(item.reduce(), node, options, isRoot);
15224
15581
  project._currentStyle = currentStyle;
15582
+ rootSize = parentSize;
15225
15583
  if (isClip || isDefs) {
15226
15584
  item.remove();
15227
15585
  item = null;
@@ -15247,12 +15605,13 @@ new function() {
15247
15605
  return PathItem.create(node.getAttribute('d'));
15248
15606
  }
15249
15607
 
15250
- function importGradient(node, type) {
15608
+ function importGradient(node, type, options) {
15251
15609
  var id = (getValue(node, 'href', true) || '').substring(1),
15610
+ definition = getDefinitionById(id, options),
15252
15611
  radial = type === 'radialgradient',
15253
15612
  gradient;
15254
- if (id) {
15255
- gradient = definitions[id].getGradient();
15613
+ if (definition) {
15614
+ gradient = definition.getGradient();
15256
15615
  if (gradient._radial ^ radial) {
15257
15616
  gradient = gradient.clone();
15258
15617
  gradient._radial = radial;
@@ -15263,7 +15622,8 @@ new function() {
15263
15622
  for (var i = 0, l = nodes.length; i < l; i++) {
15264
15623
  var child = nodes[i];
15265
15624
  if (child.nodeType === 1)
15266
- stops.push(applyAttributes(new GradientStop(), child));
15625
+ stops.push(applyAttributes(new GradientStop(), child,
15626
+ options));
15267
15627
  }
15268
15628
  gradient = new Gradient(stops, radial);
15269
15629
  }
@@ -15283,7 +15643,8 @@ new function() {
15283
15643
  '100%', '0%');
15284
15644
  }
15285
15645
  var color = applyAttributes(
15286
- new Color(gradient, origin, destination, highlight), node);
15646
+ new Color(gradient, origin, destination, highlight), node,
15647
+ options);
15287
15648
  color._scaleToBounds = scaleToBounds;
15288
15649
  return null;
15289
15650
  }
@@ -15306,13 +15667,30 @@ new function() {
15306
15667
  lineargradient: importGradient,
15307
15668
  radialgradient: importGradient,
15308
15669
 
15309
- image: function (node) {
15310
- var raster = new Raster(getValue(node, 'href', true));
15670
+ image: function (node, type, options) {
15671
+ var raster = new Raster({
15672
+ crossOrigin: options.crossOrigin,
15673
+ source: getValue(node, 'href', true)
15674
+ }),
15675
+ align = /none|x(Min|Mid|Max)Y(Min|Mid|Max)/.exec(
15676
+ getValue(node, 'preserveAspectRatio', true))
15677
+ || [null, 'Mid', 'Mid'];
15311
15678
  raster.on('load', function() {
15312
- var size = getSize(node);
15313
- this.setSize(size);
15314
- var center = getPoint(node).add(size.divide(2));
15315
- this._matrix.append(new Matrix().translate(center));
15679
+ var imageSize = this.getSize(),
15680
+ size = getSize(node, null, null, true) || imageSize,
15681
+ point = getPoint(node);
15682
+ if (align[0] !== 'none') {
15683
+ var factors = { Min: 0, Mid: 0.5, Max: 1 },
15684
+ fitted = imageSize.multiply(Math.min(
15685
+ size.width / imageSize.width,
15686
+ size.height / imageSize.height));
15687
+ point = point.add(size.subtract(fitted).multiply(
15688
+ [factors[align[1]], factors[align[2]]]));
15689
+ size = fitted;
15690
+ }
15691
+ var center = point.add(size.divide(2));
15692
+ this._matrix.append(new Matrix().translate(center)
15693
+ .scale(size.divide(imageSize)));
15316
15694
  });
15317
15695
  return raster;
15318
15696
  },
@@ -15324,13 +15702,17 @@ new function() {
15324
15702
 
15325
15703
  defs: importGroup,
15326
15704
 
15327
- use: function(node) {
15705
+ use: function(node, type, options) {
15328
15706
  var id = (getValue(node, 'href', true) || '').substring(1),
15329
- definition = definitions[id],
15707
+ definition = getDefinitionById(id, options),
15330
15708
  point = getPoint(node);
15331
15709
  return definition
15332
15710
  ? definition instanceof SymbolDefinition
15333
15711
  ? definition.place(point)
15712
+ : definition instanceof Raster
15713
+ ? importNode(getSandbox().ownerDocument
15714
+ .getElementById(id), options, false)
15715
+ .translate(point)
15334
15716
  : definition.clone().translate(point)
15335
15717
  : null;
15336
15718
  },
@@ -15349,11 +15731,16 @@ new function() {
15349
15731
  },
15350
15732
 
15351
15733
  rect: function(node) {
15734
+ var rx = getValue(node, 'rx', false, true),
15735
+ ry = getValue(node, 'ry', false, true);
15352
15736
  return new Shape.Rectangle(new Rectangle(
15353
15737
  getPoint(node),
15354
15738
  getSize(node)
15355
- ), getSize(node, 'rx', 'ry'));
15356
- },
15739
+ ), new Size(
15740
+ rx == null ? ry || 0 : rx,
15741
+ ry == null ? rx || 0 : ry
15742
+ ));
15743
+ },
15357
15744
 
15358
15745
  line: function(node) {
15359
15746
  return new Path.Line(
@@ -15363,8 +15750,14 @@ new function() {
15363
15750
 
15364
15751
  text: function(node) {
15365
15752
  var text = new PointText(getPoint(node).add(
15366
- getPoint(node, 'dx', 'dy')));
15367
- text.setContent(node.textContent.trim() || '');
15753
+ getPoint(node, 'dx', 'dy'))),
15754
+ lines = Base.each(node.childNodes, function(child) {
15755
+ if (/^tspan$/i.test(child.nodeName)
15756
+ && child.hasAttribute('y'))
15757
+ this.push(child.textContent.trim());
15758
+ }, []);
15759
+ text.setContent(lines.length > 1 ? lines.join('\n')
15760
+ : node.textContent.trim());
15368
15761
  return text;
15369
15762
  },
15370
15763
 
@@ -15418,9 +15811,11 @@ new function() {
15418
15811
  }
15419
15812
 
15420
15813
  var attributes = Base.set(Base.each(SvgStyles, function(entry) {
15421
- this[entry.attribute] = function(item, value) {
15814
+ this[entry.attribute] = function(item, value, name, node, styles,
15815
+ options) {
15422
15816
  if (item[entry.set]) {
15423
- item[entry.set](convertValue(value, entry.type, entry.fromSVG));
15817
+ item[entry.set](convertValue(value, entry.type, entry.fromSVG,
15818
+ options));
15424
15819
  if (entry.type === 'color') {
15425
15820
  var color = item[entry.get]();
15426
15821
  if (color) {
@@ -15437,12 +15832,12 @@ new function() {
15437
15832
  }, {}), {
15438
15833
  id: function(item, value) {
15439
15834
  definitions[value] = item;
15440
- if (item.setName)
15835
+ if (item.setName && value !== (+value) + '')
15441
15836
  item.setName(value);
15442
15837
  },
15443
15838
 
15444
- 'clip-path': function(item, value) {
15445
- var clip = getDefinition(value);
15839
+ 'clip-path': function(item, value, name, node, styles, options) {
15840
+ var clip = getDefinition(value, options);
15446
15841
  if (clip) {
15447
15842
  clip = clip.clone();
15448
15843
  clip.setClipMask(true);
@@ -15470,6 +15865,14 @@ new function() {
15470
15865
  item.setVisible(value !== null);
15471
15866
  },
15472
15867
 
15868
+ 'letter-spacing': function(item, value) {
15869
+ if (item.setTracking) {
15870
+ var amount = parseFloat(value) || 0;
15871
+ item.setTracking(1000 * (/em$/.test(value) ? amount
15872
+ : amount / parseFloat(item.getFontSize())));
15873
+ }
15874
+ },
15875
+
15473
15876
  'stop-color': function(item, value) {
15474
15877
  if (item.setColor)
15475
15878
  item.setColor(value);
@@ -15515,12 +15918,13 @@ new function() {
15515
15918
  });
15516
15919
 
15517
15920
  function getAttribute(node, name, styles) {
15518
- var attr = node.attributes[name],
15921
+ var style = Base.camelize(name),
15922
+ value = node.style && node.style[style];
15923
+ if (!value) {
15924
+ var attr = node.attributes[name];
15519
15925
  value = attr && attr.value;
15520
- if (!value && node.style) {
15521
- var style = Base.camelize(name);
15522
- value = node.style[style];
15523
- if (!value && styles.node[style] !== styles.parent[style])
15926
+ if (!value && node.style
15927
+ && styles.node[style] !== styles.parent[style])
15524
15928
  value = styles.node[style];
15525
15929
  }
15526
15930
  return !value ? undefined
@@ -15528,27 +15932,38 @@ new function() {
15528
15932
  : value;
15529
15933
  }
15530
15934
 
15531
- function applyAttributes(item, node, isRoot) {
15935
+ function applyAttributes(item, node, options, isRoot) {
15532
15936
  var parent = node.parentNode,
15533
15937
  styles = {
15534
15938
  node: DomElement.getStyles(node) || {},
15535
15939
  parent: !isRoot && !/^defs$/i.test(parent.tagName)
15536
15940
  && DomElement.getStyles(parent) || {}
15537
15941
  };
15942
+ if (isRoot && !styles.node.fill && item.setFillColor)
15943
+ item.setFillColor('black');
15538
15944
  Base.each(attributes, function(apply, name) {
15539
15945
  var value = getAttribute(node, name, styles);
15540
15946
  item = value !== undefined
15541
- && apply(item, value, name, node, styles) || item;
15947
+ && apply(item, value, name, node, styles, options) || item;
15542
15948
  });
15543
15949
  return item;
15544
15950
  }
15545
15951
 
15546
- function getDefinition(value) {
15952
+ function getDefinitionById(id, options) {
15953
+ if (id && !definitions[id]) {
15954
+ var node = getSandbox().ownerDocument.getElementById(id);
15955
+ if (node)
15956
+ importNode(node, options, false);
15957
+ }
15958
+ return definitions[id];
15959
+ }
15960
+
15961
+ function getDefinition(value, options) {
15547
15962
  var match = value && value.match(/\((?:["'#]*)([^"')]+)/),
15548
15963
  name = match && match[1],
15549
- res = name && definitions[window
15964
+ res = name && getDefinitionById(window
15550
15965
  ? name.replace(window.location.href.split('#')[0] + '#', '')
15551
- : name];
15966
+ : name, options);
15552
15967
  if (res && res._scaleToBounds) {
15553
15968
  res = res.clone();
15554
15969
  res._scaleToBounds = true;
@@ -15594,12 +16009,12 @@ new function() {
15594
16009
  var settings = paper.settings,
15595
16010
  applyMatrix = settings.applyMatrix,
15596
16011
  insertItems = settings.insertItems,
16012
+ importer = importers[type],
15597
16013
  item;
15598
16014
  try {
15599
16015
  settings.applyMatrix = false;
15600
16016
  settings.insertItems = false;
15601
16017
  try {
15602
- var importer = importers[type];
15603
16018
  item = importer && importer(node, type, options, isRoot)
15604
16019
  || null;
15605
16020
  } finally {
@@ -15607,8 +16022,8 @@ new function() {
15607
16022
  settings.applyMatrix = applyMatrix;
15608
16023
  }
15609
16024
  if (item) {
15610
- if (isElement && !(item instanceof Group))
15611
- item = applyAttributes(item, node, isRoot);
16025
+ if (isElement && importer !== importGroup)
16026
+ item = applyAttributes(item, node, options, isRoot);
15612
16027
  var onImport = options.onImport,
15613
16028
  data = isElement && node.getAttribute('data-paper-data');
15614
16029
  if (onImport)
@@ -15748,4 +16163,4 @@ if (typeof define === 'function' && define.amd) {
15748
16163
  }
15749
16164
 
15750
16165
  return paper;
15751
- }.call(this, typeof self === 'object' ? self : null);
16166
+ }(typeof self === 'object' ? self : null);