fabric 4.5.1-browser → 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.
- package/CHANGELOG.md +78 -0
- package/CONTRIBUTING.md +14 -0
- package/HEADER.js +1 -1
- package/README.md +3 -6
- package/SECURITY.md +5 -0
- package/build.js +1 -0
- package/dist/fabric.js +1160 -668
- package/dist/fabric.min.js +1 -1
- package/lib/event.js +7 -3
- package/package.json +9 -3
- package/publish-next.js +15 -0
- package/publish.js +3 -0
- package/src/brushes/base_brush.class.js +3 -5
- package/src/brushes/pattern_brush.class.js +7 -5
- package/src/brushes/pencil_brush.class.js +49 -37
- package/src/canvas.class.js +27 -57
- package/src/filters/saturate_filter.class.js +9 -1
- package/src/filters/vibrance_filter.class.js +122 -0
- package/src/mixins/animation.mixin.js +20 -25
- package/src/mixins/canvas_events.mixin.js +30 -59
- package/src/mixins/canvas_grouping.mixin.js +4 -4
- package/src/mixins/collection.mixin.js +11 -2
- package/src/mixins/eraser_brush.mixin.js +495 -452
- package/src/mixins/itext_behavior.mixin.js +7 -1
- package/src/mixins/itext_key_behavior.mixin.js +7 -1
- package/src/mixins/object_geometry.mixin.js +5 -35
- package/src/mixins/object_interactivity.mixin.js +18 -7
- package/src/mixins/object_straightening.mixin.js +4 -9
- package/src/mixins/observable.mixin.js +22 -0
- package/src/parser.js +13 -9
- package/src/shapes/circle.class.js +22 -19
- package/src/shapes/ellipse.class.js +2 -2
- package/src/shapes/group.class.js +24 -32
- package/src/shapes/image.class.js +3 -25
- package/src/shapes/itext.class.js +10 -0
- package/src/shapes/line.class.js +5 -21
- package/src/shapes/object.class.js +67 -32
- package/src/shapes/path.class.js +17 -18
- package/src/shapes/polygon.class.js +11 -10
- package/src/shapes/polyline.class.js +33 -24
- package/src/shapes/rect.class.js +0 -18
- package/src/shapes/text.class.js +120 -58
- package/src/shapes/triangle.class.js +0 -15
- package/src/static_canvas.class.js +43 -20
- package/src/util/animate.js +149 -16
- package/src/util/animate_color.js +2 -1
- package/src/util/lang_object.js +5 -1
- package/src/util/misc.js +193 -42
- package/src/util/path.js +89 -52
package/dist/fabric.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* build: `node build.js modules=ALL exclude=gestures,accessors,erasing requirejs minifier=uglifyjs` */
|
|
2
2
|
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
|
|
3
3
|
|
|
4
|
-
var fabric = fabric || { version: '
|
|
4
|
+
var fabric = fabric || { version: '5.0.0' };
|
|
5
5
|
if (typeof exports !== 'undefined') {
|
|
6
6
|
exports.fabric = fabric;
|
|
7
7
|
}
|
|
@@ -258,6 +258,27 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
|
|
258
258
|
return this;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
function _once(eventName, handler) {
|
|
262
|
+
var _handler = function () {
|
|
263
|
+
handler.apply(this, arguments);
|
|
264
|
+
this.off(eventName, _handler);
|
|
265
|
+
}.bind(this);
|
|
266
|
+
this.on(eventName, _handler);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function once(eventName, handler) {
|
|
270
|
+
// one object with key/value pairs was passed
|
|
271
|
+
if (arguments.length === 1) {
|
|
272
|
+
for (var prop in eventName) {
|
|
273
|
+
_once.call(this, prop, eventName[prop]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
_once.call(this, eventName, handler);
|
|
278
|
+
}
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
|
|
261
282
|
/**
|
|
262
283
|
* Stops event observing for a particular event handler. Calling this method
|
|
263
284
|
* without arguments removes all handlers for all events
|
|
@@ -326,6 +347,7 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
|
|
326
347
|
fabric.Observable = {
|
|
327
348
|
fire: fire,
|
|
328
349
|
on: on,
|
|
350
|
+
once: once,
|
|
329
351
|
off: off,
|
|
330
352
|
};
|
|
331
353
|
})();
|
|
@@ -475,10 +497,19 @@ fabric.Collection = {
|
|
|
475
497
|
/**
|
|
476
498
|
* Returns true if collection contains an object
|
|
477
499
|
* @param {Object} object Object to check against
|
|
500
|
+
* @param {Boolean} [deep=false] `true` to check all descendants, `false` to check only `_objects`
|
|
478
501
|
* @return {Boolean} `true` if collection contains an object
|
|
479
502
|
*/
|
|
480
|
-
contains: function(object) {
|
|
481
|
-
|
|
503
|
+
contains: function (object, deep) {
|
|
504
|
+
if (this._objects.indexOf(object) > -1) {
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
else if (deep) {
|
|
508
|
+
return this._objects.some(function (obj) {
|
|
509
|
+
return typeof obj.contains === 'function' && obj.contains(object, true);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
return false;
|
|
482
513
|
},
|
|
483
514
|
|
|
484
515
|
/**
|
|
@@ -731,6 +762,135 @@ fabric.CommonMethods = {
|
|
|
731
762
|
};
|
|
732
763
|
},
|
|
733
764
|
|
|
765
|
+
/**
|
|
766
|
+
* Creates a vetor from points represented as a point
|
|
767
|
+
* @static
|
|
768
|
+
* @memberOf fabric.util
|
|
769
|
+
*
|
|
770
|
+
* @typedef {Object} Point
|
|
771
|
+
* @property {number} x
|
|
772
|
+
* @property {number} y
|
|
773
|
+
*
|
|
774
|
+
* @param {Point} from
|
|
775
|
+
* @param {Point} to
|
|
776
|
+
* @returns {Point} vector
|
|
777
|
+
*/
|
|
778
|
+
createVector: function (from, to) {
|
|
779
|
+
return new fabric.Point(to.x - from.x, to.y - from.y);
|
|
780
|
+
},
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Calculates angle between 2 vectors using dot product
|
|
784
|
+
* @static
|
|
785
|
+
* @memberOf fabric.util
|
|
786
|
+
* @param {Point} a
|
|
787
|
+
* @param {Point} b
|
|
788
|
+
* @returns the angle in radian between the vectors
|
|
789
|
+
*/
|
|
790
|
+
calcAngleBetweenVectors: function (a, b) {
|
|
791
|
+
return Math.acos((a.x * b.x + a.y * b.y) / (Math.hypot(a.x, a.y) * Math.hypot(b.x, b.y)));
|
|
792
|
+
},
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* @static
|
|
796
|
+
* @memberOf fabric.util
|
|
797
|
+
* @param {Point} v
|
|
798
|
+
* @returns {Point} vector representing the unit vector of pointing to the direction of `v`
|
|
799
|
+
*/
|
|
800
|
+
getHatVector: function (v) {
|
|
801
|
+
return new fabric.Point(v.x, v.y).multiply(1 / Math.hypot(v.x, v.y));
|
|
802
|
+
},
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* @static
|
|
806
|
+
* @memberOf fabric.util
|
|
807
|
+
* @param {Point} A
|
|
808
|
+
* @param {Point} B
|
|
809
|
+
* @param {Point} C
|
|
810
|
+
* @returns {{ vector: Point, angle: number }} vector representing the bisector of A and A's angle
|
|
811
|
+
*/
|
|
812
|
+
getBisector: function (A, B, C) {
|
|
813
|
+
var AB = fabric.util.createVector(A, B), AC = fabric.util.createVector(A, C);
|
|
814
|
+
var alpha = fabric.util.calcAngleBetweenVectors(AB, AC);
|
|
815
|
+
// check if alpha is relative to AB->BC
|
|
816
|
+
var ro = fabric.util.calcAngleBetweenVectors(fabric.util.rotateVector(AB, alpha), AC);
|
|
817
|
+
var phi = alpha * (ro === 0 ? 1 : -1) / 2;
|
|
818
|
+
return {
|
|
819
|
+
vector: fabric.util.getHatVector(fabric.util.rotateVector(AB, phi)),
|
|
820
|
+
angle: alpha
|
|
821
|
+
};
|
|
822
|
+
},
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Project stroke width on points returning 2 projections for each point as follows:
|
|
826
|
+
* - `miter`: 2 points corresponding to the outer boundary and the inner boundary of stroke.
|
|
827
|
+
* - `bevel`: 2 points corresponding to the bevel boundaries, tangent to the bisector.
|
|
828
|
+
* - `round`: same as `bevel`
|
|
829
|
+
* Used to calculate object's bounding box
|
|
830
|
+
* @static
|
|
831
|
+
* @memberOf fabric.util
|
|
832
|
+
* @param {Point[]} points
|
|
833
|
+
* @param {Object} options
|
|
834
|
+
* @param {number} options.strokeWidth
|
|
835
|
+
* @param {'miter'|'bevel'|'round'} options.strokeLineJoin
|
|
836
|
+
* @param {number} options.strokeMiterLimit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit
|
|
837
|
+
* @param {boolean} options.strokeUniform
|
|
838
|
+
* @param {number} options.scaleX
|
|
839
|
+
* @param {number} options.scaleY
|
|
840
|
+
* @param {boolean} [openPath] whether the shape is open or not, affects the calculations of the first and last points
|
|
841
|
+
* @returns {fabric.Point[]} array of size 2n/4n of all suspected points
|
|
842
|
+
*/
|
|
843
|
+
projectStrokeOnPoints: function (points, options, openPath) {
|
|
844
|
+
var coords = [], s = options.strokeWidth / 2,
|
|
845
|
+
strokeUniformScalar = options.strokeUniform ?
|
|
846
|
+
new fabric.Point(1 / options.scaleX, 1 / options.scaleY) : new fabric.Point(1, 1),
|
|
847
|
+
getStrokeHatVector = function (v) {
|
|
848
|
+
var scalar = s / (Math.hypot(v.x, v.y));
|
|
849
|
+
return new fabric.Point(v.x * scalar * strokeUniformScalar.x, v.y * scalar * strokeUniformScalar.y);
|
|
850
|
+
};
|
|
851
|
+
if (points.length <= 1) {return coords;}
|
|
852
|
+
points.forEach(function (p, index) {
|
|
853
|
+
var A = new fabric.Point(p.x, p.y), B, C;
|
|
854
|
+
if (index === 0) {
|
|
855
|
+
C = points[index + 1];
|
|
856
|
+
B = openPath ? getStrokeHatVector(fabric.util.createVector(C, A)).addEquals(A) : points[points.length - 1];
|
|
857
|
+
}
|
|
858
|
+
else if (index === points.length - 1) {
|
|
859
|
+
B = points[index - 1];
|
|
860
|
+
C = openPath ? getStrokeHatVector(fabric.util.createVector(B, A)).addEquals(A) : points[0];
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
B = points[index - 1];
|
|
864
|
+
C = points[index + 1];
|
|
865
|
+
}
|
|
866
|
+
var bisector = fabric.util.getBisector(A, B, C),
|
|
867
|
+
bisectorVector = bisector.vector,
|
|
868
|
+
alpha = bisector.angle,
|
|
869
|
+
scalar,
|
|
870
|
+
miterVector;
|
|
871
|
+
if (options.strokeLineJoin === 'miter') {
|
|
872
|
+
scalar = -s / Math.sin(alpha / 2);
|
|
873
|
+
miterVector = new fabric.Point(
|
|
874
|
+
bisectorVector.x * scalar * strokeUniformScalar.x,
|
|
875
|
+
bisectorVector.y * scalar * strokeUniformScalar.y
|
|
876
|
+
);
|
|
877
|
+
if (Math.hypot(miterVector.x, miterVector.y) / s <= options.strokeMiterLimit) {
|
|
878
|
+
coords.push(A.add(miterVector));
|
|
879
|
+
coords.push(A.subtract(miterVector));
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
scalar = -s * Math.SQRT2;
|
|
884
|
+
miterVector = new fabric.Point(
|
|
885
|
+
bisectorVector.x * scalar * strokeUniformScalar.x,
|
|
886
|
+
bisectorVector.y * scalar * strokeUniformScalar.y
|
|
887
|
+
);
|
|
888
|
+
coords.push(A.add(miterVector));
|
|
889
|
+
coords.push(A.subtract(miterVector));
|
|
890
|
+
});
|
|
891
|
+
return coords;
|
|
892
|
+
},
|
|
893
|
+
|
|
734
894
|
/**
|
|
735
895
|
* Apply transform t to point p
|
|
736
896
|
* @static
|
|
@@ -1043,6 +1203,25 @@ fabric.CommonMethods = {
|
|
|
1043
1203
|
});
|
|
1044
1204
|
},
|
|
1045
1205
|
|
|
1206
|
+
/**
|
|
1207
|
+
* Creates corresponding fabric instances residing in an object, e.g. `clipPath`
|
|
1208
|
+
* @see {@link fabric.Object.ENLIVEN_PROPS}
|
|
1209
|
+
* @param {Object} object
|
|
1210
|
+
* @param {Object} [context] assign enlived props to this object (pass null to skip this)
|
|
1211
|
+
* @param {(objects:fabric.Object[]) => void} callback
|
|
1212
|
+
*/
|
|
1213
|
+
enlivenObjectEnlivables: function (object, context, callback) {
|
|
1214
|
+
var enlivenProps = fabric.Object.ENLIVEN_PROPS.filter(function (key) { return !!object[key]; });
|
|
1215
|
+
fabric.util.enlivenObjects(enlivenProps.map(function (key) { return object[key]; }), function (enlivedProps) {
|
|
1216
|
+
var objects = {};
|
|
1217
|
+
enlivenProps.forEach(function (key, index) {
|
|
1218
|
+
objects[key] = enlivedProps[index];
|
|
1219
|
+
context && (context[key] = enlivedProps[index]);
|
|
1220
|
+
});
|
|
1221
|
+
callback && callback(objects);
|
|
1222
|
+
});
|
|
1223
|
+
},
|
|
1224
|
+
|
|
1046
1225
|
/**
|
|
1047
1226
|
* Create and wait for loading of patterns
|
|
1048
1227
|
* @static
|
|
@@ -1134,46 +1313,6 @@ fabric.CommonMethods = {
|
|
|
1134
1313
|
}
|
|
1135
1314
|
},
|
|
1136
1315
|
|
|
1137
|
-
/**
|
|
1138
|
-
* Draws a dashed line between two points
|
|
1139
|
-
*
|
|
1140
|
-
* This method is used to draw dashed line around selection area.
|
|
1141
|
-
* See <a href="http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas">dotted stroke in canvas</a>
|
|
1142
|
-
*
|
|
1143
|
-
* @param {CanvasRenderingContext2D} ctx context
|
|
1144
|
-
* @param {Number} x start x coordinate
|
|
1145
|
-
* @param {Number} y start y coordinate
|
|
1146
|
-
* @param {Number} x2 end x coordinate
|
|
1147
|
-
* @param {Number} y2 end y coordinate
|
|
1148
|
-
* @param {Array} da dash array pattern
|
|
1149
|
-
*/
|
|
1150
|
-
drawDashedLine: function(ctx, x, y, x2, y2, da) {
|
|
1151
|
-
var dx = x2 - x,
|
|
1152
|
-
dy = y2 - y,
|
|
1153
|
-
len = sqrt(dx * dx + dy * dy),
|
|
1154
|
-
rot = atan2(dy, dx),
|
|
1155
|
-
dc = da.length,
|
|
1156
|
-
di = 0,
|
|
1157
|
-
draw = true;
|
|
1158
|
-
|
|
1159
|
-
ctx.save();
|
|
1160
|
-
ctx.translate(x, y);
|
|
1161
|
-
ctx.moveTo(0, 0);
|
|
1162
|
-
ctx.rotate(rot);
|
|
1163
|
-
|
|
1164
|
-
x = 0;
|
|
1165
|
-
while (len > x) {
|
|
1166
|
-
x += da[di++ % dc];
|
|
1167
|
-
if (x > len) {
|
|
1168
|
-
x = len;
|
|
1169
|
-
}
|
|
1170
|
-
ctx[draw ? 'lineTo' : 'moveTo'](x, 0);
|
|
1171
|
-
draw = !draw;
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
ctx.restore();
|
|
1175
|
-
},
|
|
1176
|
-
|
|
1177
1316
|
/**
|
|
1178
1317
|
* Creates canvas element
|
|
1179
1318
|
* @static
|
|
@@ -1301,7 +1440,7 @@ fabric.CommonMethods = {
|
|
|
1301
1440
|
* @param {Boolean} [options.flipX]
|
|
1302
1441
|
* @param {Boolean} [options.flipY]
|
|
1303
1442
|
* @param {Number} [options.skewX]
|
|
1304
|
-
* @param {Number} [options.
|
|
1443
|
+
* @param {Number} [options.skewY]
|
|
1305
1444
|
* @return {Number[]} transform matrix
|
|
1306
1445
|
*/
|
|
1307
1446
|
calcDimensionsMatrix: function(options) {
|
|
@@ -1655,7 +1794,50 @@ fabric.CommonMethods = {
|
|
|
1655
1794
|
x: bbox.width,
|
|
1656
1795
|
y: bbox.height,
|
|
1657
1796
|
};
|
|
1658
|
-
}
|
|
1797
|
+
},
|
|
1798
|
+
|
|
1799
|
+
/**
|
|
1800
|
+
* Merges 2 clip paths into one visually equal clip path
|
|
1801
|
+
*
|
|
1802
|
+
* **IMPORTANT**:\
|
|
1803
|
+
* Does **NOT** clone the arguments, clone them proir if necessary.
|
|
1804
|
+
*
|
|
1805
|
+
* Creates a wrapper (group) that contains one clip path and is clipped by the other so content is kept where both overlap.
|
|
1806
|
+
* Use this method if both the clip paths may have nested clip paths of their own, so assigning one to the other's clip path property is not possible.
|
|
1807
|
+
*
|
|
1808
|
+
* In order to handle the `inverted` property we follow logic described in the following cases:\
|
|
1809
|
+
* **(1)** both clip paths are inverted - the clip paths pass the inverted prop to the wrapper and loose it themselves.\
|
|
1810
|
+
* **(2)** one is inverted and the other isn't - the wrapper shouldn't become inverted and the inverted clip path must clip the non inverted one to produce an identical visual effect.\
|
|
1811
|
+
* **(3)** both clip paths are not inverted - wrapper and clip paths remain unchanged.
|
|
1812
|
+
*
|
|
1813
|
+
* @memberOf fabric.util
|
|
1814
|
+
* @param {fabric.Object} c1
|
|
1815
|
+
* @param {fabric.Object} c2
|
|
1816
|
+
* @returns {fabric.Object} merged clip path
|
|
1817
|
+
*/
|
|
1818
|
+
mergeClipPaths: function (c1, c2) {
|
|
1819
|
+
var a = c1, b = c2;
|
|
1820
|
+
if (a.inverted && !b.inverted) {
|
|
1821
|
+
// case (2)
|
|
1822
|
+
a = c2;
|
|
1823
|
+
b = c1;
|
|
1824
|
+
}
|
|
1825
|
+
// `b` becomes `a`'s clip path so we transform `b` to `a` coordinate plane
|
|
1826
|
+
fabric.util.applyTransformToObject(
|
|
1827
|
+
b,
|
|
1828
|
+
fabric.util.multiplyTransformMatrices(
|
|
1829
|
+
fabric.util.invertTransform(a.calcTransformMatrix()),
|
|
1830
|
+
b.calcTransformMatrix()
|
|
1831
|
+
)
|
|
1832
|
+
);
|
|
1833
|
+
// assign the `inverted` prop to the wrapping group
|
|
1834
|
+
var inverted = a.inverted && b.inverted;
|
|
1835
|
+
if (inverted) {
|
|
1836
|
+
// case (1)
|
|
1837
|
+
a.inverted = b.inverted = false;
|
|
1838
|
+
}
|
|
1839
|
+
return new fabric.Group([a], { clipPath: b, inverted: inverted });
|
|
1840
|
+
},
|
|
1659
1841
|
};
|
|
1660
1842
|
})(typeof exports !== 'undefined' ? exports : this);
|
|
1661
1843
|
|
|
@@ -2148,8 +2330,8 @@ fabric.CommonMethods = {
|
|
|
2148
2330
|
// with 100 segemnts. This will good enough to calculate the length of the curve
|
|
2149
2331
|
function pathIterator(iterator, x1, y1) {
|
|
2150
2332
|
var tempP = { x: x1, y: y1 }, p, tmpLen = 0, perc;
|
|
2151
|
-
for (perc =
|
|
2152
|
-
p = iterator(perc);
|
|
2333
|
+
for (perc = 1; perc <= 100; perc += 1) {
|
|
2334
|
+
p = iterator(perc / 100);
|
|
2153
2335
|
tmpLen += calcLineLength(tempP.x, tempP.y, p.x, p.y);
|
|
2154
2336
|
tempP = p;
|
|
2155
2337
|
}
|
|
@@ -2169,15 +2351,15 @@ fabric.CommonMethods = {
|
|
|
2169
2351
|
p, nextLen, nextStep = 0.01, angleFinder = segInfo.angleFinder, lastPerc;
|
|
2170
2352
|
// nextStep > 0.0001 covers 0.00015625 that 1/64th of 1/100
|
|
2171
2353
|
// the path
|
|
2172
|
-
while (tmpLen < distance &&
|
|
2354
|
+
while (tmpLen < distance && nextStep > 0.0001) {
|
|
2173
2355
|
p = iterator(perc);
|
|
2174
2356
|
lastPerc = perc;
|
|
2175
2357
|
nextLen = calcLineLength(tempP.x, tempP.y, p.x, p.y);
|
|
2176
2358
|
// compare tmpLen each cycle with distance, decide next perc to test.
|
|
2177
2359
|
if ((nextLen + tmpLen) > distance) {
|
|
2178
2360
|
// we discard this step and we make smaller steps.
|
|
2179
|
-
nextStep /= 2;
|
|
2180
2361
|
perc -= nextStep;
|
|
2362
|
+
nextStep /= 2;
|
|
2181
2363
|
}
|
|
2182
2364
|
else {
|
|
2183
2365
|
tempP = p;
|
|
@@ -2323,6 +2505,18 @@ fabric.CommonMethods = {
|
|
|
2323
2505
|
}
|
|
2324
2506
|
}
|
|
2325
2507
|
|
|
2508
|
+
/**
|
|
2509
|
+
*
|
|
2510
|
+
* @param {string} pathString
|
|
2511
|
+
* @return {(string|number)[][]} An array of SVG path commands
|
|
2512
|
+
* @example <caption>Usage</caption>
|
|
2513
|
+
* parsePath('M 3 4 Q 3 5 2 1 4 0 Q 9 12 2 1 4 0') === [
|
|
2514
|
+
* ['M', 3, 4],
|
|
2515
|
+
* ['Q', 3, 5, 2, 1, 4, 0],
|
|
2516
|
+
* ['Q', 9, 12, 2, 1, 4, 0],
|
|
2517
|
+
* ];
|
|
2518
|
+
*
|
|
2519
|
+
*/
|
|
2326
2520
|
function parsePath(pathString) {
|
|
2327
2521
|
var result = [],
|
|
2328
2522
|
coords = [],
|
|
@@ -2392,65 +2586,90 @@ fabric.CommonMethods = {
|
|
|
2392
2586
|
};
|
|
2393
2587
|
|
|
2394
2588
|
/**
|
|
2395
|
-
*
|
|
2396
|
-
*
|
|
2397
|
-
* @param {
|
|
2398
|
-
* @param {
|
|
2399
|
-
* @
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2589
|
+
*
|
|
2590
|
+
* Converts points to a smooth SVG path
|
|
2591
|
+
* @param {{ x: number,y: number }[]} points Array of points
|
|
2592
|
+
* @param {number} [correction] Apply a correction to the path (usually we use `width / 1000`). If value is undefined 0 is used as the correction value.
|
|
2593
|
+
* @return {(string|number)[][]} An array of SVG path commands
|
|
2594
|
+
*/
|
|
2595
|
+
function getSmoothPathFromPoints(points, correction) {
|
|
2596
|
+
var path = [], i,
|
|
2597
|
+
p1 = new fabric.Point(points[0].x, points[0].y),
|
|
2598
|
+
p2 = new fabric.Point(points[1].x, points[1].y),
|
|
2599
|
+
len = points.length, multSignX = 1, multSignY = 0, manyPoints = len > 2;
|
|
2600
|
+
correction = correction || 0;
|
|
2601
|
+
|
|
2602
|
+
if (manyPoints) {
|
|
2603
|
+
multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;
|
|
2604
|
+
multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1;
|
|
2605
|
+
}
|
|
2606
|
+
path.push(['M', p1.x - multSignX * correction, p1.y - multSignY * correction]);
|
|
2607
|
+
for (i = 1; i < len; i++) {
|
|
2608
|
+
if (!p1.eq(p2)) {
|
|
2609
|
+
var midPoint = p1.midPointFrom(p2);
|
|
2610
|
+
// p1 is our bezier control point
|
|
2611
|
+
// midpoint is our endpoint
|
|
2612
|
+
// start point is p(i-1) value.
|
|
2613
|
+
path.push(['Q', p1.x, p1.y, midPoint.x, midPoint.y]);
|
|
2614
|
+
}
|
|
2615
|
+
p1 = points[i];
|
|
2616
|
+
if ((i + 1) < points.length) {
|
|
2617
|
+
p2 = points[i + 1];
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
if (manyPoints) {
|
|
2621
|
+
multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;
|
|
2622
|
+
multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;
|
|
2623
|
+
}
|
|
2624
|
+
path.push(['L', p1.x + multSignX * correction, p1.y + multSignY * correction]);
|
|
2625
|
+
return path;
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
* Transform a path by transforming each segment.
|
|
2629
|
+
* it has to be a simplified path or it won't work.
|
|
2630
|
+
* WARNING: this depends from pathOffset for correct operation
|
|
2631
|
+
* @param {Array} path fabricJS parsed and simplified path commands
|
|
2632
|
+
* @param {Array} transform matrix that represent the transformation
|
|
2633
|
+
* @param {Object} [pathOffset] the fabric.Path pathOffset
|
|
2634
|
+
* @param {Number} pathOffset.x
|
|
2635
|
+
* @param {Number} pathOffset.y
|
|
2636
|
+
* @returns {Array} the transformed path
|
|
2637
|
+
*/
|
|
2638
|
+
function transformPath(path, transform, pathOffset) {
|
|
2639
|
+
if (pathOffset) {
|
|
2640
|
+
transform = fabric.util.multiplyTransformMatrices(
|
|
2641
|
+
transform,
|
|
2642
|
+
[1, 0, 0, 1, -pathOffset.x, -pathOffset.y]
|
|
2643
|
+
);
|
|
2418
2644
|
}
|
|
2419
|
-
return
|
|
2420
|
-
|
|
2645
|
+
return path.map(function(pathSegment) {
|
|
2646
|
+
var newSegment = pathSegment.slice(0), point = {};
|
|
2647
|
+
for (var i = 1; i < pathSegment.length - 1; i += 2) {
|
|
2648
|
+
point.x = pathSegment[i];
|
|
2649
|
+
point.y = pathSegment[i + 1];
|
|
2650
|
+
point = fabric.util.transformPoint(point, transform);
|
|
2651
|
+
newSegment[i] = point.x;
|
|
2652
|
+
newSegment[i + 1] = point.y;
|
|
2653
|
+
}
|
|
2654
|
+
return newSegment;
|
|
2655
|
+
});
|
|
2656
|
+
}
|
|
2421
2657
|
|
|
2422
2658
|
/**
|
|
2423
|
-
*
|
|
2424
|
-
* @
|
|
2425
|
-
* @
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
*/
|
|
2430
|
-
function drawArc(ctx, fx, fy, coords) {
|
|
2431
|
-
coords = coords.slice(0).unshift('X'); // command A or a does not matter
|
|
2432
|
-
var beziers = fromArcToBeziers(fx, fy, coords);
|
|
2433
|
-
beziers.forEach(function(bezier) {
|
|
2434
|
-
ctx.bezierCurveTo.apply(ctx, bezier.slice(1));
|
|
2435
|
-
});
|
|
2659
|
+
* Join path commands to go back to svg format
|
|
2660
|
+
* @param {Array} pathData fabricJS parsed path commands
|
|
2661
|
+
* @return {String} joined path 'M 0 0 L 20 30'
|
|
2662
|
+
*/
|
|
2663
|
+
fabric.util.joinPath = function(pathData) {
|
|
2664
|
+
return pathData.map(function (segment) { return segment.join(' '); }).join(' ');
|
|
2436
2665
|
};
|
|
2437
|
-
|
|
2438
2666
|
fabric.util.parsePath = parsePath;
|
|
2439
2667
|
fabric.util.makePathSimpler = makePathSimpler;
|
|
2668
|
+
fabric.util.getSmoothPathFromPoints = getSmoothPathFromPoints;
|
|
2440
2669
|
fabric.util.getPathSegmentsInfo = getPathSegmentsInfo;
|
|
2441
|
-
fabric.util.fromArcToBeziers = fromArcToBeziers;
|
|
2442
|
-
/**
|
|
2443
|
-
* Typo of `fromArcToBeziers` kept for not breaking the api once corrected.
|
|
2444
|
-
* Will be removed in fabric 5.0
|
|
2445
|
-
* @deprecated
|
|
2446
|
-
*/
|
|
2447
|
-
fabric.util.fromArcToBeizers = fromArcToBeziers;
|
|
2448
2670
|
fabric.util.getBoundsOfCurve = getBoundsOfCurve;
|
|
2449
2671
|
fabric.util.getPointOnPath = getPointOnPath;
|
|
2450
|
-
|
|
2451
|
-
// but useless and deprecated.
|
|
2452
|
-
fabric.util.getBoundsOfArc = getBoundsOfArc;
|
|
2453
|
-
fabric.util.drawArc = drawArc;
|
|
2672
|
+
fabric.util.transformPath = transformPath;
|
|
2454
2673
|
})();
|
|
2455
2674
|
|
|
2456
2675
|
|
|
@@ -2560,6 +2779,7 @@ fabric.CommonMethods = {
|
|
|
2560
2779
|
* @memberOf fabric.util.object
|
|
2561
2780
|
* @param {Object} destination Where to copy to
|
|
2562
2781
|
* @param {Object} source Where to copy from
|
|
2782
|
+
* @param {Boolean} [deep] Whether to extend nested objects
|
|
2563
2783
|
* @return {Object}
|
|
2564
2784
|
*/
|
|
2565
2785
|
|
|
@@ -2605,11 +2825,14 @@ fabric.CommonMethods = {
|
|
|
2605
2825
|
|
|
2606
2826
|
/**
|
|
2607
2827
|
* Creates an empty object and copies all enumerable properties of another object to it
|
|
2828
|
+
* This method is mostly for internal use, and not intended for duplicating shapes in canvas.
|
|
2608
2829
|
* @memberOf fabric.util.object
|
|
2609
|
-
* TODO: this function return an empty object if you try to clone null
|
|
2610
2830
|
* @param {Object} object Object to clone
|
|
2831
|
+
* @param {Boolean} [deep] Whether to clone nested objects
|
|
2611
2832
|
* @return {Object}
|
|
2612
2833
|
*/
|
|
2834
|
+
|
|
2835
|
+
//TODO: this function return an empty object if you try to clone null
|
|
2613
2836
|
function clone(object, deep) {
|
|
2614
2837
|
return extend({ }, object, deep);
|
|
2615
2838
|
}
|
|
@@ -3347,7 +3570,117 @@ fabric.log = console.log;
|
|
|
3347
3570
|
fabric.warn = console.warn;
|
|
3348
3571
|
|
|
3349
3572
|
|
|
3350
|
-
(function() {
|
|
3573
|
+
(function () {
|
|
3574
|
+
|
|
3575
|
+
var extend = fabric.util.object.extend,
|
|
3576
|
+
clone = fabric.util.object.clone;
|
|
3577
|
+
|
|
3578
|
+
/**
|
|
3579
|
+
* @typedef {Object} AnimationOptions
|
|
3580
|
+
* @property {Function} [options.onChange] Callback; invoked on every value change
|
|
3581
|
+
* @property {Function} [options.onComplete] Callback; invoked when value change is completed
|
|
3582
|
+
* @property {Number} [options.startValue=0] Starting value
|
|
3583
|
+
* @property {Number} [options.endValue=100] Ending value
|
|
3584
|
+
* @property {Number} [options.byValue=100] Value to modify the property by
|
|
3585
|
+
* @property {Function} [options.easing] Easing function
|
|
3586
|
+
* @property {Number} [options.duration=500] Duration of change (in ms)
|
|
3587
|
+
* @property {Function} [options.abort] Additional function with logic. If returns true, animation aborts.
|
|
3588
|
+
*
|
|
3589
|
+
* @typedef {() => void} CancelFunction
|
|
3590
|
+
*
|
|
3591
|
+
* @typedef {Object} AnimationCurrentState
|
|
3592
|
+
* @property {number} currentValue value in range [`startValue`, `endValue`]
|
|
3593
|
+
* @property {number} completionRate value in range [0, 1]
|
|
3594
|
+
* @property {number} durationRate value in range [0, 1]
|
|
3595
|
+
*
|
|
3596
|
+
* @typedef {(AnimationOptions & AnimationCurrentState & { cancel: CancelFunction }} AnimationContext
|
|
3597
|
+
*/
|
|
3598
|
+
|
|
3599
|
+
/**
|
|
3600
|
+
* Array holding all running animations
|
|
3601
|
+
* @memberof fabric
|
|
3602
|
+
* @type {AnimationContext[]}
|
|
3603
|
+
*/
|
|
3604
|
+
var RUNNING_ANIMATIONS = [];
|
|
3605
|
+
fabric.util.object.extend(RUNNING_ANIMATIONS, {
|
|
3606
|
+
|
|
3607
|
+
/**
|
|
3608
|
+
* cancel all running animations at the next requestAnimFrame
|
|
3609
|
+
* @returns {AnimationContext[]}
|
|
3610
|
+
*/
|
|
3611
|
+
cancelAll: function () {
|
|
3612
|
+
var animations = this.splice(0);
|
|
3613
|
+
animations.forEach(function (animation) {
|
|
3614
|
+
animation.cancel();
|
|
3615
|
+
});
|
|
3616
|
+
return animations;
|
|
3617
|
+
},
|
|
3618
|
+
|
|
3619
|
+
/**
|
|
3620
|
+
* cancel all running animations attached to canvas at the next requestAnimFrame
|
|
3621
|
+
* @param {fabric.Canvas} canvas
|
|
3622
|
+
* @returns {AnimationContext[]}
|
|
3623
|
+
*/
|
|
3624
|
+
cancelByCanvas: function (canvas) {
|
|
3625
|
+
if (!canvas) {
|
|
3626
|
+
return [];
|
|
3627
|
+
}
|
|
3628
|
+
var cancelled = this.filter(function (animation) {
|
|
3629
|
+
return typeof animation.target === 'object' && animation.target.canvas === canvas;
|
|
3630
|
+
});
|
|
3631
|
+
cancelled.forEach(function (animation) {
|
|
3632
|
+
animation.cancel();
|
|
3633
|
+
});
|
|
3634
|
+
return cancelled;
|
|
3635
|
+
},
|
|
3636
|
+
|
|
3637
|
+
/**
|
|
3638
|
+
* cancel all running animations for target at the next requestAnimFrame
|
|
3639
|
+
* @param {*} target
|
|
3640
|
+
* @returns {AnimationContext[]}
|
|
3641
|
+
*/
|
|
3642
|
+
cancelByTarget: function (target) {
|
|
3643
|
+
var cancelled = this.findAnimationsByTarget(target);
|
|
3644
|
+
cancelled.forEach(function (animation) {
|
|
3645
|
+
animation.cancel();
|
|
3646
|
+
});
|
|
3647
|
+
return cancelled;
|
|
3648
|
+
},
|
|
3649
|
+
|
|
3650
|
+
/**
|
|
3651
|
+
*
|
|
3652
|
+
* @param {CancelFunction} cancelFunc the function returned by animate
|
|
3653
|
+
* @returns {number}
|
|
3654
|
+
*/
|
|
3655
|
+
findAnimationIndex: function (cancelFunc) {
|
|
3656
|
+
return this.indexOf(this.findAnimation(cancelFunc));
|
|
3657
|
+
},
|
|
3658
|
+
|
|
3659
|
+
/**
|
|
3660
|
+
*
|
|
3661
|
+
* @param {CancelFunction} cancelFunc the function returned by animate
|
|
3662
|
+
* @returns {AnimationContext | undefined} animation's options object
|
|
3663
|
+
*/
|
|
3664
|
+
findAnimation: function (cancelFunc) {
|
|
3665
|
+
return this.find(function (animation) {
|
|
3666
|
+
return animation.cancel === cancelFunc;
|
|
3667
|
+
});
|
|
3668
|
+
},
|
|
3669
|
+
|
|
3670
|
+
/**
|
|
3671
|
+
*
|
|
3672
|
+
* @param {*} target the object that is assigned to the target property of the animation context
|
|
3673
|
+
* @returns {AnimationContext[]} array of animation options object associated with target
|
|
3674
|
+
*/
|
|
3675
|
+
findAnimationsByTarget: function (target) {
|
|
3676
|
+
if (!target) {
|
|
3677
|
+
return [];
|
|
3678
|
+
}
|
|
3679
|
+
return this.filter(function (animation) {
|
|
3680
|
+
return animation.target === target;
|
|
3681
|
+
});
|
|
3682
|
+
}
|
|
3683
|
+
});
|
|
3351
3684
|
|
|
3352
3685
|
function noop() {
|
|
3353
3686
|
return false;
|
|
@@ -3360,21 +3693,30 @@ fabric.warn = console.warn;
|
|
|
3360
3693
|
/**
|
|
3361
3694
|
* Changes value from one to another within certain period of time, invoking callbacks as value is being changed.
|
|
3362
3695
|
* @memberOf fabric.util
|
|
3363
|
-
* @param {
|
|
3364
|
-
* @
|
|
3365
|
-
* @param {Function} [options.onComplete] Callback; invoked when value change is completed
|
|
3366
|
-
* @param {Number} [options.startValue=0] Starting value
|
|
3367
|
-
* @param {Number} [options.endValue=100] Ending value
|
|
3368
|
-
* @param {Number} [options.byValue=100] Value to modify the property by
|
|
3369
|
-
* @param {Function} [options.easing] Easing function
|
|
3370
|
-
* @param {Number} [options.duration=500] Duration of change (in ms)
|
|
3371
|
-
* @param {Function} [options.abort] Additional function with logic. If returns true, onComplete is called.
|
|
3696
|
+
* @param {AnimationOptions} [options] Animation options
|
|
3697
|
+
* @returns {CancelFunction} cancel function
|
|
3372
3698
|
*/
|
|
3373
3699
|
function animate(options) {
|
|
3700
|
+
options || (options = {});
|
|
3701
|
+
var cancel = false,
|
|
3702
|
+
context,
|
|
3703
|
+
removeFromRegistry = function () {
|
|
3704
|
+
var index = fabric.runningAnimations.indexOf(context);
|
|
3705
|
+
return index > -1 && fabric.runningAnimations.splice(index, 1)[0];
|
|
3706
|
+
};
|
|
3374
3707
|
|
|
3375
|
-
|
|
3376
|
-
|
|
3708
|
+
context = extend(clone(options), {
|
|
3709
|
+
cancel: function () {
|
|
3710
|
+
cancel = true;
|
|
3711
|
+
return removeFromRegistry();
|
|
3712
|
+
},
|
|
3713
|
+
currentValue: 'startValue' in options ? options.startValue : 0,
|
|
3714
|
+
completionRate: 0,
|
|
3715
|
+
durationRate: 0
|
|
3716
|
+
});
|
|
3717
|
+
fabric.runningAnimations.push(context);
|
|
3377
3718
|
|
|
3719
|
+
requestAnimFrame(function(timestamp) {
|
|
3378
3720
|
var start = timestamp || +new Date(),
|
|
3379
3721
|
duration = options.duration || 500,
|
|
3380
3722
|
finish = start + duration, time,
|
|
@@ -3389,20 +3731,31 @@ fabric.warn = console.warn;
|
|
|
3389
3731
|
options.onStart && options.onStart();
|
|
3390
3732
|
|
|
3391
3733
|
(function tick(ticktime) {
|
|
3392
|
-
// TODO: move abort call after calculation
|
|
3393
|
-
// and pass (current,valuePerc, timePerc) as arguments
|
|
3394
3734
|
time = ticktime || +new Date();
|
|
3395
3735
|
var currentTime = time > finish ? duration : (time - start),
|
|
3396
3736
|
timePerc = currentTime / duration,
|
|
3397
3737
|
current = easing(currentTime, startValue, byValue, duration),
|
|
3398
3738
|
valuePerc = Math.abs((current - startValue) / byValue);
|
|
3399
|
-
|
|
3400
|
-
|
|
3739
|
+
// update context
|
|
3740
|
+
context.currentValue = current;
|
|
3741
|
+
context.completionRate = valuePerc;
|
|
3742
|
+
context.durationRate = timePerc;
|
|
3743
|
+
if (cancel) {
|
|
3744
|
+
return;
|
|
3745
|
+
}
|
|
3746
|
+
if (abort(current, valuePerc, timePerc)) {
|
|
3747
|
+
removeFromRegistry();
|
|
3401
3748
|
return;
|
|
3402
3749
|
}
|
|
3403
3750
|
if (time > finish) {
|
|
3751
|
+
// update context
|
|
3752
|
+
context.currentValue = endValue;
|
|
3753
|
+
context.completionRate = 1;
|
|
3754
|
+
context.durationRate = 1;
|
|
3755
|
+
// execute callbacks
|
|
3404
3756
|
onChange(endValue, 1, 1);
|
|
3405
3757
|
onComplete(endValue, 1, 1);
|
|
3758
|
+
removeFromRegistry();
|
|
3406
3759
|
return;
|
|
3407
3760
|
}
|
|
3408
3761
|
else {
|
|
@@ -3411,6 +3764,8 @@ fabric.warn = console.warn;
|
|
|
3411
3764
|
}
|
|
3412
3765
|
})(start);
|
|
3413
3766
|
});
|
|
3767
|
+
|
|
3768
|
+
return context.cancel;
|
|
3414
3769
|
}
|
|
3415
3770
|
|
|
3416
3771
|
var _requestAnimFrame = fabric.window.requestAnimationFrame ||
|
|
@@ -3442,6 +3797,7 @@ fabric.warn = console.warn;
|
|
|
3442
3797
|
fabric.util.animate = animate;
|
|
3443
3798
|
fabric.util.requestAnimFrame = requestAnimFrame;
|
|
3444
3799
|
fabric.util.cancelAnimFrame = cancelAnimFrame;
|
|
3800
|
+
fabric.runningAnimations = RUNNING_ANIMATIONS;
|
|
3445
3801
|
})();
|
|
3446
3802
|
|
|
3447
3803
|
|
|
@@ -3471,6 +3827,7 @@ fabric.warn = console.warn;
|
|
|
3471
3827
|
* @param {Function} [options.onComplete] Callback; invoked when value change is completed
|
|
3472
3828
|
* @param {Function} [options.colorEasing] Easing function. Note that this function only take two arguments (currentTime, duration). Thus the regular animation easing functions cannot be used.
|
|
3473
3829
|
* @param {Function} [options.abort] Additional function with logic. If returns true, onComplete is called.
|
|
3830
|
+
* @returns {Function} abort function
|
|
3474
3831
|
*/
|
|
3475
3832
|
function animateColor(fromColor, toColor, duration, options) {
|
|
3476
3833
|
var startColor = new fabric.Color(fromColor).getSource(),
|
|
@@ -3479,7 +3836,7 @@ fabric.warn = console.warn;
|
|
|
3479
3836
|
originalOnChange = options.onChange;
|
|
3480
3837
|
options = options || {};
|
|
3481
3838
|
|
|
3482
|
-
fabric.util.animate(fabric.util.object.extend(options, {
|
|
3839
|
+
return fabric.util.animate(fabric.util.object.extend(options, {
|
|
3483
3840
|
duration: duration || 500,
|
|
3484
3841
|
startValue: startColor,
|
|
3485
3842
|
endValue: endColor,
|
|
@@ -4923,22 +5280,26 @@ fabric.warn = console.warn;
|
|
|
4923
5280
|
if (styleContents.trim() === '') {
|
|
4924
5281
|
continue;
|
|
4925
5282
|
}
|
|
4926
|
-
|
|
4927
|
-
rules =
|
|
5283
|
+
// recovers all the rule in this form `body { style code... }`
|
|
5284
|
+
// rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g);
|
|
5285
|
+
rules = styleContents.split('}');
|
|
5286
|
+
// remove empty rules.
|
|
5287
|
+
rules = rules.filter(function(rule) { return rule.trim(); });
|
|
5288
|
+
// at this point we have hopefully an array of rules `body { style code... `
|
|
4928
5289
|
// eslint-disable-next-line no-loop-func
|
|
4929
5290
|
rules.forEach(function(rule) {
|
|
4930
5291
|
|
|
4931
|
-
var match = rule.
|
|
4932
|
-
ruleObj = { }, declaration = match[
|
|
4933
|
-
propertyValuePairs = declaration.
|
|
5292
|
+
var match = rule.split('{'),
|
|
5293
|
+
ruleObj = { }, declaration = match[1].trim(),
|
|
5294
|
+
propertyValuePairs = declaration.split(';').filter(function(pair) { return pair.trim(); });
|
|
4934
5295
|
|
|
4935
5296
|
for (i = 0, len = propertyValuePairs.length; i < len; i++) {
|
|
4936
|
-
var pair = propertyValuePairs[i].split(
|
|
4937
|
-
property = pair[0],
|
|
4938
|
-
value = pair[1];
|
|
5297
|
+
var pair = propertyValuePairs[i].split(':'),
|
|
5298
|
+
property = pair[0].trim(),
|
|
5299
|
+
value = pair[1].trim();
|
|
4939
5300
|
ruleObj[property] = value;
|
|
4940
5301
|
}
|
|
4941
|
-
rule = match[
|
|
5302
|
+
rule = match[0].trim();
|
|
4942
5303
|
rule.split(',').forEach(function(_rule) {
|
|
4943
5304
|
_rule = _rule.replace(/^svg/i, '').trim();
|
|
4944
5305
|
if (_rule === '') {
|
|
@@ -8513,8 +8874,12 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
8513
8874
|
imageSmoothingEnabled: true,
|
|
8514
8875
|
|
|
8515
8876
|
/**
|
|
8516
|
-
* The transformation (
|
|
8877
|
+
* The transformation (a Canvas 2D API transform matrix) which focuses the viewport
|
|
8517
8878
|
* @type Array
|
|
8879
|
+
* @example <caption>Default transform</caption>
|
|
8880
|
+
* canvas.viewportTransform = [1, 0, 0, 1, 0, 0];
|
|
8881
|
+
* @example <caption>Scale by 70% and translate toward bottom-right by 50, without skewing</caption>
|
|
8882
|
+
* canvas.viewportTransform = [0.7, 0, 0, 0.7, 50, 50];
|
|
8518
8883
|
* @default
|
|
8519
8884
|
*/
|
|
8520
8885
|
viewportTransform: fabric.iMatrix.concat(),
|
|
@@ -8608,7 +8973,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
8608
8973
|
* @private
|
|
8609
8974
|
*/
|
|
8610
8975
|
_isRetinaScaling: function() {
|
|
8611
|
-
return (fabric.devicePixelRatio
|
|
8976
|
+
return (fabric.devicePixelRatio > 1 && this.enableRetinaScaling);
|
|
8612
8977
|
},
|
|
8613
8978
|
|
|
8614
8979
|
/**
|
|
@@ -8616,7 +8981,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
8616
8981
|
* @return {Number} retinaScaling if applied, otherwise 1;
|
|
8617
8982
|
*/
|
|
8618
8983
|
getRetinaScaling: function() {
|
|
8619
|
-
return this._isRetinaScaling() ? fabric.devicePixelRatio : 1;
|
|
8984
|
+
return this._isRetinaScaling() ? Math.max(1, fabric.devicePixelRatio) : 1;
|
|
8620
8985
|
},
|
|
8621
8986
|
|
|
8622
8987
|
/**
|
|
@@ -8903,7 +9268,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
8903
9268
|
}
|
|
8904
9269
|
|
|
8905
9270
|
fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas');
|
|
8906
|
-
|
|
9271
|
+
this._originalCanvasStyle = this.lowerCanvasEl.style;
|
|
8907
9272
|
if (this.interactive) {
|
|
8908
9273
|
this._applyCanvasStyle(this.lowerCanvasEl);
|
|
8909
9274
|
}
|
|
@@ -8983,7 +9348,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
8983
9348
|
}
|
|
8984
9349
|
}
|
|
8985
9350
|
if (this._isCurrentlyDrawing) {
|
|
8986
|
-
this.freeDrawingBrush && this.freeDrawingBrush._setBrushStyles();
|
|
9351
|
+
this.freeDrawingBrush && this.freeDrawingBrush._setBrushStyles(this.contextTop);
|
|
8987
9352
|
}
|
|
8988
9353
|
this._initRetinaScaling();
|
|
8989
9354
|
this.calcOffset();
|
|
@@ -9050,8 +9415,8 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
9050
9415
|
},
|
|
9051
9416
|
|
|
9052
9417
|
/**
|
|
9053
|
-
* Sets viewport
|
|
9054
|
-
* @param {Array} vpt
|
|
9418
|
+
* Sets viewport transformation of this canvas instance
|
|
9419
|
+
* @param {Array} vpt a Canvas 2D API transform matrix
|
|
9055
9420
|
* @return {fabric.Canvas} instance
|
|
9056
9421
|
* @chainable true
|
|
9057
9422
|
*/
|
|
@@ -9193,7 +9558,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
9193
9558
|
* @chainable
|
|
9194
9559
|
*/
|
|
9195
9560
|
clear: function () {
|
|
9196
|
-
this.
|
|
9561
|
+
this.remove.apply(this, this.getObjects());
|
|
9197
9562
|
this.backgroundImage = null;
|
|
9198
9563
|
this.overlayImage = null;
|
|
9199
9564
|
this.backgroundColor = '';
|
|
@@ -9539,7 +9904,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
9539
9904
|
version: fabric.version,
|
|
9540
9905
|
objects: this._toObjects(methodName, propertiesToInclude),
|
|
9541
9906
|
};
|
|
9542
|
-
if (clipPath) {
|
|
9907
|
+
if (clipPath && !clipPath.excludeFromExport) {
|
|
9543
9908
|
data.clipPath = this._toObject(this.clipPath, methodName, propertiesToInclude);
|
|
9544
9909
|
}
|
|
9545
9910
|
extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));
|
|
@@ -9582,24 +9947,32 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
9582
9947
|
* @private
|
|
9583
9948
|
*/
|
|
9584
9949
|
__serializeBgOverlay: function(methodName, propertiesToInclude) {
|
|
9585
|
-
var data = {
|
|
9950
|
+
var data = {}, bgImage = this.backgroundImage, overlayImage = this.overlayImage,
|
|
9951
|
+
bgColor = this.backgroundColor, overlayColor = this.overlayColor;
|
|
9586
9952
|
|
|
9587
|
-
if (
|
|
9588
|
-
|
|
9589
|
-
|
|
9590
|
-
|
|
9953
|
+
if (bgColor && bgColor.toObject) {
|
|
9954
|
+
if (!bgColor.excludeFromExport) {
|
|
9955
|
+
data.background = bgColor.toObject(propertiesToInclude);
|
|
9956
|
+
}
|
|
9957
|
+
}
|
|
9958
|
+
else if (bgColor) {
|
|
9959
|
+
data.background = bgColor;
|
|
9591
9960
|
}
|
|
9592
9961
|
|
|
9593
|
-
if (
|
|
9594
|
-
|
|
9595
|
-
|
|
9596
|
-
|
|
9962
|
+
if (overlayColor && overlayColor.toObject) {
|
|
9963
|
+
if (!overlayColor.excludeFromExport) {
|
|
9964
|
+
data.overlay = overlayColor.toObject(propertiesToInclude);
|
|
9965
|
+
}
|
|
9597
9966
|
}
|
|
9967
|
+
else if (overlayColor) {
|
|
9968
|
+
data.overlay = overlayColor;
|
|
9969
|
+
}
|
|
9970
|
+
|
|
9598
9971
|
if (bgImage && !bgImage.excludeFromExport) {
|
|
9599
9972
|
data.backgroundImage = this._toObject(bgImage, methodName, propertiesToInclude);
|
|
9600
9973
|
}
|
|
9601
|
-
if (
|
|
9602
|
-
data.overlayImage = this._toObject(
|
|
9974
|
+
if (overlayImage && !overlayImage.excludeFromExport) {
|
|
9975
|
+
data.overlayImage = this._toObject(overlayImage, methodName, propertiesToInclude);
|
|
9603
9976
|
}
|
|
9604
9977
|
|
|
9605
9978
|
return data;
|
|
@@ -10130,6 +10503,10 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
10130
10503
|
}
|
|
10131
10504
|
this.forEachObject(function(object) {
|
|
10132
10505
|
object.dispose && object.dispose();
|
|
10506
|
+
// animation module is still optional
|
|
10507
|
+
if (fabric.runningAnimations) {
|
|
10508
|
+
fabric.runningAnimations.cancelByTarget(object);
|
|
10509
|
+
}
|
|
10133
10510
|
});
|
|
10134
10511
|
this._objects = [];
|
|
10135
10512
|
if (this.backgroundImage && this.backgroundImage.dispose) {
|
|
@@ -10142,6 +10519,13 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
|
|
10142
10519
|
this.overlayImage = null;
|
|
10143
10520
|
this._iTextInstances = null;
|
|
10144
10521
|
this.contextContainer = null;
|
|
10522
|
+
// restore canvas style
|
|
10523
|
+
this.lowerCanvasEl.classList.remove('lower-canvas');
|
|
10524
|
+
fabric.util.setStyle(this.lowerCanvasEl, this._originalCanvasStyle);
|
|
10525
|
+
delete this._originalCanvasStyle;
|
|
10526
|
+
// restore canvas size to original size in case retina scaling was applied
|
|
10527
|
+
this.lowerCanvasEl.setAttribute('width', this.width);
|
|
10528
|
+
this.lowerCanvasEl.setAttribute('height', this.height);
|
|
10145
10529
|
fabric.util.cleanUpJsdomNode(this.lowerCanvasEl);
|
|
10146
10530
|
this.lowerCanvasEl = undefined;
|
|
10147
10531
|
return this;
|
|
@@ -10305,17 +10689,15 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10305
10689
|
/**
|
|
10306
10690
|
* Sets brush styles
|
|
10307
10691
|
* @private
|
|
10692
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
10308
10693
|
*/
|
|
10309
|
-
_setBrushStyles: function() {
|
|
10310
|
-
var ctx = this.canvas.contextTop;
|
|
10694
|
+
_setBrushStyles: function (ctx) {
|
|
10311
10695
|
ctx.strokeStyle = this.color;
|
|
10312
10696
|
ctx.lineWidth = this.width;
|
|
10313
10697
|
ctx.lineCap = this.strokeLineCap;
|
|
10314
10698
|
ctx.miterLimit = this.strokeMiterLimit;
|
|
10315
10699
|
ctx.lineJoin = this.strokeLineJoin;
|
|
10316
|
-
|
|
10317
|
-
ctx.setLineDash(this.strokeDashArray || []);
|
|
10318
|
-
}
|
|
10700
|
+
ctx.setLineDash(this.strokeDashArray || []);
|
|
10319
10701
|
},
|
|
10320
10702
|
|
|
10321
10703
|
/**
|
|
@@ -10394,6 +10776,22 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10394
10776
|
*/
|
|
10395
10777
|
decimate: 0.4,
|
|
10396
10778
|
|
|
10779
|
+
/**
|
|
10780
|
+
* Draws a straight line between last recorded point to current pointer
|
|
10781
|
+
* Used for `shift` functionality
|
|
10782
|
+
*
|
|
10783
|
+
* @type boolean
|
|
10784
|
+
* @default false
|
|
10785
|
+
*/
|
|
10786
|
+
drawStraightLine: false,
|
|
10787
|
+
|
|
10788
|
+
/**
|
|
10789
|
+
* The event modifier key that makes the brush draw a straight line.
|
|
10790
|
+
* If `null` or 'none' or any other string that is not a modifier key the feature is disabled.
|
|
10791
|
+
* @type {'altKey' | 'shiftKey' | 'ctrlKey' | 'none' | undefined | null}
|
|
10792
|
+
*/
|
|
10793
|
+
straightLineKey: 'shiftKey',
|
|
10794
|
+
|
|
10397
10795
|
/**
|
|
10398
10796
|
* Constructor
|
|
10399
10797
|
* @param {fabric.Canvas} canvas
|
|
@@ -10404,6 +10802,10 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10404
10802
|
this._points = [];
|
|
10405
10803
|
},
|
|
10406
10804
|
|
|
10805
|
+
needsFullRender: function () {
|
|
10806
|
+
return this.callSuper('needsFullRender') || this._hasStraightLine;
|
|
10807
|
+
},
|
|
10808
|
+
|
|
10407
10809
|
/**
|
|
10408
10810
|
* Invoked inside on mouse down and mouse move
|
|
10409
10811
|
* @param {Object} pointer
|
|
@@ -10422,6 +10824,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10422
10824
|
if (!this.canvas._isMainEvent(options.e)) {
|
|
10423
10825
|
return;
|
|
10424
10826
|
}
|
|
10827
|
+
this.drawStraightLine = options.e[this.straightLineKey];
|
|
10425
10828
|
this._prepareForDrawing(pointer);
|
|
10426
10829
|
// capture coordinates immediately
|
|
10427
10830
|
// this allows to draw dots (when movement never occurs)
|
|
@@ -10437,6 +10840,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10437
10840
|
if (!this.canvas._isMainEvent(options.e)) {
|
|
10438
10841
|
return;
|
|
10439
10842
|
}
|
|
10843
|
+
this.drawStraightLine = options.e[this.straightLineKey];
|
|
10440
10844
|
if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {
|
|
10441
10845
|
return;
|
|
10442
10846
|
}
|
|
@@ -10469,6 +10873,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10469
10873
|
if (!this.canvas._isMainEvent(options.e)) {
|
|
10470
10874
|
return true;
|
|
10471
10875
|
}
|
|
10876
|
+
this.drawStraightLine = false;
|
|
10472
10877
|
this.oldEnd = undefined;
|
|
10473
10878
|
this._finalizeAndAddPath();
|
|
10474
10879
|
return false;
|
|
@@ -10495,6 +10900,10 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10495
10900
|
if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) {
|
|
10496
10901
|
return false;
|
|
10497
10902
|
}
|
|
10903
|
+
if (this.drawStraightLine && this._points.length > 1) {
|
|
10904
|
+
this._hasStraightLine = true;
|
|
10905
|
+
this._points.pop();
|
|
10906
|
+
}
|
|
10498
10907
|
this._points.push(point);
|
|
10499
10908
|
return true;
|
|
10500
10909
|
},
|
|
@@ -10505,8 +10914,9 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10505
10914
|
*/
|
|
10506
10915
|
_reset: function() {
|
|
10507
10916
|
this._points = [];
|
|
10508
|
-
this._setBrushStyles();
|
|
10917
|
+
this._setBrushStyles(this.canvas.contextTop);
|
|
10509
10918
|
this._setShadow();
|
|
10919
|
+
this._hasStraightLine = false;
|
|
10510
10920
|
},
|
|
10511
10921
|
|
|
10512
10922
|
/**
|
|
@@ -10521,12 +10931,13 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10521
10931
|
/**
|
|
10522
10932
|
* Draw a smooth path on the topCanvas using quadraticCurveTo
|
|
10523
10933
|
* @private
|
|
10934
|
+
* @param {CanvasRenderingContext2D} [ctx]
|
|
10524
10935
|
*/
|
|
10525
|
-
_render: function() {
|
|
10526
|
-
var
|
|
10936
|
+
_render: function(ctx) {
|
|
10937
|
+
var i, len,
|
|
10527
10938
|
p1 = this._points[0],
|
|
10528
10939
|
p2 = this._points[1];
|
|
10529
|
-
|
|
10940
|
+
ctx = ctx || this.canvas.contextTop;
|
|
10530
10941
|
this._saveAndTransform(ctx);
|
|
10531
10942
|
ctx.beginPath();
|
|
10532
10943
|
//if we only have 2 points in the path and they are the same
|
|
@@ -10560,43 +10971,26 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10560
10971
|
/**
|
|
10561
10972
|
* Converts points to SVG path
|
|
10562
10973
|
* @param {Array} points Array of points
|
|
10563
|
-
* @return {
|
|
10974
|
+
* @return {(string|number)[][]} SVG path commands
|
|
10564
10975
|
*/
|
|
10565
|
-
convertPointsToSVGPath: function(points) {
|
|
10566
|
-
var
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
len = points.length, multSignX = 1, multSignY = 0, manyPoints = len > 2;
|
|
10976
|
+
convertPointsToSVGPath: function (points) {
|
|
10977
|
+
var correction = this.width / 1000;
|
|
10978
|
+
return fabric.util.getSmoothPathFromPoints(points, correction);
|
|
10979
|
+
},
|
|
10570
10980
|
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
// p1 is our bezier control point
|
|
10580
|
-
// midpoint is our endpoint
|
|
10581
|
-
// start point is p(i-1) value.
|
|
10582
|
-
path.push('Q ', p1.x, ' ', p1.y, ' ', midPoint.x, ' ', midPoint.y, ' ');
|
|
10583
|
-
}
|
|
10584
|
-
p1 = points[i];
|
|
10585
|
-
if ((i + 1) < points.length) {
|
|
10586
|
-
p2 = points[i + 1];
|
|
10587
|
-
}
|
|
10588
|
-
}
|
|
10589
|
-
if (manyPoints) {
|
|
10590
|
-
multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;
|
|
10591
|
-
multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;
|
|
10592
|
-
}
|
|
10593
|
-
path.push('L ', p1.x + multSignX * width, ' ', p1.y + multSignY * width);
|
|
10594
|
-
return path;
|
|
10981
|
+
/**
|
|
10982
|
+
* @private
|
|
10983
|
+
* @param {(string|number)[][]} pathData SVG path commands
|
|
10984
|
+
* @returns {boolean}
|
|
10985
|
+
*/
|
|
10986
|
+
_isEmptySVGPath: function (pathData) {
|
|
10987
|
+
var pathString = fabric.util.joinPath(pathData);
|
|
10988
|
+
return pathString === 'M 0 0 Q 0 0 0 0 L 0 0';
|
|
10595
10989
|
},
|
|
10596
10990
|
|
|
10597
10991
|
/**
|
|
10598
10992
|
* Creates fabric.Path object to add on canvas
|
|
10599
|
-
* @param {
|
|
10993
|
+
* @param {(string|number)[][]} pathData Path data
|
|
10600
10994
|
* @return {fabric.Path} Path to add on canvas
|
|
10601
10995
|
*/
|
|
10602
10996
|
createPath: function(pathData) {
|
|
@@ -10653,8 +11047,8 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|
|
10653
11047
|
if (this.decimate) {
|
|
10654
11048
|
this._points = this.decimatePoints(this._points, this.decimate);
|
|
10655
11049
|
}
|
|
10656
|
-
var pathData = this.convertPointsToSVGPath(this._points)
|
|
10657
|
-
if (pathData
|
|
11050
|
+
var pathData = this.convertPointsToSVGPath(this._points);
|
|
11051
|
+
if (this._isEmptySVGPath(pathData)) {
|
|
10658
11052
|
// do not create 0 width/height paths, as they are
|
|
10659
11053
|
// rendered inconsistently across browsers
|
|
10660
11054
|
// Firefox 4, for example, renders a dot,
|
|
@@ -11077,17 +11471,19 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11077
11471
|
|
|
11078
11472
|
/**
|
|
11079
11473
|
* Creates "pattern" instance property
|
|
11474
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
11080
11475
|
*/
|
|
11081
|
-
getPattern: function() {
|
|
11082
|
-
return
|
|
11476
|
+
getPattern: function(ctx) {
|
|
11477
|
+
return ctx.createPattern(this.source || this.getPatternSrc(), 'repeat');
|
|
11083
11478
|
},
|
|
11084
11479
|
|
|
11085
11480
|
/**
|
|
11086
11481
|
* Sets brush styles
|
|
11482
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
11087
11483
|
*/
|
|
11088
|
-
_setBrushStyles: function() {
|
|
11089
|
-
this.callSuper('_setBrushStyles');
|
|
11090
|
-
|
|
11484
|
+
_setBrushStyles: function(ctx) {
|
|
11485
|
+
this.callSuper('_setBrushStyles', ctx);
|
|
11486
|
+
ctx.strokeStyle = this.getPattern(ctx);
|
|
11091
11487
|
},
|
|
11092
11488
|
|
|
11093
11489
|
/**
|
|
@@ -11111,10 +11507,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11111
11507
|
|
|
11112
11508
|
var getPointer = fabric.util.getPointer,
|
|
11113
11509
|
degreesToRadians = fabric.util.degreesToRadians,
|
|
11114
|
-
|
|
11115
|
-
supportLineDash = fabric.StaticCanvas.supports('setLineDash'),
|
|
11116
|
-
isTouchEvent = fabric.util.isTouchEvent,
|
|
11117
|
-
STROKE_OFFSET = 0.5;
|
|
11510
|
+
isTouchEvent = fabric.util.isTouchEvent;
|
|
11118
11511
|
|
|
11119
11512
|
/**
|
|
11120
11513
|
* Canvas class
|
|
@@ -11149,15 +11542,11 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11149
11542
|
* @fires dragover
|
|
11150
11543
|
* @fires dragenter
|
|
11151
11544
|
* @fires dragleave
|
|
11545
|
+
* @fires drop:before before drop event. same native event. This is added to handle edge cases
|
|
11152
11546
|
* @fires drop
|
|
11153
11547
|
* @fires after:render at the end of the render process, receives the context in the callback
|
|
11154
11548
|
* @fires before:render at start the render process, receives the context in the callback
|
|
11155
11549
|
*
|
|
11156
|
-
* the following events are deprecated:
|
|
11157
|
-
* @fires object:rotated at the end of a rotation transform
|
|
11158
|
-
* @fires object:scaled at the end of a scale transform
|
|
11159
|
-
* @fires object:moved at the end of translation transform
|
|
11160
|
-
* @fires object:skewed at the end of a skew transform
|
|
11161
11550
|
*/
|
|
11162
11551
|
fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {
|
|
11163
11552
|
|
|
@@ -11342,13 +11731,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11342
11731
|
*/
|
|
11343
11732
|
freeDrawingCursor: 'crosshair',
|
|
11344
11733
|
|
|
11345
|
-
/**
|
|
11346
|
-
* Cursor value used for rotation point
|
|
11347
|
-
* @type String
|
|
11348
|
-
* @default
|
|
11349
|
-
*/
|
|
11350
|
-
rotationCursor: 'crosshair',
|
|
11351
|
-
|
|
11352
11734
|
/**
|
|
11353
11735
|
* Cursor value used for disabled elements ( corners with disabled action )
|
|
11354
11736
|
* @type String
|
|
@@ -11454,6 +11836,13 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11454
11836
|
*/
|
|
11455
11837
|
targets: [],
|
|
11456
11838
|
|
|
11839
|
+
/**
|
|
11840
|
+
* When the option is enabled, PointerEvent is used instead of MouseEvent.
|
|
11841
|
+
* @type Boolean
|
|
11842
|
+
* @default
|
|
11843
|
+
*/
|
|
11844
|
+
enablePointerEvents: false,
|
|
11845
|
+
|
|
11457
11846
|
/**
|
|
11458
11847
|
* Keep track of the hovered target
|
|
11459
11848
|
* @type fabric.Object
|
|
@@ -11529,6 +11918,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11529
11918
|
}
|
|
11530
11919
|
if (this.hasLostContext) {
|
|
11531
11920
|
this.renderTopLayer(this.contextTop);
|
|
11921
|
+
this.hasLostContext = false;
|
|
11532
11922
|
}
|
|
11533
11923
|
var canvasToDrawOn = this.contextContainer;
|
|
11534
11924
|
this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());
|
|
@@ -11798,21 +12188,20 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11798
12188
|
* @param {CanvasRenderingContext2D} ctx to draw the selection on
|
|
11799
12189
|
*/
|
|
11800
12190
|
_drawSelection: function (ctx) {
|
|
11801
|
-
var
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
|
|
12191
|
+
var selector = this._groupSelector,
|
|
12192
|
+
viewportStart = new fabric.Point(selector.ex, selector.ey),
|
|
12193
|
+
start = fabric.util.transformPoint(viewportStart, this.viewportTransform),
|
|
12194
|
+
viewportExtent = new fabric.Point(selector.ex + selector.left, selector.ey + selector.top),
|
|
12195
|
+
extent = fabric.util.transformPoint(viewportExtent, this.viewportTransform),
|
|
12196
|
+
minX = Math.min(start.x, extent.x),
|
|
12197
|
+
minY = Math.min(start.y, extent.y),
|
|
12198
|
+
maxX = Math.max(start.x, extent.x),
|
|
12199
|
+
maxY = Math.max(start.y, extent.y),
|
|
12200
|
+
strokeOffset = this.selectionLineWidth / 2;
|
|
11806
12201
|
|
|
11807
12202
|
if (this.selectionColor) {
|
|
11808
12203
|
ctx.fillStyle = this.selectionColor;
|
|
11809
|
-
|
|
11810
|
-
ctx.fillRect(
|
|
11811
|
-
groupSelector.ex - ((left > 0) ? 0 : -left),
|
|
11812
|
-
groupSelector.ey - ((top > 0) ? 0 : -top),
|
|
11813
|
-
aleft,
|
|
11814
|
-
atop
|
|
11815
|
-
);
|
|
12204
|
+
ctx.fillRect(minX, minY, maxX - minX, maxY - minY);
|
|
11816
12205
|
}
|
|
11817
12206
|
|
|
11818
12207
|
if (!this.selectionLineWidth || !this.selectionBorderColor) {
|
|
@@ -11821,31 +12210,13 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
11821
12210
|
ctx.lineWidth = this.selectionLineWidth;
|
|
11822
12211
|
ctx.strokeStyle = this.selectionBorderColor;
|
|
11823
12212
|
|
|
12213
|
+
minX += strokeOffset;
|
|
12214
|
+
minY += strokeOffset;
|
|
12215
|
+
maxX -= strokeOffset;
|
|
12216
|
+
maxY -= strokeOffset;
|
|
11824
12217
|
// selection border
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),
|
|
11828
|
-
py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop);
|
|
11829
|
-
|
|
11830
|
-
ctx.beginPath();
|
|
11831
|
-
|
|
11832
|
-
fabric.util.drawDashedLine(ctx, px, py, px + aleft, py, this.selectionDashArray);
|
|
11833
|
-
fabric.util.drawDashedLine(ctx, px, py + atop - 1, px + aleft, py + atop - 1, this.selectionDashArray);
|
|
11834
|
-
fabric.util.drawDashedLine(ctx, px, py, px, py + atop, this.selectionDashArray);
|
|
11835
|
-
fabric.util.drawDashedLine(ctx, px + aleft - 1, py, px + aleft - 1, py + atop, this.selectionDashArray);
|
|
11836
|
-
|
|
11837
|
-
ctx.closePath();
|
|
11838
|
-
ctx.stroke();
|
|
11839
|
-
}
|
|
11840
|
-
else {
|
|
11841
|
-
fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);
|
|
11842
|
-
ctx.strokeRect(
|
|
11843
|
-
groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),
|
|
11844
|
-
groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop),
|
|
11845
|
-
aleft,
|
|
11846
|
-
atop
|
|
11847
|
-
);
|
|
11848
|
-
}
|
|
12218
|
+
fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);
|
|
12219
|
+
ctx.strokeRect(minX, minY, maxX - minX, maxY - minY);
|
|
11849
12220
|
},
|
|
11850
12221
|
|
|
11851
12222
|
/**
|
|
@@ -12217,17 +12588,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
12217
12588
|
e: e,
|
|
12218
12589
|
selected: added,
|
|
12219
12590
|
deselected: removed,
|
|
12220
|
-
// added for backward compatibility
|
|
12221
|
-
// deprecated
|
|
12222
|
-
updated: added[0] || removed[0],
|
|
12223
|
-
target: this._activeObject,
|
|
12224
12591
|
});
|
|
12225
12592
|
}
|
|
12226
12593
|
else if (objects.length > 0) {
|
|
12227
12594
|
this.fire('selection:created', {
|
|
12228
12595
|
e: e,
|
|
12229
12596
|
selected: added,
|
|
12230
|
-
target: this._activeObject,
|
|
12231
12597
|
});
|
|
12232
12598
|
}
|
|
12233
12599
|
else if (oldObjects.length > 0) {
|
|
@@ -12551,7 +12917,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
12551
12917
|
this._onDragOver = this._onDragOver.bind(this);
|
|
12552
12918
|
this._onDragEnter = this._simpleEventHandler.bind(this, 'dragenter');
|
|
12553
12919
|
this._onDragLeave = this._simpleEventHandler.bind(this, 'dragleave');
|
|
12554
|
-
this._onDrop = this.
|
|
12920
|
+
this._onDrop = this._onDrop.bind(this);
|
|
12555
12921
|
this.eventsBound = true;
|
|
12556
12922
|
},
|
|
12557
12923
|
|
|
@@ -12663,6 +13029,18 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
12663
13029
|
this._fireEnterLeaveEvents(target, e);
|
|
12664
13030
|
},
|
|
12665
13031
|
|
|
13032
|
+
/**
|
|
13033
|
+
* `drop:before` is a an event that allow you to schedule logic
|
|
13034
|
+
* before the `drop` event. Prefer `drop` event always, but if you need
|
|
13035
|
+
* to run some drop-disabling logic on an event, since there is no way
|
|
13036
|
+
* to handle event handlers ordering, use `drop:before`
|
|
13037
|
+
* @param {Event} e
|
|
13038
|
+
*/
|
|
13039
|
+
_onDrop: function (e) {
|
|
13040
|
+
this._simpleEventHandler('drop:before', e);
|
|
13041
|
+
return this._simpleEventHandler('drop', e);
|
|
13042
|
+
},
|
|
13043
|
+
|
|
12666
13044
|
/**
|
|
12667
13045
|
* @private
|
|
12668
13046
|
* @param {Event} e Event object fired on mousedown
|
|
@@ -12895,25 +13273,34 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
12895
13273
|
);
|
|
12896
13274
|
}
|
|
12897
13275
|
}
|
|
13276
|
+
var corner, pointer;
|
|
12898
13277
|
if (target) {
|
|
12899
|
-
|
|
12900
|
-
this.
|
|
13278
|
+
corner = target._findTargetCorner(
|
|
13279
|
+
this.getPointer(e, true),
|
|
13280
|
+
fabric.util.isTouchEvent(e)
|
|
13281
|
+
);
|
|
13282
|
+
if (target.selectable && target !== this._activeObject && target.activeOn === 'up') {
|
|
13283
|
+
this.setActiveObject(target, e);
|
|
12901
13284
|
shouldRender = true;
|
|
12902
13285
|
}
|
|
12903
13286
|
else {
|
|
12904
|
-
var corner = target._findTargetCorner(
|
|
12905
|
-
this.getPointer(e, true),
|
|
12906
|
-
fabric.util.isTouchEvent(e)
|
|
12907
|
-
);
|
|
12908
13287
|
var control = target.controls[corner],
|
|
12909
13288
|
mouseUpHandler = control && control.getMouseUpHandler(e, target, control);
|
|
12910
13289
|
if (mouseUpHandler) {
|
|
12911
|
-
|
|
13290
|
+
pointer = this.getPointer(e);
|
|
12912
13291
|
mouseUpHandler(e, transform, pointer.x, pointer.y);
|
|
12913
13292
|
}
|
|
12914
13293
|
}
|
|
12915
13294
|
target.isMoving = false;
|
|
12916
13295
|
}
|
|
13296
|
+
// if we are ending up a transform on a different control or a new object
|
|
13297
|
+
// fire the original mouse up from the corner that started the transform
|
|
13298
|
+
if (transform && (transform.target !== target || transform.corner !== corner)) {
|
|
13299
|
+
var originalControl = transform.target && transform.target.controls[transform.corner],
|
|
13300
|
+
originalMouseUpHandler = originalControl && originalControl.getMouseUpHandler(e, target, control);
|
|
13301
|
+
pointer = pointer || this.getPointer(e);
|
|
13302
|
+
originalMouseUpHandler && originalMouseUpHandler(e, transform, pointer.x, pointer.y);
|
|
13303
|
+
}
|
|
12917
13304
|
this._setCursorFromEvent(e, target);
|
|
12918
13305
|
this._handleEvent(e, 'up', LEFT_CLICK, isClick);
|
|
12919
13306
|
this._groupSelector = null;
|
|
@@ -12995,7 +13382,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
12995
13382
|
|
|
12996
13383
|
var transform = this._currentTransform,
|
|
12997
13384
|
target = transform.target,
|
|
12998
|
-
eventName,
|
|
12999
13385
|
options = {
|
|
13000
13386
|
e: e,
|
|
13001
13387
|
target: target,
|
|
@@ -13010,59 +13396,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
13010
13396
|
target.setCoords();
|
|
13011
13397
|
|
|
13012
13398
|
if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) {
|
|
13013
|
-
if (transform.actionPerformed) {
|
|
13014
|
-
// this is not friendly to the new control api.
|
|
13015
|
-
// is deprecated.
|
|
13016
|
-
eventName = this._addEventOptions(options, transform);
|
|
13017
|
-
this._fire(eventName, options);
|
|
13018
|
-
}
|
|
13019
13399
|
this._fire('modified', options);
|
|
13020
13400
|
}
|
|
13021
13401
|
},
|
|
13022
13402
|
|
|
13023
|
-
/**
|
|
13024
|
-
* Mutate option object in order to add by property and give back the event name.
|
|
13025
|
-
* @private
|
|
13026
|
-
* @deprecated since 4.2.0
|
|
13027
|
-
* @param {Object} options to mutate
|
|
13028
|
-
* @param {Object} transform to inspect action from
|
|
13029
|
-
*/
|
|
13030
|
-
_addEventOptions: function(options, transform) {
|
|
13031
|
-
// we can probably add more details at low cost
|
|
13032
|
-
// scale change, rotation changes, translation changes
|
|
13033
|
-
var eventName, by;
|
|
13034
|
-
switch (transform.action) {
|
|
13035
|
-
case 'scaleX':
|
|
13036
|
-
eventName = 'scaled';
|
|
13037
|
-
by = 'x';
|
|
13038
|
-
break;
|
|
13039
|
-
case 'scaleY':
|
|
13040
|
-
eventName = 'scaled';
|
|
13041
|
-
by = 'y';
|
|
13042
|
-
break;
|
|
13043
|
-
case 'skewX':
|
|
13044
|
-
eventName = 'skewed';
|
|
13045
|
-
by = 'x';
|
|
13046
|
-
break;
|
|
13047
|
-
case 'skewY':
|
|
13048
|
-
eventName = 'skewed';
|
|
13049
|
-
by = 'y';
|
|
13050
|
-
break;
|
|
13051
|
-
case 'scale':
|
|
13052
|
-
eventName = 'scaled';
|
|
13053
|
-
by = 'equally';
|
|
13054
|
-
break;
|
|
13055
|
-
case 'rotate':
|
|
13056
|
-
eventName = 'rotated';
|
|
13057
|
-
break;
|
|
13058
|
-
case 'drag':
|
|
13059
|
-
eventName = 'moved';
|
|
13060
|
-
break;
|
|
13061
|
-
}
|
|
13062
|
-
options.by = by;
|
|
13063
|
-
return eventName;
|
|
13064
|
-
},
|
|
13065
|
-
|
|
13066
13403
|
/**
|
|
13067
13404
|
* @private
|
|
13068
13405
|
* @param {Event} e Event object fired on mousedown
|
|
@@ -13157,8 +13494,8 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
13157
13494
|
if (this.selection && (!target ||
|
|
13158
13495
|
(!target.selectable && !target.isEditing && target !== this._activeObject))) {
|
|
13159
13496
|
this._groupSelector = {
|
|
13160
|
-
ex:
|
|
13161
|
-
ey:
|
|
13497
|
+
ex: this._absolutePointer.x,
|
|
13498
|
+
ey: this._absolutePointer.y,
|
|
13162
13499
|
top: 0,
|
|
13163
13500
|
left: 0
|
|
13164
13501
|
};
|
|
@@ -13251,7 +13588,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
13251
13588
|
|
|
13252
13589
|
// We initially clicked in an empty area, so we draw a box for multiple selection
|
|
13253
13590
|
if (groupSelector) {
|
|
13254
|
-
pointer = this.
|
|
13591
|
+
pointer = this._absolutePointer;
|
|
13255
13592
|
|
|
13256
13593
|
groupSelector.left = pointer.x - groupSelector.ex;
|
|
13257
13594
|
groupSelector.top = pointer.y - groupSelector.ey;
|
|
@@ -13597,10 +13934,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|
|
13597
13934
|
continue;
|
|
13598
13935
|
}
|
|
13599
13936
|
|
|
13600
|
-
if ((allowIntersect && currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2)) ||
|
|
13601
|
-
currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2) ||
|
|
13602
|
-
(allowIntersect && currentObject.containsPoint(selectionX1Y1)) ||
|
|
13603
|
-
(allowIntersect && currentObject.containsPoint(selectionX2Y2))
|
|
13937
|
+
if ((allowIntersect && currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2, true)) ||
|
|
13938
|
+
currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2, true) ||
|
|
13939
|
+
(allowIntersect && currentObject.containsPoint(selectionX1Y1, null, true)) ||
|
|
13940
|
+
(allowIntersect && currentObject.containsPoint(selectionX2Y2, null, true))
|
|
13604
13941
|
) {
|
|
13605
13942
|
group.push(currentObject);
|
|
13606
13943
|
// only add one object if it's a click
|
|
@@ -13974,7 +14311,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
13974
14311
|
toFixed = fabric.util.toFixed,
|
|
13975
14312
|
capitalize = fabric.util.string.capitalize,
|
|
13976
14313
|
degreesToRadians = fabric.util.degreesToRadians,
|
|
13977
|
-
supportsLineDash = fabric.StaticCanvas.supports('setLineDash'),
|
|
13978
14314
|
objectCaching = !fabric.isLikelyNode,
|
|
13979
14315
|
ALIASING_LIMIT = 2;
|
|
13980
14316
|
|
|
@@ -14503,6 +14839,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14503
14839
|
/**
|
|
14504
14840
|
* When `false`, the stoke width will scale with the object.
|
|
14505
14841
|
* When `true`, the stroke will always match the exact pixel size entered for stroke width.
|
|
14842
|
+
* this Property does not work on Text classes or drawing call that uses strokeText,fillText methods
|
|
14506
14843
|
* default to false
|
|
14507
14844
|
* @since 2.6.0
|
|
14508
14845
|
* @type Boolean
|
|
@@ -14745,6 +15082,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14745
15082
|
additionalHeight = height * 0.1;
|
|
14746
15083
|
}
|
|
14747
15084
|
}
|
|
15085
|
+
if (this instanceof fabric.Text && this.path) {
|
|
15086
|
+
shouldRedraw = true;
|
|
15087
|
+
shouldResizeCanvas = true;
|
|
15088
|
+
additionalWidth += this.getHeightOfLine(0) * this.zoomX;
|
|
15089
|
+
additionalHeight += this.getHeightOfLine(0) * this.zoomY;
|
|
15090
|
+
}
|
|
14748
15091
|
if (shouldRedraw) {
|
|
14749
15092
|
if (shouldResizeCanvas) {
|
|
14750
15093
|
canvas.width = Math.ceil(width + additionalWidth);
|
|
@@ -14834,7 +15177,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14834
15177
|
skewY: toFixed(this.skewY, NUM_FRACTION_DIGITS),
|
|
14835
15178
|
};
|
|
14836
15179
|
|
|
14837
|
-
if (this.clipPath) {
|
|
15180
|
+
if (this.clipPath && !this.clipPath.excludeFromExport) {
|
|
14838
15181
|
object.clipPath = this.clipPath.toObject(propertiesToInclude);
|
|
14839
15182
|
object.clipPath.inverted = this.clipPath.inverted;
|
|
14840
15183
|
object.clipPath.absolutePositioned = this.clipPath.absolutePositioned;
|
|
@@ -14897,6 +15240,17 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
14897
15240
|
* @return {Object} object with scaleX and scaleY properties
|
|
14898
15241
|
*/
|
|
14899
15242
|
getObjectScaling: function() {
|
|
15243
|
+
// if the object is a top level one, on the canvas, we go for simple aritmetic
|
|
15244
|
+
// otherwise the complex method with angles will return approximations and decimals
|
|
15245
|
+
// and will likely kill the cache when not needed
|
|
15246
|
+
// https://github.com/fabricjs/fabric.js/issues/7157
|
|
15247
|
+
if (!this.group) {
|
|
15248
|
+
return {
|
|
15249
|
+
scaleX: this.scaleX,
|
|
15250
|
+
scaleY: this.scaleY,
|
|
15251
|
+
};
|
|
15252
|
+
}
|
|
15253
|
+
// if we are inside a group total zoom calculation is complex, we defer to generic matrices
|
|
14900
15254
|
var options = fabric.util.qrDecompose(this.calcTransformMatrix());
|
|
14901
15255
|
return { scaleX: Math.abs(options.scaleX), scaleY: Math.abs(options.scaleY) };
|
|
14902
15256
|
},
|
|
@@ -15136,26 +15490,26 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15136
15490
|
/**
|
|
15137
15491
|
* Execute the drawing operation for an object clipPath
|
|
15138
15492
|
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
15493
|
+
* @param {fabric.Object} clipPath
|
|
15139
15494
|
*/
|
|
15140
|
-
drawClipPathOnCache: function(ctx) {
|
|
15141
|
-
var path = this.clipPath;
|
|
15495
|
+
drawClipPathOnCache: function(ctx, clipPath) {
|
|
15142
15496
|
ctx.save();
|
|
15143
15497
|
// DEBUG: uncomment this line, comment the following
|
|
15144
15498
|
// ctx.globalAlpha = 0.4
|
|
15145
|
-
if (
|
|
15499
|
+
if (clipPath.inverted) {
|
|
15146
15500
|
ctx.globalCompositeOperation = 'destination-out';
|
|
15147
15501
|
}
|
|
15148
15502
|
else {
|
|
15149
15503
|
ctx.globalCompositeOperation = 'destination-in';
|
|
15150
15504
|
}
|
|
15151
15505
|
//ctx.scale(1 / 2, 1 / 2);
|
|
15152
|
-
if (
|
|
15506
|
+
if (clipPath.absolutePositioned) {
|
|
15153
15507
|
var m = fabric.util.invertTransform(this.calcTransformMatrix());
|
|
15154
15508
|
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
|
15155
15509
|
}
|
|
15156
|
-
|
|
15157
|
-
ctx.scale(1 /
|
|
15158
|
-
ctx.drawImage(
|
|
15510
|
+
clipPath.transform(ctx);
|
|
15511
|
+
ctx.scale(1 / clipPath.zoomX, 1 / clipPath.zoomY);
|
|
15512
|
+
ctx.drawImage(clipPath._cacheCanvas, -clipPath.cacheTranslationX, -clipPath.cacheTranslationY);
|
|
15159
15513
|
ctx.restore();
|
|
15160
15514
|
},
|
|
15161
15515
|
|
|
@@ -15174,22 +15528,26 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15174
15528
|
this._renderBackground(ctx);
|
|
15175
15529
|
}
|
|
15176
15530
|
this._render(ctx);
|
|
15177
|
-
this._drawClipPath(ctx);
|
|
15531
|
+
this._drawClipPath(ctx, this.clipPath);
|
|
15178
15532
|
this.fill = originalFill;
|
|
15179
15533
|
this.stroke = originalStroke;
|
|
15180
15534
|
},
|
|
15181
15535
|
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15536
|
+
/**
|
|
15537
|
+
* Prepare clipPath state and cache and draw it on instance's cache
|
|
15538
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
15539
|
+
* @param {fabric.Object} clipPath
|
|
15540
|
+
*/
|
|
15541
|
+
_drawClipPath: function (ctx, clipPath) {
|
|
15542
|
+
if (!clipPath) { return; }
|
|
15185
15543
|
// needed to setup a couple of variables
|
|
15186
15544
|
// path canvas gets overridden with this one.
|
|
15187
15545
|
// TODO find a better solution?
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
this.drawClipPathOnCache(ctx);
|
|
15546
|
+
clipPath.canvas = this.canvas;
|
|
15547
|
+
clipPath.shouldCache();
|
|
15548
|
+
clipPath._transformDone = true;
|
|
15549
|
+
clipPath.renderCache({ forClipping: true });
|
|
15550
|
+
this.drawClipPathOnCache(ctx, clipPath);
|
|
15193
15551
|
},
|
|
15194
15552
|
|
|
15195
15553
|
/**
|
|
@@ -15319,9 +15677,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15319
15677
|
* Sets line dash
|
|
15320
15678
|
* @param {CanvasRenderingContext2D} ctx Context to set the dash line on
|
|
15321
15679
|
* @param {Array} dashArray array representing dashes
|
|
15322
|
-
* @param {Function} alternative function to call if browser does not support lineDash
|
|
15323
15680
|
*/
|
|
15324
|
-
_setLineDash: function(ctx, dashArray
|
|
15681
|
+
_setLineDash: function(ctx, dashArray) {
|
|
15325
15682
|
if (!dashArray || dashArray.length === 0) {
|
|
15326
15683
|
return;
|
|
15327
15684
|
}
|
|
@@ -15329,16 +15686,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15329
15686
|
if (1 & dashArray.length) {
|
|
15330
15687
|
dashArray.push.apply(dashArray, dashArray);
|
|
15331
15688
|
}
|
|
15332
|
-
|
|
15333
|
-
ctx.setLineDash(dashArray);
|
|
15334
|
-
}
|
|
15335
|
-
else {
|
|
15336
|
-
alternative && alternative(ctx);
|
|
15337
|
-
}
|
|
15689
|
+
ctx.setLineDash(dashArray);
|
|
15338
15690
|
},
|
|
15339
15691
|
|
|
15340
15692
|
/**
|
|
15341
15693
|
* Renders controls and borders for the object
|
|
15694
|
+
* the context here is not transformed
|
|
15342
15695
|
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
15343
15696
|
* @param {Object} [styleOverride] properties to override the object style
|
|
15344
15697
|
*/
|
|
@@ -15357,12 +15710,14 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15357
15710
|
if (!this.group) {
|
|
15358
15711
|
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
|
|
15359
15712
|
}
|
|
15360
|
-
if (
|
|
15361
|
-
|
|
15713
|
+
if (this.flipX) {
|
|
15714
|
+
options.angle -= 180;
|
|
15715
|
+
}
|
|
15716
|
+
ctx.rotate(degreesToRadians(this.group ? options.angle : this.angle));
|
|
15717
|
+
if (styleOverride.forActiveSelection || this.group) {
|
|
15362
15718
|
drawBorders && this.drawBordersInGroup(ctx, options, styleOverride);
|
|
15363
15719
|
}
|
|
15364
15720
|
else {
|
|
15365
|
-
ctx.rotate(degreesToRadians(this.angle));
|
|
15366
15721
|
drawBorders && this.drawBorders(ctx, styleOverride);
|
|
15367
15722
|
}
|
|
15368
15723
|
drawControls && this.drawControls(ctx, styleOverride);
|
|
@@ -15505,7 +15860,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15505
15860
|
else if (this.strokeUniform) {
|
|
15506
15861
|
ctx.scale(1 / this.scaleX, 1 / this.scaleY);
|
|
15507
15862
|
}
|
|
15508
|
-
this._setLineDash(ctx, this.strokeDashArray
|
|
15863
|
+
this._setLineDash(ctx, this.strokeDashArray);
|
|
15509
15864
|
this._setStrokeStyles(ctx, this);
|
|
15510
15865
|
ctx.stroke();
|
|
15511
15866
|
ctx.restore();
|
|
@@ -15894,6 +16249,15 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15894
16249
|
if (this.globalCompositeOperation) {
|
|
15895
16250
|
ctx.globalCompositeOperation = this.globalCompositeOperation;
|
|
15896
16251
|
}
|
|
16252
|
+
},
|
|
16253
|
+
|
|
16254
|
+
/**
|
|
16255
|
+
* cancel instance's running animations
|
|
16256
|
+
*/
|
|
16257
|
+
dispose: function () {
|
|
16258
|
+
if (fabric.runningAnimations) {
|
|
16259
|
+
fabric.runningAnimations.cancelByTarget(this);
|
|
16260
|
+
}
|
|
15897
16261
|
}
|
|
15898
16262
|
});
|
|
15899
16263
|
|
|
@@ -15911,6 +16275,15 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15911
16275
|
*/
|
|
15912
16276
|
fabric.Object.NUM_FRACTION_DIGITS = 2;
|
|
15913
16277
|
|
|
16278
|
+
/**
|
|
16279
|
+
* Defines which properties should be enlivened from the object passed to {@link fabric.Object._fromObject}
|
|
16280
|
+
* @static
|
|
16281
|
+
* @memberOf fabric.Object
|
|
16282
|
+
* @constant
|
|
16283
|
+
* @type string[]
|
|
16284
|
+
*/
|
|
16285
|
+
fabric.Object.ENLIVEN_PROPS = ['clipPath'];
|
|
16286
|
+
|
|
15914
16287
|
fabric.Object._fromObject = function(className, object, callback, extraParam) {
|
|
15915
16288
|
var klass = fabric[className];
|
|
15916
16289
|
object = clone(object, true);
|
|
@@ -15921,8 +16294,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
15921
16294
|
if (typeof patterns[1] !== 'undefined') {
|
|
15922
16295
|
object.stroke = patterns[1];
|
|
15923
16296
|
}
|
|
15924
|
-
fabric.util.
|
|
15925
|
-
object.clipPath = enlivedProps[0];
|
|
16297
|
+
fabric.util.enlivenObjectEnlivables(object, object, function () {
|
|
15926
16298
|
var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);
|
|
15927
16299
|
callback && callback(instance);
|
|
15928
16300
|
});
|
|
@@ -16243,7 +16615,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
16243
16615
|
/**
|
|
16244
16616
|
* Describe object's corner position in canvas element coordinates.
|
|
16245
16617
|
* includes padding. Used of object detection.
|
|
16246
|
-
* set and refreshed with setCoords
|
|
16618
|
+
* set and refreshed with setCoords.
|
|
16247
16619
|
* @memberOf fabric.Object.prototype
|
|
16248
16620
|
*/
|
|
16249
16621
|
lineCoords: null,
|
|
@@ -16627,21 +16999,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
16627
16999
|
return this.scale(value / this.height / boundingRectFactor);
|
|
16628
17000
|
},
|
|
16629
17001
|
|
|
16630
|
-
/**
|
|
16631
|
-
* Calculates and returns the .coords of an object.
|
|
16632
|
-
* unused by the library, only for the end dev.
|
|
16633
|
-
* @return {Object} Object with tl, tr, br, bl ....
|
|
16634
|
-
* @chainable
|
|
16635
|
-
* @deprecated
|
|
16636
|
-
*/
|
|
16637
|
-
calcCoords: function(absolute) {
|
|
16638
|
-
// this is a compatibility function to avoid removing calcCoords now.
|
|
16639
|
-
if (absolute) {
|
|
16640
|
-
return this.calcACoords();
|
|
16641
|
-
}
|
|
16642
|
-
return this.calcOCoords();
|
|
16643
|
-
},
|
|
16644
|
-
|
|
16645
17002
|
calcLineCoords: function() {
|
|
16646
17003
|
var vpt = this.getViewportTransform(),
|
|
16647
17004
|
padding = this.padding, angle = degreesToRadians(this.angle),
|
|
@@ -16716,7 +17073,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
16716
17073
|
* oCoords are used to find the corners
|
|
16717
17074
|
* aCoords are used to quickly find an object on the canvas
|
|
16718
17075
|
* lineCoords are used to quickly find object during pointer events.
|
|
16719
|
-
* See {@link https://github.com/
|
|
17076
|
+
* See {@link https://github.com/fabricjs/fabric.js/wiki/When-to-call-setCoords} and {@link http://fabricjs.com/fabric-gotchas}
|
|
17077
|
+
*
|
|
16720
17078
|
* @param {Boolean} [skipCorners] skip calculation of oCoords.
|
|
16721
17079
|
* @return {fabric.Object} thisArg
|
|
16722
17080
|
* @chainable
|
|
@@ -16813,23 +17171,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
16813
17171
|
return cache.value;
|
|
16814
17172
|
},
|
|
16815
17173
|
|
|
16816
|
-
/*
|
|
16817
|
-
* Calculate object dimensions from its properties
|
|
16818
|
-
* @private
|
|
16819
|
-
* @deprecated since 3.4.0, please use fabric.util._calcDimensionsTransformMatrix
|
|
16820
|
-
* not including or including flipX, flipY to emulate the flipping boolean
|
|
16821
|
-
* @return {Object} .x width dimension
|
|
16822
|
-
* @return {Object} .y height dimension
|
|
16823
|
-
*/
|
|
16824
|
-
_calcDimensionsTransformMatrix: function(skewX, skewY, flipping) {
|
|
16825
|
-
return util.calcDimensionsMatrix({
|
|
16826
|
-
skewX: skewX,
|
|
16827
|
-
skewY: skewY,
|
|
16828
|
-
scaleX: this.scaleX * (flipping && this.flipX ? -1 : 1),
|
|
16829
|
-
scaleY: this.scaleY * (flipping && this.flipY ? -1 : 1)
|
|
16830
|
-
});
|
|
16831
|
-
},
|
|
16832
|
-
|
|
16833
17174
|
/*
|
|
16834
17175
|
* Calculate object dimensions from its properties
|
|
16835
17176
|
* @private
|
|
@@ -16858,7 +17199,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
16858
17199
|
if (typeof skewY === 'undefined') {
|
|
16859
17200
|
skewY = this.skewY;
|
|
16860
17201
|
}
|
|
16861
|
-
var dimensions
|
|
17202
|
+
var dimensions, dimX, dimY,
|
|
16862
17203
|
noSkew = skewX === 0 && skewY === 0;
|
|
16863
17204
|
|
|
16864
17205
|
if (this.strokeUniform) {
|
|
@@ -16866,6 +17207,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
16866
17207
|
dimY = this.height;
|
|
16867
17208
|
}
|
|
16868
17209
|
else {
|
|
17210
|
+
dimensions = this._getNonTransformedDimensions();
|
|
16869
17211
|
dimX = dimensions.x;
|
|
16870
17212
|
dimY = dimensions.y;
|
|
16871
17213
|
}
|
|
@@ -17497,7 +17839,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17497
17839
|
|
|
17498
17840
|
ctx.save();
|
|
17499
17841
|
ctx.strokeStyle = styleOverride.borderColor || this.borderColor;
|
|
17500
|
-
this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray
|
|
17842
|
+
this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray);
|
|
17501
17843
|
|
|
17502
17844
|
ctx.strokeRect(
|
|
17503
17845
|
-width / 2,
|
|
@@ -17550,7 +17892,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17550
17892
|
height =
|
|
17551
17893
|
bbox.y + strokeWidth * (strokeUniform ? this.canvas.getZoom() : options.scaleY) + borderScaleFactor;
|
|
17552
17894
|
ctx.save();
|
|
17553
|
-
this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray
|
|
17895
|
+
this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray);
|
|
17554
17896
|
ctx.strokeStyle = styleOverride.borderColor || this.borderColor;
|
|
17555
17897
|
ctx.strokeRect(
|
|
17556
17898
|
-width / 2,
|
|
@@ -17575,18 +17917,29 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17575
17917
|
drawControls: function(ctx, styleOverride) {
|
|
17576
17918
|
styleOverride = styleOverride || {};
|
|
17577
17919
|
ctx.save();
|
|
17578
|
-
|
|
17920
|
+
var retinaScaling = this.canvas.getRetinaScaling(), matrix, p;
|
|
17921
|
+
ctx.setTransform(retinaScaling, 0, 0, retinaScaling, 0, 0);
|
|
17579
17922
|
ctx.strokeStyle = ctx.fillStyle = styleOverride.cornerColor || this.cornerColor;
|
|
17580
17923
|
if (!this.transparentCorners) {
|
|
17581
17924
|
ctx.strokeStyle = styleOverride.cornerStrokeColor || this.cornerStrokeColor;
|
|
17582
17925
|
}
|
|
17583
|
-
this._setLineDash(ctx, styleOverride.cornerDashArray || this.cornerDashArray
|
|
17926
|
+
this._setLineDash(ctx, styleOverride.cornerDashArray || this.cornerDashArray);
|
|
17584
17927
|
this.setCoords();
|
|
17928
|
+
if (this.group) {
|
|
17929
|
+
// fabricJS does not really support drawing controls inside groups,
|
|
17930
|
+
// this piece of code here helps having at least the control in places.
|
|
17931
|
+
// If an application needs to show some objects as selected because of some UI state
|
|
17932
|
+
// can still call Object._renderControls() on any object they desire, independently of groups.
|
|
17933
|
+
// using no padding, circular controls and hiding the rotating cursor is higly suggested,
|
|
17934
|
+
matrix = this.group.calcTransformMatrix();
|
|
17935
|
+
}
|
|
17585
17936
|
this.forEachControl(function(control, key, fabricObject) {
|
|
17937
|
+
p = fabricObject.oCoords[key];
|
|
17586
17938
|
if (control.getVisibility(fabricObject, key)) {
|
|
17587
|
-
|
|
17588
|
-
|
|
17589
|
-
|
|
17939
|
+
if (matrix) {
|
|
17940
|
+
p = fabric.util.transformPoint(p, matrix);
|
|
17941
|
+
}
|
|
17942
|
+
control.render(ctx, p.x, p.y, styleOverride, fabricObject);
|
|
17590
17943
|
}
|
|
17591
17944
|
});
|
|
17592
17945
|
ctx.restore();
|
|
@@ -17682,8 +18035,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17682
18035
|
* @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
|
|
17683
18036
|
* @param {Function} [callbacks.onComplete] Invoked on completion
|
|
17684
18037
|
* @param {Function} [callbacks.onChange] Invoked on every step of animation
|
|
17685
|
-
* @return {fabric.
|
|
17686
|
-
* @chainable
|
|
18038
|
+
* @return {fabric.AnimationContext} context
|
|
17687
18039
|
*/
|
|
17688
18040
|
fxCenterObjectH: function (object, callbacks) {
|
|
17689
18041
|
callbacks = callbacks || { };
|
|
@@ -17693,7 +18045,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17693
18045
|
onChange = callbacks.onChange || empty,
|
|
17694
18046
|
_this = this;
|
|
17695
18047
|
|
|
17696
|
-
fabric.util.animate({
|
|
18048
|
+
return fabric.util.animate({
|
|
18049
|
+
target: this,
|
|
17697
18050
|
startValue: object.left,
|
|
17698
18051
|
endValue: this.getCenter().left,
|
|
17699
18052
|
duration: this.FX_DURATION,
|
|
@@ -17707,8 +18060,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17707
18060
|
onComplete();
|
|
17708
18061
|
}
|
|
17709
18062
|
});
|
|
17710
|
-
|
|
17711
|
-
return this;
|
|
17712
18063
|
},
|
|
17713
18064
|
|
|
17714
18065
|
/**
|
|
@@ -17717,8 +18068,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17717
18068
|
* @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
|
|
17718
18069
|
* @param {Function} [callbacks.onComplete] Invoked on completion
|
|
17719
18070
|
* @param {Function} [callbacks.onChange] Invoked on every step of animation
|
|
17720
|
-
* @return {fabric.
|
|
17721
|
-
* @chainable
|
|
18071
|
+
* @return {fabric.AnimationContext} context
|
|
17722
18072
|
*/
|
|
17723
18073
|
fxCenterObjectV: function (object, callbacks) {
|
|
17724
18074
|
callbacks = callbacks || { };
|
|
@@ -17728,7 +18078,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17728
18078
|
onChange = callbacks.onChange || empty,
|
|
17729
18079
|
_this = this;
|
|
17730
18080
|
|
|
17731
|
-
fabric.util.animate({
|
|
18081
|
+
return fabric.util.animate({
|
|
18082
|
+
target: this,
|
|
17732
18083
|
startValue: object.top,
|
|
17733
18084
|
endValue: this.getCenter().top,
|
|
17734
18085
|
duration: this.FX_DURATION,
|
|
@@ -17742,8 +18093,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17742
18093
|
onComplete();
|
|
17743
18094
|
}
|
|
17744
18095
|
});
|
|
17745
|
-
|
|
17746
|
-
return this;
|
|
17747
18096
|
},
|
|
17748
18097
|
|
|
17749
18098
|
/**
|
|
@@ -17752,8 +18101,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17752
18101
|
* @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties
|
|
17753
18102
|
* @param {Function} [callbacks.onComplete] Invoked on completion
|
|
17754
18103
|
* @param {Function} [callbacks.onChange] Invoked on every step of animation
|
|
17755
|
-
* @return {fabric.
|
|
17756
|
-
* @chainable
|
|
18104
|
+
* @return {fabric.AnimationContext} context
|
|
17757
18105
|
*/
|
|
17758
18106
|
fxRemove: function (object, callbacks) {
|
|
17759
18107
|
callbacks = callbacks || { };
|
|
@@ -17763,7 +18111,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17763
18111
|
onChange = callbacks.onChange || empty,
|
|
17764
18112
|
_this = this;
|
|
17765
18113
|
|
|
17766
|
-
fabric.util.animate({
|
|
18114
|
+
return fabric.util.animate({
|
|
18115
|
+
target: this,
|
|
17767
18116
|
startValue: object.opacity,
|
|
17768
18117
|
endValue: 0,
|
|
17769
18118
|
duration: this.FX_DURATION,
|
|
@@ -17777,8 +18126,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
17777
18126
|
onComplete();
|
|
17778
18127
|
}
|
|
17779
18128
|
});
|
|
17780
|
-
|
|
17781
|
-
return this;
|
|
17782
18129
|
}
|
|
17783
18130
|
});
|
|
17784
18131
|
|
|
@@ -17789,7 +18136,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17789
18136
|
* @param {Number|Object} value Value to animate property to (if string was given first) or options object
|
|
17790
18137
|
* @return {fabric.Object} thisArg
|
|
17791
18138
|
* @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation}
|
|
17792
|
-
* @
|
|
18139
|
+
* @return {fabric.AnimationContext | fabric.AnimationContext[]} animation context (or an array if passed multiple properties)
|
|
17793
18140
|
*
|
|
17794
18141
|
* As object — multiple properties
|
|
17795
18142
|
*
|
|
@@ -17802,22 +18149,22 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17802
18149
|
* object.animate('left', { duration: ... });
|
|
17803
18150
|
*
|
|
17804
18151
|
*/
|
|
17805
|
-
animate: function() {
|
|
18152
|
+
animate: function () {
|
|
17806
18153
|
if (arguments[0] && typeof arguments[0] === 'object') {
|
|
17807
|
-
var propsToAnimate = [], prop, skipCallbacks;
|
|
18154
|
+
var propsToAnimate = [], prop, skipCallbacks, out = [];
|
|
17808
18155
|
for (prop in arguments[0]) {
|
|
17809
18156
|
propsToAnimate.push(prop);
|
|
17810
18157
|
}
|
|
17811
18158
|
for (var i = 0, len = propsToAnimate.length; i < len; i++) {
|
|
17812
18159
|
prop = propsToAnimate[i];
|
|
17813
18160
|
skipCallbacks = i !== len - 1;
|
|
17814
|
-
this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks);
|
|
18161
|
+
out.push(this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks));
|
|
17815
18162
|
}
|
|
18163
|
+
return out;
|
|
17816
18164
|
}
|
|
17817
18165
|
else {
|
|
17818
|
-
this._animate.apply(this, arguments);
|
|
18166
|
+
return this._animate.apply(this, arguments);
|
|
17819
18167
|
}
|
|
17820
|
-
return this;
|
|
17821
18168
|
},
|
|
17822
18169
|
|
|
17823
18170
|
/**
|
|
@@ -17865,13 +18212,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17865
18212
|
}
|
|
17866
18213
|
|
|
17867
18214
|
var _options = {
|
|
18215
|
+
target: this,
|
|
17868
18216
|
startValue: options.from,
|
|
17869
18217
|
endValue: to,
|
|
17870
18218
|
byValue: options.by,
|
|
17871
18219
|
easing: options.easing,
|
|
17872
18220
|
duration: options.duration,
|
|
17873
|
-
abort: options.abort && function
|
|
17874
|
-
return options.abort.call(_this);
|
|
18221
|
+
abort: options.abort && function(value, valueProgress, timeProgress) {
|
|
18222
|
+
return options.abort.call(_this, value, valueProgress, timeProgress);
|
|
17875
18223
|
},
|
|
17876
18224
|
onChange: function (value, valueProgress, timeProgress) {
|
|
17877
18225
|
if (propPair) {
|
|
@@ -17896,10 +18244,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17896
18244
|
};
|
|
17897
18245
|
|
|
17898
18246
|
if (propIsColor) {
|
|
17899
|
-
fabric.util.animateColor(_options.startValue, _options.endValue, _options.duration, _options);
|
|
18247
|
+
return fabric.util.animateColor(_options.startValue, _options.endValue, _options.duration, _options);
|
|
17900
18248
|
}
|
|
17901
18249
|
else {
|
|
17902
|
-
fabric.util.animate(_options);
|
|
18250
|
+
return fabric.util.animate(_options);
|
|
17903
18251
|
}
|
|
17904
18252
|
}
|
|
17905
18253
|
});
|
|
@@ -17912,8 +18260,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
17912
18260
|
var fabric = global.fabric || (global.fabric = { }),
|
|
17913
18261
|
extend = fabric.util.object.extend,
|
|
17914
18262
|
clone = fabric.util.object.clone,
|
|
17915
|
-
coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 }
|
|
17916
|
-
supportsLineDash = fabric.StaticCanvas.supports('setLineDash');
|
|
18263
|
+
coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 };
|
|
17917
18264
|
|
|
17918
18265
|
if (fabric.Line) {
|
|
17919
18266
|
fabric.warn('fabric.Line is already defined');
|
|
@@ -18061,13 +18408,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18061
18408
|
_render: function(ctx) {
|
|
18062
18409
|
ctx.beginPath();
|
|
18063
18410
|
|
|
18064
|
-
|
|
18065
|
-
|
|
18066
|
-
|
|
18067
|
-
|
|
18068
|
-
ctx.moveTo(p.x1, p.y1);
|
|
18069
|
-
ctx.lineTo(p.x2, p.y2);
|
|
18070
|
-
}
|
|
18411
|
+
|
|
18412
|
+
var p = this.calcLinePoints();
|
|
18413
|
+
ctx.moveTo(p.x1, p.y1);
|
|
18414
|
+
ctx.lineTo(p.x2, p.y2);
|
|
18071
18415
|
|
|
18072
18416
|
ctx.lineWidth = this.strokeWidth;
|
|
18073
18417
|
|
|
@@ -18080,18 +18424,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18080
18424
|
ctx.strokeStyle = origStrokeStyle;
|
|
18081
18425
|
},
|
|
18082
18426
|
|
|
18083
|
-
/**
|
|
18084
|
-
* @private
|
|
18085
|
-
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
18086
|
-
*/
|
|
18087
|
-
_renderDashedStroke: function(ctx) {
|
|
18088
|
-
var p = this.calcLinePoints();
|
|
18089
|
-
|
|
18090
|
-
ctx.beginPath();
|
|
18091
|
-
fabric.util.drawDashedLine(ctx, p.x1, p.y1, p.x2, p.y2, this.strokeDashArray);
|
|
18092
|
-
ctx.closePath();
|
|
18093
|
-
},
|
|
18094
|
-
|
|
18095
18427
|
/**
|
|
18096
18428
|
* This function is an helper for svg import. it returns the center of the object in the svg
|
|
18097
18429
|
* untransformed coordinates
|
|
@@ -18252,7 +18584,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18252
18584
|
'use strict';
|
|
18253
18585
|
|
|
18254
18586
|
var fabric = global.fabric || (global.fabric = { }),
|
|
18255
|
-
|
|
18587
|
+
degreesToRadians = fabric.util.degreesToRadians;
|
|
18256
18588
|
|
|
18257
18589
|
if (fabric.Circle) {
|
|
18258
18590
|
fabric.warn('fabric.Circle is already defined.');
|
|
@@ -18282,22 +18614,20 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18282
18614
|
radius: 0,
|
|
18283
18615
|
|
|
18284
18616
|
/**
|
|
18285
|
-
*
|
|
18286
|
-
* deprecated type, this should be in degree, this was an oversight.
|
|
18617
|
+
* degrees of start of the circle.
|
|
18287
18618
|
* probably will change to degrees in next major version
|
|
18288
|
-
* @type Number
|
|
18619
|
+
* @type Number 0 - 359
|
|
18289
18620
|
* @default 0
|
|
18290
18621
|
*/
|
|
18291
18622
|
startAngle: 0,
|
|
18292
18623
|
|
|
18293
18624
|
/**
|
|
18294
18625
|
* End angle of the circle
|
|
18295
|
-
* deprecated type, this should be in degree, this was an oversight.
|
|
18296
18626
|
* probably will change to degrees in next major version
|
|
18297
|
-
* @type Number
|
|
18298
|
-
* @default
|
|
18627
|
+
* @type Number 1 - 360
|
|
18628
|
+
* @default 360
|
|
18299
18629
|
*/
|
|
18300
|
-
endAngle:
|
|
18630
|
+
endAngle: 360,
|
|
18301
18631
|
|
|
18302
18632
|
cacheProperties: fabric.Object.prototype.cacheProperties.concat('radius', 'startAngle', 'endAngle'),
|
|
18303
18633
|
|
|
@@ -18335,7 +18665,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18335
18665
|
*/
|
|
18336
18666
|
_toSVG: function() {
|
|
18337
18667
|
var svgString, x = 0, y = 0,
|
|
18338
|
-
angle = (this.endAngle - this.startAngle) %
|
|
18668
|
+
angle = (this.endAngle - this.startAngle) % 360;
|
|
18339
18669
|
|
|
18340
18670
|
if (angle === 0) {
|
|
18341
18671
|
svgString = [
|
|
@@ -18346,14 +18676,17 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18346
18676
|
];
|
|
18347
18677
|
}
|
|
18348
18678
|
else {
|
|
18349
|
-
var
|
|
18350
|
-
|
|
18351
|
-
|
|
18352
|
-
|
|
18353
|
-
|
|
18679
|
+
var start = degreesToRadians(this.startAngle),
|
|
18680
|
+
end = degreesToRadians(this.endAngle),
|
|
18681
|
+
radius = this.radius,
|
|
18682
|
+
startX = fabric.util.cos(start) * radius,
|
|
18683
|
+
startY = fabric.util.sin(start) * radius,
|
|
18684
|
+
endX = fabric.util.cos(end) * radius,
|
|
18685
|
+
endY = fabric.util.sin(end) * radius,
|
|
18686
|
+
largeFlag = angle > 180 ? '1' : '0';
|
|
18354
18687
|
svgString = [
|
|
18355
18688
|
'<path d="M ' + startX + ' ' + startY,
|
|
18356
|
-
' A ' +
|
|
18689
|
+
' A ' + radius + ' ' + radius,
|
|
18357
18690
|
' 0 ', +largeFlag + ' 1', ' ' + endX + ' ' + endY,
|
|
18358
18691
|
'" ', 'COMMON_PARTS', ' />\n'
|
|
18359
18692
|
];
|
|
@@ -18372,8 +18705,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18372
18705
|
0,
|
|
18373
18706
|
0,
|
|
18374
18707
|
this.radius,
|
|
18375
|
-
this.startAngle,
|
|
18376
|
-
this.endAngle,
|
|
18708
|
+
degreesToRadians(this.startAngle),
|
|
18709
|
+
degreesToRadians(this.endAngle),
|
|
18710
|
+
false
|
|
18711
|
+
);
|
|
18377
18712
|
this._renderPaintInOrder(ctx);
|
|
18378
18713
|
},
|
|
18379
18714
|
|
|
@@ -18447,10 +18782,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18447
18782
|
* @memberOf fabric.Circle
|
|
18448
18783
|
* @param {Object} object Object to create an instance from
|
|
18449
18784
|
* @param {function} [callback] invoked with new instance as first argument
|
|
18450
|
-
* @return {
|
|
18785
|
+
* @return {void}
|
|
18451
18786
|
*/
|
|
18452
18787
|
fabric.Circle.fromObject = function(object, callback) {
|
|
18453
|
-
|
|
18788
|
+
fabric.Object._fromObject('Circle', object, callback);
|
|
18454
18789
|
};
|
|
18455
18790
|
|
|
18456
18791
|
})(typeof exports !== 'undefined' ? exports : this);
|
|
@@ -18514,21 +18849,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18514
18849
|
this._renderPaintInOrder(ctx);
|
|
18515
18850
|
},
|
|
18516
18851
|
|
|
18517
|
-
/**
|
|
18518
|
-
* @private
|
|
18519
|
-
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
18520
|
-
*/
|
|
18521
|
-
_renderDashedStroke: function(ctx) {
|
|
18522
|
-
var widthBy2 = this.width / 2,
|
|
18523
|
-
heightBy2 = this.height / 2;
|
|
18524
|
-
|
|
18525
|
-
ctx.beginPath();
|
|
18526
|
-
fabric.util.drawDashedLine(ctx, -widthBy2, heightBy2, 0, -heightBy2, this.strokeDashArray);
|
|
18527
|
-
fabric.util.drawDashedLine(ctx, 0, -heightBy2, widthBy2, heightBy2, this.strokeDashArray);
|
|
18528
|
-
fabric.util.drawDashedLine(ctx, widthBy2, heightBy2, -widthBy2, heightBy2, this.strokeDashArray);
|
|
18529
|
-
ctx.closePath();
|
|
18530
|
-
},
|
|
18531
|
-
|
|
18532
18852
|
/* _TO_SVG_START_ */
|
|
18533
18853
|
/**
|
|
18534
18854
|
* Returns svg representation of an instance
|
|
@@ -18740,10 +19060,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18740
19060
|
* @memberOf fabric.Ellipse
|
|
18741
19061
|
* @param {Object} object Object to create an instance from
|
|
18742
19062
|
* @param {function} [callback] invoked with new instance as first argument
|
|
18743
|
-
* @return {
|
|
19063
|
+
* @return {void}
|
|
18744
19064
|
*/
|
|
18745
19065
|
fabric.Ellipse.fromObject = function(object, callback) {
|
|
18746
|
-
|
|
19066
|
+
fabric.Object._fromObject('Ellipse', object, callback);
|
|
18747
19067
|
};
|
|
18748
19068
|
|
|
18749
19069
|
})(typeof exports !== 'undefined' ? exports : this);
|
|
@@ -18862,24 +19182,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18862
19182
|
this._renderPaintInOrder(ctx);
|
|
18863
19183
|
},
|
|
18864
19184
|
|
|
18865
|
-
/**
|
|
18866
|
-
* @private
|
|
18867
|
-
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
18868
|
-
*/
|
|
18869
|
-
_renderDashedStroke: function(ctx) {
|
|
18870
|
-
var x = -this.width / 2,
|
|
18871
|
-
y = -this.height / 2,
|
|
18872
|
-
w = this.width,
|
|
18873
|
-
h = this.height;
|
|
18874
|
-
|
|
18875
|
-
ctx.beginPath();
|
|
18876
|
-
fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);
|
|
18877
|
-
fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);
|
|
18878
|
-
fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);
|
|
18879
|
-
fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);
|
|
18880
|
-
ctx.closePath();
|
|
18881
|
-
},
|
|
18882
|
-
|
|
18883
19185
|
/**
|
|
18884
19186
|
* Returns object representation of an instance
|
|
18885
19187
|
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
|
@@ -18964,7 +19266,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18964
19266
|
extend = fabric.util.object.extend,
|
|
18965
19267
|
min = fabric.util.array.min,
|
|
18966
19268
|
max = fabric.util.array.max,
|
|
18967
|
-
toFixed = fabric.util.toFixed
|
|
19269
|
+
toFixed = fabric.util.toFixed,
|
|
19270
|
+
projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;
|
|
18968
19271
|
|
|
18969
19272
|
if (fabric.Polyline) {
|
|
18970
19273
|
fabric.warn('fabric.Polyline is already defined');
|
|
@@ -18993,6 +19296,17 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
18993
19296
|
*/
|
|
18994
19297
|
points: null,
|
|
18995
19298
|
|
|
19299
|
+
/**
|
|
19300
|
+
* WARNING: Feature in progress
|
|
19301
|
+
* Calculate the exact bounding box taking in account strokeWidth on acute angles
|
|
19302
|
+
* this will be turned to true by default on fabric 6.0
|
|
19303
|
+
* maybe will be left in as an optimization since calculations may be slow
|
|
19304
|
+
* @deprecated
|
|
19305
|
+
* @type Boolean
|
|
19306
|
+
* @default false
|
|
19307
|
+
*/
|
|
19308
|
+
exactBoundingBox: false,
|
|
19309
|
+
|
|
18996
19310
|
cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'),
|
|
18997
19311
|
|
|
18998
19312
|
/**
|
|
@@ -19021,13 +19335,25 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19021
19335
|
this._setPositionDimensions(options);
|
|
19022
19336
|
},
|
|
19023
19337
|
|
|
19338
|
+
/**
|
|
19339
|
+
* @private
|
|
19340
|
+
*/
|
|
19341
|
+
_projectStrokeOnPoints: function () {
|
|
19342
|
+
return projectStrokeOnPoints(this.points, this, true);
|
|
19343
|
+
},
|
|
19344
|
+
|
|
19024
19345
|
_setPositionDimensions: function(options) {
|
|
19025
|
-
var calcDim = this._calcDimensions(options), correctLeftTop
|
|
19026
|
-
|
|
19027
|
-
this.
|
|
19346
|
+
var calcDim = this._calcDimensions(options), correctLeftTop,
|
|
19347
|
+
correctSize = this.exactBoundingBox ? this.strokeWidth : 0;
|
|
19348
|
+
this.width = calcDim.width - correctSize;
|
|
19349
|
+
this.height = calcDim.height - correctSize;
|
|
19028
19350
|
if (!options.fromSVG) {
|
|
19029
19351
|
correctLeftTop = this.translateToGivenOrigin(
|
|
19030
|
-
{
|
|
19352
|
+
{
|
|
19353
|
+
// this looks bad, but is one way to keep it optional for now.
|
|
19354
|
+
x: calcDim.left - this.strokeWidth / 2 + correctSize / 2,
|
|
19355
|
+
y: calcDim.top - this.strokeWidth / 2 + correctSize / 2
|
|
19356
|
+
},
|
|
19031
19357
|
'left',
|
|
19032
19358
|
'top',
|
|
19033
19359
|
this.originX,
|
|
@@ -19041,8 +19367,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19041
19367
|
this.top = options.fromSVG ? calcDim.top : correctLeftTop.y;
|
|
19042
19368
|
}
|
|
19043
19369
|
this.pathOffset = {
|
|
19044
|
-
x: calcDim.left + this.width / 2,
|
|
19045
|
-
y: calcDim.top + this.height / 2
|
|
19370
|
+
x: calcDim.left + this.width / 2 + correctSize / 2,
|
|
19371
|
+
y: calcDim.top + this.height / 2 + correctSize / 2
|
|
19046
19372
|
};
|
|
19047
19373
|
},
|
|
19048
19374
|
|
|
@@ -19058,7 +19384,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19058
19384
|
*/
|
|
19059
19385
|
_calcDimensions: function() {
|
|
19060
19386
|
|
|
19061
|
-
var points = this.points,
|
|
19387
|
+
var points = this.exactBoundingBox ? this._projectStrokeOnPoints() : this.points,
|
|
19062
19388
|
minX = min(points, 'x') || 0,
|
|
19063
19389
|
minY = min(points, 'y') || 0,
|
|
19064
19390
|
maxX = max(points, 'x') || 0,
|
|
@@ -19070,7 +19396,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19070
19396
|
left: minX,
|
|
19071
19397
|
top: minY,
|
|
19072
19398
|
width: width,
|
|
19073
|
-
height: height
|
|
19399
|
+
height: height,
|
|
19074
19400
|
};
|
|
19075
19401
|
},
|
|
19076
19402
|
|
|
@@ -19144,21 +19470,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19144
19470
|
this._renderPaintInOrder(ctx);
|
|
19145
19471
|
},
|
|
19146
19472
|
|
|
19147
|
-
/**
|
|
19148
|
-
* @private
|
|
19149
|
-
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
19150
|
-
*/
|
|
19151
|
-
_renderDashedStroke: function(ctx) {
|
|
19152
|
-
var p1, p2;
|
|
19153
|
-
|
|
19154
|
-
ctx.beginPath();
|
|
19155
|
-
for (var i = 0, len = this.points.length; i < len; i++) {
|
|
19156
|
-
p1 = this.points[i];
|
|
19157
|
-
p2 = this.points[i + 1] || p1;
|
|
19158
|
-
fabric.util.drawDashedLine(ctx, p1.x, p1.y, p2.x, p2.y, this.strokeDashArray);
|
|
19159
|
-
}
|
|
19160
|
-
},
|
|
19161
|
-
|
|
19162
19473
|
/**
|
|
19163
19474
|
* Returns complexity of an instance
|
|
19164
19475
|
* @return {Number} complexity of this instance
|
|
@@ -19221,7 +19532,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19221
19532
|
|
|
19222
19533
|
'use strict';
|
|
19223
19534
|
|
|
19224
|
-
var fabric = global.fabric || (global.fabric = {
|
|
19535
|
+
var fabric = global.fabric || (global.fabric = {}),
|
|
19536
|
+
projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;
|
|
19225
19537
|
|
|
19226
19538
|
if (fabric.Polygon) {
|
|
19227
19539
|
fabric.warn('fabric.Polygon is already defined');
|
|
@@ -19243,6 +19555,13 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19243
19555
|
*/
|
|
19244
19556
|
type: 'polygon',
|
|
19245
19557
|
|
|
19558
|
+
/**
|
|
19559
|
+
* @private
|
|
19560
|
+
*/
|
|
19561
|
+
_projectStrokeOnPoints: function () {
|
|
19562
|
+
return projectStrokeOnPoints(this.points, this);
|
|
19563
|
+
},
|
|
19564
|
+
|
|
19246
19565
|
/**
|
|
19247
19566
|
* @private
|
|
19248
19567
|
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
@@ -19255,14 +19574,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19255
19574
|
this._renderPaintInOrder(ctx);
|
|
19256
19575
|
},
|
|
19257
19576
|
|
|
19258
|
-
/**
|
|
19259
|
-
* @private
|
|
19260
|
-
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
19261
|
-
*/
|
|
19262
|
-
_renderDashedStroke: function(ctx) {
|
|
19263
|
-
this.callSuper('_renderDashedStroke', ctx);
|
|
19264
|
-
ctx.closePath();
|
|
19265
|
-
},
|
|
19266
19577
|
});
|
|
19267
19578
|
|
|
19268
19579
|
/* _FROM_SVG_START_ */
|
|
@@ -19291,9 +19602,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19291
19602
|
* @memberOf fabric.Polygon
|
|
19292
19603
|
* @param {Object} object Object to create an instance from
|
|
19293
19604
|
* @param {Function} [callback] Callback to invoke when an fabric.Path instance is created
|
|
19605
|
+
* @return {void}
|
|
19294
19606
|
*/
|
|
19295
19607
|
fabric.Polygon.fromObject = function(object, callback) {
|
|
19296
|
-
|
|
19608
|
+
fabric.Object._fromObject('Polygon', object, callback, 'points');
|
|
19297
19609
|
};
|
|
19298
19610
|
|
|
19299
19611
|
})(typeof exports !== 'undefined' ? exports : this);
|
|
@@ -19307,6 +19619,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19307
19619
|
min = fabric.util.array.min,
|
|
19308
19620
|
max = fabric.util.array.max,
|
|
19309
19621
|
extend = fabric.util.object.extend,
|
|
19622
|
+
clone = fabric.util.object.clone,
|
|
19310
19623
|
_toString = Object.prototype.toString,
|
|
19311
19624
|
toFixed = fabric.util.toFixed;
|
|
19312
19625
|
|
|
@@ -19348,26 +19661,26 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19348
19661
|
* @param {Object} [options] Options object
|
|
19349
19662
|
* @return {fabric.Path} thisArg
|
|
19350
19663
|
*/
|
|
19351
|
-
initialize: function(path, options) {
|
|
19352
|
-
options = options || {
|
|
19664
|
+
initialize: function (path, options) {
|
|
19665
|
+
options = clone(options || {});
|
|
19666
|
+
delete options.path;
|
|
19353
19667
|
this.callSuper('initialize', options);
|
|
19354
|
-
|
|
19355
|
-
|
|
19356
|
-
}
|
|
19668
|
+
this._setPath(path || [], options);
|
|
19669
|
+
},
|
|
19357
19670
|
|
|
19671
|
+
/**
|
|
19672
|
+
* @private
|
|
19673
|
+
* @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens)
|
|
19674
|
+
* @param {Object} [options] Options object
|
|
19675
|
+
*/
|
|
19676
|
+
_setPath: function (path, options) {
|
|
19358
19677
|
var fromArray = _toString.call(path) === '[object Array]';
|
|
19359
19678
|
|
|
19360
|
-
this.path =
|
|
19361
|
-
? fabric.util.
|
|
19362
|
-
|
|
19363
|
-
: fabric.util.makePathSimpler(
|
|
19364
|
-
fabric.util.parsePath(path)
|
|
19365
|
-
);
|
|
19679
|
+
this.path = fabric.util.makePathSimpler(
|
|
19680
|
+
fromArray ? path : fabric.util.parsePath(path)
|
|
19681
|
+
);
|
|
19366
19682
|
|
|
19367
|
-
|
|
19368
|
-
return;
|
|
19369
|
-
}
|
|
19370
|
-
fabric.Polyline.prototype._setPositionDimensions.call(this, options);
|
|
19683
|
+
fabric.Polyline.prototype._setPositionDimensions.call(this, options || {});
|
|
19371
19684
|
},
|
|
19372
19685
|
|
|
19373
19686
|
/**
|
|
@@ -19494,9 +19807,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19494
19807
|
* of the instance
|
|
19495
19808
|
*/
|
|
19496
19809
|
_toSVG: function() {
|
|
19497
|
-
var path =
|
|
19498
|
-
return path.join(' ');
|
|
19499
|
-
}).join(' ');
|
|
19810
|
+
var path = fabric.util.joinPath(this.path);
|
|
19500
19811
|
return [
|
|
19501
19812
|
'<path ', 'COMMON_PARTS',
|
|
19502
19813
|
'd="', path,
|
|
@@ -19923,13 +20234,17 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
19923
20234
|
*/
|
|
19924
20235
|
toObject: function(propertiesToInclude) {
|
|
19925
20236
|
var _includeDefaultValues = this.includeDefaultValues;
|
|
19926
|
-
var objsToObject = this._objects
|
|
19927
|
-
|
|
19928
|
-
|
|
19929
|
-
|
|
19930
|
-
|
|
19931
|
-
|
|
19932
|
-
|
|
20237
|
+
var objsToObject = this._objects
|
|
20238
|
+
.filter(function (obj) {
|
|
20239
|
+
return !obj.excludeFromExport;
|
|
20240
|
+
})
|
|
20241
|
+
.map(function (obj) {
|
|
20242
|
+
var originalDefaults = obj.includeDefaultValues;
|
|
20243
|
+
obj.includeDefaultValues = _includeDefaultValues;
|
|
20244
|
+
var _obj = obj.toObject(propertiesToInclude);
|
|
20245
|
+
obj.includeDefaultValues = originalDefaults;
|
|
20246
|
+
return _obj;
|
|
20247
|
+
});
|
|
19933
20248
|
var obj = fabric.Object.prototype.toObject.call(this, propertiesToInclude);
|
|
19934
20249
|
obj.objects = objsToObject;
|
|
19935
20250
|
return obj;
|
|
@@ -20022,7 +20337,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
20022
20337
|
for (var i = 0, len = this._objects.length; i < len; i++) {
|
|
20023
20338
|
this._objects[i].render(ctx);
|
|
20024
20339
|
}
|
|
20025
|
-
this._drawClipPath(ctx);
|
|
20340
|
+
this._drawClipPath(ctx, this.clipPath);
|
|
20026
20341
|
},
|
|
20027
20342
|
|
|
20028
20343
|
/**
|
|
@@ -20068,25 +20383,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
20068
20383
|
return this;
|
|
20069
20384
|
},
|
|
20070
20385
|
|
|
20071
|
-
/**
|
|
20072
|
-
* Realises the transform from this group onto the supplied object
|
|
20073
|
-
* i.e. it tells you what would happen if the supplied object was in
|
|
20074
|
-
* the group, and then the group was destroyed. It mutates the supplied
|
|
20075
|
-
* object.
|
|
20076
|
-
* Warning: this method is not useful anymore, it has been kept to no break the api.
|
|
20077
|
-
* is not used in the fabricJS codebase
|
|
20078
|
-
* this method will be reduced to using the utility.
|
|
20079
|
-
* @private
|
|
20080
|
-
* @deprecated
|
|
20081
|
-
* @param {fabric.Object} object
|
|
20082
|
-
* @param {Array} parentMatrix parent transformation
|
|
20083
|
-
* @return {fabric.Object} transformedObject
|
|
20084
|
-
*/
|
|
20085
|
-
realizeTransform: function(object, parentMatrix) {
|
|
20086
|
-
fabric.util.addTransformToObject(object, parentMatrix);
|
|
20087
|
-
return object;
|
|
20088
|
-
},
|
|
20089
|
-
|
|
20090
20386
|
/**
|
|
20091
20387
|
* Destroys a group (restoring state of its objects)
|
|
20092
20388
|
* @return {fabric.Group} thisArg
|
|
@@ -20101,6 +20397,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
20101
20397
|
return this._restoreObjectsState();
|
|
20102
20398
|
},
|
|
20103
20399
|
|
|
20400
|
+
dispose: function () {
|
|
20401
|
+
this.callSuper('dispose');
|
|
20402
|
+
this.forEachObject(function (object) {
|
|
20403
|
+
object.dispose && object.dispose();
|
|
20404
|
+
});
|
|
20405
|
+
this._objects = [];
|
|
20406
|
+
},
|
|
20407
|
+
|
|
20104
20408
|
/**
|
|
20105
20409
|
* make a group an active selection, remove the group from canvas
|
|
20106
20410
|
* the group has to be on canvas for this to work.
|
|
@@ -20264,11 +20568,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
20264
20568
|
});
|
|
20265
20569
|
return;
|
|
20266
20570
|
}
|
|
20267
|
-
fabric.util.enlivenObjects(objects, function(enlivenedObjects) {
|
|
20268
|
-
fabric.util.
|
|
20269
|
-
|
|
20270
|
-
|
|
20271
|
-
delete options.objects;
|
|
20571
|
+
fabric.util.enlivenObjects(objects, function (enlivenedObjects) {
|
|
20572
|
+
var options = fabric.util.object.clone(object, true);
|
|
20573
|
+
delete options.objects;
|
|
20574
|
+
fabric.util.enlivenObjectEnlivables(object, options, function () {
|
|
20272
20575
|
callback && callback(new fabric.Group(enlivenedObjects, options, true));
|
|
20273
20576
|
});
|
|
20274
20577
|
});
|
|
@@ -20638,7 +20941,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
20638
20941
|
/**
|
|
20639
20942
|
* Delete textures, reference to elements and eventually JSDOM cleanup
|
|
20640
20943
|
*/
|
|
20641
|
-
dispose: function() {
|
|
20944
|
+
dispose: function () {
|
|
20945
|
+
this.callSuper('dispose');
|
|
20642
20946
|
this.removeTexture(this.cacheKey);
|
|
20643
20947
|
this.removeTexture(this.cacheKey + '_filtered');
|
|
20644
20948
|
this._cacheContext = undefined;
|
|
@@ -20685,28 +20989,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
20685
20989
|
ctx.closePath();
|
|
20686
20990
|
},
|
|
20687
20991
|
|
|
20688
|
-
/**
|
|
20689
|
-
* @private
|
|
20690
|
-
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
20691
|
-
*/
|
|
20692
|
-
_renderDashedStroke: function(ctx) {
|
|
20693
|
-
var x = -this.width / 2,
|
|
20694
|
-
y = -this.height / 2,
|
|
20695
|
-
w = this.width,
|
|
20696
|
-
h = this.height;
|
|
20697
|
-
|
|
20698
|
-
ctx.save();
|
|
20699
|
-
this._setStrokeStyles(ctx, this);
|
|
20700
|
-
|
|
20701
|
-
ctx.beginPath();
|
|
20702
|
-
fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);
|
|
20703
|
-
fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);
|
|
20704
|
-
fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);
|
|
20705
|
-
fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);
|
|
20706
|
-
ctx.closePath();
|
|
20707
|
-
ctx.restore();
|
|
20708
|
-
},
|
|
20709
|
-
|
|
20710
20992
|
/**
|
|
20711
20993
|
* Returns object representation of an instance
|
|
20712
20994
|
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
|
@@ -21170,8 +21452,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
21170
21452
|
object.filters = filters || [];
|
|
21171
21453
|
fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) {
|
|
21172
21454
|
object.resizeFilter = resizeFilters[0];
|
|
21173
|
-
fabric.util.
|
|
21174
|
-
object.clipPath = enlivedProps[0];
|
|
21455
|
+
fabric.util.enlivenObjectEnlivables(object, object, function () {
|
|
21175
21456
|
var image = new fabric.Image(img, object);
|
|
21176
21457
|
callback(image, false);
|
|
21177
21458
|
});
|
|
@@ -21242,8 +21523,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
21242
21523
|
* @chainable
|
|
21243
21524
|
*/
|
|
21244
21525
|
straighten: function() {
|
|
21245
|
-
this.rotate(this._getAngleValueForStraighten());
|
|
21246
|
-
return this;
|
|
21526
|
+
return this.rotate(this._getAngleValueForStraighten());
|
|
21247
21527
|
},
|
|
21248
21528
|
|
|
21249
21529
|
/**
|
|
@@ -21252,7 +21532,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
21252
21532
|
* @param {Function} [callbacks.onComplete] Invoked on completion
|
|
21253
21533
|
* @param {Function} [callbacks.onChange] Invoked on every step of animation
|
|
21254
21534
|
* @return {fabric.Object} thisArg
|
|
21255
|
-
* @chainable
|
|
21256
21535
|
*/
|
|
21257
21536
|
fxStraighten: function(callbacks) {
|
|
21258
21537
|
callbacks = callbacks || { };
|
|
@@ -21262,7 +21541,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
21262
21541
|
onChange = callbacks.onChange || empty,
|
|
21263
21542
|
_this = this;
|
|
21264
21543
|
|
|
21265
|
-
fabric.util.animate({
|
|
21544
|
+
return fabric.util.animate({
|
|
21545
|
+
target: this,
|
|
21266
21546
|
startValue: this.get('angle'),
|
|
21267
21547
|
endValue: this._getAngleValueForStraighten(),
|
|
21268
21548
|
duration: this.FX_DURATION,
|
|
@@ -21275,8 +21555,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|
|
21275
21555
|
onComplete();
|
|
21276
21556
|
},
|
|
21277
21557
|
});
|
|
21278
|
-
|
|
21279
|
-
return this;
|
|
21280
21558
|
}
|
|
21281
21559
|
});
|
|
21282
21560
|
|
|
@@ -21298,13 +21576,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|
|
21298
21576
|
* Same as {@link fabric.Canvas.prototype.straightenObject}, but animated
|
|
21299
21577
|
* @param {fabric.Object} object Object to straighten
|
|
21300
21578
|
* @return {fabric.Canvas} thisArg
|
|
21301
|
-
* @chainable
|
|
21302
21579
|
*/
|
|
21303
21580
|
fxStraightenObject: function (object) {
|
|
21304
|
-
object.fxStraighten({
|
|
21581
|
+
return object.fxStraighten({
|
|
21305
21582
|
onChange: this.requestRenderAllBound
|
|
21306
21583
|
});
|
|
21307
|
-
return this;
|
|
21308
21584
|
}
|
|
21309
21585
|
});
|
|
21310
21586
|
|
|
@@ -24690,7 +24966,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
24690
24966
|
* @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
|
|
24691
24967
|
* @example
|
|
24692
24968
|
* var filter = new fabric.Image.filters.Saturation({
|
|
24693
|
-
* saturation:
|
|
24969
|
+
* saturation: 1
|
|
24694
24970
|
* });
|
|
24695
24971
|
* object.filters.push(filter);
|
|
24696
24972
|
* object.applyFilters();
|
|
@@ -24718,6 +24994,14 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
24718
24994
|
'gl_FragColor = color;\n' +
|
|
24719
24995
|
'}',
|
|
24720
24996
|
|
|
24997
|
+
/**
|
|
24998
|
+
* Saturation value, from -1 to 1.
|
|
24999
|
+
* Increases/decreases the color saturation.
|
|
25000
|
+
* A value of 0 has no effect.
|
|
25001
|
+
*
|
|
25002
|
+
* @param {Number} saturation
|
|
25003
|
+
* @default
|
|
25004
|
+
*/
|
|
24721
25005
|
saturation: 0,
|
|
24722
25006
|
|
|
24723
25007
|
mainParameter: 'saturation',
|
|
@@ -24786,6 +25070,130 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
24786
25070
|
})(typeof exports !== 'undefined' ? exports : this);
|
|
24787
25071
|
|
|
24788
25072
|
|
|
25073
|
+
(function(global) {
|
|
25074
|
+
|
|
25075
|
+
'use strict';
|
|
25076
|
+
|
|
25077
|
+
var fabric = global.fabric || (global.fabric = { }),
|
|
25078
|
+
filters = fabric.Image.filters,
|
|
25079
|
+
createClass = fabric.util.createClass;
|
|
25080
|
+
|
|
25081
|
+
/**
|
|
25082
|
+
* Vibrance filter class
|
|
25083
|
+
* @class fabric.Image.filters.Vibrance
|
|
25084
|
+
* @memberOf fabric.Image.filters
|
|
25085
|
+
* @extends fabric.Image.filters.BaseFilter
|
|
25086
|
+
* @see {@link fabric.Image.filters.Vibrance#initialize} for constructor definition
|
|
25087
|
+
* @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
|
|
25088
|
+
* @example
|
|
25089
|
+
* var filter = new fabric.Image.filters.Vibrance({
|
|
25090
|
+
* vibrance: 1
|
|
25091
|
+
* });
|
|
25092
|
+
* object.filters.push(filter);
|
|
25093
|
+
* object.applyFilters();
|
|
25094
|
+
*/
|
|
25095
|
+
filters.Vibrance = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Vibrance.prototype */ {
|
|
25096
|
+
|
|
25097
|
+
/**
|
|
25098
|
+
* Filter type
|
|
25099
|
+
* @param {String} type
|
|
25100
|
+
* @default
|
|
25101
|
+
*/
|
|
25102
|
+
type: 'Vibrance',
|
|
25103
|
+
|
|
25104
|
+
fragmentSource: 'precision highp float;\n' +
|
|
25105
|
+
'uniform sampler2D uTexture;\n' +
|
|
25106
|
+
'uniform float uVibrance;\n' +
|
|
25107
|
+
'varying vec2 vTexCoord;\n' +
|
|
25108
|
+
'void main() {\n' +
|
|
25109
|
+
'vec4 color = texture2D(uTexture, vTexCoord);\n' +
|
|
25110
|
+
'float max = max(color.r, max(color.g, color.b));\n' +
|
|
25111
|
+
'float avg = (color.r + color.g + color.b) / 3.0;\n' +
|
|
25112
|
+
'float amt = (abs(max - avg) * 2.0) * uVibrance;\n' +
|
|
25113
|
+
'color.r += max != color.r ? (max - color.r) * amt : 0.00;\n' +
|
|
25114
|
+
'color.g += max != color.g ? (max - color.g) * amt : 0.00;\n' +
|
|
25115
|
+
'color.b += max != color.b ? (max - color.b) * amt : 0.00;\n' +
|
|
25116
|
+
'gl_FragColor = color;\n' +
|
|
25117
|
+
'}',
|
|
25118
|
+
|
|
25119
|
+
/**
|
|
25120
|
+
* Vibrance value, from -1 to 1.
|
|
25121
|
+
* Increases/decreases the saturation of more muted colors with less effect on saturated colors.
|
|
25122
|
+
* A value of 0 has no effect.
|
|
25123
|
+
*
|
|
25124
|
+
* @param {Number} vibrance
|
|
25125
|
+
* @default
|
|
25126
|
+
*/
|
|
25127
|
+
vibrance: 0,
|
|
25128
|
+
|
|
25129
|
+
mainParameter: 'vibrance',
|
|
25130
|
+
|
|
25131
|
+
/**
|
|
25132
|
+
* Constructor
|
|
25133
|
+
* @memberOf fabric.Image.filters.Vibrance.prototype
|
|
25134
|
+
* @param {Object} [options] Options object
|
|
25135
|
+
* @param {Number} [options.vibrance=0] Vibrance value for the image (between -1 and 1)
|
|
25136
|
+
*/
|
|
25137
|
+
|
|
25138
|
+
/**
|
|
25139
|
+
* Apply the Vibrance operation to a Uint8ClampedArray representing the pixels of an image.
|
|
25140
|
+
*
|
|
25141
|
+
* @param {Object} options
|
|
25142
|
+
* @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.
|
|
25143
|
+
*/
|
|
25144
|
+
applyTo2d: function(options) {
|
|
25145
|
+
if (this.vibrance === 0) {
|
|
25146
|
+
return;
|
|
25147
|
+
}
|
|
25148
|
+
var imageData = options.imageData,
|
|
25149
|
+
data = imageData.data, len = data.length,
|
|
25150
|
+
adjust = -this.vibrance, i, max, avg, amt;
|
|
25151
|
+
|
|
25152
|
+
for (i = 0; i < len; i += 4) {
|
|
25153
|
+
max = Math.max(data[i], data[i + 1], data[i + 2]);
|
|
25154
|
+
avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
|
|
25155
|
+
amt = ((Math.abs(max - avg) * 2 / 255) * adjust);
|
|
25156
|
+
data[i] += max !== data[i] ? (max - data[i]) * amt : 0;
|
|
25157
|
+
data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * amt : 0;
|
|
25158
|
+
data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * amt : 0;
|
|
25159
|
+
}
|
|
25160
|
+
},
|
|
25161
|
+
|
|
25162
|
+
/**
|
|
25163
|
+
* Return WebGL uniform locations for this filter's shader.
|
|
25164
|
+
*
|
|
25165
|
+
* @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.
|
|
25166
|
+
* @param {WebGLShaderProgram} program This filter's compiled shader program.
|
|
25167
|
+
*/
|
|
25168
|
+
getUniformLocations: function(gl, program) {
|
|
25169
|
+
return {
|
|
25170
|
+
uVibrance: gl.getUniformLocation(program, 'uVibrance'),
|
|
25171
|
+
};
|
|
25172
|
+
},
|
|
25173
|
+
|
|
25174
|
+
/**
|
|
25175
|
+
* Send data from this filter to its shader program's uniforms.
|
|
25176
|
+
*
|
|
25177
|
+
* @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.
|
|
25178
|
+
* @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects
|
|
25179
|
+
*/
|
|
25180
|
+
sendUniformData: function(gl, uniformLocations) {
|
|
25181
|
+
gl.uniform1f(uniformLocations.uVibrance, -this.vibrance);
|
|
25182
|
+
},
|
|
25183
|
+
});
|
|
25184
|
+
|
|
25185
|
+
/**
|
|
25186
|
+
* Returns filter instance from an object representation
|
|
25187
|
+
* @static
|
|
25188
|
+
* @param {Object} object Object to create an instance from
|
|
25189
|
+
* @param {Function} [callback] to be invoked after filter creation
|
|
25190
|
+
* @return {fabric.Image.filters.Vibrance} Instance of fabric.Image.filters.Vibrance
|
|
25191
|
+
*/
|
|
25192
|
+
fabric.Image.filters.Vibrance.fromObject = fabric.Image.filters.BaseFilter.fromObject;
|
|
25193
|
+
|
|
25194
|
+
})(typeof exports !== 'undefined' ? exports : this);
|
|
25195
|
+
|
|
25196
|
+
|
|
24789
25197
|
(function(global) {
|
|
24790
25198
|
|
|
24791
25199
|
'use strict';
|
|
@@ -25338,7 +25746,8 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
25338
25746
|
|
|
25339
25747
|
var additionalProps =
|
|
25340
25748
|
('fontFamily fontWeight fontSize text underline overline linethrough' +
|
|
25341
|
-
' textAlign fontStyle lineHeight textBackgroundColor charSpacing styles
|
|
25749
|
+
' textAlign fontStyle lineHeight textBackgroundColor charSpacing styles' +
|
|
25750
|
+
' direction path pathStartOffset pathSide pathAlign').split(' ');
|
|
25342
25751
|
|
|
25343
25752
|
/**
|
|
25344
25753
|
* Text class
|
|
@@ -25365,7 +25774,10 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
25365
25774
|
'charSpacing',
|
|
25366
25775
|
'textAlign',
|
|
25367
25776
|
'styles',
|
|
25368
|
-
'path'
|
|
25777
|
+
'path',
|
|
25778
|
+
'pathStartOffset',
|
|
25779
|
+
'pathSide',
|
|
25780
|
+
'pathAlign'
|
|
25369
25781
|
],
|
|
25370
25782
|
|
|
25371
25783
|
/**
|
|
@@ -25523,13 +25935,55 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
25523
25935
|
shadow: null,
|
|
25524
25936
|
|
|
25525
25937
|
/**
|
|
25526
|
-
* fabric.Path that the text
|
|
25527
|
-
*
|
|
25938
|
+
* fabric.Path that the text should follow.
|
|
25939
|
+
* since 4.6.0 the path will be drawn automatically.
|
|
25940
|
+
* if you want to make the path visible, give it a stroke and strokeWidth or fill value
|
|
25941
|
+
* if you want it to be hidden, assign visible = false to the path.
|
|
25942
|
+
* This feature is in BETA, and SVG import/export is not yet supported.
|
|
25528
25943
|
* @type fabric.Path
|
|
25944
|
+
* @example
|
|
25945
|
+
* var textPath = new fabric.Text('Text on a path', {
|
|
25946
|
+
* top: 150,
|
|
25947
|
+
* left: 150,
|
|
25948
|
+
* textAlign: 'center',
|
|
25949
|
+
* charSpacing: -50,
|
|
25950
|
+
* path: new fabric.Path('M 0 0 C 50 -100 150 -100 200 0', {
|
|
25951
|
+
* strokeWidth: 1,
|
|
25952
|
+
* visible: false
|
|
25953
|
+
* }),
|
|
25954
|
+
* pathSide: 'left',
|
|
25955
|
+
* pathStartOffset: 0
|
|
25956
|
+
* });
|
|
25529
25957
|
* @default
|
|
25530
25958
|
*/
|
|
25531
25959
|
path: null,
|
|
25532
25960
|
|
|
25961
|
+
/**
|
|
25962
|
+
* Offset amount for text path starting position
|
|
25963
|
+
* Only used when text has a path
|
|
25964
|
+
* @type Number
|
|
25965
|
+
* @default
|
|
25966
|
+
*/
|
|
25967
|
+
pathStartOffset: 0,
|
|
25968
|
+
|
|
25969
|
+
/**
|
|
25970
|
+
* Which side of the path the text should be drawn on.
|
|
25971
|
+
* Only used when text has a path
|
|
25972
|
+
* @type {String} 'left|right'
|
|
25973
|
+
* @default
|
|
25974
|
+
*/
|
|
25975
|
+
pathSide: 'left',
|
|
25976
|
+
|
|
25977
|
+
/**
|
|
25978
|
+
* How text is aligned to the path. This property determines
|
|
25979
|
+
* the perpendicular position of each character relative to the path.
|
|
25980
|
+
* (one of "baseline", "center", "ascender", "descender")
|
|
25981
|
+
* This feature is in BETA, and its behavior may change
|
|
25982
|
+
* @type String
|
|
25983
|
+
* @default
|
|
25984
|
+
*/
|
|
25985
|
+
pathAlign: 'baseline',
|
|
25986
|
+
|
|
25533
25987
|
/**
|
|
25534
25988
|
* @private
|
|
25535
25989
|
*/
|
|
@@ -25673,6 +26127,8 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
25673
26127
|
/**
|
|
25674
26128
|
* Return a context for measurement of text string.
|
|
25675
26129
|
* if created it gets stored for reuse
|
|
26130
|
+
* this is for internal use, please do not use it
|
|
26131
|
+
* @private
|
|
25676
26132
|
* @param {String} text Text string
|
|
25677
26133
|
* @param {Object} [options] Options object
|
|
25678
26134
|
* @return {fabric.Text} thisArg
|
|
@@ -25808,6 +26264,8 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
25808
26264
|
* @param {CanvasRenderingContext2D} ctx Context to render on
|
|
25809
26265
|
*/
|
|
25810
26266
|
_render: function(ctx) {
|
|
26267
|
+
var path = this.path;
|
|
26268
|
+
path && !path.isNotVisible() && path._render(ctx);
|
|
25811
26269
|
this._setTextStyles(ctx);
|
|
25812
26270
|
this._renderTextLinesBackground(ctx);
|
|
25813
26271
|
this._renderTextDecoration(ctx, 'underline');
|
|
@@ -25842,7 +26300,20 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
25842
26300
|
* @param {String} [charStyle.fontStyle] Font style (italic|normal)
|
|
25843
26301
|
*/
|
|
25844
26302
|
_setTextStyles: function(ctx, charStyle, forMeasuring) {
|
|
25845
|
-
ctx.textBaseline = '
|
|
26303
|
+
ctx.textBaseline = 'alphabetical';
|
|
26304
|
+
if (this.path) {
|
|
26305
|
+
switch (this.pathAlign) {
|
|
26306
|
+
case 'center':
|
|
26307
|
+
ctx.textBaseline = 'middle';
|
|
26308
|
+
break;
|
|
26309
|
+
case 'ascender':
|
|
26310
|
+
ctx.textBaseline = 'top';
|
|
26311
|
+
break;
|
|
26312
|
+
case 'descender':
|
|
26313
|
+
ctx.textBaseline = 'bottom';
|
|
26314
|
+
break;
|
|
26315
|
+
}
|
|
26316
|
+
}
|
|
25846
26317
|
ctx.font = this._getFontDeclaration(charStyle, forMeasuring);
|
|
25847
26318
|
},
|
|
25848
26319
|
|
|
@@ -26067,29 +26538,15 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
26067
26538
|
_measureLine: function(lineIndex) {
|
|
26068
26539
|
var width = 0, i, grapheme, line = this._textLines[lineIndex], prevGrapheme,
|
|
26069
26540
|
graphemeInfo, numOfSpaces = 0, lineBounds = new Array(line.length),
|
|
26070
|
-
positionInPath = 0, startingPoint, totalPathLength, path = this.path
|
|
26541
|
+
positionInPath = 0, startingPoint, totalPathLength, path = this.path,
|
|
26542
|
+
reverse = this.pathSide === 'right';
|
|
26071
26543
|
|
|
26072
26544
|
this.__charBounds[lineIndex] = lineBounds;
|
|
26073
|
-
if (path) {
|
|
26074
|
-
startingPoint = fabric.util.getPointOnPath(path.path, 0, path.segmentsInfo);
|
|
26075
|
-
totalPathLength = path.segmentsInfo[path.segmentsInfo.length - 1].length;
|
|
26076
|
-
startingPoint.x += path.pathOffset.x;
|
|
26077
|
-
startingPoint.y += path.pathOffset.y;
|
|
26078
|
-
}
|
|
26079
26545
|
for (i = 0; i < line.length; i++) {
|
|
26080
26546
|
grapheme = line[i];
|
|
26081
26547
|
graphemeInfo = this._getGraphemeBox(grapheme, lineIndex, i, prevGrapheme);
|
|
26082
|
-
if (path) {
|
|
26083
|
-
if (positionInPath > totalPathLength) {
|
|
26084
|
-
positionInPath %= totalPathLength;
|
|
26085
|
-
}
|
|
26086
|
-
// it would probably much fater to send all the grapheme position for a line
|
|
26087
|
-
// and calculate path position/angle at once.
|
|
26088
|
-
this._setGraphemeOnPath(positionInPath, graphemeInfo, startingPoint);
|
|
26089
|
-
}
|
|
26090
26548
|
lineBounds[i] = graphemeInfo;
|
|
26091
26549
|
width += graphemeInfo.kernedWidth;
|
|
26092
|
-
positionInPath += graphemeInfo.kernedWidth;
|
|
26093
26550
|
prevGrapheme = grapheme;
|
|
26094
26551
|
}
|
|
26095
26552
|
// this latest bound box represent the last character of the line
|
|
@@ -26100,6 +26557,40 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
26100
26557
|
kernedWidth: 0,
|
|
26101
26558
|
height: this.fontSize
|
|
26102
26559
|
};
|
|
26560
|
+
if (path) {
|
|
26561
|
+
totalPathLength = path.segmentsInfo[path.segmentsInfo.length - 1].length;
|
|
26562
|
+
startingPoint = fabric.util.getPointOnPath(path.path, 0, path.segmentsInfo);
|
|
26563
|
+
startingPoint.x += path.pathOffset.x;
|
|
26564
|
+
startingPoint.y += path.pathOffset.y;
|
|
26565
|
+
switch (this.textAlign) {
|
|
26566
|
+
case 'left':
|
|
26567
|
+
positionInPath = reverse ? (totalPathLength - width) : 0;
|
|
26568
|
+
break;
|
|
26569
|
+
case 'center':
|
|
26570
|
+
positionInPath = (totalPathLength - width) / 2;
|
|
26571
|
+
break;
|
|
26572
|
+
case 'right':
|
|
26573
|
+
positionInPath = reverse ? 0 : (totalPathLength - width);
|
|
26574
|
+
break;
|
|
26575
|
+
//todo - add support for justify
|
|
26576
|
+
}
|
|
26577
|
+
positionInPath += this.pathStartOffset * (reverse ? -1 : 1);
|
|
26578
|
+
for (i = reverse ? line.length - 1 : 0;
|
|
26579
|
+
reverse ? i >= 0 : i < line.length;
|
|
26580
|
+
reverse ? i-- : i++) {
|
|
26581
|
+
graphemeInfo = lineBounds[i];
|
|
26582
|
+
if (positionInPath > totalPathLength) {
|
|
26583
|
+
positionInPath %= totalPathLength;
|
|
26584
|
+
}
|
|
26585
|
+
else if (positionInPath < 0) {
|
|
26586
|
+
positionInPath += totalPathLength;
|
|
26587
|
+
}
|
|
26588
|
+
// it would probably much faster to send all the grapheme position for a line
|
|
26589
|
+
// and calculate path position/angle at once.
|
|
26590
|
+
this._setGraphemeOnPath(positionInPath, graphemeInfo, startingPoint);
|
|
26591
|
+
positionInPath += graphemeInfo.kernedWidth;
|
|
26592
|
+
}
|
|
26593
|
+
}
|
|
26103
26594
|
return { width: width, numOfSpaces: numOfSpaces };
|
|
26104
26595
|
},
|
|
26105
26596
|
|
|
@@ -26119,7 +26610,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
26119
26610
|
var info = fabric.util.getPointOnPath(path.path, centerPosition, path.segmentsInfo);
|
|
26120
26611
|
graphemeInfo.renderLeft = info.x - startingPoint.x;
|
|
26121
26612
|
graphemeInfo.renderTop = info.y - startingPoint.y;
|
|
26122
|
-
graphemeInfo.angle = info.angle;
|
|
26613
|
+
graphemeInfo.angle = info.angle + (this.pathSide === 'right' ? Math.PI : 0);
|
|
26123
26614
|
},
|
|
26124
26615
|
|
|
26125
26616
|
/**
|
|
@@ -26287,16 +26778,17 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
26287
26778
|
path = this.path,
|
|
26288
26779
|
shortCut = !isJustify && this.charSpacing === 0 && this.isEmptyStyles(lineIndex) && !path,
|
|
26289
26780
|
isLtr = this.direction === 'ltr', sign = this.direction === 'ltr' ? 1 : -1,
|
|
26290
|
-
drawingLeft;
|
|
26291
|
-
|
|
26781
|
+
drawingLeft, currentDirection = ctx.canvas.getAttribute('dir');
|
|
26292
26782
|
ctx.save();
|
|
26783
|
+
if (currentDirection !== this.direction) {
|
|
26784
|
+
ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');
|
|
26785
|
+
ctx.direction = isLtr ? 'ltr' : 'rtl';
|
|
26786
|
+
ctx.textAlign = isLtr ? 'left' : 'right';
|
|
26787
|
+
}
|
|
26293
26788
|
top -= lineHeight * this._fontSizeFraction / this.lineHeight;
|
|
26294
26789
|
if (shortCut) {
|
|
26295
26790
|
// render all the line in one pass without checking
|
|
26296
26791
|
// drawingLeft = isLtr ? left : left - this.getLineWidth(lineIndex);
|
|
26297
|
-
ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');
|
|
26298
|
-
ctx.direction = isLtr ? 'ltr' : 'rtl';
|
|
26299
|
-
ctx.textAlign = isLtr ? 'left' : 'right';
|
|
26300
26792
|
this._renderChar(method, ctx, lineIndex, 0, line.join(''), left, top, lineHeight);
|
|
26301
26793
|
ctx.restore();
|
|
26302
26794
|
return;
|
|
@@ -26333,9 +26825,6 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
26333
26825
|
}
|
|
26334
26826
|
else {
|
|
26335
26827
|
drawingLeft = left;
|
|
26336
|
-
ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');
|
|
26337
|
-
ctx.direction = isLtr ? 'ltr' : 'rtl';
|
|
26338
|
-
ctx.textAlign = isLtr ? 'left' : 'right';
|
|
26339
26828
|
this._renderChar(method, ctx, lineIndex, i, charsToRender, drawingLeft, top, lineHeight);
|
|
26340
26829
|
}
|
|
26341
26830
|
charsToRender = '';
|
|
@@ -26586,19 +27075,12 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
26586
27075
|
* @return {Number} Line width
|
|
26587
27076
|
*/
|
|
26588
27077
|
getLineWidth: function(lineIndex) {
|
|
26589
|
-
if (this.__lineWidths[lineIndex]) {
|
|
27078
|
+
if (this.__lineWidths[lineIndex] !== undefined) {
|
|
26590
27079
|
return this.__lineWidths[lineIndex];
|
|
26591
27080
|
}
|
|
26592
27081
|
|
|
26593
|
-
var
|
|
26594
|
-
|
|
26595
|
-
if (line === '') {
|
|
26596
|
-
width = 0;
|
|
26597
|
-
}
|
|
26598
|
-
else {
|
|
26599
|
-
lineInfo = this.measureLine(lineIndex);
|
|
26600
|
-
width = lineInfo.width;
|
|
26601
|
-
}
|
|
27082
|
+
var lineInfo = this.measureLine(lineIndex);
|
|
27083
|
+
var width = lineInfo.width;
|
|
26602
27084
|
this.__lineWidths[lineIndex] = width;
|
|
26603
27085
|
return width;
|
|
26604
27086
|
},
|
|
@@ -26788,25 +27270,13 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
26788
27270
|
* @return {Object} Object representation of an instance
|
|
26789
27271
|
*/
|
|
26790
27272
|
toObject: function(propertiesToInclude) {
|
|
26791
|
-
var
|
|
26792
|
-
|
|
26793
|
-
|
|
26794
|
-
'fontWeight',
|
|
26795
|
-
'fontFamily',
|
|
26796
|
-
'fontStyle',
|
|
26797
|
-
'lineHeight',
|
|
26798
|
-
'underline',
|
|
26799
|
-
'overline',
|
|
26800
|
-
'linethrough',
|
|
26801
|
-
'textAlign',
|
|
26802
|
-
'textBackgroundColor',
|
|
26803
|
-
'charSpacing',
|
|
26804
|
-
'path',
|
|
26805
|
-
'direction',
|
|
26806
|
-
].concat(propertiesToInclude);
|
|
26807
|
-
var obj = this.callSuper('toObject', additionalProperties);
|
|
27273
|
+
var allProperties = additionalProps.concat(propertiesToInclude);
|
|
27274
|
+
var obj = this.callSuper('toObject', allProperties);
|
|
27275
|
+
// styles will be overridden with a properly cloned structure
|
|
26808
27276
|
obj.styles = clone(this.styles, true);
|
|
26809
|
-
obj.path
|
|
27277
|
+
if (obj.path) {
|
|
27278
|
+
obj.path = this.path.toObject();
|
|
27279
|
+
}
|
|
26810
27280
|
return obj;
|
|
26811
27281
|
},
|
|
26812
27282
|
|
|
@@ -27460,6 +27930,16 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
27460
27930
|
*/
|
|
27461
27931
|
caching: true,
|
|
27462
27932
|
|
|
27933
|
+
/**
|
|
27934
|
+
* DOM container to append the hiddenTextarea.
|
|
27935
|
+
* An alternative to attaching to the document.body.
|
|
27936
|
+
* Useful to reduce laggish redraw of the full document.body tree and
|
|
27937
|
+
* also with modals event capturing that won't let the textarea take focus.
|
|
27938
|
+
* @type HTMLElement
|
|
27939
|
+
* @default
|
|
27940
|
+
*/
|
|
27941
|
+
hiddenTextareaContainer: null,
|
|
27942
|
+
|
|
27463
27943
|
/**
|
|
27464
27944
|
* @private
|
|
27465
27945
|
*/
|
|
@@ -28697,7 +29177,13 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
|
|
|
28697
29177
|
this.insertCharStyleObject(cursorLoc.lineIndex + i, 0, addedLines[i], copiedStyle);
|
|
28698
29178
|
}
|
|
28699
29179
|
else if (copiedStyle) {
|
|
28700
|
-
this
|
|
29180
|
+
// this test is required in order to close #6841
|
|
29181
|
+
// when a pasted buffer begins with a newline then
|
|
29182
|
+
// this.styles[cursorLoc.lineIndex + i] and copiedStyle[0]
|
|
29183
|
+
// may be undefined for some reason
|
|
29184
|
+
if (this.styles[cursorLoc.lineIndex + i] && copiedStyle[0]) {
|
|
29185
|
+
this.styles[cursorLoc.lineIndex + i][0] = copiedStyle[0];
|
|
29186
|
+
}
|
|
28701
29187
|
}
|
|
28702
29188
|
copiedStyle = copiedStyle && copiedStyle.slice(addedLines[i] + 1);
|
|
28703
29189
|
}
|
|
@@ -29061,7 +29547,13 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|
|
29061
29547
|
this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top +
|
|
29062
29548
|
'; left: ' + style.left + '; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px;' +
|
|
29063
29549
|
' paddingーtop: ' + style.fontSize + ';';
|
|
29064
|
-
|
|
29550
|
+
|
|
29551
|
+
if (this.hiddenTextareaContainer) {
|
|
29552
|
+
this.hiddenTextareaContainer.appendChild(this.hiddenTextarea);
|
|
29553
|
+
}
|
|
29554
|
+
else {
|
|
29555
|
+
fabric.document.body.appendChild(this.hiddenTextarea);
|
|
29556
|
+
}
|
|
29065
29557
|
|
|
29066
29558
|
fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));
|
|
29067
29559
|
fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this));
|