fabric 4.6.0 → 5.0.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.
@@ -866,7 +866,13 @@
866
866
  this.insertCharStyleObject(cursorLoc.lineIndex + i, 0, addedLines[i], copiedStyle);
867
867
  }
868
868
  else if (copiedStyle) {
869
- this.styles[cursorLoc.lineIndex + i][0] = copiedStyle[0];
869
+ // this test is required in order to close #6841
870
+ // when a pasted buffer begins with a newline then
871
+ // this.styles[cursorLoc.lineIndex + i] and copiedStyle[0]
872
+ // may be undefined for some reason
873
+ if (this.styles[cursorLoc.lineIndex + i] && copiedStyle[0]) {
874
+ this.styles[cursorLoc.lineIndex + i][0] = copiedStyle[0];
875
+ }
870
876
  }
871
877
  copiedStyle = copiedStyle && copiedStyle.slice(addedLines[i] + 1);
872
878
  }
@@ -45,7 +45,7 @@
45
45
  /**
46
46
  * Describe object's corner position in canvas element coordinates.
47
47
  * includes padding. Used of object detection.
48
- * set and refreshed with setCoords and calcCoords.
48
+ * set and refreshed with setCoords.
49
49
  * @memberOf fabric.Object.prototype
50
50
  */
51
51
  lineCoords: null,
@@ -429,21 +429,6 @@
429
429
  return this.scale(value / this.height / boundingRectFactor);
430
430
  },
431
431
 
432
- /**
433
- * Calculates and returns the .coords of an object.
434
- * unused by the library, only for the end dev.
435
- * @return {Object} Object with tl, tr, br, bl ....
436
- * @chainable
437
- * @deprecated
438
- */
439
- calcCoords: function(absolute) {
440
- // this is a compatibility function to avoid removing calcCoords now.
441
- if (absolute) {
442
- return this.calcACoords();
443
- }
444
- return this.calcOCoords();
445
- },
446
-
447
432
  calcLineCoords: function() {
448
433
  var vpt = this.getViewportTransform(),
449
434
  padding = this.padding, angle = degreesToRadians(this.angle),
@@ -518,7 +503,8 @@
518
503
  * oCoords are used to find the corners
519
504
  * aCoords are used to quickly find an object on the canvas
520
505
  * lineCoords are used to quickly find object during pointer events.
521
- * See {@link https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords|When-to-call-setCoords}
506
+ * See {@link https://github.com/fabricjs/fabric.js/wiki/When-to-call-setCoords} and {@link http://fabricjs.com/fabric-gotchas}
507
+ *
522
508
  * @param {Boolean} [skipCorners] skip calculation of oCoords.
523
509
  * @return {fabric.Object} thisArg
524
510
  * @chainable
@@ -615,23 +601,6 @@
615
601
  return cache.value;
616
602
  },
617
603
 
618
- /*
619
- * Calculate object dimensions from its properties
620
- * @private
621
- * @deprecated since 3.4.0, please use fabric.util._calcDimensionsTransformMatrix
622
- * not including or including flipX, flipY to emulate the flipping boolean
623
- * @return {Object} .x width dimension
624
- * @return {Object} .y height dimension
625
- */
626
- _calcDimensionsTransformMatrix: function(skewX, skewY, flipping) {
627
- return util.calcDimensionsMatrix({
628
- skewX: skewX,
629
- skewY: skewY,
630
- scaleX: this.scaleX * (flipping && this.flipX ? -1 : 1),
631
- scaleY: this.scaleY * (flipping && this.flipY ? -1 : 1)
632
- });
633
- },
634
-
635
604
  /*
636
605
  * Calculate object dimensions from its properties
637
606
  * @private
@@ -18,8 +18,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
18
18
  * @chainable
19
19
  */
20
20
  straighten: function() {
21
- this.rotate(this._getAngleValueForStraighten());
22
- return this;
21
+ return this.rotate(this._getAngleValueForStraighten());
23
22
  },
24
23
 
25
24
  /**
@@ -28,7 +27,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
28
27
  * @param {Function} [callbacks.onComplete] Invoked on completion
29
28
  * @param {Function} [callbacks.onChange] Invoked on every step of animation
30
29
  * @return {fabric.Object} thisArg
31
- * @chainable
32
30
  */
33
31
  fxStraighten: function(callbacks) {
34
32
  callbacks = callbacks || { };
@@ -38,7 +36,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
38
36
  onChange = callbacks.onChange || empty,
39
37
  _this = this;
40
38
 
41
- fabric.util.animate({
39
+ return fabric.util.animate({
40
+ target: this,
42
41
  startValue: this.get('angle'),
43
42
  endValue: this._getAngleValueForStraighten(),
44
43
  duration: this.FX_DURATION,
@@ -51,8 +50,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
51
50
  onComplete();
52
51
  },
53
52
  });
54
-
55
- return this;
56
53
  }
57
54
  });
58
55
 
@@ -74,12 +71,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
74
71
  * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated
75
72
  * @param {fabric.Object} object Object to straighten
76
73
  * @return {fabric.Canvas} thisArg
77
- * @chainable
78
74
  */
79
75
  fxStraightenObject: function (object) {
80
- object.fxStraighten({
76
+ return object.fxStraighten({
81
77
  onChange: this.requestRenderAllBound
82
78
  });
83
- return this;
84
79
  }
85
80
  });
package/src/parser.js CHANGED
@@ -1001,22 +1001,26 @@
1001
1001
  if (styleContents.trim() === '') {
1002
1002
  continue;
1003
1003
  }
1004
- rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g);
1005
- rules = rules.map(function(rule) { return rule.trim(); });
1004
+ // recovers all the rule in this form `body { style code... }`
1005
+ // rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g);
1006
+ rules = styleContents.split('}');
1007
+ // remove empty rules.
1008
+ rules = rules.filter(function(rule) { return rule.trim(); });
1009
+ // at this point we have hopefully an array of rules `body { style code... `
1006
1010
  // eslint-disable-next-line no-loop-func
1007
1011
  rules.forEach(function(rule) {
1008
1012
 
1009
- var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/),
1010
- ruleObj = { }, declaration = match[2].trim(),
1011
- propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/);
1013
+ var match = rule.split('{'),
1014
+ ruleObj = { }, declaration = match[1].trim(),
1015
+ propertyValuePairs = declaration.split(';').filter(function(pair) { return pair.trim(); });
1012
1016
 
1013
1017
  for (i = 0, len = propertyValuePairs.length; i < len; i++) {
1014
- var pair = propertyValuePairs[i].split(/\s*:\s*/),
1015
- property = pair[0],
1016
- value = pair[1];
1018
+ var pair = propertyValuePairs[i].split(':'),
1019
+ property = pair[0].trim(),
1020
+ value = pair[1].trim();
1017
1021
  ruleObj[property] = value;
1018
1022
  }
1019
- rule = match[1];
1023
+ rule = match[0].trim();
1020
1024
  rule.split(',').forEach(function(_rule) {
1021
1025
  _rule = _rule.replace(/^svg/i, '').trim();
1022
1026
  if (_rule === '') {
@@ -3,7 +3,7 @@
3
3
  'use strict';
4
4
 
5
5
  var fabric = global.fabric || (global.fabric = { }),
6
- pi = Math.PI;
6
+ degreesToRadians = fabric.util.degreesToRadians;
7
7
 
8
8
  if (fabric.Circle) {
9
9
  fabric.warn('fabric.Circle is already defined.');
@@ -33,22 +33,20 @@
33
33
  radius: 0,
34
34
 
35
35
  /**
36
- * Start angle of the circle, moving clockwise
37
- * deprecated type, this should be in degree, this was an oversight.
36
+ * degrees of start of the circle.
38
37
  * probably will change to degrees in next major version
39
- * @type Number
38
+ * @type Number 0 - 359
40
39
  * @default 0
41
40
  */
42
41
  startAngle: 0,
43
42
 
44
43
  /**
45
44
  * End angle of the circle
46
- * deprecated type, this should be in degree, this was an oversight.
47
45
  * probably will change to degrees in next major version
48
- * @type Number
49
- * @default 2Pi
46
+ * @type Number 1 - 360
47
+ * @default 360
50
48
  */
51
- endAngle: pi * 2,
49
+ endAngle: 360,
52
50
 
53
51
  cacheProperties: fabric.Object.prototype.cacheProperties.concat('radius', 'startAngle', 'endAngle'),
54
52
 
@@ -86,7 +84,7 @@
86
84
  */
87
85
  _toSVG: function() {
88
86
  var svgString, x = 0, y = 0,
89
- angle = (this.endAngle - this.startAngle) % ( 2 * pi);
87
+ angle = (this.endAngle - this.startAngle) % 360;
90
88
 
91
89
  if (angle === 0) {
92
90
  svgString = [
@@ -97,14 +95,17 @@
97
95
  ];
98
96
  }
99
97
  else {
100
- var startX = fabric.util.cos(this.startAngle) * this.radius,
101
- startY = fabric.util.sin(this.startAngle) * this.radius,
102
- endX = fabric.util.cos(this.endAngle) * this.radius,
103
- endY = fabric.util.sin(this.endAngle) * this.radius,
104
- largeFlag = angle > pi ? '1' : '0';
98
+ var start = degreesToRadians(this.startAngle),
99
+ end = degreesToRadians(this.endAngle),
100
+ radius = this.radius,
101
+ startX = fabric.util.cos(start) * radius,
102
+ startY = fabric.util.sin(start) * radius,
103
+ endX = fabric.util.cos(end) * radius,
104
+ endY = fabric.util.sin(end) * radius,
105
+ largeFlag = angle > 180 ? '1' : '0';
105
106
  svgString = [
106
107
  '<path d="M ' + startX + ' ' + startY,
107
- ' A ' + this.radius + ' ' + this.radius,
108
+ ' A ' + radius + ' ' + radius,
108
109
  ' 0 ', +largeFlag + ' 1', ' ' + endX + ' ' + endY,
109
110
  '" ', 'COMMON_PARTS', ' />\n'
110
111
  ];
@@ -123,8 +124,10 @@
123
124
  0,
124
125
  0,
125
126
  this.radius,
126
- this.startAngle,
127
- this.endAngle, false);
127
+ degreesToRadians(this.startAngle),
128
+ degreesToRadians(this.endAngle),
129
+ false
130
+ );
128
131
  this._renderPaintInOrder(ctx);
129
132
  },
130
133
 
@@ -343,7 +343,7 @@
343
343
  for (var i = 0, len = this._objects.length; i < len; i++) {
344
344
  this._objects[i].render(ctx);
345
345
  }
346
- this._drawClipPath(ctx);
346
+ this._drawClipPath(ctx, this.clipPath);
347
347
  },
348
348
 
349
349
  /**
@@ -389,25 +389,6 @@
389
389
  return this;
390
390
  },
391
391
 
392
- /**
393
- * Realises the transform from this group onto the supplied object
394
- * i.e. it tells you what would happen if the supplied object was in
395
- * the group, and then the group was destroyed. It mutates the supplied
396
- * object.
397
- * Warning: this method is not useful anymore, it has been kept to no break the api.
398
- * is not used in the fabricJS codebase
399
- * this method will be reduced to using the utility.
400
- * @private
401
- * @deprecated
402
- * @param {fabric.Object} object
403
- * @param {Array} parentMatrix parent transformation
404
- * @return {fabric.Object} transformedObject
405
- */
406
- realizeTransform: function(object, parentMatrix) {
407
- fabric.util.addTransformToObject(object, parentMatrix);
408
- return object;
409
- },
410
-
411
392
  /**
412
393
  * Destroys a group (restoring state of its objects)
413
394
  * @return {fabric.Group} thisArg
@@ -422,6 +403,14 @@
422
403
  return this._restoreObjectsState();
423
404
  },
424
405
 
406
+ dispose: function () {
407
+ this.callSuper('dispose');
408
+ this.forEachObject(function (object) {
409
+ object.dispose && object.dispose();
410
+ });
411
+ this._objects = [];
412
+ },
413
+
425
414
  /**
426
415
  * make a group an active selection, remove the group from canvas
427
416
  * the group has to be on canvas for this to work.
@@ -585,11 +574,10 @@
585
574
  });
586
575
  return;
587
576
  }
588
- fabric.util.enlivenObjects(objects, function(enlivenedObjects) {
589
- fabric.util.enlivenObjects([object.clipPath], function(enlivedClipPath) {
590
- var options = fabric.util.object.clone(object, true);
591
- options.clipPath = enlivedClipPath[0];
592
- delete options.objects;
577
+ fabric.util.enlivenObjects(objects, function (enlivenedObjects) {
578
+ var options = fabric.util.object.clone(object, true);
579
+ delete options.objects;
580
+ fabric.util.enlivenObjectEnlivables(object, options, function () {
593
581
  callback && callback(new fabric.Group(enlivenedObjects, options, true));
594
582
  });
595
583
  });
@@ -202,7 +202,8 @@
202
202
  /**
203
203
  * Delete textures, reference to elements and eventually JSDOM cleanup
204
204
  */
205
- dispose: function() {
205
+ dispose: function () {
206
+ this.callSuper('dispose');
206
207
  this.removeTexture(this.cacheKey);
207
208
  this.removeTexture(this.cacheKey + '_filtered');
208
209
  this._cacheContext = undefined;
@@ -712,8 +713,7 @@
712
713
  object.filters = filters || [];
713
714
  fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) {
714
715
  object.resizeFilter = resizeFilters[0];
715
- fabric.util.enlivenObjects([object.clipPath], function(enlivedProps) {
716
- object.clipPath = enlivedProps[0];
716
+ fabric.util.enlivenObjectEnlivables(object, object, function () {
717
717
  var image = new fabric.Image(img, object);
718
718
  callback(image, false);
719
719
  });
@@ -536,6 +536,7 @@
536
536
  /**
537
537
  * When `false`, the stoke width will scale with the object.
538
538
  * When `true`, the stroke will always match the exact pixel size entered for stroke width.
539
+ * this Property does not work on Text classes or drawing call that uses strokeText,fillText methods
539
540
  * default to false
540
541
  * @since 2.6.0
541
542
  * @type Boolean
@@ -1186,26 +1187,26 @@
1186
1187
  /**
1187
1188
  * Execute the drawing operation for an object clipPath
1188
1189
  * @param {CanvasRenderingContext2D} ctx Context to render on
1190
+ * @param {fabric.Object} clipPath
1189
1191
  */
1190
- drawClipPathOnCache: function(ctx) {
1191
- var path = this.clipPath;
1192
+ drawClipPathOnCache: function(ctx, clipPath) {
1192
1193
  ctx.save();
1193
1194
  // DEBUG: uncomment this line, comment the following
1194
1195
  // ctx.globalAlpha = 0.4
1195
- if (path.inverted) {
1196
+ if (clipPath.inverted) {
1196
1197
  ctx.globalCompositeOperation = 'destination-out';
1197
1198
  }
1198
1199
  else {
1199
1200
  ctx.globalCompositeOperation = 'destination-in';
1200
1201
  }
1201
1202
  //ctx.scale(1 / 2, 1 / 2);
1202
- if (path.absolutePositioned) {
1203
+ if (clipPath.absolutePositioned) {
1203
1204
  var m = fabric.util.invertTransform(this.calcTransformMatrix());
1204
1205
  ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
1205
1206
  }
1206
- path.transform(ctx);
1207
- ctx.scale(1 / path.zoomX, 1 / path.zoomY);
1208
- ctx.drawImage(path._cacheCanvas, -path.cacheTranslationX, -path.cacheTranslationY);
1207
+ clipPath.transform(ctx);
1208
+ ctx.scale(1 / clipPath.zoomX, 1 / clipPath.zoomY);
1209
+ ctx.drawImage(clipPath._cacheCanvas, -clipPath.cacheTranslationX, -clipPath.cacheTranslationY);
1209
1210
  ctx.restore();
1210
1211
  },
1211
1212
 
@@ -1224,22 +1225,26 @@
1224
1225
  this._renderBackground(ctx);
1225
1226
  }
1226
1227
  this._render(ctx);
1227
- this._drawClipPath(ctx);
1228
+ this._drawClipPath(ctx, this.clipPath);
1228
1229
  this.fill = originalFill;
1229
1230
  this.stroke = originalStroke;
1230
1231
  },
1231
1232
 
1232
- _drawClipPath: function(ctx) {
1233
- var path = this.clipPath;
1234
- if (!path) { return; }
1233
+ /**
1234
+ * Prepare clipPath state and cache and draw it on instance's cache
1235
+ * @param {CanvasRenderingContext2D} ctx
1236
+ * @param {fabric.Object} clipPath
1237
+ */
1238
+ _drawClipPath: function (ctx, clipPath) {
1239
+ if (!clipPath) { return; }
1235
1240
  // needed to setup a couple of variables
1236
1241
  // path canvas gets overridden with this one.
1237
1242
  // TODO find a better solution?
1238
- path.canvas = this.canvas;
1239
- path.shouldCache();
1240
- path._transformDone = true;
1241
- path.renderCache({ forClipping: true });
1242
- this.drawClipPathOnCache(ctx);
1243
+ clipPath.canvas = this.canvas;
1244
+ clipPath.shouldCache();
1245
+ clipPath._transformDone = true;
1246
+ clipPath.renderCache({ forClipping: true });
1247
+ this.drawClipPathOnCache(ctx, clipPath);
1243
1248
  },
1244
1249
 
1245
1250
  /**
@@ -1383,6 +1388,7 @@
1383
1388
 
1384
1389
  /**
1385
1390
  * Renders controls and borders for the object
1391
+ * the context here is not transformed
1386
1392
  * @param {CanvasRenderingContext2D} ctx Context to render on
1387
1393
  * @param {Object} [styleOverride] properties to override the object style
1388
1394
  */
@@ -1401,7 +1407,10 @@
1401
1407
  if (!this.group) {
1402
1408
  ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
1403
1409
  }
1404
- ctx.rotate(degreesToRadians(options.angle));
1410
+ if (this.flipX) {
1411
+ options.angle -= 180;
1412
+ }
1413
+ ctx.rotate(degreesToRadians(this.group ? options.angle : this.angle));
1405
1414
  if (styleOverride.forActiveSelection || this.group) {
1406
1415
  drawBorders && this.drawBordersInGroup(ctx, options, styleOverride);
1407
1416
  }
@@ -1937,6 +1946,15 @@
1937
1946
  if (this.globalCompositeOperation) {
1938
1947
  ctx.globalCompositeOperation = this.globalCompositeOperation;
1939
1948
  }
1949
+ },
1950
+
1951
+ /**
1952
+ * cancel instance's running animations
1953
+ */
1954
+ dispose: function () {
1955
+ if (fabric.runningAnimations) {
1956
+ fabric.runningAnimations.cancelByTarget(this);
1957
+ }
1940
1958
  }
1941
1959
  });
1942
1960
 
@@ -1954,6 +1972,15 @@
1954
1972
  */
1955
1973
  fabric.Object.NUM_FRACTION_DIGITS = 2;
1956
1974
 
1975
+ /**
1976
+ * Defines which properties should be enlivened from the object passed to {@link fabric.Object._fromObject}
1977
+ * @static
1978
+ * @memberOf fabric.Object
1979
+ * @constant
1980
+ * @type string[]
1981
+ */
1982
+ fabric.Object.ENLIVEN_PROPS = ['clipPath'];
1983
+
1957
1984
  fabric.Object._fromObject = function(className, object, callback, extraParam) {
1958
1985
  var klass = fabric[className];
1959
1986
  object = clone(object, true);
@@ -1964,8 +1991,7 @@
1964
1991
  if (typeof patterns[1] !== 'undefined') {
1965
1992
  object.stroke = patterns[1];
1966
1993
  }
1967
- fabric.util.enlivenObjects([object.clipPath], function(enlivedProps) {
1968
- object.clipPath = enlivedProps[0];
1994
+ fabric.util.enlivenObjectEnlivables(object, object, function () {
1969
1995
  var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);
1970
1996
  callback && callback(instance);
1971
1997
  });
@@ -6,6 +6,7 @@
6
6
  min = fabric.util.array.min,
7
7
  max = fabric.util.array.max,
8
8
  extend = fabric.util.object.extend,
9
+ clone = fabric.util.object.clone,
9
10
  _toString = Object.prototype.toString,
10
11
  toFixed = fabric.util.toFixed;
11
12
 
@@ -47,23 +48,26 @@
47
48
  * @param {Object} [options] Options object
48
49
  * @return {fabric.Path} thisArg
49
50
  */
50
- initialize: function(path, options) {
51
- options = options || { };
51
+ initialize: function (path, options) {
52
+ options = clone(options || {});
53
+ delete options.path;
52
54
  this.callSuper('initialize', options);
53
- if (!path) {
54
- path = [];
55
- }
55
+ this._setPath(path || [], options);
56
+ },
56
57
 
58
+ /**
59
+ * @private
60
+ * @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens)
61
+ * @param {Object} [options] Options object
62
+ */
63
+ _setPath: function (path, options) {
57
64
  var fromArray = _toString.call(path) === '[object Array]';
58
65
 
59
66
  this.path = fabric.util.makePathSimpler(
60
67
  fromArray ? path : fabric.util.parsePath(path)
61
68
  );
62
69
 
63
- if (!this.path) {
64
- return;
65
- }
66
- fabric.Polyline.prototype._setPositionDimensions.call(this, options);
70
+ fabric.Polyline.prototype._setPositionDimensions.call(this, options || {});
67
71
  },
68
72
 
69
73
  /**
@@ -2,7 +2,8 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- var fabric = global.fabric || (global.fabric = { });
5
+ var fabric = global.fabric || (global.fabric = {}),
6
+ projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;
6
7
 
7
8
  if (fabric.Polygon) {
8
9
  fabric.warn('fabric.Polygon is already defined');
@@ -24,6 +25,13 @@
24
25
  */
25
26
  type: 'polygon',
26
27
 
28
+ /**
29
+ * @private
30
+ */
31
+ _projectStrokeOnPoints: function () {
32
+ return projectStrokeOnPoints(this.points, this);
33
+ },
34
+
27
35
  /**
28
36
  * @private
29
37
  * @param {CanvasRenderingContext2D} ctx Context to render on
@@ -6,7 +6,8 @@
6
6
  extend = fabric.util.object.extend,
7
7
  min = fabric.util.array.min,
8
8
  max = fabric.util.array.max,
9
- toFixed = fabric.util.toFixed;
9
+ toFixed = fabric.util.toFixed,
10
+ projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;
10
11
 
11
12
  if (fabric.Polyline) {
12
13
  fabric.warn('fabric.Polyline is already defined');
@@ -35,6 +36,17 @@
35
36
  */
36
37
  points: null,
37
38
 
39
+ /**
40
+ * WARNING: Feature in progress
41
+ * Calculate the exact bounding box taking in account strokeWidth on acute angles
42
+ * this will be turned to true by default on fabric 6.0
43
+ * maybe will be left in as an optimization since calculations may be slow
44
+ * @deprecated
45
+ * @type Boolean
46
+ * @default false
47
+ */
48
+ exactBoundingBox: false,
49
+
38
50
  cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'),
39
51
 
40
52
  /**
@@ -63,13 +75,25 @@
63
75
  this._setPositionDimensions(options);
64
76
  },
65
77
 
78
+ /**
79
+ * @private
80
+ */
81
+ _projectStrokeOnPoints: function () {
82
+ return projectStrokeOnPoints(this.points, this, true);
83
+ },
84
+
66
85
  _setPositionDimensions: function(options) {
67
- var calcDim = this._calcDimensions(options), correctLeftTop;
68
- this.width = calcDim.width;
69
- this.height = calcDim.height;
86
+ var calcDim = this._calcDimensions(options), correctLeftTop,
87
+ correctSize = this.exactBoundingBox ? this.strokeWidth : 0;
88
+ this.width = calcDim.width - correctSize;
89
+ this.height = calcDim.height - correctSize;
70
90
  if (!options.fromSVG) {
71
91
  correctLeftTop = this.translateToGivenOrigin(
72
- { x: calcDim.left - this.strokeWidth / 2, y: calcDim.top - this.strokeWidth / 2 },
92
+ {
93
+ // this looks bad, but is one way to keep it optional for now.
94
+ x: calcDim.left - this.strokeWidth / 2 + correctSize / 2,
95
+ y: calcDim.top - this.strokeWidth / 2 + correctSize / 2
96
+ },
73
97
  'left',
74
98
  'top',
75
99
  this.originX,
@@ -83,8 +107,8 @@
83
107
  this.top = options.fromSVG ? calcDim.top : correctLeftTop.y;
84
108
  }
85
109
  this.pathOffset = {
86
- x: calcDim.left + this.width / 2,
87
- y: calcDim.top + this.height / 2
110
+ x: calcDim.left + this.width / 2 + correctSize / 2,
111
+ y: calcDim.top + this.height / 2 + correctSize / 2
88
112
  };
89
113
  },
90
114
 
@@ -100,7 +124,7 @@
100
124
  */
101
125
  _calcDimensions: function() {
102
126
 
103
- var points = this.points,
127
+ var points = this.exactBoundingBox ? this._projectStrokeOnPoints() : this.points,
104
128
  minX = min(points, 'x') || 0,
105
129
  minY = min(points, 'y') || 0,
106
130
  maxX = max(points, 'x') || 0,
@@ -112,7 +136,7 @@
112
136
  left: minX,
113
137
  top: minY,
114
138
  width: width,
115
- height: height
139
+ height: height,
116
140
  };
117
141
  },
118
142