fabric 2.4.5 → 2.7.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.
- package/.travis.yml +3 -6
- package/CHANGELOG.md +23 -0
- package/dist/fabric.js +289 -219
- package/package.json +4 -4
package/.travis.yml
CHANGED
|
@@ -75,10 +75,7 @@ jobs:
|
|
|
75
75
|
- stage: Unit Tests
|
|
76
76
|
env: CANVAS=canvas-prebuilt
|
|
77
77
|
node_js: "8"
|
|
78
|
-
|
|
79
|
-
directories:
|
|
80
|
-
- ''
|
|
81
|
-
install: npm install && npm remove canvas && npm install canvas-prebuilt@^1.6.11
|
|
78
|
+
install: npm install && npm remove canvas && npm install canvas-prebuilt@^1.6.11 qunit@2.6.1
|
|
82
79
|
addons:
|
|
83
80
|
apt:
|
|
84
81
|
packages: # avoid installing packages
|
|
@@ -88,14 +85,14 @@ jobs:
|
|
|
88
85
|
script: npm run build:fast && npm run test:visual
|
|
89
86
|
- stage: Visual Tests
|
|
90
87
|
env: LAUNCHER=Chrome
|
|
91
|
-
install: npm install testem@1.18.4 qunit@2.6.
|
|
88
|
+
install: npm install testem@1.18.4 qunit@2.6.2
|
|
92
89
|
script: npm run build:fast && testem ci --port 8080 -f testem-visual.json -l $LAUNCHER
|
|
93
90
|
addons:
|
|
94
91
|
apt:
|
|
95
92
|
packages: # avoid installing packages
|
|
96
93
|
- stage: Visual Tests
|
|
97
94
|
env: LAUNCHER=Firefox
|
|
98
|
-
install: npm install testem@1.18.4 qunit@2.6.
|
|
95
|
+
install: npm install testem@1.18.4 qunit@2.6.2
|
|
99
96
|
script: npm run build:fast && testem ci --port 8080 -f testem-visual.json -l $LAUNCHER
|
|
100
97
|
addons:
|
|
101
98
|
apt:
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.7.0]
|
|
4
|
+
- Add: strokeUniform property, avoid stroke scaling with paths [#5473](https://github.com/fabricjs/fabric.js/pull/5473)
|
|
5
|
+
- Fix: fix bug in image setSrc [#5502](https://github.com/fabricjs/fabric.js/pull/5502)
|
|
6
|
+
- Add: strokeUniform import/export svg [#5527](https://github.com/fabricjs/fabric.js/pull/5527)
|
|
7
|
+
- Fix: GraphemeSplit and toSvg for circle [#5544](https://github.com/fabricjs/fabric.js/pull/5544)
|
|
8
|
+
- Improvement: support running in a XML document [#5530](https://github.com/fabricjs/fabric.js/pull/5530)
|
|
9
|
+
|
|
10
|
+
## [2.6.0]
|
|
11
|
+
- Fix: avoid ie11 to throw on weird draw images [#5428](https://github.com/fabricjs/fabric.js/pull/5428)
|
|
12
|
+
- Fix: a rare case of invisible clipPath [#5477](https://github.com/fabricjs/fabric.js/pull/5477)
|
|
13
|
+
- Fix: testability of code under node when webgl is involved [#5478](https://github.com/fabricjs/fabric.js/pull/5478)
|
|
14
|
+
- Add: Grapeheme text wrapping for Textbox (Textbox.splitByGrapheme) [#5479](https://github.com/fabricjs/fabric.js/pull/5479)
|
|
15
|
+
- Add: fabric.Object.toCanvasElement [#5481](https://github.com/fabricjs/fabric.js/pull/5481)
|
|
16
|
+
|
|
17
|
+
## [2.5.0]
|
|
18
|
+
- Fix: textbox transform report newScaleX and newScaleY values [#5464](https://github.com/fabricjs/fabric.js/pull/5464)
|
|
19
|
+
- Fix: export of svg and gradient with transforms [#5456](https://github.com/fabricjs/fabric.js/pull/5456)
|
|
20
|
+
- Fix: detection of controls in perPixelTargetFind + cache [#5455](https://github.com/fabricjs/fabric.js/pull/5455)
|
|
21
|
+
- Add: added canvas.toCanvasElement method [#5452](https://github.com/fabricjs/fabric.js/pull/5452)
|
|
22
|
+
|
|
23
|
+
## [2.4.6]
|
|
24
|
+
- Fix: unbreak the svg export broken in 2.4.5 [#5438](https://github.com/fabricjs/fabric.js/pull/5438)
|
|
25
|
+
|
|
3
26
|
## [2.4.5]
|
|
4
27
|
- Fix: svg import/export for canvas+clipPath and letterspacing. [#5424](https://github.com/fabricjs/fabric.js/pull/5424)
|
|
5
28
|
- Fix: avoid stroke dash from group selection to leak on upper canvas [#5392](https://github.com/fabricjs/fabric.js/pull/5392)
|
package/dist/fabric.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* build: `node build.js modules=ALL exclude=gestures,accessors requirejs minifier=uglifyjs` */
|
|
2
2
|
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
|
|
3
3
|
|
|
4
|
-
var fabric = fabric || { version: '2.
|
|
4
|
+
var fabric = fabric || { version: '2.7.0' };
|
|
5
5
|
if (typeof exports !== 'undefined') {
|
|
6
6
|
exports.fabric = fabric;
|
|
7
7
|
}
|
|
@@ -11,7 +11,10 @@ else if (typeof define === 'function' && define.amd) {
|
|
|
11
11
|
}
|
|
12
12
|
/* _AMD_END_ */
|
|
13
13
|
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
|
14
|
-
|
|
14
|
+
if (document instanceof HTMLDocument)
|
|
15
|
+
fabric.document = document;
|
|
16
|
+
else
|
|
17
|
+
fabric.document = document.implementation.createHTMLDocument("");
|
|
15
18
|
fabric.window = window;
|
|
16
19
|
}
|
|
17
20
|
else {
|
|
@@ -56,7 +59,7 @@ fabric.SHARED_ATTRIBUTES = [
|
|
|
56
59
|
'stroke', 'stroke-dasharray', 'stroke-linecap', 'stroke-dashoffset',
|
|
57
60
|
'stroke-linejoin', 'stroke-miterlimit',
|
|
58
61
|
'stroke-opacity', 'stroke-width',
|
|
59
|
-
'id', 'paint-order',
|
|
62
|
+
'id', 'paint-order', 'vector-effect',
|
|
60
63
|
'instantiated_by_use', 'clip-path'
|
|
61
64
|
];
|
|
62
65
|
/* _FROM_SVG_END_ */
|
|
@@ -1174,6 +1177,7 @@ fabric.CommonMethods = {
|
|
|
1174
1177
|
|
|
1175
1178
|
/**
|
|
1176
1179
|
* Creates a canvas element that is a copy of another and is also painted
|
|
1180
|
+
* @param {CanvasElement} canvas to copy size and content of
|
|
1177
1181
|
* @static
|
|
1178
1182
|
* @memberOf fabric.util
|
|
1179
1183
|
* @return {CanvasElement} initialized canvas element
|
|
@@ -1186,6 +1190,19 @@ fabric.CommonMethods = {
|
|
|
1186
1190
|
return newCanvas;
|
|
1187
1191
|
},
|
|
1188
1192
|
|
|
1193
|
+
/**
|
|
1194
|
+
* since 2.6.0 moved from canvas instance to utility.
|
|
1195
|
+
* @param {CanvasElement} canvasEl to copy size and content of
|
|
1196
|
+
* @param {String} format 'jpeg' or 'png', in some browsers 'webp' is ok too
|
|
1197
|
+
* @param {Number} quality <= 1 and > 0
|
|
1198
|
+
* @static
|
|
1199
|
+
* @memberOf fabric.util
|
|
1200
|
+
* @return {String} data url
|
|
1201
|
+
*/
|
|
1202
|
+
toDataURL: function(canvasEl, format, quality) {
|
|
1203
|
+
return canvasEl.toDataURL('image/' + format, quality);
|
|
1204
|
+
},
|
|
1205
|
+
|
|
1189
1206
|
/**
|
|
1190
1207
|
* Creates image element (works on client and node)
|
|
1191
1208
|
* @static
|
|
@@ -3397,6 +3414,7 @@ if (typeof console !== 'undefined') {
|
|
|
3397
3414
|
opacity: 'opacity',
|
|
3398
3415
|
'clip-path': 'clipPath',
|
|
3399
3416
|
'clip-rule': 'clipRule',
|
|
3417
|
+
'vector-effect': 'strokeUniform'
|
|
3400
3418
|
},
|
|
3401
3419
|
|
|
3402
3420
|
colorAttributes = {
|
|
@@ -3428,6 +3446,9 @@ if (typeof console !== 'undefined') {
|
|
|
3428
3446
|
if ((attr === 'fill' || attr === 'stroke') && value === 'none') {
|
|
3429
3447
|
value = '';
|
|
3430
3448
|
}
|
|
3449
|
+
else if (attr === 'vector-effect') {
|
|
3450
|
+
value = value === 'non-scaling-stroke';
|
|
3451
|
+
}
|
|
3431
3452
|
else if (attr === 'strokeDashArray') {
|
|
3432
3453
|
if (value === 'none') {
|
|
3433
3454
|
value = null;
|
|
@@ -5874,29 +5895,25 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
5874
5895
|
var coords = clone(this.coords, true), i, len,
|
|
5875
5896
|
markup, commonAttributes, colorStops = clone(this.colorStops, true),
|
|
5876
5897
|
needsSwap = coords.r1 > coords.r2,
|
|
5877
|
-
|
|
5898
|
+
transform = this.gradientTransform ? this.gradientTransform.concat() : fabric.iMatrix.concat(),
|
|
5899
|
+
offsetX = object.width / 2 - this.offsetX, offsetY = object.height / 2 - this.offsetY;
|
|
5878
5900
|
// colorStops must be sorted ascending
|
|
5879
5901
|
colorStops.sort(function(a, b) {
|
|
5880
5902
|
return a.offset - b.offset;
|
|
5881
5903
|
});
|
|
5904
|
+
|
|
5882
5905
|
if (object.type === 'path') {
|
|
5883
5906
|
offsetX -= object.pathOffset.x;
|
|
5884
5907
|
offsetY -= object.pathOffset.y;
|
|
5885
5908
|
}
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
}
|
|
5890
|
-
else if (prop === 'y1' || prop === 'y2') {
|
|
5891
|
-
coords[prop] += this.offsetY - offsetY;
|
|
5892
|
-
}
|
|
5893
|
-
}
|
|
5909
|
+
|
|
5910
|
+
transform[4] -= offsetX;
|
|
5911
|
+
transform[5] -= offsetY;
|
|
5894
5912
|
|
|
5895
5913
|
commonAttributes = 'id="SVGID_' + this.id +
|
|
5896
5914
|
'" gradientUnits="userSpaceOnUse"';
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
}
|
|
5915
|
+
commonAttributes += ' gradientTransform="matrix(' + transform.join(' ') + ')" ';
|
|
5916
|
+
|
|
5900
5917
|
if (this.type === 'linear') {
|
|
5901
5918
|
markup = [
|
|
5902
5919
|
'<linearGradient ',
|
|
@@ -6631,6 +6648,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
6631
6648
|
|
|
6632
6649
|
/**
|
|
6633
6650
|
* Indicates whether toObject/toDatalessObject should include default values
|
|
6651
|
+
* if set to false, takes precedence over the object value.
|
|
6634
6652
|
* @type Boolean
|
|
6635
6653
|
* @default
|
|
6636
6654
|
*/
|
|
@@ -7713,7 +7731,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
7713
7731
|
objects: this._toObjects(methodName, propertiesToInclude),
|
|
7714
7732
|
};
|
|
7715
7733
|
if (clipPath) {
|
|
7716
|
-
clipPath =
|
|
7734
|
+
data.clipPath = this._toObjectMethod(clipPath, methodName, propertiesToInclude);
|
|
7717
7735
|
}
|
|
7718
7736
|
extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));
|
|
7719
7737
|
|
|
@@ -8331,7 +8349,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
8331
8349
|
* (either those of HTMLCanvasElement itself, or rendering context)
|
|
8332
8350
|
*
|
|
8333
8351
|
* @param {String} methodName Method to check support for;
|
|
8334
|
-
* Could be one of "
|
|
8352
|
+
* Could be one of "setLineDash"
|
|
8335
8353
|
* @return {Boolean | null} `true` if method is supported (or at least exists),
|
|
8336
8354
|
* `null` if canvas element or context can not be initialized
|
|
8337
8355
|
*/
|
|
@@ -8349,23 +8367,9 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
8349
8367
|
|
|
8350
8368
|
switch (methodName) {
|
|
8351
8369
|
|
|
8352
|
-
case 'getImageData':
|
|
8353
|
-
return typeof ctx.getImageData !== 'undefined';
|
|
8354
|
-
|
|
8355
8370
|
case 'setLineDash':
|
|
8356
8371
|
return typeof ctx.setLineDash !== 'undefined';
|
|
8357
8372
|
|
|
8358
|
-
case 'toDataURL':
|
|
8359
|
-
return typeof el.toDataURL !== 'undefined';
|
|
8360
|
-
|
|
8361
|
-
case 'toDataURLWithQuality':
|
|
8362
|
-
try {
|
|
8363
|
-
el.toDataURL('image/jpeg', 0);
|
|
8364
|
-
return true;
|
|
8365
|
-
}
|
|
8366
|
-
catch (e) { }
|
|
8367
|
-
return false;
|
|
8368
|
-
|
|
8369
8373
|
default:
|
|
8370
8374
|
return null;
|
|
8371
8375
|
}
|
|
@@ -9714,13 +9718,15 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
9714
9718
|
* @return {Boolean}
|
|
9715
9719
|
*/
|
|
9716
9720
|
isTargetTransparent: function (target, x, y) {
|
|
9717
|
-
|
|
9721
|
+
// in case the target is the activeObject, we cannot execute this optimization
|
|
9722
|
+
// because we need to draw controls too.
|
|
9723
|
+
if (target.shouldCache() && target._cacheCanvas && target !== this._activeObject) {
|
|
9718
9724
|
var normalizedPointer = this._normalizePointer(target, {x: x, y: y}),
|
|
9719
|
-
targetRelativeX = target.cacheTranslationX + (normalizedPointer.x * target.zoomX),
|
|
9720
|
-
targetRelativeY = target.cacheTranslationY + (normalizedPointer.y * target.zoomY);
|
|
9725
|
+
targetRelativeX = Math.max(target.cacheTranslationX + (normalizedPointer.x * target.zoomX), 0),
|
|
9726
|
+
targetRelativeY = Math.max(target.cacheTranslationY + (normalizedPointer.y * target.zoomY), 0);
|
|
9721
9727
|
|
|
9722
9728
|
var isTransparent = fabric.util.isTransparent(
|
|
9723
|
-
target._cacheContext, targetRelativeX, targetRelativeY, this.targetFindTolerance);
|
|
9729
|
+
target._cacheContext, Math.round(targetRelativeX), Math.round(targetRelativeY), this.targetFindTolerance);
|
|
9724
9730
|
|
|
9725
9731
|
return isTransparent;
|
|
9726
9732
|
}
|
|
@@ -9850,8 +9856,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
9850
9856
|
|
|
9851
9857
|
/**
|
|
9852
9858
|
* @private
|
|
9859
|
+
* @param {Boolean} alreadySelected true if target is already selected
|
|
9860
|
+
* @param {String} corner a string representing the corner ml, mr, tl ...
|
|
9861
|
+
* @param {Event} e Event object
|
|
9862
|
+
* @param {fabric.Object} [target] inserted back to help overriding. Unused
|
|
9853
9863
|
*/
|
|
9854
|
-
_getActionFromCorner: function(alreadySelected, corner, e) {
|
|
9864
|
+
_getActionFromCorner: function(alreadySelected, corner, e /* target */) {
|
|
9855
9865
|
if (!corner || !alreadySelected) {
|
|
9856
9866
|
return 'drag';
|
|
9857
9867
|
}
|
|
@@ -9882,7 +9892,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
9882
9892
|
|
|
9883
9893
|
var pointer = this.getPointer(e),
|
|
9884
9894
|
corner = target._findTargetCorner(this.getPointer(e, true)),
|
|
9885
|
-
action = this._getActionFromCorner(alreadySelected, corner, e),
|
|
9895
|
+
action = this._getActionFromCorner(alreadySelected, corner, e, target),
|
|
9886
9896
|
origin = this._getOriginFromCorner(target, corner);
|
|
9887
9897
|
|
|
9888
9898
|
this._currentTransform = {
|
|
@@ -10099,12 +10109,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
10099
10109
|
*/
|
|
10100
10110
|
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
|
|
10101
10111
|
var target = transform.target, forbidScalingX = false, forbidScalingY = false, scaled = false,
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
changeX = target.scaleX !== scaleX;
|
|
10107
|
-
changeY = target.scaleY !== scaleY;
|
|
10112
|
+
scaleX = localMouse.x * target.scaleX / _dim.x,
|
|
10113
|
+
scaleY = localMouse.y * target.scaleY / _dim.y,
|
|
10114
|
+
changeX = target.scaleX !== scaleX,
|
|
10115
|
+
changeY = target.scaleY !== scaleY;
|
|
10108
10116
|
|
|
10109
10117
|
if (lockScalingFlip && scaleX <= 0 && scaleX < target.scaleX) {
|
|
10110
10118
|
forbidScalingX = true;
|
|
@@ -10124,10 +10132,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
10124
10132
|
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));
|
|
10125
10133
|
}
|
|
10126
10134
|
else if (by === 'x' && !target.get('lockUniScaling')) {
|
|
10127
|
-
forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled =
|
|
10135
|
+
forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = changeX));
|
|
10128
10136
|
}
|
|
10129
10137
|
else if (by === 'y' && !target.get('lockUniScaling')) {
|
|
10130
|
-
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled =
|
|
10138
|
+
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = changeY));
|
|
10131
10139
|
}
|
|
10132
10140
|
transform.newScaleX = scaleX;
|
|
10133
10141
|
transform.newScaleY = scaleY;
|
|
@@ -10145,15 +10153,15 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
10145
10153
|
lastDist = _dim.y * transform.original.scaleY / target.scaleY +
|
|
10146
10154
|
_dim.x * transform.original.scaleX / target.scaleX,
|
|
10147
10155
|
scaled, signX = localMouse.x < 0 ? -1 : 1,
|
|
10148
|
-
signY = localMouse.y < 0 ? -1 : 1;
|
|
10156
|
+
signY = localMouse.y < 0 ? -1 : 1, newScaleX, newScaleY;
|
|
10149
10157
|
|
|
10150
10158
|
// We use transform.scaleX/Y instead of target.scaleX/Y
|
|
10151
10159
|
// because the object may have a min scale and we'll loose the proportions
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
scaled =
|
|
10155
|
-
target.set('scaleX',
|
|
10156
|
-
target.set('scaleY',
|
|
10160
|
+
newScaleX = signX * Math.abs(transform.original.scaleX * dist / lastDist);
|
|
10161
|
+
newScaleY = signY * Math.abs(transform.original.scaleY * dist / lastDist);
|
|
10162
|
+
scaled = newScaleX !== target.scaleX || newScaleY !== target.scaleY;
|
|
10163
|
+
target.set('scaleX', newScaleX);
|
|
10164
|
+
target.set('scaleY', newScaleY);
|
|
10157
10165
|
return scaled;
|
|
10158
10166
|
},
|
|
10159
10167
|
|
|
@@ -12077,9 +12085,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
12077
12085
|
|
|
12078
12086
|
|
|
12079
12087
|
(function () {
|
|
12080
|
-
|
|
12081
|
-
var supportQuality = fabric.StaticCanvas.supports('toDataURLWithQuality');
|
|
12082
|
-
|
|
12083
12088
|
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
|
|
12084
12089
|
|
|
12085
12090
|
/**
|
|
@@ -12119,69 +12124,57 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
12119
12124
|
|
|
12120
12125
|
var format = options.format || 'png',
|
|
12121
12126
|
quality = options.quality || 1,
|
|
12122
|
-
multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ?
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
* @
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12127
|
+
multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? this.getRetinaScaling() : 1),
|
|
12128
|
+
canvasEl = this.toCanvasElement(multiplier, options);
|
|
12129
|
+
return fabric.util.toDataURL(canvasEl, format, quality);
|
|
12130
|
+
},
|
|
12131
|
+
|
|
12132
|
+
/**
|
|
12133
|
+
* Create a new HTMLCanvas element painted with the current canvas content.
|
|
12134
|
+
* No need to resize the actual one or repaint it.
|
|
12135
|
+
* Will transfer object ownership to a new canvas, paint it, and set everything back.
|
|
12136
|
+
* This is an intermediary step used to get to a dataUrl but also it is usefull to
|
|
12137
|
+
* create quick image copies of a canvas without passing for the dataUrl string
|
|
12138
|
+
* @param {Number} [multiplier] a zoom factor.
|
|
12139
|
+
* @param {Object} [cropping] Cropping informations
|
|
12140
|
+
* @param {Number} [cropping.left] Cropping left offset.
|
|
12141
|
+
* @param {Number} [cropping.top] Cropping top offset.
|
|
12142
|
+
* @param {Number} [cropping.width] Cropping width.
|
|
12143
|
+
* @param {Number} [cropping.height] Cropping height.
|
|
12144
|
+
*/
|
|
12145
|
+
toCanvasElement: function(multiplier, cropping) {
|
|
12146
|
+
multiplier = multiplier || 1;
|
|
12147
|
+
cropping = cropping || { };
|
|
12148
|
+
var scaledWidth = (cropping.width || this.width) * multiplier,
|
|
12140
12149
|
scaledHeight = (cropping.height || this.height) * multiplier,
|
|
12141
12150
|
zoom = this.getZoom(),
|
|
12151
|
+
originalWidth = this.width,
|
|
12152
|
+
originalHeight = this.height,
|
|
12142
12153
|
newZoom = zoom * multiplier,
|
|
12143
12154
|
vp = this.viewportTransform,
|
|
12144
|
-
translateX = (vp[4] - cropping.left) * multiplier,
|
|
12145
|
-
translateY = (vp[5] - cropping.top) * multiplier,
|
|
12146
|
-
newVp = [newZoom, 0, 0, newZoom, translateX, translateY],
|
|
12155
|
+
translateX = (vp[4] - (cropping.left || 0)) * multiplier,
|
|
12156
|
+
translateY = (vp[5] - (cropping.top || 0)) * multiplier,
|
|
12147
12157
|
originalInteractive = this.interactive,
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
// setting interactive to false avoid exporting controls
|
|
12158
|
+
originalContext = this.contextContainer,
|
|
12159
|
+
newVp = [newZoom, 0, 0, newZoom, translateX, translateY],
|
|
12160
|
+
canvasEl = fabric.util.createCanvasElement();
|
|
12161
|
+
canvasEl.width = scaledWidth;
|
|
12162
|
+
canvasEl.height = scaledHeight;
|
|
12154
12163
|
this.interactive = false;
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12164
|
+
this.viewportTransform = newVp;
|
|
12165
|
+
this.width = scaledWidth;
|
|
12166
|
+
this.height = scaledHeight;
|
|
12167
|
+
this.calcViewportBoundaries();
|
|
12168
|
+
this.contextContainer = canvasEl.getContext('2d');
|
|
12169
|
+
// will be renderAllExport();
|
|
12160
12170
|
this.renderAll();
|
|
12161
|
-
var data = this.__toDataURL(format, quality, cropping);
|
|
12162
|
-
this.interactive = originalInteractive;
|
|
12163
|
-
this.skipOffscreen = originalSkipOffScreen;
|
|
12164
12171
|
this.viewportTransform = vp;
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
return data;
|
|
12172
|
-
},
|
|
12173
|
-
|
|
12174
|
-
/**
|
|
12175
|
-
* @private
|
|
12176
|
-
*/
|
|
12177
|
-
__toDataURL: function(format, quality) {
|
|
12178
|
-
|
|
12179
|
-
var canvasEl = this.contextContainer.canvas;
|
|
12180
|
-
var data = supportQuality
|
|
12181
|
-
? canvasEl.toDataURL('image/' + format, quality)
|
|
12182
|
-
: canvasEl.toDataURL('image/' + format);
|
|
12183
|
-
|
|
12184
|
-
return data;
|
|
12172
|
+
this.width = originalWidth;
|
|
12173
|
+
this.height = originalHeight;
|
|
12174
|
+
this.calcViewportBoundaries();
|
|
12175
|
+
this.contextContainer = originalContext;
|
|
12176
|
+
this.interactive = originalInteractive;
|
|
12177
|
+
return canvasEl;
|
|
12185
12178
|
},
|
|
12186
12179
|
});
|
|
12187
12180
|
|
|
@@ -12975,6 +12968,18 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
12975
12968
|
*/
|
|
12976
12969
|
noScaleCache: true,
|
|
12977
12970
|
|
|
12971
|
+
/**
|
|
12972
|
+
* When `false`, the stoke width will scale with the object.
|
|
12973
|
+
* When `true`, the stroke will always match the exact pixel size entered for stroke width.
|
|
12974
|
+
* default to false
|
|
12975
|
+
* @since 2.6.0
|
|
12976
|
+
* @type Boolean
|
|
12977
|
+
* @default false
|
|
12978
|
+
* @type Boolean
|
|
12979
|
+
* @default false
|
|
12980
|
+
*/
|
|
12981
|
+
strokeUniform: false,
|
|
12982
|
+
|
|
12978
12983
|
/**
|
|
12979
12984
|
* When set to `true`, object's cache will be rerendered next render call.
|
|
12980
12985
|
* since 1.7.0
|
|
@@ -13010,7 +13015,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13010
13015
|
'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +
|
|
13011
13016
|
'stroke strokeWidth strokeDashArray strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit ' +
|
|
13012
13017
|
'angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor ' +
|
|
13013
|
-
'skewX skewY fillRule paintFirst clipPath'
|
|
13018
|
+
'skewX skewY fillRule paintFirst clipPath strokeUniform'
|
|
13014
13019
|
).split(' '),
|
|
13015
13020
|
|
|
13016
13021
|
/**
|
|
@@ -13021,7 +13026,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13021
13026
|
* @type Array
|
|
13022
13027
|
*/
|
|
13023
13028
|
cacheProperties: (
|
|
13024
|
-
'fill stroke strokeWidth strokeDashArray width height paintFirst' +
|
|
13029
|
+
'fill stroke strokeWidth strokeDashArray width height paintFirst strokeUniform' +
|
|
13025
13030
|
' strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit backgroundColor clipPath'
|
|
13026
13031
|
).split(' '),
|
|
13027
13032
|
|
|
@@ -13590,8 +13595,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13590
13595
|
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
13591
13596
|
*/
|
|
13592
13597
|
drawObject: function(ctx, forClipping) {
|
|
13593
|
-
|
|
13598
|
+
var originalFill = this.fill, originalStroke = this.stroke;
|
|
13594
13599
|
if (forClipping) {
|
|
13600
|
+
this.fill = 'black';
|
|
13601
|
+
this.stroke = '';
|
|
13595
13602
|
this._setClippingProperties(ctx);
|
|
13596
13603
|
}
|
|
13597
13604
|
else {
|
|
@@ -13601,6 +13608,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13601
13608
|
}
|
|
13602
13609
|
this._render(ctx);
|
|
13603
13610
|
this._drawClipPath(ctx);
|
|
13611
|
+
this.fill = originalFill;
|
|
13612
|
+
this.stroke = originalStroke;
|
|
13604
13613
|
},
|
|
13605
13614
|
|
|
13606
13615
|
_drawClipPath: function(ctx) {
|
|
@@ -13738,6 +13747,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13738
13747
|
else {
|
|
13739
13748
|
alternative && alternative(ctx);
|
|
13740
13749
|
}
|
|
13750
|
+
if (this.strokeUniform) {
|
|
13751
|
+
ctx.setLineDash(ctx.getLineDash().map(function(value) { return value * ctx.lineWidth; }));
|
|
13752
|
+
}
|
|
13741
13753
|
},
|
|
13742
13754
|
|
|
13743
13755
|
/**
|
|
@@ -13781,18 +13793,19 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13781
13793
|
return;
|
|
13782
13794
|
}
|
|
13783
13795
|
|
|
13784
|
-
var
|
|
13785
|
-
|
|
13796
|
+
var shadow = this.shadow, canvas = this.canvas,
|
|
13797
|
+
multX = (canvas && canvas.viewportTransform[0]) || 1,
|
|
13798
|
+
multY = (canvas && canvas.viewportTransform[3]) || 1,
|
|
13786
13799
|
scaling = this.getObjectScaling();
|
|
13787
|
-
if (
|
|
13800
|
+
if (canvas && canvas._isRetinaScaling()) {
|
|
13788
13801
|
multX *= fabric.devicePixelRatio;
|
|
13789
13802
|
multY *= fabric.devicePixelRatio;
|
|
13790
13803
|
}
|
|
13791
|
-
ctx.shadowColor =
|
|
13792
|
-
ctx.shadowBlur =
|
|
13804
|
+
ctx.shadowColor = shadow.color;
|
|
13805
|
+
ctx.shadowBlur = shadow.blur * fabric.browserShadowBlurConstant *
|
|
13793
13806
|
(multX + multY) * (scaling.scaleX + scaling.scaleY) / 4;
|
|
13794
|
-
ctx.shadowOffsetX =
|
|
13795
|
-
ctx.shadowOffsetY =
|
|
13807
|
+
ctx.shadowOffsetX = shadow.offsetX * multX * scaling.scaleX;
|
|
13808
|
+
ctx.shadowOffsetY = shadow.offsetY * multY * scaling.scaleY;
|
|
13796
13809
|
},
|
|
13797
13810
|
|
|
13798
13811
|
/**
|
|
@@ -13812,6 +13825,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13812
13825
|
* @private
|
|
13813
13826
|
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
13814
13827
|
* @param {Object} filler fabric.Pattern or fabric.Gradient
|
|
13828
|
+
* @return {Object} offset.offsetX offset for text rendering
|
|
13829
|
+
* @return {Object} offset.offsetY offset for text rendering
|
|
13815
13830
|
*/
|
|
13816
13831
|
_applyPatternGradientTransform: function(ctx, filler) {
|
|
13817
13832
|
if (!filler || !filler.toLive) {
|
|
@@ -13872,6 +13887,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13872
13887
|
}
|
|
13873
13888
|
|
|
13874
13889
|
ctx.save();
|
|
13890
|
+
if (this.strokeUniform) {
|
|
13891
|
+
ctx.scale(1 / this.scaleX, 1 / this.scaleY);
|
|
13892
|
+
}
|
|
13875
13893
|
this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
|
|
13876
13894
|
this._applyPatternGradientTransform(ctx, this.stroke);
|
|
13877
13895
|
ctx.stroke();
|
|
@@ -13952,6 +13970,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13952
13970
|
|
|
13953
13971
|
/**
|
|
13954
13972
|
* Creates an instance of fabric.Image out of an object
|
|
13973
|
+
* could make use of both toDataUrl or toCanvasElement.
|
|
13955
13974
|
* @param {Function} callback callback, invoked with an instance as a first argument
|
|
13956
13975
|
* @param {Object} [options] for clone as image, passed to toDataURL
|
|
13957
13976
|
* @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
|
|
@@ -13967,20 +13986,16 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13967
13986
|
* @return {fabric.Object} thisArg
|
|
13968
13987
|
*/
|
|
13969
13988
|
cloneAsImage: function(callback, options) {
|
|
13970
|
-
var
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
}
|
|
13975
|
-
});
|
|
13989
|
+
var canvasEl = this.toCanvasElement(options);
|
|
13990
|
+
if (callback) {
|
|
13991
|
+
callback(new fabric.Image(canvasEl));
|
|
13992
|
+
}
|
|
13976
13993
|
return this;
|
|
13977
13994
|
},
|
|
13978
13995
|
|
|
13979
13996
|
/**
|
|
13980
|
-
* Converts an object into a
|
|
13997
|
+
* Converts an object into a HTMLCanvas element
|
|
13981
13998
|
* @param {Object} options Options object
|
|
13982
|
-
* @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
|
|
13983
|
-
* @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
|
|
13984
13999
|
* @param {Number} [options.multiplier=1] Multiplier to scale by
|
|
13985
14000
|
* @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14
|
|
13986
14001
|
* @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
|
|
@@ -13991,11 +14006,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13991
14006
|
* @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2
|
|
13992
14007
|
* @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
|
|
13993
14008
|
*/
|
|
13994
|
-
|
|
14009
|
+
toCanvasElement: function(options) {
|
|
13995
14010
|
options || (options = { });
|
|
13996
14011
|
|
|
13997
14012
|
var utils = fabric.util, origParams = utils.saveObjectTransform(this),
|
|
13998
|
-
originalShadow = this.shadow, abs = Math.abs
|
|
14013
|
+
originalShadow = this.shadow, abs = Math.abs,
|
|
14014
|
+
multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? fabric.devicePixelRatio : 1);
|
|
13999
14015
|
|
|
14000
14016
|
if (options.withoutTransform) {
|
|
14001
14017
|
utils.resetObjectTransform(this);
|
|
@@ -14021,7 +14037,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14021
14037
|
el.width += el.width % 2 ? 2 - el.width % 2 : 0;
|
|
14022
14038
|
el.height += el.height % 2 ? 2 - el.height % 2 : 0;
|
|
14023
14039
|
var canvas = new fabric.StaticCanvas(el, {
|
|
14024
|
-
enableRetinaScaling:
|
|
14040
|
+
enableRetinaScaling: false,
|
|
14025
14041
|
renderOnAddRemove: false,
|
|
14026
14042
|
skipOffscreen: false,
|
|
14027
14043
|
});
|
|
@@ -14032,10 +14048,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14032
14048
|
|
|
14033
14049
|
var originalCanvas = this.canvas;
|
|
14034
14050
|
canvas.add(this);
|
|
14035
|
-
var
|
|
14051
|
+
var canvasEl = canvas.toCanvasElement(multiplier || 1, options);
|
|
14036
14052
|
this.shadow = originalShadow;
|
|
14037
|
-
this.set(origParams).setCoords();
|
|
14038
14053
|
this.canvas = originalCanvas;
|
|
14054
|
+
this.set(origParams).setCoords();
|
|
14039
14055
|
// canvas.dispose will call image.dispose that will nullify the elements
|
|
14040
14056
|
// since this canvas is a simple element for the process, we remove references
|
|
14041
14057
|
// to objects in this way in order to avoid object trashing.
|
|
@@ -14043,7 +14059,27 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14043
14059
|
canvas.dispose();
|
|
14044
14060
|
canvas = null;
|
|
14045
14061
|
|
|
14046
|
-
return
|
|
14062
|
+
return canvasEl;
|
|
14063
|
+
},
|
|
14064
|
+
|
|
14065
|
+
/**
|
|
14066
|
+
* Converts an object into a data-url-like string
|
|
14067
|
+
* @param {Object} options Options object
|
|
14068
|
+
* @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
|
|
14069
|
+
* @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
|
|
14070
|
+
* @param {Number} [options.multiplier=1] Multiplier to scale by
|
|
14071
|
+
* @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14
|
|
14072
|
+
* @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
|
|
14073
|
+
* @param {Number} [options.width] Cropping width. Introduced in v1.2.14
|
|
14074
|
+
* @param {Number} [options.height] Cropping height. Introduced in v1.2.14
|
|
14075
|
+
* @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4
|
|
14076
|
+
* @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4
|
|
14077
|
+
* @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2
|
|
14078
|
+
* @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
|
|
14079
|
+
*/
|
|
14080
|
+
toDataURL: function(options) {
|
|
14081
|
+
options || (options = { });
|
|
14082
|
+
return fabric.util.toDataURL(this.toCanvasElement(options), options.format || 'png', options.quality || 1);
|
|
14047
14083
|
},
|
|
14048
14084
|
|
|
14049
14085
|
/**
|
|
@@ -14785,7 +14821,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14785
14821
|
/**
|
|
14786
14822
|
* Checks if object is contained within the canvas with current viewportTransform
|
|
14787
14823
|
* the check is done stopping at first point that appears on screen
|
|
14788
|
-
* @param {Boolean} [calculate] use coordinates of current position instead of .
|
|
14824
|
+
* @param {Boolean} [calculate] use coordinates of current position instead of .aCoords
|
|
14789
14825
|
* @return {Boolean} true if object is fully or partially contained within canvas
|
|
14790
14826
|
*/
|
|
14791
14827
|
isOnScreen: function(calculate) {
|
|
@@ -15213,12 +15249,25 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15213
15249
|
if (typeof skewY === 'undefined') {
|
|
15214
15250
|
skewY = this.skewY;
|
|
15215
15251
|
}
|
|
15216
|
-
var dimensions = this._getNonTransformedDimensions()
|
|
15217
|
-
|
|
15218
|
-
|
|
15252
|
+
var dimensions = this._getNonTransformedDimensions(), dimX, dimY,
|
|
15253
|
+
noSkew = skewX === 0 && skewY === 0;
|
|
15254
|
+
|
|
15255
|
+
if (this.strokeUniform) {
|
|
15256
|
+
dimX = this.width;
|
|
15257
|
+
dimY = this.height;
|
|
15219
15258
|
}
|
|
15220
|
-
|
|
15221
|
-
|
|
15259
|
+
else {
|
|
15260
|
+
dimX = dimensions.x;
|
|
15261
|
+
dimY = dimensions.y;
|
|
15262
|
+
}
|
|
15263
|
+
if (noSkew) {
|
|
15264
|
+
return this._finalizeDiemensions(dimX * this.scaleX, dimY * this.scaleY);
|
|
15265
|
+
}
|
|
15266
|
+
else {
|
|
15267
|
+
dimX /= 2;
|
|
15268
|
+
dimY /= 2;
|
|
15269
|
+
}
|
|
15270
|
+
var points = [
|
|
15222
15271
|
{
|
|
15223
15272
|
x: -dimX,
|
|
15224
15273
|
y: -dimY
|
|
@@ -15241,9 +15290,23 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15241
15290
|
points[i] = fabric.util.transformPoint(points[i], transformMatrix);
|
|
15242
15291
|
}
|
|
15243
15292
|
bbox = fabric.util.makeBoundingBoxFromPoints(points);
|
|
15244
|
-
return
|
|
15293
|
+
return this._finalizeDiemensions(bbox.width, bbox.height);
|
|
15245
15294
|
},
|
|
15246
15295
|
|
|
15296
|
+
/*
|
|
15297
|
+
* Calculate object bounding boxdimensions from its properties scale, skew.
|
|
15298
|
+
* @param Number width width of the bbox
|
|
15299
|
+
* @param Number height height of the bbox
|
|
15300
|
+
* @private
|
|
15301
|
+
* @return {Object} .x finalized width dimension
|
|
15302
|
+
* @return {Object} .y finalized height dimension
|
|
15303
|
+
*/
|
|
15304
|
+
_finalizeDiemensions: function(width, height) {
|
|
15305
|
+
return this.strokeUniform ?
|
|
15306
|
+
{ x: width + this.strokeWidth, y: height + this.strokeWidth }
|
|
15307
|
+
:
|
|
15308
|
+
{ x: width, y: height };
|
|
15309
|
+
},
|
|
15247
15310
|
/*
|
|
15248
15311
|
* Calculate object dimensions for controls. include padding and canvas zoom
|
|
15249
15312
|
* private
|
|
@@ -15556,10 +15619,12 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
15556
15619
|
styleInfo = noStyle ? '' : 'style="' + this.getSvgStyles() + '" ',
|
|
15557
15620
|
shadowInfo = withShadow ? 'style="' + this.getSvgFilter() + '" ' : '',
|
|
15558
15621
|
clipPath = this.clipPath,
|
|
15622
|
+
vectorEffect = this.strokeUniform ? 'vector-effect="non-scaling-stroke" ' : '',
|
|
15559
15623
|
absoluteClipPath = this.clipPath && this.clipPath.absolutePositioned,
|
|
15560
15624
|
commonPieces, markup = [], clipPathMarkup,
|
|
15561
15625
|
// insert commons in the markup, style and svgCommons
|
|
15562
|
-
index = objectMarkup.indexOf('COMMON_PARTS')
|
|
15626
|
+
index = objectMarkup.indexOf('COMMON_PARTS'),
|
|
15627
|
+
additionalTransform = options.additionalTransform;
|
|
15563
15628
|
if (clipPath) {
|
|
15564
15629
|
clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;
|
|
15565
15630
|
clipPathMarkup = '<clipPath id="' + clipPath.clipPathId + '" >\n' +
|
|
@@ -15579,7 +15644,9 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
15579
15644
|
);
|
|
15580
15645
|
commonPieces = [
|
|
15581
15646
|
styleInfo,
|
|
15582
|
-
|
|
15647
|
+
vectorEffect,
|
|
15648
|
+
noStyle ? '' : this.addPaintOrder(), ' ',
|
|
15649
|
+
additionalTransform ? 'transform="' + additionalTransform + '" ' : '',
|
|
15583
15650
|
].join('');
|
|
15584
15651
|
objectMarkup[index] = commonPieces;
|
|
15585
15652
|
if (this.fill && this.fill.toLive) {
|
|
@@ -16811,7 +16878,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
16811
16878
|
'<path d="M ' + startX + ' ' + startY,
|
|
16812
16879
|
' A ' + this.radius + ' ' + this.radius,
|
|
16813
16880
|
' 0 ', +largeFlag + ' 1', ' ' + endX + ' ' + endY,
|
|
16814
|
-
'"', 'COMMON_PARTS', ' />\n'
|
|
16881
|
+
'" ', 'COMMON_PARTS', ' />\n'
|
|
16815
16882
|
];
|
|
16816
16883
|
}
|
|
16817
16884
|
return svgString;
|
|
@@ -18249,6 +18316,16 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18249
18316
|
this._toSVG(), { reviver: reviver, additionalTransform: additionalTransform }
|
|
18250
18317
|
);
|
|
18251
18318
|
},
|
|
18319
|
+
|
|
18320
|
+
/**
|
|
18321
|
+
* Returns svg representation of an instance
|
|
18322
|
+
* @param {Function} [reviver] Method for further parsing of svg representation.
|
|
18323
|
+
* @return {String} svg representation of an instance
|
|
18324
|
+
*/
|
|
18325
|
+
toSVG: function(reviver) {
|
|
18326
|
+
var additionalTransform = this._getOffsetTransform();
|
|
18327
|
+
return this._createBaseSVGMarkup(this._toSVG(), { reviver: reviver, additionalTransform: additionalTransform });
|
|
18328
|
+
},
|
|
18252
18329
|
/* _TO_SVG_END_ */
|
|
18253
18330
|
|
|
18254
18331
|
/**
|
|
@@ -19460,6 +19537,15 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19460
19537
|
*/
|
|
19461
19538
|
strokeWidth: 0,
|
|
19462
19539
|
|
|
19540
|
+
/**
|
|
19541
|
+
* When calling {@link fabric.Image.getSrc}, return value from element src with `element.getAttribute('src')`.
|
|
19542
|
+
* This allows for relative urls as image src.
|
|
19543
|
+
* @since 2.7.0
|
|
19544
|
+
* @type Boolean
|
|
19545
|
+
* @default
|
|
19546
|
+
*/
|
|
19547
|
+
srcFromAttribute: false,
|
|
19548
|
+
|
|
19463
19549
|
/**
|
|
19464
19550
|
* private
|
|
19465
19551
|
* contains last value of scaleX to detect
|
|
@@ -19508,7 +19594,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19508
19594
|
|
|
19509
19595
|
/**
|
|
19510
19596
|
* key used to retrieve the texture representing this image
|
|
19511
|
-
* since 2.0.0
|
|
19597
|
+
* @since 2.0.0
|
|
19512
19598
|
* @type String
|
|
19513
19599
|
* @default
|
|
19514
19600
|
*/
|
|
@@ -19516,7 +19602,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19516
19602
|
|
|
19517
19603
|
/**
|
|
19518
19604
|
* Image crop in pixels from original image size.
|
|
19519
|
-
* since 2.0.0
|
|
19605
|
+
* @since 2.0.0
|
|
19520
19606
|
* @type Number
|
|
19521
19607
|
* @default
|
|
19522
19608
|
*/
|
|
@@ -19524,7 +19610,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19524
19610
|
|
|
19525
19611
|
/**
|
|
19526
19612
|
* Image crop in pixels from original image size.
|
|
19527
|
-
* since 2.0.0
|
|
19613
|
+
* @since 2.0.0
|
|
19528
19614
|
* @type Number
|
|
19529
19615
|
* @default
|
|
19530
19616
|
*/
|
|
@@ -19764,7 +19850,13 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19764
19850
|
if (element.toDataURL) {
|
|
19765
19851
|
return element.toDataURL();
|
|
19766
19852
|
}
|
|
19767
|
-
|
|
19853
|
+
|
|
19854
|
+
if (this.srcFromAttribute) {
|
|
19855
|
+
return element.getAttribute('src');
|
|
19856
|
+
}
|
|
19857
|
+
else {
|
|
19858
|
+
return element.src;
|
|
19859
|
+
}
|
|
19768
19860
|
}
|
|
19769
19861
|
else {
|
|
19770
19862
|
return this.src || '';
|
|
@@ -19783,7 +19875,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19783
19875
|
fabric.util.loadImage(src, function(img) {
|
|
19784
19876
|
this.setElement(img, options);
|
|
19785
19877
|
this._setWidthHeight();
|
|
19786
|
-
callback(this);
|
|
19878
|
+
callback && callback(this);
|
|
19787
19879
|
}, this, options && options.crossOrigin);
|
|
19788
19880
|
return this;
|
|
19789
19881
|
},
|
|
@@ -19920,14 +20012,15 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19920
20012
|
},
|
|
19921
20013
|
|
|
19922
20014
|
_renderFill: function(ctx) {
|
|
19923
|
-
var
|
|
19924
|
-
|
|
19925
|
-
|
|
19926
|
-
|
|
19927
|
-
|
|
19928
|
-
|
|
19929
|
-
|
|
19930
|
-
|
|
20015
|
+
var elementToDraw = this._element,
|
|
20016
|
+
w = this.width, h = this.height,
|
|
20017
|
+
sW = Math.min(elementToDraw.naturalWidth || elementToDraw.width, w * this._filterScalingX),
|
|
20018
|
+
sH = Math.min(elementToDraw.naturalHeight || elementToDraw.height, h * this._filterScalingY),
|
|
20019
|
+
x = -w / 2, y = -h / 2,
|
|
20020
|
+
sX = Math.max(0, this.cropX * this._filterScalingX),
|
|
20021
|
+
sY = Math.max(0, this.cropY * this._filterScalingY);
|
|
20022
|
+
|
|
20023
|
+
elementToDraw && ctx.drawImage(elementToDraw, sX, sY, sW, sH, x, y, w, h);
|
|
19931
20024
|
},
|
|
19932
20025
|
|
|
19933
20026
|
/**
|
|
@@ -20454,51 +20547,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
20454
20547
|
return pipelineState;
|
|
20455
20548
|
},
|
|
20456
20549
|
|
|
20457
|
-
/**
|
|
20458
|
-
* The same as the applyFilter method but with additional logging of WebGL
|
|
20459
|
-
* errors.
|
|
20460
|
-
*/
|
|
20461
|
-
applyFiltersDebug: function(filters, source, width, height, targetCanvas, cacheKey) {
|
|
20462
|
-
// The following code is useful when debugging a specific issue but adds ~10x slowdown.
|
|
20463
|
-
var gl = this.gl;
|
|
20464
|
-
var ret = this.applyFilters(filters, source, width, height, targetCanvas, cacheKey);
|
|
20465
|
-
var glError = gl.getError();
|
|
20466
|
-
if (glError !== gl.NO_ERROR) {
|
|
20467
|
-
var errorString = this.glErrorToString(gl, glError);
|
|
20468
|
-
var error = new Error('WebGL Error ' + errorString);
|
|
20469
|
-
error.glErrorCode = glError;
|
|
20470
|
-
throw error;
|
|
20471
|
-
}
|
|
20472
|
-
return ret;
|
|
20473
|
-
},
|
|
20474
|
-
|
|
20475
|
-
glErrorToString: function(context, errorCode) {
|
|
20476
|
-
if (!context) {
|
|
20477
|
-
return 'Context undefined for error code: ' + errorCode;
|
|
20478
|
-
}
|
|
20479
|
-
else if (typeof errorCode !== 'number') {
|
|
20480
|
-
return 'Error code is not a number';
|
|
20481
|
-
}
|
|
20482
|
-
switch (errorCode) {
|
|
20483
|
-
case context.NO_ERROR:
|
|
20484
|
-
return 'NO_ERROR';
|
|
20485
|
-
case context.INVALID_ENUM:
|
|
20486
|
-
return 'INVALID_ENUM';
|
|
20487
|
-
case context.INVALID_VALUE:
|
|
20488
|
-
return 'INVALID_VALUE';
|
|
20489
|
-
case context.INVALID_OPERATION:
|
|
20490
|
-
return 'INVALID_OPERATION';
|
|
20491
|
-
case context.INVALID_FRAMEBUFFER_OPERATION:
|
|
20492
|
-
return 'INVALID_FRAMEBUFFER_OPERATION';
|
|
20493
|
-
case context.OUT_OF_MEMORY:
|
|
20494
|
-
return 'OUT_OF_MEMORY';
|
|
20495
|
-
case context.CONTEXT_LOST_WEBGL:
|
|
20496
|
-
return 'CONTEXT_LOST_WEBGL';
|
|
20497
|
-
default:
|
|
20498
|
-
return 'UNKNOWN_ERROR';
|
|
20499
|
-
}
|
|
20500
|
-
},
|
|
20501
|
-
|
|
20502
20550
|
/**
|
|
20503
20551
|
* Detach event listeners, remove references, and clean up caches.
|
|
20504
20552
|
*/
|
|
@@ -20592,9 +20640,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
20592
20640
|
if (this.gpuInfo) {
|
|
20593
20641
|
return this.gpuInfo;
|
|
20594
20642
|
}
|
|
20595
|
-
var gl = this.gl;
|
|
20643
|
+
var gl = this.gl, gpuInfo = { renderer: '', vendor: '' };
|
|
20644
|
+
if (!gl) {
|
|
20645
|
+
return gpuInfo;
|
|
20646
|
+
}
|
|
20596
20647
|
var ext = gl.getExtension('WEBGL_debug_renderer_info');
|
|
20597
|
-
var gpuInfo = { renderer: '', vendor: '' };
|
|
20598
20648
|
if (ext) {
|
|
20599
20649
|
var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
|
|
20600
20650
|
var vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);
|
|
@@ -28682,6 +28732,20 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|
|
28682
28732
|
*/
|
|
28683
28733
|
_dimensionAffectingProps: fabric.Text.prototype._dimensionAffectingProps.concat('width'),
|
|
28684
28734
|
|
|
28735
|
+
/**
|
|
28736
|
+
* Use this regular expression to split strings in breakable lines
|
|
28737
|
+
* @private
|
|
28738
|
+
*/
|
|
28739
|
+
_wordJoiners: /[ \t\r]/,
|
|
28740
|
+
|
|
28741
|
+
/**
|
|
28742
|
+
* Use this boolean property in order to split strings that have no white space concept.
|
|
28743
|
+
* this is a cheap way to help with chinese/japaense
|
|
28744
|
+
* @type Boolean
|
|
28745
|
+
* @since 2.6.0
|
|
28746
|
+
*/
|
|
28747
|
+
splitByGrapheme: false,
|
|
28748
|
+
|
|
28685
28749
|
/**
|
|
28686
28750
|
* Unlike superclass's version of this function, Textbox does not update
|
|
28687
28751
|
* its width.
|
|
@@ -28731,7 +28795,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|
|
28731
28795
|
charCount++;
|
|
28732
28796
|
realLineCount++;
|
|
28733
28797
|
}
|
|
28734
|
-
else if (this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) && i > 0) {
|
|
28798
|
+
else if (!this.graphemeSplit && this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) && i > 0) {
|
|
28735
28799
|
// this case deals with space's that are removed from end of lines when wrapping
|
|
28736
28800
|
realLineCharCount++;
|
|
28737
28801
|
charCount++;
|
|
@@ -28918,19 +28982,20 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|
|
28918
28982
|
* to.
|
|
28919
28983
|
*/
|
|
28920
28984
|
_wrapLine: function(_line, lineIndex, desiredWidth, reservedSpace) {
|
|
28921
|
-
var lineWidth
|
|
28922
|
-
|
|
28923
|
-
|
|
28985
|
+
var lineWidth = 0,
|
|
28986
|
+
splitByGrapheme = this.splitByGrapheme,
|
|
28987
|
+
graphemeLines = [],
|
|
28988
|
+
line = [],
|
|
28924
28989
|
// spaces in different languges?
|
|
28925
|
-
words
|
|
28926
|
-
word
|
|
28927
|
-
offset
|
|
28928
|
-
infix
|
|
28929
|
-
wordWidth
|
|
28930
|
-
infixWidth
|
|
28990
|
+
words = splitByGrapheme ? fabric.util.string.graphemeSplit(_line) : _line.split(this._wordJoiners),
|
|
28991
|
+
word = '',
|
|
28992
|
+
offset = 0,
|
|
28993
|
+
infix = splitByGrapheme ? '' : ' ',
|
|
28994
|
+
wordWidth = 0,
|
|
28995
|
+
infixWidth = 0,
|
|
28931
28996
|
largestWordWidth = 0,
|
|
28932
28997
|
lineJustStarted = true,
|
|
28933
|
-
additionalSpace = this._getWidthOfCharSpacing(),
|
|
28998
|
+
additionalSpace = splitByGrapheme ? 0 : this._getWidthOfCharSpacing(),
|
|
28934
28999
|
reservedSpace = reservedSpace || 0;
|
|
28935
29000
|
|
|
28936
29001
|
desiredWidth -= reservedSpace;
|
|
@@ -28952,7 +29017,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|
|
28952
29017
|
lineWidth += additionalSpace;
|
|
28953
29018
|
}
|
|
28954
29019
|
|
|
28955
|
-
if (!lineJustStarted) {
|
|
29020
|
+
if (!lineJustStarted && !splitByGrapheme) {
|
|
28956
29021
|
line.push(infix);
|
|
28957
29022
|
}
|
|
28958
29023
|
line = line.concat(word);
|
|
@@ -29024,7 +29089,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|
|
29024
29089
|
* @return {Object} object representation of an instance
|
|
29025
29090
|
*/
|
|
29026
29091
|
toObject: function(propertiesToInclude) {
|
|
29027
|
-
return this.callSuper('toObject', ['minWidth'].concat(propertiesToInclude));
|
|
29092
|
+
return this.callSuper('toObject', ['minWidth', 'splitByGrapheme'].concat(propertiesToInclude));
|
|
29028
29093
|
}
|
|
29029
29094
|
});
|
|
29030
29095
|
|
|
@@ -29052,13 +29117,18 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|
|
29052
29117
|
fabric.Canvas.prototype._setObjectScale = function(localMouse, transform,
|
|
29053
29118
|
lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
|
|
29054
29119
|
|
|
29055
|
-
var t = transform.target
|
|
29120
|
+
var t = transform.target, scaled,
|
|
29121
|
+
scaleX = localMouse.x * t.scaleX / _dim.x,
|
|
29122
|
+
scaleY = localMouse.y * t.scaleY / _dim.y;
|
|
29056
29123
|
if (by === 'x' && t instanceof fabric.Textbox) {
|
|
29057
29124
|
var tw = t._getTransformedDimensions().x;
|
|
29058
29125
|
var w = t.width * (localMouse.x / tw);
|
|
29126
|
+
transform.newScaleX = scaleX;
|
|
29127
|
+
transform.newScaleY = scaleY;
|
|
29059
29128
|
if (w >= t.getMinWidth()) {
|
|
29129
|
+
scaled = w !== t.width;
|
|
29060
29130
|
t.set('width', w);
|
|
29061
|
-
return
|
|
29131
|
+
return scaled;
|
|
29062
29132
|
}
|
|
29063
29133
|
}
|
|
29064
29134
|
else {
|
package/package.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
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": "2.
|
|
6
|
-
"
|
|
5
|
+
"version": "2.7.0",
|
|
6
|
+
"authors": "Juriy Zaytsev <kangax@gmail.com>",
|
|
7
7
|
"contributors": [
|
|
8
8
|
{
|
|
9
9
|
"name": "Andrea Bogazzi",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"testem:ci": "testem ci"
|
|
61
61
|
},
|
|
62
62
|
"optionalDependencies": {
|
|
63
|
-
"canvas": "^1.6.
|
|
63
|
+
"canvas": "^1.6.13",
|
|
64
64
|
"jsdom": "^9.12.0",
|
|
65
65
|
"xmldom": "0.1.x"
|
|
66
66
|
},
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"eslint": "4.18.x",
|
|
69
69
|
"istanbul": "0.4.x",
|
|
70
70
|
"onchange": "^3.x.x",
|
|
71
|
-
"qunit": "
|
|
71
|
+
"qunit": "2.6.2",
|
|
72
72
|
"testem": "^1.18.4",
|
|
73
73
|
"uglify-js": "3.3.x",
|
|
74
74
|
"pixelmatch": "^4.0.2",
|