fabric 4.6.0-browser → 5.1.0-browser

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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,49 +690,6 @@
542
690
  }
543
691
  },
544
692
 
545
- /**
546
- * WARNING: THIS WAS TO SUPPORT OLD BROWSERS. deprecated.
547
- * WILL BE REMOVED IN FABRIC 5.0
548
- * Draws a dashed line between two points
549
- *
550
- * This method is used to draw dashed line around selection area.
551
- * See <a href="http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas">dotted stroke in canvas</a>
552
- *
553
- * @param {CanvasRenderingContext2D} ctx context
554
- * @param {Number} x start x coordinate
555
- * @param {Number} y start y coordinate
556
- * @param {Number} x2 end x coordinate
557
- * @param {Number} y2 end y coordinate
558
- * @param {Array} da dash array pattern
559
- * @deprecated
560
- */
561
- drawDashedLine: function(ctx, x, y, x2, y2, da) {
562
- var dx = x2 - x,
563
- dy = y2 - y,
564
- len = sqrt(dx * dx + dy * dy),
565
- rot = atan2(dy, dx),
566
- dc = da.length,
567
- di = 0,
568
- draw = true;
569
-
570
- ctx.save();
571
- ctx.translate(x, y);
572
- ctx.moveTo(0, 0);
573
- ctx.rotate(rot);
574
-
575
- x = 0;
576
- while (len > x) {
577
- x += da[di++ % dc];
578
- if (x > len) {
579
- x = len;
580
- }
581
- ctx[draw ? 'lineTo' : 'moveTo'](x, 0);
582
- draw = !draw;
583
- }
584
-
585
- ctx.restore();
586
- },
587
-
588
693
  /**
589
694
  * Creates canvas element
590
695
  * @static
@@ -712,7 +817,7 @@
712
817
  * @param {Boolean} [options.flipX]
713
818
  * @param {Boolean} [options.flipY]
714
819
  * @param {Number} [options.skewX]
715
- * @param {Number} [options.skewX]
820
+ * @param {Number} [options.skewY]
716
821
  * @return {Number[]} transform matrix
717
822
  */
718
823
  calcDimensionsMatrix: function(options) {
@@ -1066,6 +1171,49 @@
1066
1171
  x: bbox.width,
1067
1172
  y: bbox.height,
1068
1173
  };
1069
- }
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
+ },
1070
1218
  };
1071
1219
  })(typeof exports !== 'undefined' ? exports : this);
package/src/util/path.js CHANGED
@@ -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 && perc <= 1 && nextStep > 0.0001) {
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;
@@ -811,50 +811,6 @@
811
811
  });
812
812
  }
813
813
 
814
- /**
815
- * Calculate bounding box of a elliptic-arc
816
- * @deprecated
817
- * @param {Number} fx start point of arc
818
- * @param {Number} fy
819
- * @param {Number} rx horizontal radius
820
- * @param {Number} ry vertical radius
821
- * @param {Number} rot angle of horizontal axis
822
- * @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points
823
- * @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction
824
- * @param {Number} tx end point of arc
825
- * @param {Number} ty
826
- */
827
- function getBoundsOfArc(fx, fy, rx, ry, rot, large, sweep, tx, ty) {
828
-
829
- var fromX = 0, fromY = 0, bound, bounds = [],
830
- segs = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);
831
-
832
- for (var i = 0, len = segs.length; i < len; i++) {
833
- bound = getBoundsOfCurve(fromX, fromY, segs[i][1], segs[i][2], segs[i][3], segs[i][4], segs[i][5], segs[i][6]);
834
- bounds.push({ x: bound[0].x + fx, y: bound[0].y + fy });
835
- bounds.push({ x: bound[1].x + fx, y: bound[1].y + fy });
836
- fromX = segs[i][5];
837
- fromY = segs[i][6];
838
- }
839
- return bounds;
840
- };
841
-
842
- /**
843
- * Draws arc
844
- * @deprecated
845
- * @param {CanvasRenderingContext2D} ctx
846
- * @param {Number} fx
847
- * @param {Number} fy
848
- * @param {Array} coords coords of the arc, without the front 'A/a'
849
- */
850
- function drawArc(ctx, fx, fy, coords) {
851
- coords = coords.slice(0).unshift('X'); // command A or a does not matter
852
- var beziers = fromArcToBeziers(fx, fy, coords);
853
- beziers.forEach(function(bezier) {
854
- ctx.bezierCurveTo.apply(ctx, bezier.slice(1));
855
- });
856
- };
857
-
858
814
  /**
859
815
  * Join path commands to go back to svg format
860
816
  * @param {Array} pathData fabricJS parsed path commands
@@ -870,14 +826,4 @@
870
826
  fabric.util.getBoundsOfCurve = getBoundsOfCurve;
871
827
  fabric.util.getPointOnPath = getPointOnPath;
872
828
  fabric.util.transformPath = transformPath;
873
- /**
874
- * Typo of `fromArcToBeziers` kept for not breaking the api once corrected.
875
- * Will be removed in fabric 5.0
876
- * @deprecated
877
- */
878
- fabric.util.fromArcToBeizers = fromArcToBeziers;
879
- // kept because we do not want to make breaking changes.
880
- // but useless and deprecated.
881
- fabric.util.getBoundsOfArc = getBoundsOfArc;
882
- fabric.util.drawArc = drawArc;
883
829
  })();