paper 0.13.0 → 0.14.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 (50) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/README.md +16 -13
  3. package/dist/docs/assets/js/paper.js +434 -128
  4. package/dist/docs/classes/ChangeFlag.html +384 -0
  5. package/dist/docs/classes/Color.html +1 -1
  6. package/dist/docs/classes/CompoundPath.html +58 -4
  7. package/dist/docs/classes/Curve.html +1 -1
  8. package/dist/docs/classes/CurveLocation.html +1 -1
  9. package/dist/docs/classes/Event.html +1 -1
  10. package/dist/docs/classes/Gradient.html +1 -1
  11. package/dist/docs/classes/GradientStop.html +1 -1
  12. package/dist/docs/classes/Group.html +89 -4
  13. package/dist/docs/classes/HitResult.html +3 -2
  14. package/dist/docs/classes/HostItem.html +6721 -0
  15. package/dist/docs/classes/Item.html +58 -4
  16. package/dist/docs/classes/Key.html +1 -1
  17. package/dist/docs/classes/KeyEvent.html +1 -1
  18. package/dist/docs/classes/Layer.html +89 -4
  19. package/dist/docs/classes/Matrix.html +1 -1
  20. package/dist/docs/classes/MouseEvent.html +1 -1
  21. package/dist/docs/classes/PaperScope.html +2 -1
  22. package/dist/docs/classes/PaperScript.html +2 -1
  23. package/dist/docs/classes/Path.html +59 -5
  24. package/dist/docs/classes/PathItem.html +58 -4
  25. package/dist/docs/classes/Point.html +1 -1
  26. package/dist/docs/classes/PointText.html +58 -4
  27. package/dist/docs/classes/Project.html +188 -1
  28. package/dist/docs/classes/Raster.html +58 -4
  29. package/dist/docs/classes/Rectangle.html +1 -1
  30. package/dist/docs/classes/Segment.html +1 -1
  31. package/dist/docs/classes/Shape.html +58 -4
  32. package/dist/docs/classes/Size.html +1 -1
  33. package/dist/docs/classes/Style.html +2 -2
  34. package/dist/docs/classes/SymbolDefinition.html +1 -1
  35. package/dist/docs/classes/SymbolItem.html +58 -4
  36. package/dist/docs/classes/TextItem.html +58 -4
  37. package/dist/docs/classes/Tool.html +126 -1
  38. package/dist/docs/classes/ToolEvent.html +1 -1
  39. package/dist/docs/classes/Tween.html +1 -1
  40. package/dist/docs/classes/View.html +144 -2
  41. package/dist/docs/classes/global.html +1 -1
  42. package/dist/docs/classes/index.html +2 -2
  43. package/dist/docs/index.html +1 -1
  44. package/dist/paper-core.js +425 -123
  45. package/dist/paper-core.min.js +3 -3
  46. package/dist/paper-full.js +434 -128
  47. package/dist/paper-full.min.js +3 -3
  48. package/dist/paper-sourced.js +18631 -0
  49. package/dist/paper.d.ts +284 -7
  50. package/package.json +6 -10
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Paper.js v0.13.0 - The Swiss Army Knife of Vector Graphics Scripting.
2
+ * Paper.js v0.14.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: Mon Oct 19 15:31:53 2026 +0200
12
+ * Date: Tue Oct 20 01:20:31 2026 +0200
13
13
  *
14
14
  ***
15
15
  *
@@ -780,7 +780,8 @@ var PaperScope = Base.extend({
780
780
  applyMatrix: true,
781
781
  insertItems: true,
782
782
  handleSize: 4,
783
- hitTolerance: 0
783
+ hitTolerance: 0,
784
+ scaleStrokes: false
784
785
  });
785
786
  this.project = null;
786
787
  this.projects = [];
@@ -824,7 +825,7 @@ var PaperScope = Base.extend({
824
825
  }
825
826
  },
826
827
 
827
- version: "0.13.0",
828
+ version: "0.14.0",
828
829
 
829
830
  getView: function() {
830
831
  var project = this.project;
@@ -837,7 +838,8 @@ var PaperScope = Base.extend({
837
838
 
838
839
  execute: function(code, options) {
839
840
  var exports = paper.PaperScript.execute(code, this, options);
840
- View.updateFocus();
841
+ if (window)
842
+ View.updateFocus();
841
843
  return exports;
842
844
  },
843
845
 
@@ -851,9 +853,10 @@ var PaperScope = Base.extend({
851
853
  }
852
854
  });
853
855
  });
854
- for (var key in this)
855
- if (!/^_/.test(key) && this[key])
856
+ for (var key in this) {
857
+ if (!/^_/.test(key) && this[key] && !(key in scope))
856
858
  scope[key] = this[key];
859
+ }
857
860
  },
858
861
 
859
862
  setup: function(element) {
@@ -930,6 +933,10 @@ var PaperScopeItem = Base.extend(Emitter, {
930
933
  return this._scope[this._reference] === this;
931
934
  },
932
935
 
936
+ getScope: function() {
937
+ return this._scope;
938
+ },
939
+
933
940
  remove: function() {
934
941
  if (this._index == null)
935
942
  return false;
@@ -2646,6 +2653,10 @@ var Matrix = Base.extend({
2646
2653
  return det && !isNaN(det) && isFinite(this._tx) && isFinite(this._ty);
2647
2654
  },
2648
2655
 
2656
+ _getMeanScale: function() {
2657
+ return Math.sqrt(Math.abs(this._a * this._d - this._b * this._c));
2658
+ },
2659
+
2649
2660
  isSingular: function() {
2650
2661
  return !this.isInvertible();
2651
2662
  },
@@ -2934,6 +2945,48 @@ var Line = Base.extend({
2934
2945
  }
2935
2946
  });
2936
2947
 
2948
+ var ChangeFlag = {
2949
+ APPEARANCE: 0x1,
2950
+
2951
+ CHILDREN: 0x2,
2952
+
2953
+ INSERTION: 0x4,
2954
+
2955
+ GEOMETRY: 0x8,
2956
+
2957
+ MATRIX: 0x10,
2958
+
2959
+ SEGMENTS: 0x20,
2960
+
2961
+ STROKE: 0x40,
2962
+
2963
+ STYLE: 0x80,
2964
+
2965
+ ATTRIBUTE: 0x100,
2966
+
2967
+ CONTENT: 0x200,
2968
+
2969
+ PIXELS: 0x400,
2970
+
2971
+ CLIPPING: 0x800,
2972
+
2973
+ VIEW: 0x1000
2974
+ };
2975
+
2976
+ var Change = {
2977
+ CHILDREN: ChangeFlag.CHILDREN | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
2978
+ INSERTION: ChangeFlag.INSERTION | ChangeFlag.APPEARANCE,
2979
+ GEOMETRY: ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
2980
+ MATRIX: ChangeFlag.MATRIX | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
2981
+ SEGMENTS: ChangeFlag.SEGMENTS | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
2982
+ STROKE: ChangeFlag.STROKE | ChangeFlag.STYLE | ChangeFlag.APPEARANCE,
2983
+ STYLE: ChangeFlag.STYLE | ChangeFlag.APPEARANCE,
2984
+ ATTRIBUTE: ChangeFlag.ATTRIBUTE | ChangeFlag.APPEARANCE,
2985
+ CONTENT: ChangeFlag.CONTENT | ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE,
2986
+ PIXELS: ChangeFlag.PIXELS | ChangeFlag.APPEARANCE,
2987
+ VIEW: ChangeFlag.VIEW | ChangeFlag.APPEARANCE
2988
+ };
2989
+
2937
2990
  var Project = PaperScopeItem.extend({
2938
2991
  _class: 'Project',
2939
2992
  _list: 'projects',
@@ -2967,7 +3020,7 @@ var Project = PaperScopeItem.extend({
2967
3020
  }
2968
3021
  }
2969
3022
  var changes = this._changes;
2970
- if (changes && item) {
3023
+ if (changes && item && item.isInserted()) {
2971
3024
  var changesById = this._changesById,
2972
3025
  id = item._id,
2973
3026
  entry = changesById[id];
@@ -2979,6 +3032,26 @@ var Project = PaperScopeItem.extend({
2979
3032
  }
2980
3033
  },
2981
3034
 
3035
+ getTrackChanges: function() {
3036
+ return !!this._changes;
3037
+ },
3038
+
3039
+ setTrackChanges: function(trackChanges) {
3040
+ if (!this._changes ^ !trackChanges) {
3041
+ this._changes = trackChanges ? [] : null;
3042
+ this._changesById = trackChanges ? {} : null;
3043
+ }
3044
+ },
3045
+
3046
+ takeChanges: function() {
3047
+ var changes = this._changes;
3048
+ if (changes) {
3049
+ this._changes = [];
3050
+ this._changesById = {};
3051
+ }
3052
+ return changes || null;
3053
+ },
3054
+
2982
3055
  clear: function() {
2983
3056
  var children = this._children;
2984
3057
  for (var i = children.length - 1; i >= 0; i--)
@@ -3274,6 +3347,10 @@ new function() {
3274
3347
  matrix = this._matrix = new Matrix(),
3275
3348
  project = hasProps && props.project || paper.project,
3276
3349
  settings = paper.settings;
3350
+ if (!project) {
3351
+ throw new Error('Unable to create an item without a project. '
3352
+ + 'Call paper.setup() or create a Project first.');
3353
+ }
3277
3354
  this._id = internal ? null : UID.get();
3278
3355
  this._parent = this._index = null;
3279
3356
  this._applyMatrix = this._canApplyMatrix && settings.applyMatrix;
@@ -3807,6 +3884,10 @@ new function() {
3807
3884
  return this._project._view;
3808
3885
  },
3809
3886
 
3887
+ getScope: function() {
3888
+ return this._project._scope;
3889
+ },
3890
+
3810
3891
  _installEvents: function _installEvents(install) {
3811
3892
  _installEvents.base.call(this, install);
3812
3893
  if (this._selection)
@@ -4079,7 +4160,7 @@ new function() {
4079
4160
 
4080
4161
  _hitTest: function(point, options, parentViewMatrix) {
4081
4162
  if (this._locked || !this._visible || this._guide && !options.guides
4082
- || this.isEmpty()) {
4163
+ || !this._shell && this.isEmpty()) {
4083
4164
  return null;
4084
4165
  }
4085
4166
 
@@ -4094,7 +4175,7 @@ new function() {
4094
4175
  .prepended(this.getView()._matrix.inverted())
4095
4176
  ._shiftless().invert()));
4096
4177
  point = pointMatrix._inverseTransform(point);
4097
- if (!point || !this._children &&
4178
+ if (!point || (this._shell || !this._children) &&
4098
4179
  !this.getBounds({ internal: true, stroke: true, handle: true })
4099
4180
  .expand(tolerancePadding.multiply(2))._containsPoint(point)) {
4100
4181
  return null;
@@ -4110,10 +4191,21 @@ new function() {
4110
4191
  res;
4111
4192
 
4112
4193
  function filter(hit) {
4194
+ if (Array.isArray(hit)) {
4195
+ var first = null;
4196
+ for (var i = 0, l = hit.length; i < l; i++) {
4197
+ var res = filter(hit[i]);
4198
+ first = first || res;
4199
+ }
4200
+ return first;
4201
+ }
4113
4202
  if (hit && match && !match(hit))
4114
4203
  hit = null;
4115
- if (hit && options.all)
4204
+ if (hit && options.all) {
4205
+ if (hit.point)
4206
+ hit.point = that.getGlobalMatrix().transform(hit.point);
4116
4207
  options.all.push(hit);
4208
+ }
4117
4209
  return hit;
4118
4210
  }
4119
4211
 
@@ -4157,14 +4249,14 @@ new function() {
4157
4249
  : viewMatrix._shiftless().invert()))
4158
4250
  || null;
4159
4251
  }
4160
- if (res && res.point) {
4252
+ if (res && res.point && !options.all) {
4161
4253
  res.point = pointMatrix.transform(res.point);
4162
4254
  }
4163
4255
  return res;
4164
4256
  },
4165
4257
 
4166
4258
  _hitTestSelf: function(point, options) {
4167
- if (options.fill && this.hasFill() && this._contains(point))
4259
+ if (options.fill && this.getFillColor() && this._contains(point))
4168
4260
  return new HitResult('fill', this);
4169
4261
  },
4170
4262
 
@@ -4287,6 +4379,19 @@ new function() {
4287
4379
  }, {
4288
4380
 
4289
4381
  importJSON: function(json) {
4382
+ json = typeof json === 'string' ? JSON.parse(json) : json;
4383
+ var props = json && json[0] === this._class && json[1];
4384
+ if (Base.isPlainObject(props)) {
4385
+ var item = new this.constructor(Item.NO_INSERT),
4386
+ fields = Base.set({}, this._serializeFields,
4387
+ this instanceof Group ? null : this._style._defaults),
4388
+ defaults = {};
4389
+ for (var key in fields) {
4390
+ if (!(key in props) && !Base.equals(this[key], item[key]))
4391
+ defaults[key] = item[key];
4392
+ }
4393
+ this.set(defaults);
4394
+ }
4290
4395
  var res = Base.importJSON(json, this);
4291
4396
  return res !== this ? this.addChild(res) : res;
4292
4397
  },
@@ -4433,14 +4538,14 @@ new function() {
4433
4538
  if (this._name)
4434
4539
  this._removeNamed();
4435
4540
  this._installEvents(false);
4541
+ if (notifySelf && project._changes)
4542
+ this._changed(5);
4436
4543
  if (index != null) {
4437
4544
  if (project._activeLayer === this)
4438
4545
  project._activeLayer = this.getNextSibling()
4439
4546
  || this.getPreviousSibling();
4440
4547
  Base.splice(owner._children, null, index, 1);
4441
4548
  }
4442
- if (notifySelf && project._changes)
4443
- this._changed(5);
4444
4549
  if (notifyParent)
4445
4550
  owner._changed(11, this);
4446
4551
  this._parent = null;
@@ -4799,7 +4904,7 @@ new function() {
4799
4904
  opacity = Numerical.clamp(this._opacity, 0, 1),
4800
4905
  normalBlend = blendMode === 'normal',
4801
4906
  nativeBlend = BlendMode.nativeModes[blendMode],
4802
- direct = normalBlend && opacity === 1
4907
+ direct = normalBlend && opacity === 1 && !this._isolated
4803
4908
  || param.dontStart
4804
4909
  || param.clip
4805
4910
  || (nativeBlend || normalBlend && opacity < 1)
@@ -5015,8 +5120,10 @@ var Group = Item.extend({
5015
5120
  _selectBounds: false,
5016
5121
  _selectChildren: true,
5017
5122
  _serializeFields: {
5123
+ isolated: false,
5018
5124
  children: []
5019
5125
  },
5126
+ _isolated: false,
5020
5127
 
5021
5128
  initialize: function Group(arg) {
5022
5129
  this._children = [];
@@ -5058,6 +5165,15 @@ var Group = Item.extend({
5058
5165
  child.setClipMask(clipped);
5059
5166
  },
5060
5167
 
5168
+ isIsolated: function() {
5169
+ return this._isolated;
5170
+ },
5171
+
5172
+ setIsolated: function(isolated) {
5173
+ this._isolated = !!isolated;
5174
+ this._changed(257);
5175
+ },
5176
+
5061
5177
  _getBounds: function _getBounds(matrix, options) {
5062
5178
  var clipItem = this._getClipItem();
5063
5179
  return clipItem
@@ -5402,7 +5518,7 @@ new function() {
5402
5518
  var hit = false,
5403
5519
  style = this._style,
5404
5520
  hitStroke = options.stroke && style.hasStroke(),
5405
- hitFill = options.fill && style.hasFill();
5521
+ hitFill = options.fill && !!style.getFillColor();
5406
5522
  if (hitStroke || hitFill) {
5407
5523
  var type = this._type,
5408
5524
  radius = this._radius,
@@ -5492,6 +5608,7 @@ var Raster = Item.extend({
5492
5608
  _boundsOptions: { stroke: false, handle: false },
5493
5609
  _serializeFields: {
5494
5610
  crossOrigin: null,
5611
+ size: new Size(),
5495
5612
  source: null
5496
5613
  },
5497
5614
  _prioritize: ['crossOrigin'],
@@ -5641,6 +5758,14 @@ var Raster = Item.extend({
5641
5758
  }
5642
5759
  },
5643
5760
 
5761
+ set: function set(props, exclude) {
5762
+ if (props && props.source && props.size) {
5763
+ this._size = new Size(props.size);
5764
+ exclude = Base.set({ size: true }, exclude);
5765
+ }
5766
+ return set.base.call(this, props, exclude);
5767
+ },
5768
+
5644
5769
  _setImage: function(image) {
5645
5770
  if (this._canvas)
5646
5771
  CanvasProvider.release(this._canvas);
@@ -5653,9 +5778,11 @@ var Raster = Item.extend({
5653
5778
  this._canvas = null;
5654
5779
  this._loaded = !!(image && image.src && image.complete);
5655
5780
  }
5656
- this._size = new Size(
5657
- image ? image.naturalWidth || image.width : 0,
5658
- image ? image.naturalHeight || image.height : 0);
5781
+ this._size = image && !this._loaded
5782
+ ? this._size || new Size()
5783
+ : new Size(
5784
+ image ? image.naturalWidth || image.width : 0,
5785
+ image ? image.naturalHeight || image.height : 0);
5659
5786
  this._context = null;
5660
5787
  this._changed(1033);
5661
5788
  },
@@ -8230,6 +8357,15 @@ var PathItem = Item.extend({
8230
8357
  initialize: function PathItem() {
8231
8358
  },
8232
8359
 
8360
+ _scaleStroke: function(matrix) {
8361
+ var style = this._style;
8362
+ if (this._project._scope.settings.scaleStrokes
8363
+ && style.getStrokeScaling()) {
8364
+ style.setStrokeWidth(style.getStrokeWidth()
8365
+ * matrix._getMeanScale());
8366
+ }
8367
+ },
8368
+
8233
8369
  statics: {
8234
8370
  create: function(arg) {
8235
8371
  var data,
@@ -8698,6 +8834,7 @@ var Path = PathItem.extend({
8698
8834
  coords = new Array(6);
8699
8835
  for (var i = 0, l = segments.length; i < l; i++)
8700
8836
  segments[i]._transformCoordinates(matrix, coords, true);
8837
+ this._scaleStroke(matrix);
8701
8838
  return true;
8702
8839
  },
8703
8840
 
@@ -9328,8 +9465,9 @@ var Path = PathItem.extend({
9328
9465
  strokePadding = tolerancePadding,
9329
9466
  join, cap, miterLimit,
9330
9467
  area, loc, res,
9468
+ hits = options.all && [],
9331
9469
  hitStroke = options.stroke && style.hasStroke(),
9332
- hitFill = options.fill && style.hasFill(),
9470
+ hitFill = options.fill && !!style.getFillColor(),
9333
9471
  hitCurves = options.curves,
9334
9472
  strokeRadius = hitStroke
9335
9473
  ? style.getStrokeWidth() / 2
@@ -9357,10 +9495,13 @@ var Path = PathItem.extend({
9357
9495
  if (pt !== anchor)
9358
9496
  pt = pt.add(anchor);
9359
9497
  if (isCloseEnough(pt, strokePadding)) {
9360
- return new HitResult(name, that, {
9498
+ var hit = new HitResult(name, that, {
9361
9499
  segment: seg,
9362
9500
  point: pt
9363
9501
  });
9502
+ if (!hits)
9503
+ return hit;
9504
+ hits.push(hit);
9364
9505
  }
9365
9506
  }
9366
9507
  }
@@ -9434,7 +9575,7 @@ var Path = PathItem.extend({
9434
9575
  }
9435
9576
  }
9436
9577
  }
9437
- return !loc && hitFill && this._contains(point)
9578
+ res = !loc && hitFill && this._contains(point)
9438
9579
  || loc && !hitStroke && !hitCurves
9439
9580
  ? new HitResult('fill', this)
9440
9581
  : loc
@@ -9443,6 +9584,16 @@ var Path = PathItem.extend({
9443
9584
  point: loc.getPoint()
9444
9585
  })
9445
9586
  : null;
9587
+ if (hits) {
9588
+ hits.sort(function(hit1, hit2) {
9589
+ return hit1.point.getDistance(point)
9590
+ - hit2.point.getDistance(point);
9591
+ });
9592
+ if (res)
9593
+ hits.push(res);
9594
+ return hits;
9595
+ }
9596
+ return res;
9446
9597
  }
9447
9598
 
9448
9599
  }, Base.each(Curve._evaluateMethods,
@@ -10234,10 +10385,9 @@ Path.inject({ statics: new function() {
10234
10385
  center = Point.readNamed(args, 'center'),
10235
10386
  sides = Base.readNamed(args, 'sides'),
10236
10387
  radius = Base.readNamed(args, 'radius'),
10237
- step = 360 / sides,
10238
- three = sides % 3 === 0,
10239
- vector = new Point(0, three ? -radius : radius),
10240
- offset = three ? -1 : 0.5,
10388
+ step = -360 / sides,
10389
+ offset = sides % 2 ? 0 : -0.5,
10390
+ vector = new Point(0, -radius),
10241
10391
  segments = new Array(sides);
10242
10392
  for (var i = 0; i < sides; i++)
10243
10393
  segments[i] = new Segment(center.add(
@@ -10281,6 +10431,11 @@ var CompoundPath = PathItem.extend({
10281
10431
  }
10282
10432
  },
10283
10433
 
10434
+ _transformContent: function _transformContent(matrix) {
10435
+ this._scaleStroke(matrix);
10436
+ return _transformContent.base.apply(this, arguments);
10437
+ },
10438
+
10284
10439
  insertChildren: function insertChildren(index, items) {
10285
10440
  var list = items,
10286
10441
  first = list[0];
@@ -11768,6 +11923,16 @@ var PointText = TextItem.extend({
11768
11923
  hasStroke = style.hasStroke(),
11769
11924
  leading = style.getLeading(),
11770
11925
  shadowColor = ctx.shadowColor;
11926
+ if (hasStroke && !style.getStrokeScaling()) {
11927
+ var scale = viewMatrix._getMeanScale();
11928
+ ctx.lineWidth /= scale;
11929
+ if ('setLineDash' in ctx) {
11930
+ ctx.setLineDash(ctx.getLineDash().map(function(dash) {
11931
+ return dash / scale;
11932
+ }));
11933
+ ctx.lineDashOffset /= scale;
11934
+ }
11935
+ }
11771
11936
  ctx.font = style.getFontStyle();
11772
11937
  ctx.textAlign = style.getJustification();
11773
11938
  ctx.letterSpacing = style.getTrackingStyle();
@@ -11805,7 +11970,7 @@ var PointText = TextItem.extend({
11805
11970
  },
11806
11971
 
11807
11972
  _hitTestSelf: function(point, options) {
11808
- if (options.fill && this.hasFill()) {
11973
+ if (options.fill && this.getFillColor()) {
11809
11974
  var bounds = this.getInternalBounds(),
11810
11975
  closest = point.clamp(bounds.getTopLeft(true),
11811
11976
  bounds.getBottomRight(true));
@@ -13005,8 +13170,12 @@ DomEvent.requestAnimationFrame = new function() {
13005
13170
  for (var i = 0, l = functions.length; i < l; i++)
13006
13171
  functions[i]();
13007
13172
  requested = nativeRequest && callbacks.length;
13008
- if (requested)
13173
+ if (requested) {
13009
13174
  nativeRequest(handleCallbacks);
13175
+ } else if (timer && !callbacks.length) {
13176
+ clearInterval(timer);
13177
+ timer = null;
13178
+ }
13010
13179
  }
13011
13180
 
13012
13181
  return function(callback) {
@@ -13032,7 +13201,7 @@ var View = Base.extend(Emitter, {
13032
13201
  }
13033
13202
 
13034
13203
  function getCanvasSize() {
13035
- var size = DomElement.getSize(element);
13204
+ var size = new Size(element.offsetWidth, element.offsetHeight);
13036
13205
  return size.isNaN() || size.isZero()
13037
13206
  ? new Size(getSize('width'), getSize('height'))
13038
13207
  : size.subtract(DomElement.getInsets(element));
@@ -13163,7 +13332,8 @@ var View = Base.extend(Emitter, {
13163
13332
  if (that._animate) {
13164
13333
  that.requestUpdate();
13165
13334
  var element = that._element;
13166
- if ((!DomElement.getPrefixed(document, 'hidden')
13335
+ if (!element
13336
+ || (!DomElement.getPrefixed(document, 'hidden')
13167
13337
  || PaperScope.getAttribute(element, 'keepalive')
13168
13338
  === 'true') && DomElement.isInView(element)) {
13169
13339
  that._handleFrame();
@@ -13240,6 +13410,10 @@ var View = Base.extend(Emitter, {
13240
13410
  return this._project;
13241
13411
  },
13242
13412
 
13413
+ getScope: function() {
13414
+ return this._scope;
13415
+ },
13416
+
13243
13417
  getPixelRatio: function() {
13244
13418
  return this._pixelRatio;
13245
13419
  },
@@ -13460,8 +13634,6 @@ var View = Base.extend(Emitter, {
13460
13634
  }
13461
13635
  },
13462
13636
  new function() {
13463
- if (!window)
13464
- return;
13465
13637
  var prevFocus,
13466
13638
  tempFocus,
13467
13639
  dragging = false,
@@ -13489,26 +13661,28 @@ new function() {
13489
13661
  view._handleMouseEvent('mousemove', event, point);
13490
13662
  }
13491
13663
 
13492
- var navigator = window.navigator,
13493
- mousedown, mousemove, mouseup;
13494
- if (navigator.pointerEnabled || navigator.msPointerEnabled) {
13495
- mousedown = 'pointerdown MSPointerDown';
13496
- mousemove = 'pointermove MSPointerMove';
13497
- mouseup = 'pointerup pointercancel MSPointerUp MSPointerCancel';
13498
- } else {
13499
- mousedown = 'touchstart';
13500
- mousemove = 'touchmove';
13501
- mouseup = 'touchend touchcancel';
13502
- if (!('ontouchstart' in window && navigator.userAgent.match(
13503
- /mobile|tablet|ip(ad|hone|od)|android|silk/i))) {
13504
- mousedown += ' mousedown';
13505
- mousemove += ' mousemove';
13506
- mouseup += ' mouseup';
13664
+ var viewEvents = {};
13665
+
13666
+ if (window) {
13667
+ var navigator = window.navigator,
13668
+ mousedown, mousemove, mouseup;
13669
+ if (navigator.pointerEnabled || navigator.msPointerEnabled) {
13670
+ mousedown = 'pointerdown MSPointerDown';
13671
+ mousemove = 'pointermove MSPointerMove';
13672
+ mouseup = 'pointerup pointercancel MSPointerUp MSPointerCancel';
13673
+ } else {
13674
+ mousedown = 'touchstart';
13675
+ mousemove = 'touchmove';
13676
+ mouseup = 'touchend touchcancel';
13677
+ if (!('ontouchstart' in window && navigator.userAgent.match(
13678
+ /mobile|tablet|ip(ad|hone|od)|android|silk/i))) {
13679
+ mousedown += ' mousedown';
13680
+ mousemove += ' mousemove';
13681
+ mouseup += ' mouseup';
13682
+ }
13507
13683
  }
13508
- }
13509
13684
 
13510
- var viewEvents = {},
13511
- docEvents = {
13685
+ var docEvents = {
13512
13686
  mouseout: function(event) {
13513
13687
  var view = View._focused,
13514
13688
  target = DomEvent.getRelatedTarget(event);
@@ -13519,54 +13693,55 @@ new function() {
13519
13693
  scroll: updateFocus
13520
13694
  };
13521
13695
 
13522
- viewEvents[mousedown] = function(event) {
13523
- var view = View._focused = getView(event);
13524
- if (!dragging) {
13525
- dragging = true;
13526
- view._handleMouseEvent('mousedown', event);
13527
- }
13528
- };
13696
+ viewEvents[mousedown] = function(event) {
13697
+ var view = View._focused = getView(event);
13698
+ if (!dragging) {
13699
+ dragging = true;
13700
+ view._handleMouseEvent('mousedown', event);
13701
+ }
13702
+ };
13529
13703
 
13530
- docEvents[mousemove] = function(event) {
13531
- var view = View._focused;
13532
- if (!mouseDown) {
13533
- var target = getView(event);
13534
- if (target) {
13535
- if (view !== target) {
13536
- if (view)
13537
- handleMouseMove(view, event);
13538
- if (!prevFocus)
13539
- prevFocus = view;
13540
- view = View._focused = tempFocus = target;
13541
- }
13542
- } else if (tempFocus && tempFocus === view) {
13543
- if (prevFocus && !prevFocus.isInserted())
13704
+ docEvents[mousemove] = function(event) {
13705
+ var view = View._focused;
13706
+ if (!mouseDown) {
13707
+ var target = getView(event);
13708
+ if (target) {
13709
+ if (view !== target) {
13710
+ if (view)
13711
+ handleMouseMove(view, event);
13712
+ if (!prevFocus)
13713
+ prevFocus = view;
13714
+ view = View._focused = tempFocus = target;
13715
+ }
13716
+ } else if (tempFocus && tempFocus === view) {
13717
+ if (prevFocus && !prevFocus.isInserted())
13718
+ prevFocus = null;
13719
+ view = View._focused = prevFocus;
13544
13720
  prevFocus = null;
13545
- view = View._focused = prevFocus;
13546
- prevFocus = null;
13547
- updateFocus();
13721
+ updateFocus();
13722
+ }
13548
13723
  }
13549
- }
13550
- if (view)
13551
- handleMouseMove(view, event);
13552
- };
13724
+ if (view)
13725
+ handleMouseMove(view, event);
13726
+ };
13553
13727
 
13554
- docEvents[mousedown] = function() {
13555
- mouseDown = true;
13556
- };
13728
+ docEvents[mousedown] = function() {
13729
+ mouseDown = true;
13730
+ };
13557
13731
 
13558
- docEvents[mouseup] = function(event) {
13559
- var view = View._focused;
13560
- if (view && dragging)
13561
- view._handleMouseEvent('mouseup', event);
13562
- mouseDown = dragging = false;
13563
- };
13732
+ docEvents[mouseup] = function(event) {
13733
+ var view = View._focused;
13734
+ if (view && dragging)
13735
+ view._handleMouseEvent('mouseup', event);
13736
+ mouseDown = dragging = false;
13737
+ };
13564
13738
 
13565
- DomEvent.add(document, docEvents);
13739
+ DomEvent.add(document, docEvents);
13566
13740
 
13567
- DomEvent.add(window, {
13568
- load: updateFocus
13569
- });
13741
+ DomEvent.add(window, {
13742
+ load: updateFocus
13743
+ });
13744
+ }
13570
13745
 
13571
13746
  var called = false,
13572
13747
  prevented = false,
@@ -13632,9 +13807,27 @@ new function() {
13632
13807
  point, prevPoint));
13633
13808
  }
13634
13809
 
13810
+ function createEvent(type, options) {
13811
+ if (options.modifiers)
13812
+ Key.modifiers.set(options.modifiers);
13813
+ return {
13814
+ type: type,
13815
+ timeStamp: options.timeStamp != null ? options.timeStamp
13816
+ : Date.now(),
13817
+ button: options.button || 0,
13818
+ cancelable: true,
13819
+ defaultPrevented: false,
13820
+ preventDefault: function() {
13821
+ this.defaultPrevented = true;
13822
+ },
13823
+ stopPropagation: function() {}
13824
+ };
13825
+ }
13826
+
13635
13827
  var itemEventsMap = {
13636
13828
  mousedown: {
13637
13829
  mousedown: 1,
13830
+ mouseup: 1,
13638
13831
  mousedrag: 1,
13639
13832
  click: 1,
13640
13833
  doubleclick: 1
@@ -13656,6 +13849,28 @@ new function() {
13656
13849
  return {
13657
13850
  _viewEvents: viewEvents,
13658
13851
 
13852
+ dispatchMouseEvent: function(type, point, options) {
13853
+ if (!/^mouse(down|move|up)$/.test(type))
13854
+ throw new Error('Unknown mouse event type: \'' + type + '\'.');
13855
+ var event = createEvent(type, options || {});
13856
+ if (type === 'mousedown') {
13857
+ View._focused = this;
13858
+ mouseDown = dragging = true;
13859
+ }
13860
+ this._handleMouseEvent(type, event, new Point(point));
13861
+ if (type === 'mouseup')
13862
+ mouseDown = dragging = false;
13863
+ return event.defaultPrevented;
13864
+ },
13865
+
13866
+ dispatchKeyEvent: function(type, key, options) {
13867
+ if (!/^key(down|up)$/.test(type))
13868
+ throw new Error('Unknown key event type: \'' + type + '\'.');
13869
+ options = options || {};
13870
+ Key._handleKey(type === 'keydown', key, options.character,
13871
+ createEvent(type, options), this);
13872
+ },
13873
+
13659
13874
  _handleMouseEvent: function(type, event, point) {
13660
13875
  var itemEvents = this._itemEvents,
13661
13876
  hitItems = itemEvents.native[type],
@@ -13668,12 +13883,37 @@ new function() {
13668
13883
  || tool && tool.responds(type);
13669
13884
  }
13670
13885
 
13886
+ function needsUp(hitItem) {
13887
+ if (view.responds('mouseup')
13888
+ || tool && tool.responds('mouseup'))
13889
+ return true;
13890
+ for (var item = hitItem; item; item = item._parent) {
13891
+ for (var key in itemEventsMap.mouseup) {
13892
+ if (item.responds(key))
13893
+ return true;
13894
+ }
13895
+ }
13896
+ return false;
13897
+ }
13898
+
13899
+ if (event.shiftKey !== undefined) {
13900
+ Key.modifiers.set({
13901
+ shift: event.shiftKey,
13902
+ control: event.ctrlKey,
13903
+ alt: event.altKey,
13904
+ meta: event.metaKey
13905
+ });
13906
+ }
13671
13907
  if (nativeMove && dragging && responds('mousedrag'))
13672
13908
  type = 'mousedrag';
13673
13909
  if (!point)
13674
13910
  point = this.getEventPoint(event);
13675
13911
 
13676
- var inView = this.getBounds().contains(point),
13912
+ var target = DomEvent.getTarget(event),
13913
+ isCovered = nativeMove && !dragging && target
13914
+ && target.nodeType === 1
13915
+ && !target.contains(this._element),
13916
+ inView = !isCovered && this.getBounds().contains(point),
13677
13917
  hit = hitItems && inView && view._project.hitTest(point, {
13678
13918
  tolerance: 0,
13679
13919
  fill: true,
@@ -13740,7 +13980,7 @@ new function() {
13740
13980
 
13741
13981
  if (
13742
13982
  event.cancelable !== false
13743
- && (called && !mouse.move || mouse.down && responds('mouseup'))
13983
+ && (called && !mouse.move || mouse.down && needsUp(hitItem))
13744
13984
  ) {
13745
13985
  event.preventDefault();
13746
13986
  }
@@ -13759,11 +13999,9 @@ new function() {
13759
13999
  }
13760
14000
  }
13761
14001
 
13762
- if (this.isVisible()) {
13763
- emit(this);
13764
- if (tool && tool.responds(type))
13765
- emit(tool);
13766
- }
14002
+ emit(this);
14003
+ if (tool && tool.responds(type))
14004
+ emit(tool);
13767
14005
  },
13768
14006
 
13769
14007
  _countItemEvent: function(type, sign) {
@@ -13821,20 +14059,20 @@ var CanvasView = View.extend({
13821
14059
  },
13822
14060
 
13823
14061
  _setElementSize: function _setElementSize(width, height) {
13824
- var pixelRatio = this._pixelRatio;
14062
+ var pixelRatio = this._pixelRatio,
14063
+ element = this._element;
13825
14064
  _setElementSize.base.call(this, width * pixelRatio, height * pixelRatio);
14065
+ if (!PaperScope.hasAttribute(element, 'resize')) {
14066
+ var style = element.style,
14067
+ insets = DomElement.getStyles(element).boxSizing
14068
+ === 'border-box'
14069
+ ? DomElement.getInsets(element)
14070
+ : new Size();
14071
+ style.width = (width + insets.width) + 'px';
14072
+ style.height = (height + insets.height) + 'px';
14073
+ }
13826
14074
  if (pixelRatio !== 1) {
13827
- var element = this._element,
13828
- ctx = this._context;
13829
- if (!PaperScope.hasAttribute(element, 'resize')) {
13830
- var style = element.style,
13831
- insets = DomElement.getStyles(element).boxSizing
13832
- === 'border-box'
13833
- ? DomElement.getInsets(element)
13834
- : new Size();
13835
- style.width = (width + insets.width) + 'px';
13836
- style.height = (height + insets.height) + 'px';
13837
- }
14075
+ var ctx = this._context;
13838
14076
  ctx.restore();
13839
14077
  ctx.save();
13840
14078
  ctx.scale(pixelRatio, pixelRatio);
@@ -14000,11 +14238,16 @@ var Key = new function() {
14000
14238
  (key.length > 1 ? Base.hyphenate(key) : key.toLowerCase());
14001
14239
  }
14002
14240
 
14003
- function handleKey(down, key, character, event) {
14004
- View.updateFocus();
14005
- var type = down ? 'keydown' : 'keyup',
14006
- view = View._focused,
14007
- name;
14241
+ function handleKey(down, key, character, event, view) {
14242
+ if (!view) {
14243
+ View.updateFocus();
14244
+ view = View._focused;
14245
+ if (view && !view.isVisible())
14246
+ view = null;
14247
+ }
14248
+ if (character == null)
14249
+ character = down ? key.length > 1 ? '' : key : charMap[key] || '';
14250
+ var name;
14008
14251
  keyMap[key] = down;
14009
14252
  if (down) {
14010
14253
  charMap[key] = character;
@@ -14020,7 +14263,7 @@ var Key = new function() {
14020
14263
  } else {
14021
14264
  for (var k in metaFixMap) {
14022
14265
  if (k in charMap)
14023
- handleKey(false, k, metaFixMap[k], event);
14266
+ handleKey(false, k, metaFixMap[k], event, view);
14024
14267
  }
14025
14268
  metaFixMap = null;
14026
14269
  }
@@ -14075,6 +14318,8 @@ var Key = new function() {
14075
14318
  });
14076
14319
 
14077
14320
  return {
14321
+ _handleKey: handleKey,
14322
+
14078
14323
  modifiers: modifiers,
14079
14324
 
14080
14325
  isDown: function(key) {
@@ -14241,6 +14486,14 @@ var Tool = PaperScopeItem.extend({
14241
14486
  }
14242
14487
  },
14243
14488
 
14489
+ getEventInterval: function() {
14490
+ return this._eventInterval;
14491
+ },
14492
+
14493
+ setEventInterval: function(interval) {
14494
+ this._eventInterval = interval;
14495
+ },
14496
+
14244
14497
  getFixedDistance: function() {
14245
14498
  return this._minDistance == this._maxDistance
14246
14499
  ? this._minDistance : null;
@@ -14297,7 +14550,24 @@ var Tool = PaperScopeItem.extend({
14297
14550
  if (mouse.down) {
14298
14551
  update();
14299
14552
  emit();
14553
+ if (this._eventInterval > 0) {
14554
+ clearInterval(this._timer);
14555
+ this._timer = setInterval(function() {
14556
+ if (tool.isActive()) {
14557
+ paper = tool._scope;
14558
+ tool._lastPoint = tool._point;
14559
+ tool._moveCount++;
14560
+ if (tool.responds('mousedrag')) {
14561
+ tool.emit('mousedrag',
14562
+ new ToolEvent(tool, 'mousedrag', event));
14563
+ }
14564
+ } else {
14565
+ clearInterval(tool._timer);
14566
+ }
14567
+ }, this._eventInterval);
14568
+ }
14300
14569
  } else if (mouse.up) {
14570
+ clearInterval(this._timer);
14301
14571
  update(null, this._maxDistance);
14302
14572
  emit();
14303
14573
  } else if (responds) {
@@ -14674,8 +14944,9 @@ var CanvasProvider = Base.exports.CanvasProvider = {
14674
14944
  release: function(obj) {
14675
14945
  var canvas = obj && obj.canvas ? obj.canvas : obj;
14676
14946
  if (canvas && canvas.getContext) {
14677
- canvas.getContext('2d').restore();
14678
- this.canvases.push(canvas);
14947
+ canvas.width = canvas.height = 0;
14948
+ if (this.canvases.length < 8)
14949
+ this.canvases.push(canvas);
14679
14950
  }
14680
14951
  }
14681
14952
  };
@@ -15007,7 +15278,7 @@ var SvgStyles = Base.each({
15007
15278
  dashArray: ['stroke-dasharray', 'array'],
15008
15279
  dashOffset: ['stroke-dashoffset', 'number'],
15009
15280
  fontFamily: ['font-family', 'string'],
15010
- fontWeight: ['font-weight', 'string'],
15281
+ fontWeight: ['font-weight', 'font'],
15011
15282
  fontSize: ['font-size', 'number'],
15012
15283
  tracking: ['letter-spacing', 'tracking'],
15013
15284
  justification: ['text-anchor', 'lookup', {
@@ -15329,6 +15600,13 @@ new function() {
15329
15600
  PointText: exportText
15330
15601
  };
15331
15602
 
15603
+ var cssBlendModes = Base.each(['normal', 'multiply', 'screen', 'overlay',
15604
+ 'darken', 'lighten', 'color-dodge', 'color-burn', 'hard-light',
15605
+ 'soft-light', 'difference', 'exclusion', 'hue', 'saturation',
15606
+ 'color', 'luminosity'], function(mode) {
15607
+ this[mode] = true;
15608
+ }, {});
15609
+
15332
15610
  function applyStyle(item, node, options, isRoot) {
15333
15611
  var attrs = {},
15334
15612
  parent = !isRoot && item.getParent(),
@@ -15355,7 +15633,19 @@ new function() {
15355
15633
  attrs[entry.attribute + '-opacity'] = alpha;
15356
15634
  }
15357
15635
  if (type === 'style') {
15358
- style.push(entry.attribute + ': ' + value);
15636
+ if (cssBlendModes[value]) {
15637
+ style.push(entry.attribute + ': ' + value);
15638
+ } else {
15639
+ attrs['data-paper-blend-mode'] = value;
15640
+ }
15641
+ } else if (type === 'font') {
15642
+ var font = ('' + value).match(
15643
+ /^(.*?)\s*\b(italic|oblique)\b\s*(.*)$/i);
15644
+ attrs[entry.attribute] = font
15645
+ ? (font[1] + ' ' + font[3]).trim() || 'normal'
15646
+ : value;
15647
+ if (font)
15648
+ attrs['font-style'] = font[2].toLowerCase();
15359
15649
  } else {
15360
15650
  attrs[entry.attribute] = value == null ? 'none'
15361
15651
  : type === 'color' ? value.gradient
@@ -15868,6 +16158,20 @@ new function() {
15868
16158
  item.setVisible(value !== null);
15869
16159
  },
15870
16160
 
16161
+ 'data-paper-blend-mode': function(item, value) {
16162
+ if (item.setBlendMode)
16163
+ item.setBlendMode(value);
16164
+ },
16165
+
16166
+ 'font-style': function(item, value) {
16167
+ if (item.setFontWeight && /^(italic|oblique)$/.test(value)) {
16168
+ var weight = ('' + item.getFontWeight())
16169
+ .replace(/\s*\b(italic|oblique)\b/gi, '');
16170
+ item.setFontWeight(/^(normal|400)$/.test(weight) ? value
16171
+ : weight + ' ' + value);
16172
+ }
16173
+ },
16174
+
15871
16175
  'letter-spacing': function(item, value) {
15872
16176
  if (item.setTracking) {
15873
16177
  var amount = parseFloat(value) || 0;
@@ -17778,11 +18082,13 @@ Base.exports.PaperScript = function() {
17778
18082
  function execute(code, scope, options) {
17779
18083
  paper = scope;
17780
18084
  var view = scope.getView(),
17781
- tool = /\btool\.\w+|\s+on(?:Key|Mouse)(?:Up|Down|Move|Drag)\b/
17782
- .test(code) && !/\bnew\s+Tool\b/.test(code)
18085
+ tool = new RegExp('\\btool\\.\\w+|\\s+(?:'
18086
+ + Tool.prototype._events.join('|') + ')\\b').test(code)
18087
+ && !/\bnew\s+Tool\b/.test(code)
17783
18088
  ? new Tool() : null,
17784
18089
  toolHandlers = tool ? tool._events : [],
17785
- handlers = ['onFrame', 'onResize'].concat(toolHandlers),
18090
+ handlers = ['onFrame', 'onResize'].concat(toolHandlers,
18091
+ options && options.handlers || []),
17786
18092
  params = [],
17787
18093
  args = [],
17788
18094
  func,
@@ -17790,7 +18096,8 @@ Base.exports.PaperScript = function() {
17790
18096
  code = compiled.code;
17791
18097
  function expose(scope, hidden) {
17792
18098
  for (var key in scope) {
17793
- if ((hidden || !/^_/.test(key)) && new RegExp('([\\b\\s\\W]|^)'
18099
+ if ((hidden || !/^_/.test(key) && !(key in self))
18100
+ && new RegExp('([\\b\\s\\W]|^)'
17794
18101
  + key.replace(/\$/g, '\\$') + '\\b').test(code)) {
17795
18102
  params.push(key);
17796
18103
  args.push(scope[key]);
@@ -17918,14 +18225,13 @@ Base.exports.PaperScript = function() {
17918
18225
  var paper = new (PaperScope.inject(Base.exports, {
17919
18226
  Base: Base,
17920
18227
  Numerical: Numerical,
18228
+ ChangeFlag: ChangeFlag,
17921
18229
  Key: Key,
17922
18230
  DomEvent: DomEvent,
17923
18231
  DomElement: DomElement,
17924
18232
  document: document,
17925
18233
  window: window,
17926
- PlacedSymbol: SymbolItem
17927
- }).inject({
17928
- enumerable: false,
18234
+ PlacedSymbol: SymbolItem,
17929
18235
  Symbol: SymbolDefinition
17930
18236
  }))();
17931
18237