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/src/util/lang_object.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @memberOf fabric.util.object
|
|
9
9
|
* @param {Object} destination Where to copy to
|
|
10
10
|
* @param {Object} source Where to copy from
|
|
11
|
+
* @param {Boolean} [deep] Whether to extend nested objects
|
|
11
12
|
* @return {Object}
|
|
12
13
|
*/
|
|
13
14
|
|
|
@@ -53,11 +54,14 @@
|
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* Creates an empty object and copies all enumerable properties of another object to it
|
|
57
|
+
* This method is mostly for internal use, and not intended for duplicating shapes in canvas.
|
|
56
58
|
* @memberOf fabric.util.object
|
|
57
|
-
* TODO: this function return an empty object if you try to clone null
|
|
58
59
|
* @param {Object} object Object to clone
|
|
60
|
+
* @param {Boolean} [deep] Whether to clone nested objects
|
|
59
61
|
* @return {Object}
|
|
60
62
|
*/
|
|
63
|
+
|
|
64
|
+
//TODO: this function return an empty object if you try to clone null
|
|
61
65
|
function clone(object, deep) {
|
|
62
66
|
return extend({ }, object, deep);
|
|
63
67
|
}
|
package/src/util/misc.js
CHANGED
|
@@ -139,6 +139,135 @@
|
|
|
139
139
|
};
|
|
140
140
|
},
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Creates a vetor from points represented as a point
|
|
144
|
+
* @static
|
|
145
|
+
* @memberOf fabric.util
|
|
146
|
+
*
|
|
147
|
+
* @typedef {Object} Point
|
|
148
|
+
* @property {number} x
|
|
149
|
+
* @property {number} y
|
|
150
|
+
*
|
|
151
|
+
* @param {Point} from
|
|
152
|
+
* @param {Point} to
|
|
153
|
+
* @returns {Point} vector
|
|
154
|
+
*/
|
|
155
|
+
createVector: function (from, to) {
|
|
156
|
+
return new fabric.Point(to.x - from.x, to.y - from.y);
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Calculates angle between 2 vectors using dot product
|
|
161
|
+
* @static
|
|
162
|
+
* @memberOf fabric.util
|
|
163
|
+
* @param {Point} a
|
|
164
|
+
* @param {Point} b
|
|
165
|
+
* @returns the angle in radian between the vectors
|
|
166
|
+
*/
|
|
167
|
+
calcAngleBetweenVectors: function (a, b) {
|
|
168
|
+
return Math.acos((a.x * b.x + a.y * b.y) / (Math.hypot(a.x, a.y) * Math.hypot(b.x, b.y)));
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @static
|
|
173
|
+
* @memberOf fabric.util
|
|
174
|
+
* @param {Point} v
|
|
175
|
+
* @returns {Point} vector representing the unit vector of pointing to the direction of `v`
|
|
176
|
+
*/
|
|
177
|
+
getHatVector: function (v) {
|
|
178
|
+
return new fabric.Point(v.x, v.y).multiply(1 / Math.hypot(v.x, v.y));
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @static
|
|
183
|
+
* @memberOf fabric.util
|
|
184
|
+
* @param {Point} A
|
|
185
|
+
* @param {Point} B
|
|
186
|
+
* @param {Point} C
|
|
187
|
+
* @returns {{ vector: Point, angle: number }} vector representing the bisector of A and A's angle
|
|
188
|
+
*/
|
|
189
|
+
getBisector: function (A, B, C) {
|
|
190
|
+
var AB = fabric.util.createVector(A, B), AC = fabric.util.createVector(A, C);
|
|
191
|
+
var alpha = fabric.util.calcAngleBetweenVectors(AB, AC);
|
|
192
|
+
// check if alpha is relative to AB->BC
|
|
193
|
+
var ro = fabric.util.calcAngleBetweenVectors(fabric.util.rotateVector(AB, alpha), AC);
|
|
194
|
+
var phi = alpha * (ro === 0 ? 1 : -1) / 2;
|
|
195
|
+
return {
|
|
196
|
+
vector: fabric.util.getHatVector(fabric.util.rotateVector(AB, phi)),
|
|
197
|
+
angle: alpha
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Project stroke width on points returning 2 projections for each point as follows:
|
|
203
|
+
* - `miter`: 2 points corresponding to the outer boundary and the inner boundary of stroke.
|
|
204
|
+
* - `bevel`: 2 points corresponding to the bevel boundaries, tangent to the bisector.
|
|
205
|
+
* - `round`: same as `bevel`
|
|
206
|
+
* Used to calculate object's bounding box
|
|
207
|
+
* @static
|
|
208
|
+
* @memberOf fabric.util
|
|
209
|
+
* @param {Point[]} points
|
|
210
|
+
* @param {Object} options
|
|
211
|
+
* @param {number} options.strokeWidth
|
|
212
|
+
* @param {'miter'|'bevel'|'round'} options.strokeLineJoin
|
|
213
|
+
* @param {number} options.strokeMiterLimit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit
|
|
214
|
+
* @param {boolean} options.strokeUniform
|
|
215
|
+
* @param {number} options.scaleX
|
|
216
|
+
* @param {number} options.scaleY
|
|
217
|
+
* @param {boolean} [openPath] whether the shape is open or not, affects the calculations of the first and last points
|
|
218
|
+
* @returns {fabric.Point[]} array of size 2n/4n of all suspected points
|
|
219
|
+
*/
|
|
220
|
+
projectStrokeOnPoints: function (points, options, openPath) {
|
|
221
|
+
var coords = [], s = options.strokeWidth / 2,
|
|
222
|
+
strokeUniformScalar = options.strokeUniform ?
|
|
223
|
+
new fabric.Point(1 / options.scaleX, 1 / options.scaleY) : new fabric.Point(1, 1),
|
|
224
|
+
getStrokeHatVector = function (v) {
|
|
225
|
+
var scalar = s / (Math.hypot(v.x, v.y));
|
|
226
|
+
return new fabric.Point(v.x * scalar * strokeUniformScalar.x, v.y * scalar * strokeUniformScalar.y);
|
|
227
|
+
};
|
|
228
|
+
if (points.length <= 1) {return coords;}
|
|
229
|
+
points.forEach(function (p, index) {
|
|
230
|
+
var A = new fabric.Point(p.x, p.y), B, C;
|
|
231
|
+
if (index === 0) {
|
|
232
|
+
C = points[index + 1];
|
|
233
|
+
B = openPath ? getStrokeHatVector(fabric.util.createVector(C, A)).addEquals(A) : points[points.length - 1];
|
|
234
|
+
}
|
|
235
|
+
else if (index === points.length - 1) {
|
|
236
|
+
B = points[index - 1];
|
|
237
|
+
C = openPath ? getStrokeHatVector(fabric.util.createVector(B, A)).addEquals(A) : points[0];
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
B = points[index - 1];
|
|
241
|
+
C = points[index + 1];
|
|
242
|
+
}
|
|
243
|
+
var bisector = fabric.util.getBisector(A, B, C),
|
|
244
|
+
bisectorVector = bisector.vector,
|
|
245
|
+
alpha = bisector.angle,
|
|
246
|
+
scalar,
|
|
247
|
+
miterVector;
|
|
248
|
+
if (options.strokeLineJoin === 'miter') {
|
|
249
|
+
scalar = -s / Math.sin(alpha / 2);
|
|
250
|
+
miterVector = new fabric.Point(
|
|
251
|
+
bisectorVector.x * scalar * strokeUniformScalar.x,
|
|
252
|
+
bisectorVector.y * scalar * strokeUniformScalar.y
|
|
253
|
+
);
|
|
254
|
+
if (Math.hypot(miterVector.x, miterVector.y) / s <= options.strokeMiterLimit) {
|
|
255
|
+
coords.push(A.add(miterVector));
|
|
256
|
+
coords.push(A.subtract(miterVector));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
scalar = -s * Math.SQRT2;
|
|
261
|
+
miterVector = new fabric.Point(
|
|
262
|
+
bisectorVector.x * scalar * strokeUniformScalar.x,
|
|
263
|
+
bisectorVector.y * scalar * strokeUniformScalar.y
|
|
264
|
+
);
|
|
265
|
+
coords.push(A.add(miterVector));
|
|
266
|
+
coords.push(A.subtract(miterVector));
|
|
267
|
+
});
|
|
268
|
+
return coords;
|
|
269
|
+
},
|
|
270
|
+
|
|
142
271
|
/**
|
|
143
272
|
* Apply transform t to point p
|
|
144
273
|
* @static
|
|
@@ -451,6 +580,25 @@
|
|
|
451
580
|
});
|
|
452
581
|
},
|
|
453
582
|
|
|
583
|
+
/**
|
|
584
|
+
* Creates corresponding fabric instances residing in an object, e.g. `clipPath`
|
|
585
|
+
* @see {@link fabric.Object.ENLIVEN_PROPS}
|
|
586
|
+
* @param {Object} object
|
|
587
|
+
* @param {Object} [context] assign enlived props to this object (pass null to skip this)
|
|
588
|
+
* @param {(objects:fabric.Object[]) => void} callback
|
|
589
|
+
*/
|
|
590
|
+
enlivenObjectEnlivables: function (object, context, callback) {
|
|
591
|
+
var enlivenProps = fabric.Object.ENLIVEN_PROPS.filter(function (key) { return !!object[key]; });
|
|
592
|
+
fabric.util.enlivenObjects(enlivenProps.map(function (key) { return object[key]; }), function (enlivedProps) {
|
|
593
|
+
var objects = {};
|
|
594
|
+
enlivenProps.forEach(function (key, index) {
|
|
595
|
+
objects[key] = enlivedProps[index];
|
|
596
|
+
context && (context[key] = enlivedProps[index]);
|
|
597
|
+
});
|
|
598
|
+
callback && callback(objects);
|
|
599
|
+
});
|
|
600
|
+
},
|
|
601
|
+
|
|
454
602
|
/**
|
|
455
603
|
* Create and wait for loading of patterns
|
|
456
604
|
* @static
|
|
@@ -542,46 +690,6 @@
|
|
|
542
690
|
}
|
|
543
691
|
},
|
|
544
692
|
|
|
545
|
-
/**
|
|
546
|
-
* Draws a dashed line between two points
|
|
547
|
-
*
|
|
548
|
-
* This method is used to draw dashed line around selection area.
|
|
549
|
-
* See <a href="http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas">dotted stroke in canvas</a>
|
|
550
|
-
*
|
|
551
|
-
* @param {CanvasRenderingContext2D} ctx context
|
|
552
|
-
* @param {Number} x start x coordinate
|
|
553
|
-
* @param {Number} y start y coordinate
|
|
554
|
-
* @param {Number} x2 end x coordinate
|
|
555
|
-
* @param {Number} y2 end y coordinate
|
|
556
|
-
* @param {Array} da dash array pattern
|
|
557
|
-
*/
|
|
558
|
-
drawDashedLine: function(ctx, x, y, x2, y2, da) {
|
|
559
|
-
var dx = x2 - x,
|
|
560
|
-
dy = y2 - y,
|
|
561
|
-
len = sqrt(dx * dx + dy * dy),
|
|
562
|
-
rot = atan2(dy, dx),
|
|
563
|
-
dc = da.length,
|
|
564
|
-
di = 0,
|
|
565
|
-
draw = true;
|
|
566
|
-
|
|
567
|
-
ctx.save();
|
|
568
|
-
ctx.translate(x, y);
|
|
569
|
-
ctx.moveTo(0, 0);
|
|
570
|
-
ctx.rotate(rot);
|
|
571
|
-
|
|
572
|
-
x = 0;
|
|
573
|
-
while (len > x) {
|
|
574
|
-
x += da[di++ % dc];
|
|
575
|
-
if (x > len) {
|
|
576
|
-
x = len;
|
|
577
|
-
}
|
|
578
|
-
ctx[draw ? 'lineTo' : 'moveTo'](x, 0);
|
|
579
|
-
draw = !draw;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
ctx.restore();
|
|
583
|
-
},
|
|
584
|
-
|
|
585
693
|
/**
|
|
586
694
|
* Creates canvas element
|
|
587
695
|
* @static
|
|
@@ -709,7 +817,7 @@
|
|
|
709
817
|
* @param {Boolean} [options.flipX]
|
|
710
818
|
* @param {Boolean} [options.flipY]
|
|
711
819
|
* @param {Number} [options.skewX]
|
|
712
|
-
* @param {Number} [options.
|
|
820
|
+
* @param {Number} [options.skewY]
|
|
713
821
|
* @return {Number[]} transform matrix
|
|
714
822
|
*/
|
|
715
823
|
calcDimensionsMatrix: function(options) {
|
|
@@ -1063,6 +1171,49 @@
|
|
|
1063
1171
|
x: bbox.width,
|
|
1064
1172
|
y: bbox.height,
|
|
1065
1173
|
};
|
|
1066
|
-
}
|
|
1174
|
+
},
|
|
1175
|
+
|
|
1176
|
+
/**
|
|
1177
|
+
* Merges 2 clip paths into one visually equal clip path
|
|
1178
|
+
*
|
|
1179
|
+
* **IMPORTANT**:\
|
|
1180
|
+
* Does **NOT** clone the arguments, clone them proir if necessary.
|
|
1181
|
+
*
|
|
1182
|
+
* Creates a wrapper (group) that contains one clip path and is clipped by the other so content is kept where both overlap.
|
|
1183
|
+
* 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.
|
|
1184
|
+
*
|
|
1185
|
+
* In order to handle the `inverted` property we follow logic described in the following cases:\
|
|
1186
|
+
* **(1)** both clip paths are inverted - the clip paths pass the inverted prop to the wrapper and loose it themselves.\
|
|
1187
|
+
* **(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.\
|
|
1188
|
+
* **(3)** both clip paths are not inverted - wrapper and clip paths remain unchanged.
|
|
1189
|
+
*
|
|
1190
|
+
* @memberOf fabric.util
|
|
1191
|
+
* @param {fabric.Object} c1
|
|
1192
|
+
* @param {fabric.Object} c2
|
|
1193
|
+
* @returns {fabric.Object} merged clip path
|
|
1194
|
+
*/
|
|
1195
|
+
mergeClipPaths: function (c1, c2) {
|
|
1196
|
+
var a = c1, b = c2;
|
|
1197
|
+
if (a.inverted && !b.inverted) {
|
|
1198
|
+
// case (2)
|
|
1199
|
+
a = c2;
|
|
1200
|
+
b = c1;
|
|
1201
|
+
}
|
|
1202
|
+
// `b` becomes `a`'s clip path so we transform `b` to `a` coordinate plane
|
|
1203
|
+
fabric.util.applyTransformToObject(
|
|
1204
|
+
b,
|
|
1205
|
+
fabric.util.multiplyTransformMatrices(
|
|
1206
|
+
fabric.util.invertTransform(a.calcTransformMatrix()),
|
|
1207
|
+
b.calcTransformMatrix()
|
|
1208
|
+
)
|
|
1209
|
+
);
|
|
1210
|
+
// assign the `inverted` prop to the wrapping group
|
|
1211
|
+
var inverted = a.inverted && b.inverted;
|
|
1212
|
+
if (inverted) {
|
|
1213
|
+
// case (1)
|
|
1214
|
+
a.inverted = b.inverted = false;
|
|
1215
|
+
}
|
|
1216
|
+
return new fabric.Group([a], { clipPath: b, inverted: inverted });
|
|
1217
|
+
},
|
|
1067
1218
|
};
|
|
1068
1219
|
})(typeof exports !== 'undefined' ? exports : this);
|
package/src/util/path.js
CHANGED
|
@@ -486,8 +486,8 @@
|
|
|
486
486
|
// with 100 segemnts. This will good enough to calculate the length of the curve
|
|
487
487
|
function pathIterator(iterator, x1, y1) {
|
|
488
488
|
var tempP = { x: x1, y: y1 }, p, tmpLen = 0, perc;
|
|
489
|
-
for (perc =
|
|
490
|
-
p = iterator(perc);
|
|
489
|
+
for (perc = 1; perc <= 100; perc += 1) {
|
|
490
|
+
p = iterator(perc / 100);
|
|
491
491
|
tmpLen += calcLineLength(tempP.x, tempP.y, p.x, p.y);
|
|
492
492
|
tempP = p;
|
|
493
493
|
}
|
|
@@ -507,15 +507,15 @@
|
|
|
507
507
|
p, nextLen, nextStep = 0.01, angleFinder = segInfo.angleFinder, lastPerc;
|
|
508
508
|
// nextStep > 0.0001 covers 0.00015625 that 1/64th of 1/100
|
|
509
509
|
// the path
|
|
510
|
-
while (tmpLen < distance &&
|
|
510
|
+
while (tmpLen < distance && nextStep > 0.0001) {
|
|
511
511
|
p = iterator(perc);
|
|
512
512
|
lastPerc = perc;
|
|
513
513
|
nextLen = calcLineLength(tempP.x, tempP.y, p.x, p.y);
|
|
514
514
|
// compare tmpLen each cycle with distance, decide next perc to test.
|
|
515
515
|
if ((nextLen + tmpLen) > distance) {
|
|
516
516
|
// we discard this step and we make smaller steps.
|
|
517
|
-
nextStep /= 2;
|
|
518
517
|
perc -= nextStep;
|
|
518
|
+
nextStep /= 2;
|
|
519
519
|
}
|
|
520
520
|
else {
|
|
521
521
|
tempP = p;
|
|
@@ -661,6 +661,18 @@
|
|
|
661
661
|
}
|
|
662
662
|
}
|
|
663
663
|
|
|
664
|
+
/**
|
|
665
|
+
*
|
|
666
|
+
* @param {string} pathString
|
|
667
|
+
* @return {(string|number)[][]} An array of SVG path commands
|
|
668
|
+
* @example <caption>Usage</caption>
|
|
669
|
+
* parsePath('M 3 4 Q 3 5 2 1 4 0 Q 9 12 2 1 4 0') === [
|
|
670
|
+
* ['M', 3, 4],
|
|
671
|
+
* ['Q', 3, 5, 2, 1, 4, 0],
|
|
672
|
+
* ['Q', 9, 12, 2, 1, 4, 0],
|
|
673
|
+
* ];
|
|
674
|
+
*
|
|
675
|
+
*/
|
|
664
676
|
function parsePath(pathString) {
|
|
665
677
|
var result = [],
|
|
666
678
|
coords = [],
|
|
@@ -730,63 +742,88 @@
|
|
|
730
742
|
};
|
|
731
743
|
|
|
732
744
|
/**
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
* @param {
|
|
736
|
-
* @param {
|
|
737
|
-
* @
|
|
738
|
-
* @param {Number} ry vertical radius
|
|
739
|
-
* @param {Number} rot angle of horizontal axis
|
|
740
|
-
* @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points
|
|
741
|
-
* @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction
|
|
742
|
-
* @param {Number} tx end point of arc
|
|
743
|
-
* @param {Number} ty
|
|
745
|
+
*
|
|
746
|
+
* Converts points to a smooth SVG path
|
|
747
|
+
* @param {{ x: number,y: number }[]} points Array of points
|
|
748
|
+
* @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.
|
|
749
|
+
* @return {(string|number)[][]} An array of SVG path commands
|
|
744
750
|
*/
|
|
745
|
-
function
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
fromY = segs[i][6];
|
|
751
|
+
function getSmoothPathFromPoints(points, correction) {
|
|
752
|
+
var path = [], i,
|
|
753
|
+
p1 = new fabric.Point(points[0].x, points[0].y),
|
|
754
|
+
p2 = new fabric.Point(points[1].x, points[1].y),
|
|
755
|
+
len = points.length, multSignX = 1, multSignY = 0, manyPoints = len > 2;
|
|
756
|
+
correction = correction || 0;
|
|
757
|
+
|
|
758
|
+
if (manyPoints) {
|
|
759
|
+
multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;
|
|
760
|
+
multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1;
|
|
756
761
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
762
|
+
path.push(['M', p1.x - multSignX * correction, p1.y - multSignY * correction]);
|
|
763
|
+
for (i = 1; i < len; i++) {
|
|
764
|
+
if (!p1.eq(p2)) {
|
|
765
|
+
var midPoint = p1.midPointFrom(p2);
|
|
766
|
+
// p1 is our bezier control point
|
|
767
|
+
// midpoint is our endpoint
|
|
768
|
+
// start point is p(i-1) value.
|
|
769
|
+
path.push(['Q', p1.x, p1.y, midPoint.x, midPoint.y]);
|
|
770
|
+
}
|
|
771
|
+
p1 = points[i];
|
|
772
|
+
if ((i + 1) < points.length) {
|
|
773
|
+
p2 = points[i + 1];
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
if (manyPoints) {
|
|
777
|
+
multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;
|
|
778
|
+
multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;
|
|
779
|
+
}
|
|
780
|
+
path.push(['L', p1.x + multSignX * correction, p1.y + multSignY * correction]);
|
|
781
|
+
return path;
|
|
782
|
+
}
|
|
760
783
|
/**
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
-
* @param {
|
|
765
|
-
* @param {
|
|
766
|
-
* @param {
|
|
784
|
+
* Transform a path by transforming each segment.
|
|
785
|
+
* it has to be a simplified path or it won't work.
|
|
786
|
+
* WARNING: this depends from pathOffset for correct operation
|
|
787
|
+
* @param {Array} path fabricJS parsed and simplified path commands
|
|
788
|
+
* @param {Array} transform matrix that represent the transformation
|
|
789
|
+
* @param {Object} [pathOffset] the fabric.Path pathOffset
|
|
790
|
+
* @param {Number} pathOffset.x
|
|
791
|
+
* @param {Number} pathOffset.y
|
|
792
|
+
* @returns {Array} the transformed path
|
|
767
793
|
*/
|
|
768
|
-
function
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
794
|
+
function transformPath(path, transform, pathOffset) {
|
|
795
|
+
if (pathOffset) {
|
|
796
|
+
transform = fabric.util.multiplyTransformMatrices(
|
|
797
|
+
transform,
|
|
798
|
+
[1, 0, 0, 1, -pathOffset.x, -pathOffset.y]
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
return path.map(function(pathSegment) {
|
|
802
|
+
var newSegment = pathSegment.slice(0), point = {};
|
|
803
|
+
for (var i = 1; i < pathSegment.length - 1; i += 2) {
|
|
804
|
+
point.x = pathSegment[i];
|
|
805
|
+
point.y = pathSegment[i + 1];
|
|
806
|
+
point = fabric.util.transformPoint(point, transform);
|
|
807
|
+
newSegment[i] = point.x;
|
|
808
|
+
newSegment[i + 1] = point.y;
|
|
809
|
+
}
|
|
810
|
+
return newSegment;
|
|
773
811
|
});
|
|
774
|
-
}
|
|
812
|
+
}
|
|
775
813
|
|
|
814
|
+
/**
|
|
815
|
+
* Join path commands to go back to svg format
|
|
816
|
+
* @param {Array} pathData fabricJS parsed path commands
|
|
817
|
+
* @return {String} joined path 'M 0 0 L 20 30'
|
|
818
|
+
*/
|
|
819
|
+
fabric.util.joinPath = function(pathData) {
|
|
820
|
+
return pathData.map(function (segment) { return segment.join(' '); }).join(' ');
|
|
821
|
+
};
|
|
776
822
|
fabric.util.parsePath = parsePath;
|
|
777
823
|
fabric.util.makePathSimpler = makePathSimpler;
|
|
824
|
+
fabric.util.getSmoothPathFromPoints = getSmoothPathFromPoints;
|
|
778
825
|
fabric.util.getPathSegmentsInfo = getPathSegmentsInfo;
|
|
779
|
-
fabric.util.fromArcToBeziers = fromArcToBeziers;
|
|
780
|
-
/**
|
|
781
|
-
* Typo of `fromArcToBeziers` kept for not breaking the api once corrected.
|
|
782
|
-
* Will be removed in fabric 5.0
|
|
783
|
-
* @deprecated
|
|
784
|
-
*/
|
|
785
|
-
fabric.util.fromArcToBeizers = fromArcToBeziers;
|
|
786
826
|
fabric.util.getBoundsOfCurve = getBoundsOfCurve;
|
|
787
827
|
fabric.util.getPointOnPath = getPointOnPath;
|
|
788
|
-
|
|
789
|
-
// but useless and deprecated.
|
|
790
|
-
fabric.util.getBoundsOfArc = getBoundsOfArc;
|
|
791
|
-
fabric.util.drawArc = drawArc;
|
|
828
|
+
fabric.util.transformPath = transformPath;
|
|
792
829
|
})();
|