fabric 4.6.0-browser → 5.1.0-browser

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.
package/lib/event.js CHANGED
@@ -1368,7 +1368,11 @@ root.gesture = function(conf) {
1368
1368
  var dx = touch.move.x - self.x;
1369
1369
  var dy = touch.move.y - self.y;
1370
1370
  var distance = Math.sqrt(dx * dx + dy * dy);
1371
- scale += distance / start.distance;
1371
+ // If touch start.distance from centroid is 0, scale should not be updated.
1372
+ // This prevents dividing by 0 in cases where start.distance is oddly 0.
1373
+ if (start.distance !== 0) {
1374
+ scale += distance / start.distance;
1375
+ }
1372
1376
  // Calculate rotation.
1373
1377
  var angle = Math.atan2(dx, dy) / RAD_DEG;
1374
1378
  var rotate = (start.angle - angle + 360) % 360 - 180;
@@ -1765,8 +1769,8 @@ root.tap = function(conf) {
1765
1769
  var identifier = touch.identifier || Infinity;
1766
1770
  var pt = conf.tracker[identifier];
1767
1771
  if (!pt) continue;
1768
- var x = (touch.pageX - bbox.x1);
1769
- var y = (touch.pageY - bbox.y1);
1772
+ var x = (touch.pageX - bbox.x1 - parseInt(window.scrollX));
1773
+ var y = (touch.pageY - bbox.y1 - parseInt(window.scrollY));
1770
1774
  ///
1771
1775
  var dx = x - pt.start.x;
1772
1776
  var dy = y - pt.start.y;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "fabric",
3
3
  "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
4
4
  "homepage": "http://fabricjs.com/",
5
- "version": "4.6.0-browser",
5
+ "version": "5.1.0-browser",
6
6
  "author": "Juriy Zaytsev <kangax@gmail.com>",
7
7
  "contributors": [
8
8
  {
@@ -44,6 +44,7 @@
44
44
  },
45
45
  "license": "MIT",
46
46
  "scripts": {
47
+ "changelog": "auto-changelog -o change-output.md --unreleased-only",
47
48
  "build": "node build.js modules=ALL requirejs exclude=gestures,accessors,erasing",
48
49
  "build:fast": "node build.js modules=ALL requirejs fast exclude=gestures,accessors,erasing",
49
50
  "build:watch": "onchange 'src/**/**' 'HEADER.js' 'lib/**/**' -- npm run build_export",
@@ -69,17 +70,18 @@
69
70
  },
70
71
  "optionalDependencies": {},
71
72
  "devDependencies": {
73
+ "auto-changelog": "^2.3.0",
72
74
  "chalk": "^2.4.1",
73
75
  "eslint": "4.18.x",
74
76
  "nyc": "^15.1.0",
75
- "onchange": "^3.x.x",
77
+ "onchange": "^7.1.0",
76
78
  "pixelmatch": "^4.0.2",
77
79
  "qunit": "^2.13.0",
78
80
  "testem": "^3.2.0",
79
81
  "uglify-js": "3.3.x"
80
82
  },
81
83
  "engines": {
82
- "node": ">=8.0.0"
84
+ "node": ">=14.0.0"
83
85
  },
84
86
  "main": "./dist/fabric.js",
85
87
  "dependencies": {}
@@ -68,9 +68,9 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
68
68
  /**
69
69
  * Sets brush styles
70
70
  * @private
71
+ * @param {CanvasRenderingContext2D} ctx
71
72
  */
72
- _setBrushStyles: function() {
73
- var ctx = this.canvas.contextTop;
73
+ _setBrushStyles: function (ctx) {
74
74
  ctx.strokeStyle = this.color;
75
75
  ctx.lineWidth = this.width;
76
76
  ctx.lineCap = this.strokeLineCap;
@@ -29,17 +29,19 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
29
29
 
30
30
  /**
31
31
  * Creates "pattern" instance property
32
+ * @param {CanvasRenderingContext2D} ctx
32
33
  */
33
- getPattern: function() {
34
- return this.canvas.contextTop.createPattern(this.source || this.getPatternSrc(), 'repeat');
34
+ getPattern: function(ctx) {
35
+ return ctx.createPattern(this.source || this.getPatternSrc(), 'repeat');
35
36
  },
36
37
 
37
38
  /**
38
39
  * Sets brush styles
40
+ * @param {CanvasRenderingContext2D} ctx
39
41
  */
40
- _setBrushStyles: function() {
41
- this.callSuper('_setBrushStyles');
42
- this.canvas.contextTop.strokeStyle = this.getPattern();
42
+ _setBrushStyles: function(ctx) {
43
+ this.callSuper('_setBrushStyles', ctx);
44
+ ctx.strokeStyle = this.getPattern(ctx);
43
45
  },
44
46
 
45
47
  /**
@@ -13,6 +13,22 @@
13
13
  */
14
14
  decimate: 0.4,
15
15
 
16
+ /**
17
+ * Draws a straight line between last recorded point to current pointer
18
+ * Used for `shift` functionality
19
+ *
20
+ * @type boolean
21
+ * @default false
22
+ */
23
+ drawStraightLine: false,
24
+
25
+ /**
26
+ * The event modifier key that makes the brush draw a straight line.
27
+ * If `null` or 'none' or any other string that is not a modifier key the feature is disabled.
28
+ * @type {'altKey' | 'shiftKey' | 'ctrlKey' | 'none' | undefined | null}
29
+ */
30
+ straightLineKey: 'shiftKey',
31
+
16
32
  /**
17
33
  * Constructor
18
34
  * @param {fabric.Canvas} canvas
@@ -23,6 +39,10 @@
23
39
  this._points = [];
24
40
  },
25
41
 
42
+ needsFullRender: function () {
43
+ return this.callSuper('needsFullRender') || this._hasStraightLine;
44
+ },
45
+
26
46
  /**
27
47
  * Invoked inside on mouse down and mouse move
28
48
  * @param {Object} pointer
@@ -41,6 +61,7 @@
41
61
  if (!this.canvas._isMainEvent(options.e)) {
42
62
  return;
43
63
  }
64
+ this.drawStraightLine = options.e[this.straightLineKey];
44
65
  this._prepareForDrawing(pointer);
45
66
  // capture coordinates immediately
46
67
  // this allows to draw dots (when movement never occurs)
@@ -56,6 +77,7 @@
56
77
  if (!this.canvas._isMainEvent(options.e)) {
57
78
  return;
58
79
  }
80
+ this.drawStraightLine = options.e[this.straightLineKey];
59
81
  if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {
60
82
  return;
61
83
  }
@@ -88,6 +110,7 @@
88
110
  if (!this.canvas._isMainEvent(options.e)) {
89
111
  return true;
90
112
  }
113
+ this.drawStraightLine = false;
91
114
  this.oldEnd = undefined;
92
115
  this._finalizeAndAddPath();
93
116
  return false;
@@ -114,6 +137,10 @@
114
137
  if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) {
115
138
  return false;
116
139
  }
140
+ if (this.drawStraightLine && this._points.length > 1) {
141
+ this._hasStraightLine = true;
142
+ this._points.pop();
143
+ }
117
144
  this._points.push(point);
118
145
  return true;
119
146
  },
@@ -124,8 +151,9 @@
124
151
  */
125
152
  _reset: function() {
126
153
  this._points = [];
127
- this._setBrushStyles();
154
+ this._setBrushStyles(this.canvas.contextTop);
128
155
  this._setShadow();
156
+ this._hasStraightLine = false;
129
157
  },
130
158
 
131
159
  /**
@@ -140,12 +168,13 @@
140
168
  /**
141
169
  * Draw a smooth path on the topCanvas using quadraticCurveTo
142
170
  * @private
171
+ * @param {CanvasRenderingContext2D} [ctx]
143
172
  */
144
- _render: function() {
145
- var ctx = this.canvas.contextTop, i, len,
173
+ _render: function(ctx) {
174
+ var i, len,
146
175
  p1 = this._points[0],
147
176
  p2 = this._points[1];
148
-
177
+ ctx = ctx || this.canvas.contextTop;
149
178
  this._saveAndTransform(ctx);
150
179
  ctx.beginPath();
151
180
  //if we only have 2 points in the path and they are the same
@@ -37,15 +37,11 @@
37
37
  * @fires dragover
38
38
  * @fires dragenter
39
39
  * @fires dragleave
40
+ * @fires drop:before before drop event. same native event. This is added to handle edge cases
40
41
  * @fires drop
41
42
  * @fires after:render at the end of the render process, receives the context in the callback
42
43
  * @fires before:render at start the render process, receives the context in the callback
43
44
  *
44
- * the following events are deprecated:
45
- * @fires object:rotated at the end of a rotation transform
46
- * @fires object:scaled at the end of a scale transform
47
- * @fires object:moved at the end of translation transform
48
- * @fires object:skewed at the end of a skew transform
49
45
  */
50
46
  fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {
51
47
 
@@ -230,13 +226,6 @@
230
226
  */
231
227
  freeDrawingCursor: 'crosshair',
232
228
 
233
- /**
234
- * Cursor value used for rotation point
235
- * @type String
236
- * @default
237
- */
238
- rotationCursor: 'crosshair',
239
-
240
229
  /**
241
230
  * Cursor value used for disabled elements ( corners with disabled action )
242
231
  * @type String
@@ -342,6 +331,13 @@
342
331
  */
343
332
  targets: [],
344
333
 
334
+ /**
335
+ * When the option is enabled, PointerEvent is used instead of MouseEvent.
336
+ * @type Boolean
337
+ * @default
338
+ */
339
+ enablePointerEvents: false,
340
+
345
341
  /**
346
342
  * Keep track of the hovered target
347
343
  * @type fabric.Object
@@ -417,6 +413,7 @@
417
413
  }
418
414
  if (this.hasLostContext) {
419
415
  this.renderTopLayer(this.contextTop);
416
+ this.hasLostContext = false;
420
417
  }
421
418
  var canvasToDrawOn = this.contextContainer;
422
419
  this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());
@@ -1086,17 +1083,12 @@
1086
1083
  e: e,
1087
1084
  selected: added,
1088
1085
  deselected: removed,
1089
- // added for backward compatibility
1090
- // deprecated
1091
- updated: added[0] || removed[0],
1092
- target: this._activeObject,
1093
1086
  });
1094
1087
  }
1095
1088
  else if (objects.length > 0) {
1096
1089
  this.fire('selection:created', {
1097
1090
  e: e,
1098
1091
  selected: added,
1099
- target: this._activeObject,
1100
1092
  });
1101
1093
  }
1102
1094
  else if (oldObjects.length > 0) {
@@ -32,17 +32,23 @@
32
32
  /**
33
33
  * Color to make the blend operation with. default to a reddish color since black or white
34
34
  * gives always strong result.
35
+ * @type String
36
+ * @default
35
37
  **/
36
38
  color: '#F95C63',
37
39
 
38
40
  /**
39
41
  * Blend mode for the filter: one of multiply, add, diff, screen, subtract,
40
42
  * darken, lighten, overlay, exclusion, tint.
43
+ * @type String
44
+ * @default
41
45
  **/
42
46
  mode: 'multiply',
43
47
 
44
48
  /**
45
49
  * alpha value. represent the strength of the blend color operation.
50
+ * @type Number
51
+ * @default
46
52
  **/
47
53
  alpha: 1,
48
54
 
@@ -36,8 +36,9 @@
36
36
  image: null,
37
37
 
38
38
  /**
39
- * Blend mode for the filter: one of multiply, add, diff, screen, subtract,
40
- * darken, lighten, overlay, exclusion, tint.
39
+ * Blend mode for the filter (one of "multiply", "mask")
40
+ * @type String
41
+ * @default
41
42
  **/
42
43
  mode: 'multiply',
43
44
 
@@ -73,6 +73,8 @@
73
73
  * blur value, in percentage of image dimensions.
74
74
  * specific to keep the image blur constant at different resolutions
75
75
  * range between 0 and 1.
76
+ * @type Number
77
+ * @default
76
78
  */
77
79
  blur: 0,
78
80
 
@@ -66,8 +66,10 @@
66
66
  mainParameter: 'matrix',
67
67
 
68
68
  /**
69
- * Lock the colormatrix on the color part, skipping alpha, manly for non webgl scenario
69
+ * Lock the colormatrix on the color part, skipping alpha, mainly for non webgl scenario
70
70
  * to save some calculation
71
+ * @type Boolean
72
+ * @default true
71
73
  */
72
74
  colorsOnly: true,
73
75
 
@@ -13,8 +13,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
13
13
  * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
14
14
  * @param {Function} [callbacks.onComplete] Invoked on completion
15
15
  * @param {Function} [callbacks.onChange] Invoked on every step of animation
16
- * @return {fabric.Canvas} thisArg
17
- * @chainable
16
+ * @return {fabric.AnimationContext} context
18
17
  */
19
18
  fxCenterObjectH: function (object, callbacks) {
20
19
  callbacks = callbacks || { };
@@ -24,7 +23,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
24
23
  onChange = callbacks.onChange || empty,
25
24
  _this = this;
26
25
 
27
- fabric.util.animate({
26
+ return fabric.util.animate({
27
+ target: this,
28
28
  startValue: object.left,
29
29
  endValue: this.getCenter().left,
30
30
  duration: this.FX_DURATION,
@@ -38,8 +38,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
38
38
  onComplete();
39
39
  }
40
40
  });
41
-
42
- return this;
43
41
  },
44
42
 
45
43
  /**
@@ -48,8 +46,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
48
46
  * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
49
47
  * @param {Function} [callbacks.onComplete] Invoked on completion
50
48
  * @param {Function} [callbacks.onChange] Invoked on every step of animation
51
- * @return {fabric.Canvas} thisArg
52
- * @chainable
49
+ * @return {fabric.AnimationContext} context
53
50
  */
54
51
  fxCenterObjectV: function (object, callbacks) {
55
52
  callbacks = callbacks || { };
@@ -59,7 +56,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
59
56
  onChange = callbacks.onChange || empty,
60
57
  _this = this;
61
58
 
62
- fabric.util.animate({
59
+ return fabric.util.animate({
60
+ target: this,
63
61
  startValue: object.top,
64
62
  endValue: this.getCenter().top,
65
63
  duration: this.FX_DURATION,
@@ -73,8 +71,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
73
71
  onComplete();
74
72
  }
75
73
  });
76
-
77
- return this;
78
74
  },
79
75
 
80
76
  /**
@@ -83,8 +79,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
83
79
  * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
84
80
  * @param {Function} [callbacks.onComplete] Invoked on completion
85
81
  * @param {Function} [callbacks.onChange] Invoked on every step of animation
86
- * @return {fabric.Canvas} thisArg
87
- * @chainable
82
+ * @return {fabric.AnimationContext} context
88
83
  */
89
84
  fxRemove: function (object, callbacks) {
90
85
  callbacks = callbacks || { };
@@ -94,7 +89,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
94
89
  onChange = callbacks.onChange || empty,
95
90
  _this = this;
96
91
 
97
- fabric.util.animate({
92
+ return fabric.util.animate({
93
+ target: this,
98
94
  startValue: object.opacity,
99
95
  endValue: 0,
100
96
  duration: this.FX_DURATION,
@@ -108,8 +104,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
108
104
  onComplete();
109
105
  }
110
106
  });
111
-
112
- return this;
113
107
  }
114
108
  });
115
109
 
@@ -120,7 +114,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
120
114
  * @param {Number|Object} value Value to animate property to (if string was given first) or options object
121
115
  * @return {fabric.Object} thisArg
122
116
  * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation}
123
- * @chainable
117
+ * @return {fabric.AnimationContext | fabric.AnimationContext[]} animation context (or an array if passed multiple properties)
124
118
  *
125
119
  * As object — multiple properties
126
120
  *
@@ -133,22 +127,22 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
133
127
  * object.animate('left', { duration: ... });
134
128
  *
135
129
  */
136
- animate: function() {
130
+ animate: function () {
137
131
  if (arguments[0] && typeof arguments[0] === 'object') {
138
- var propsToAnimate = [], prop, skipCallbacks;
132
+ var propsToAnimate = [], prop, skipCallbacks, out = [];
139
133
  for (prop in arguments[0]) {
140
134
  propsToAnimate.push(prop);
141
135
  }
142
136
  for (var i = 0, len = propsToAnimate.length; i < len; i++) {
143
137
  prop = propsToAnimate[i];
144
138
  skipCallbacks = i !== len - 1;
145
- this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks);
139
+ out.push(this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks));
146
140
  }
141
+ return out;
147
142
  }
148
143
  else {
149
- this._animate.apply(this, arguments);
144
+ return this._animate.apply(this, arguments);
150
145
  }
151
- return this;
152
146
  },
153
147
 
154
148
  /**
@@ -196,6 +190,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
196
190
  }
197
191
 
198
192
  var _options = {
193
+ target: this,
199
194
  startValue: options.from,
200
195
  endValue: to,
201
196
  byValue: options.by,
@@ -106,7 +106,7 @@
106
106
  this._onDragOver = this._onDragOver.bind(this);
107
107
  this._onDragEnter = this._simpleEventHandler.bind(this, 'dragenter');
108
108
  this._onDragLeave = this._simpleEventHandler.bind(this, 'dragleave');
109
- this._onDrop = this._simpleEventHandler.bind(this, 'drop');
109
+ this._onDrop = this._onDrop.bind(this);
110
110
  this.eventsBound = true;
111
111
  },
112
112
 
@@ -218,6 +218,18 @@
218
218
  this._fireEnterLeaveEvents(target, e);
219
219
  },
220
220
 
221
+ /**
222
+ * `drop:before` is a an event that allow you to schedule logic
223
+ * before the `drop` event. Prefer `drop` event always, but if you need
224
+ * to run some drop-disabling logic on an event, since there is no way
225
+ * to handle event handlers ordering, use `drop:before`
226
+ * @param {Event} e
227
+ */
228
+ _onDrop: function (e) {
229
+ this._simpleEventHandler('drop:before', e);
230
+ return this._simpleEventHandler('drop', e);
231
+ },
232
+
221
233
  /**
222
234
  * @private
223
235
  * @param {Event} e Event object fired on mousedown
@@ -450,25 +462,34 @@
450
462
  );
451
463
  }
452
464
  }
465
+ var corner, pointer;
453
466
  if (target) {
467
+ corner = target._findTargetCorner(
468
+ this.getPointer(e, true),
469
+ fabric.util.isTouchEvent(e)
470
+ );
454
471
  if (target.selectable && target !== this._activeObject && target.activeOn === 'up') {
455
472
  this.setActiveObject(target, e);
456
473
  shouldRender = true;
457
474
  }
458
475
  else {
459
- var corner = target._findTargetCorner(
460
- this.getPointer(e, true),
461
- fabric.util.isTouchEvent(e)
462
- );
463
476
  var control = target.controls[corner],
464
477
  mouseUpHandler = control && control.getMouseUpHandler(e, target, control);
465
478
  if (mouseUpHandler) {
466
- var pointer = this.getPointer(e);
479
+ pointer = this.getPointer(e);
467
480
  mouseUpHandler(e, transform, pointer.x, pointer.y);
468
481
  }
469
482
  }
470
483
  target.isMoving = false;
471
484
  }
485
+ // if we are ending up a transform on a different control or a new object
486
+ // fire the original mouse up from the corner that started the transform
487
+ if (transform && (transform.target !== target || transform.corner !== corner)) {
488
+ var originalControl = transform.target && transform.target.controls[transform.corner],
489
+ originalMouseUpHandler = originalControl && originalControl.getMouseUpHandler(e, target, control);
490
+ pointer = pointer || this.getPointer(e);
491
+ originalMouseUpHandler && originalMouseUpHandler(e, transform, pointer.x, pointer.y);
492
+ }
472
493
  this._setCursorFromEvent(e, target);
473
494
  this._handleEvent(e, 'up', LEFT_CLICK, isClick);
474
495
  this._groupSelector = null;
@@ -550,7 +571,6 @@
550
571
 
551
572
  var transform = this._currentTransform,
552
573
  target = transform.target,
553
- eventName,
554
574
  options = {
555
575
  e: e,
556
576
  target: target,
@@ -565,59 +585,10 @@
565
585
  target.setCoords();
566
586
 
567
587
  if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) {
568
- if (transform.actionPerformed) {
569
- // this is not friendly to the new control api.
570
- // is deprecated.
571
- eventName = this._addEventOptions(options, transform);
572
- this._fire(eventName, options);
573
- }
574
588
  this._fire('modified', options);
575
589
  }
576
590
  },
577
591
 
578
- /**
579
- * Mutate option object in order to add by property and give back the event name.
580
- * @private
581
- * @deprecated since 4.2.0
582
- * @param {Object} options to mutate
583
- * @param {Object} transform to inspect action from
584
- */
585
- _addEventOptions: function(options, transform) {
586
- // we can probably add more details at low cost
587
- // scale change, rotation changes, translation changes
588
- var eventName, by;
589
- switch (transform.action) {
590
- case 'scaleX':
591
- eventName = 'scaled';
592
- by = 'x';
593
- break;
594
- case 'scaleY':
595
- eventName = 'scaled';
596
- by = 'y';
597
- break;
598
- case 'skewX':
599
- eventName = 'skewed';
600
- by = 'x';
601
- break;
602
- case 'skewY':
603
- eventName = 'skewed';
604
- by = 'y';
605
- break;
606
- case 'scale':
607
- eventName = 'scaled';
608
- by = 'equally';
609
- break;
610
- case 'rotate':
611
- eventName = 'rotated';
612
- break;
613
- case 'drag':
614
- eventName = 'moved';
615
- break;
616
- }
617
- options.by = by;
618
- return eventName;
619
- },
620
-
621
592
  /**
622
593
  * @private
623
594
  * @param {Event} e Event object fired on mousedown