@joint/core 4.1.3 → 4.2.0-alpha.1

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.
Files changed (58) hide show
  1. package/README.md +4 -2
  2. package/dist/geometry.js +129 -124
  3. package/dist/geometry.min.js +4 -3
  4. package/dist/joint.d.ts +352 -160
  5. package/dist/joint.js +3654 -2191
  6. package/dist/joint.min.js +4 -3
  7. package/dist/joint.nowrap.js +3653 -2188
  8. package/dist/joint.nowrap.min.js +4 -3
  9. package/dist/vectorizer.js +489 -279
  10. package/dist/vectorizer.min.js +4 -3
  11. package/dist/version.mjs +1 -1
  12. package/package.json +33 -27
  13. package/src/V/create.mjs +51 -0
  14. package/src/V/index.mjs +89 -159
  15. package/src/V/namespace.mjs +9 -0
  16. package/src/V/transform.mjs +183 -0
  17. package/src/V/traverse.mjs +16 -0
  18. package/src/alg/Deque.mjs +126 -0
  19. package/src/anchors/index.mjs +140 -33
  20. package/src/cellTools/Boundary.mjs +15 -13
  21. package/src/cellTools/Button.mjs +7 -5
  22. package/src/cellTools/Control.mjs +38 -15
  23. package/src/cellTools/HoverConnect.mjs +5 -1
  24. package/src/cellTools/helpers.mjs +44 -3
  25. package/src/config/index.mjs +8 -0
  26. package/src/connectionPoints/index.mjs +24 -9
  27. package/src/connectionStrategies/index.mjs +1 -1
  28. package/src/connectors/jumpover.mjs +1 -1
  29. package/src/dia/Cell.mjs +32 -12
  30. package/src/dia/CellView.mjs +53 -38
  31. package/src/dia/Element.mjs +81 -35
  32. package/src/dia/ElementView.mjs +2 -1
  33. package/src/dia/HighlighterView.mjs +54 -11
  34. package/src/dia/LinkView.mjs +118 -98
  35. package/src/dia/Paper.mjs +831 -231
  36. package/src/dia/PaperLayer.mjs +9 -2
  37. package/src/dia/ToolView.mjs +4 -0
  38. package/src/dia/ToolsView.mjs +12 -3
  39. package/src/dia/attributes/text.mjs +16 -5
  40. package/src/dia/layers/GridLayer.mjs +5 -0
  41. package/src/dia/ports.mjs +344 -111
  42. package/src/elementTools/HoverConnect.mjs +14 -8
  43. package/src/env/index.mjs +7 -4
  44. package/src/g/rect.mjs +7 -0
  45. package/src/highlighters/stroke.mjs +1 -1
  46. package/src/layout/ports/port.mjs +30 -15
  47. package/src/layout/ports/portLabel.mjs +1 -1
  48. package/src/linkAnchors/index.mjs +2 -2
  49. package/src/linkTools/Anchor.mjs +2 -2
  50. package/src/linkTools/Vertices.mjs +4 -6
  51. package/src/mvc/View.mjs +4 -0
  52. package/src/mvc/ViewBase.mjs +1 -1
  53. package/src/util/util.mjs +1 -1
  54. package/src/util/utilHelpers.mjs +2 -0
  55. package/types/geometry.d.ts +65 -59
  56. package/types/joint.d.ts +278 -102
  57. package/types/vectorizer.d.ts +11 -1
  58. package/src/V/annotation.mjs +0 -0
@@ -1,21 +1,21 @@
1
- /*! JointJS v4.1.3 (2025-02-04) - JavaScript diagramming library
2
-
1
+ /*! JointJS v4.2.0-alpha.1 (2025-09-25) - JavaScript diagramming library
3
2
 
4
3
  This Source Code Form is subject to the terms of the Mozilla Public
5
4
  License, v. 2.0. If a copy of the MPL was not distributed with this
6
5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
6
  */
7
+
8
8
  (function (global, factory) {
9
9
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
10
10
  typeof define === 'function' && define.amd ? define(factory) :
11
- (global = global || self, global.V = factory());
12
- }(this, function () { 'use strict';
11
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.V = factory());
12
+ })(this, (function () { 'use strict';
13
13
 
14
14
  // Declare shorthands to the most used math functions.
15
15
  const {
16
- round,
16
+ round: round$3,
17
17
  floor,
18
- PI
18
+ PI: PI$1
19
19
  } = Math;
20
20
  const scale = {
21
21
  // Return the `value` from the `domain` interval scaled to the `range` interval.
@@ -29,15 +29,15 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
29
29
  return angle % 360 + (angle < 0 ? 360 : 0);
30
30
  };
31
31
  const snapToGrid = function (value, gridSize) {
32
- return gridSize * round(value / gridSize);
32
+ return gridSize * round$3(value / gridSize);
33
33
  };
34
34
  const toDeg = function (rad) {
35
- return 180 * rad / PI % 360;
35
+ return 180 * rad / PI$1 % 360;
36
36
  };
37
37
  const toRad = function (deg, over360) {
38
38
  over360 = over360 || false;
39
39
  deg = over360 ? deg : deg % 360;
40
- return deg * PI / 180;
40
+ return deg * PI$1 / 180;
41
41
  };
42
42
 
43
43
  // Return a random integer from the interval [min,max], inclusive.
@@ -56,10 +56,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
56
56
  };
57
57
 
58
58
  // @return the bearing (cardinal direction) of the line. For example N, W, or SE.
59
+ // @returns {String} One of the following bearings : NE, E, SE, S, SW, W, NW, N.
59
60
  const {
60
- cos,
61
- sin,
62
- atan2
61
+ cos: cos$2,
62
+ sin: sin$2,
63
+ atan2: atan2$1
63
64
  } = Math;
64
65
  const bearing = function (p, q) {
65
66
  var lat1 = toRad(p.y);
@@ -67,9 +68,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
67
68
  var lon1 = p.x;
68
69
  var lon2 = q.x;
69
70
  var dLon = toRad(lon2 - lon1);
70
- var y = sin(dLon) * cos(lat2);
71
- var x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
72
- var brng = toDeg(atan2(y, x));
71
+ var y = sin$2(dLon) * cos$2(lat2);
72
+ var x = cos$2(lat1) * sin$2(lat2) - sin$2(lat1) * cos$2(lat2) * cos$2(dLon);
73
+ var brng = toDeg(atan2$1(y, x));
73
74
  var bearings = ['NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N'];
74
75
  var index = brng - 22.5;
75
76
  if (index < 0) index += 360;
@@ -112,16 +113,16 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
112
113
  * `Point(Point(10, 20))`
113
114
  */
114
115
  const {
115
- abs,
116
+ abs: abs$2,
116
117
  cos: cos$1,
117
118
  sin: sin$1,
118
- sqrt,
119
- min,
120
- max,
121
- atan2: atan2$1,
122
- round: round$1,
123
- pow,
124
- PI: PI$1
119
+ sqrt: sqrt$2,
120
+ min: min$3,
121
+ max: max$3,
122
+ atan2,
123
+ round: round$2,
124
+ pow: pow$3,
125
+ PI
125
126
  } = Math;
126
127
  const Point = function (x, y) {
127
128
  if (!(this instanceof Point)) {
@@ -145,8 +146,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
145
146
  // @param {point} [optional] Origin.
146
147
  Point.fromPolar = function (distance, angle, origin) {
147
148
  origin = new Point(origin);
148
- var x = abs(distance * cos$1(angle));
149
- var y = abs(distance * sin$1(angle));
149
+ var x = abs$2(distance * cos$1(angle));
150
+ var y = abs$2(distance * sin$1(angle));
150
151
  var deg = normalizeAngle(toDeg(angle));
151
152
  if (deg < 90) {
152
153
  y = -y;
@@ -187,8 +188,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
187
188
  if (r.containsPoint(this)) {
188
189
  return this;
189
190
  }
190
- this.x = min(max(this.x, r.x), r.x + r.width);
191
- this.y = min(max(this.y, r.y), r.y + r.height);
191
+ this.x = min$3(max$3(this.x, r.x), r.x + r.width);
192
+ this.y = min$3(max$3(this.y, r.y), r.y + r.height);
192
193
  return this;
193
194
  },
194
195
  // Compute the angle between vector from me to p1 and the vector from me to p2.
@@ -254,11 +255,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
254
255
  return new Point((1 - t) * x + t * p.x, (1 - t) * y + t * p.y);
255
256
  },
256
257
  magnitude: function () {
257
- return sqrt(this.x * this.x + this.y * this.y) || 0.01;
258
+ return sqrt$2(this.x * this.x + this.y * this.y) || 0.01;
258
259
  },
259
260
  // Returns a manhattan (taxi-cab) distance between me and point `p`.
260
261
  manhattanDistance: function (p) {
261
- return abs(p.x - this.x) + abs(p.y - this.y);
262
+ return abs$2(p.x - this.x) + abs$2(p.y - this.y);
262
263
  },
263
264
  // Move point on line starting from ref ending at me by
264
265
  // distance distance.
@@ -315,12 +316,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
315
316
  f = 1000;
316
317
  break;
317
318
  default:
318
- f = pow(10, precision);
319
+ f = pow$3(10, precision);
319
320
  break;
320
321
  }
321
322
  }
322
- this.x = round$1(this.x * f) / f;
323
- this.y = round$1(this.y * f) / f;
323
+ this.x = round$2(this.x * f) / f;
324
+ this.y = round$2(this.y * f) / f;
324
325
  return this;
325
326
  },
326
327
  // Scale point with origin.
@@ -347,13 +348,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
347
348
  // Invert the y-axis.
348
349
  var y = -(p.y - this.y);
349
350
  var x = p.x - this.x;
350
- var rad = atan2$1(y, x); // defined for all 0 corner cases
351
+ var rad = atan2(y, x); // defined for all 0 corner cases
351
352
 
352
353
  // Correction for III. and IV. quadrant.
353
354
  if (rad < 0) {
354
- rad = 2 * PI$1 + rad;
355
+ rad = 2 * PI + rad;
355
356
  }
356
- return 180 * rad / PI$1;
357
+ return 180 * rad / PI;
357
358
  },
358
359
  toJSON: function () {
359
360
  return {
@@ -367,7 +368,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
367
368
  o = o && new Point(o) || new Point(0, 0);
368
369
  var x = this.x;
369
370
  var y = this.y;
370
- this.x = sqrt((x - o.x) * (x - o.x) + (y - o.y) * (y - o.y)); // r
371
+ this.x = sqrt$2((x - o.x) * (x - o.x) + (y - o.y) * (y - o.y)); // r
371
372
  this.y = toRad(o.theta(new Point(x, y)));
372
373
  return this;
373
374
  },
@@ -399,8 +400,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
399
400
  const point = Point;
400
401
 
401
402
  const {
402
- max: max$1,
403
- min: min$1
403
+ max: max$2,
404
+ min: min$2
404
405
  } = Math;
405
406
  const Line = function (p1, p2) {
406
407
  if (!(this instanceof Line)) {
@@ -420,10 +421,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
420
421
  return this.start.angleBetween(this.end, horizontalPoint);
421
422
  },
422
423
  bbox: function () {
423
- var left = min$1(this.start.x, this.end.x);
424
- var top = min$1(this.start.y, this.end.y);
425
- var right = max$1(this.start.x, this.end.x);
426
- var bottom = max$1(this.start.y, this.end.y);
424
+ var left = min$2(this.start.x, this.end.x);
425
+ var top = min$2(this.start.y, this.end.y);
426
+ var right = max$2(this.start.x, this.end.x);
427
+ var bottom = max$2(this.start.y, this.end.y);
427
428
  return new Rect(left, top, right - left, bottom - top);
428
429
  },
429
430
  // @return the bearing (cardinal direction) of the line. For example N, W, or SE.
@@ -444,7 +445,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
444
445
  // @return {number} the normalized length of the closest point on the line to point `p`
445
446
  closestPointNormalizedLength: function (p) {
446
447
  var product = this.vector().dot(new Line(this.start, p).vector());
447
- var cpNormalizedLength = min$1(1, max$1(0, product / this.squaredLength()));
448
+ var cpNormalizedLength = min$2(1, max$2(0, product / this.squaredLength()));
448
449
 
449
450
  // cpNormalizedLength returns `NaN` if this line has zero length
450
451
  // we can work with that - if `NaN`, return 0
@@ -650,8 +651,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
650
651
 
651
652
  const {
652
653
  sqrt: sqrt$1,
653
- round: round$2,
654
- pow: pow$1
654
+ round: round$1,
655
+ pow: pow$2
655
656
  } = Math;
656
657
  const Ellipse = function (c, a, b) {
657
658
  if (!(this instanceof Ellipse)) {
@@ -799,14 +800,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
799
800
  f = 1000;
800
801
  break;
801
802
  default:
802
- f = pow$1(10, precision);
803
+ f = pow$2(10, precision);
803
804
  break;
804
805
  }
805
806
  }
806
- this.x = round$2(this.x * f) / f;
807
- this.y = round$2(this.y * f) / f;
808
- this.a = round$2(this.a * f) / f;
809
- this.b = round$2(this.b * f) / f;
807
+ this.x = round$1(this.x * f) / f;
808
+ this.y = round$1(this.y * f) / f;
809
+ this.a = round$1(this.a * f) / f;
810
+ this.b = round$1(this.b * f) / f;
810
811
  return this;
811
812
  },
812
813
  /** Compute angle between tangent and x axis
@@ -844,12 +845,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
844
845
 
845
846
  const {
846
847
  abs: abs$1,
847
- cos: cos$2,
848
- sin: sin$2,
849
- min: min$2,
850
- max: max$2,
851
- round: round$3,
852
- pow: pow$2
848
+ cos,
849
+ sin,
850
+ min: min$1,
851
+ max: max$1,
852
+ round,
853
+ pow: pow$1
853
854
  } = Math;
854
855
  const Rect = function (x, y, w, h) {
855
856
  if (!(this instanceof Rect)) {
@@ -870,14 +871,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
870
871
  e = new Ellipse(e);
871
872
  return new Rect(e.x - e.a, e.y - e.b, 2 * e.a, 2 * e.b);
872
873
  };
873
- Rect.fromPointUnion = function () {
874
- if (arguments.length === 0) return null;
874
+ Rect.fromPointUnion = function (...points) {
875
+ if (points.length === 0) return null;
875
876
  const p = new Point();
876
877
  let minX, minY, maxX, maxY;
877
878
  minX = minY = Infinity;
878
879
  maxX = maxY = -Infinity;
879
- for (let i = 0; i < arguments.length; i++) {
880
- p.update(i < 0 || arguments.length <= i ? undefined : arguments[i]);
880
+ for (let i = 0; i < points.length; i++) {
881
+ p.update(points[i]);
881
882
  const x = p.x;
882
883
  const y = p.y;
883
884
  if (x < minX) minX = x;
@@ -887,14 +888,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
887
888
  }
888
889
  return new Rect(minX, minY, maxX - minX, maxY - minY);
889
890
  };
890
- Rect.fromRectUnion = function () {
891
- if (arguments.length === 0) return null;
891
+ Rect.fromRectUnion = function (...rects) {
892
+ if (rects.length === 0) return null;
892
893
  const r = new Rect();
893
894
  let minX, minY, maxX, maxY;
894
895
  minX = minY = Infinity;
895
896
  maxX = maxY = -Infinity;
896
- for (let i = 0; i < arguments.length; i++) {
897
- r.update(i < 0 || arguments.length <= i ? undefined : arguments[i]);
897
+ for (let i = 0; i < rects.length; i++) {
898
+ r.update(rects[i]);
898
899
  const x = r.x;
899
900
  const y = r.y;
900
901
  const mX = x + r.width;
@@ -920,8 +921,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
920
921
  height
921
922
  } = this;
922
923
  const theta = toRad(angle);
923
- const st = abs$1(sin$2(theta));
924
- const ct = abs$1(cos$2(theta));
924
+ const st = abs$1(sin(theta));
925
+ const ct = abs$1(cos(theta));
925
926
  const w = width * ct + height * st;
926
927
  const h = width * st + height * ct;
927
928
  this.x += (width - w) / 2;
@@ -1022,9 +1023,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
1022
1023
 
1023
1024
  // No intersection found
1024
1025
  if (rCorner.x <= myOrigin.x || rCorner.y <= myOrigin.y || rOrigin.x >= myCorner.x || rOrigin.y >= myCorner.y) return null;
1025
- var x = max$2(myOrigin.x, rOrigin.x);
1026
- var y = max$2(myOrigin.y, rOrigin.y);
1027
- return new Rect(x, y, min$2(myCorner.x, rCorner.x) - x, min$2(myCorner.y, rCorner.y) - y);
1026
+ var x = max$1(myOrigin.x, rOrigin.x);
1027
+ var y = max$1(myOrigin.y, rOrigin.y);
1028
+ return new Rect(x, y, min$1(myCorner.x, rCorner.x) - x, min$1(myCorner.y, rCorner.y) - y);
1028
1029
  },
1029
1030
  intersectionWithLine: function (line) {
1030
1031
  var r = this;
@@ -1115,13 +1116,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
1115
1116
  sy4 = (this.y + this.height - oy) / (p4.y - oy);
1116
1117
  }
1117
1118
  return {
1118
- sx: min$2(sx1, sx2, sx3, sx4),
1119
- sy: min$2(sy1, sy2, sy3, sy4)
1119
+ sx: min$1(sx1, sx2, sx3, sx4),
1120
+ sy: min$1(sy1, sy2, sy3, sy4)
1120
1121
  };
1121
1122
  },
1122
1123
  maxRectUniformScaleToFit: function (rect, origin) {
1123
1124
  var scale = this.maxRectScaleToFit(rect, origin);
1124
- return min$2(scale.sx, scale.sy);
1125
+ return min$1(scale.sx, scale.sy);
1125
1126
  },
1126
1127
  // Move and expand me.
1127
1128
  // @param r {rectangle} representing deltas
@@ -1132,6 +1133,12 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
1132
1133
  this.height += r.height || 0;
1133
1134
  return this;
1134
1135
  },
1136
+ moveAroundPoint: function (origin, angle) {
1137
+ const newCenter = this.center().rotate(origin, angle);
1138
+ this.x = newCenter.x - this.width / 2;
1139
+ this.y = newCenter.y - this.height / 2;
1140
+ return this;
1141
+ },
1135
1142
  // Normalize the rectangle; i.e., make it so that it has a non-negative width and height.
1136
1143
  // If width < 0 the function swaps the left and right corners,
1137
1144
  // and it swaps the top and bottom corners if height < 0
@@ -1203,14 +1210,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
1203
1210
  f = 1000;
1204
1211
  break;
1205
1212
  default:
1206
- f = pow$2(10, precision);
1213
+ f = pow$1(10, precision);
1207
1214
  break;
1208
1215
  }
1209
1216
  }
1210
- this.x = round$3(this.x * f) / f;
1211
- this.y = round$3(this.y * f) / f;
1212
- this.width = round$3(this.width * f) / f;
1213
- this.height = round$3(this.height * f) / f;
1217
+ this.x = round(this.x * f) / f;
1218
+ this.y = round(this.y * f) / f;
1219
+ this.width = round(this.width * f) / f;
1220
+ this.height = round(this.height * f) / f;
1214
1221
  return this;
1215
1222
  },
1216
1223
  // Scale rectangle with origin.
@@ -1800,8 +1807,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
1800
1807
  }
1801
1808
  return this;
1802
1809
  },
1803
- simplify: function () {
1804
- let opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1810
+ simplify: function (opt = {}) {
1805
1811
  const points = this.points;
1806
1812
  if (points.length < 3) return this; // we need at least 3 points
1807
1813
 
@@ -1948,11 +1954,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
1948
1954
  });
1949
1955
 
1950
1956
  const {
1951
- abs: abs$2,
1952
- sqrt: sqrt$2,
1953
- min: min$3,
1954
- max: max$3,
1955
- pow: pow$3
1957
+ abs,
1958
+ sqrt,
1959
+ min,
1960
+ max,
1961
+ pow
1956
1962
  } = Math;
1957
1963
  const Curve = function (p1, p2, p3, p4) {
1958
1964
  if (!(this instanceof Curve)) {
@@ -2101,9 +2107,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2101
2107
  a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
2102
2108
  c = 3 * y1 - 3 * y0;
2103
2109
  }
2104
- if (abs$2(a) < 1e-12) {
2110
+ if (abs(a) < 1e-12) {
2105
2111
  // Numerical robustness
2106
- if (abs$2(b) < 1e-12) {
2112
+ if (abs(b) < 1e-12) {
2107
2113
  // Numerical robustness
2108
2114
  continue;
2109
2115
  }
@@ -2112,7 +2118,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2112
2118
  continue;
2113
2119
  }
2114
2120
  b2ac = b * b - 4 * c * a;
2115
- sqrtb2ac = sqrt$2(b2ac);
2121
+ sqrtb2ac = sqrt(b2ac);
2116
2122
  if (b2ac < 0) continue;
2117
2123
  t1 = (-b + sqrtb2ac) / (2 * a);
2118
2124
  if (0 < t1 && t1 < 1) tvalues.push(t1);
@@ -2153,10 +2159,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2153
2159
  bounds[0].length = jlen + 2;
2154
2160
  bounds[1].length = jlen + 2;
2155
2161
  points.length = jlen + 2;
2156
- var left = min$3.apply(null, bounds[0]);
2157
- var top = min$3.apply(null, bounds[1]);
2158
- var right = max$3.apply(null, bounds[0]);
2159
- var bottom = max$3.apply(null, bounds[1]);
2162
+ var left = min.apply(null, bounds[0]);
2163
+ var top = min.apply(null, bounds[1]);
2164
+ var right = max.apply(null, bounds[0]);
2165
+ var bottom = max.apply(null, bounds[1]);
2160
2166
  return new Rect(left, top, right - left, bottom - top);
2161
2167
  },
2162
2168
  clone: function () {
@@ -2230,7 +2236,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2230
2236
  minSumDist = sumDist;
2231
2237
  }
2232
2238
  }
2233
- var precisionRatio = pow$3(10, -precision);
2239
+ var precisionRatio = pow(10, -precision);
2234
2240
 
2235
2241
  // recursively divide investigated subdivision:
2236
2242
  // until distance between baselinePoint and closest path endpoint is within 10^(-precision)
@@ -2241,8 +2247,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2241
2247
  // - note that this function is not monotonic = it doesn't converge stably but has "teeth"
2242
2248
  // - the function decreases while one of the endpoints is fixed but "jumps" whenever we switch
2243
2249
  // - this criterion works well for points lying far away from the curve
2244
- var startPrecisionRatio = distFromStart ? abs$2(distFromStart - distFromEnd) / distFromStart : 0;
2245
- var endPrecisionRatio = distFromEnd ? abs$2(distFromStart - distFromEnd) / distFromEnd : 0;
2250
+ var startPrecisionRatio = distFromStart ? abs(distFromStart - distFromEnd) / distFromStart : 0;
2251
+ var endPrecisionRatio = distFromEnd ? abs(distFromStart - distFromEnd) / distFromEnd : 0;
2246
2252
  var hasRequiredPrecision = startPrecisionRatio < precisionRatio || endPrecisionRatio < precisionRatio;
2247
2253
 
2248
2254
  // check if we have reached at least one required minimal distance
@@ -2409,7 +2415,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2409
2415
  var isPoint = !this.isDifferentiable();
2410
2416
  if (isPoint) return subdivisions;
2411
2417
  var previousLength = this.endpointDistance();
2412
- var precisionRatio = pow$3(10, -precision);
2418
+ var precisionRatio = pow(10, -precision);
2413
2419
 
2414
2420
  // special case #2: sine-like curves may have the same observed length in iteration 0 and 1 - skip iteration 1
2415
2421
  // - not a problem for further iterations because cubic curves cannot have more than two local extrema
@@ -2641,7 +2647,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2641
2647
  // e.g. at precision 1, the length may be underestimated by up to 10% and cause this function to return 1
2642
2648
 
2643
2649
  var curveLength = this.length(localOpt);
2644
- var precisionRatio = pow$3(10, -precision);
2650
+ var precisionRatio = pow(10, -precision);
2645
2651
 
2646
2652
  // recursively divide investigated subdivision:
2647
2653
  // until distance between baselinePoint and closest path endpoint is within 10^(-precision)
@@ -2776,6 +2782,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
2776
2782
  }
2777
2783
 
2778
2784
  // Accepts path data string, array of segments, array of Curves and/or Lines, or a Polyline.
2785
+ // Path created is not guaranteed to be a valid (serializable) path (might not start with an M).
2779
2786
  const Path = function (arg) {
2780
2787
  if (!(this instanceof Path)) {
2781
2788
  return new Path(arg);
@@ -5080,8 +5087,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5080
5087
  }
5081
5088
  });
5082
5089
  }
5083
- function _polylineWithLine(polyline, line) {
5084
- let opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
5090
+ function _polylineWithLine(polyline, line, opt = {}) {
5085
5091
  const {
5086
5092
  interior = false
5087
5093
  } = opt;
@@ -5114,8 +5120,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5114
5120
  }
5115
5121
  return false;
5116
5122
  }
5117
- function _polylineWithEllipse(polyline, ellipse) {
5118
- let opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
5123
+ function _polylineWithEllipse(polyline, ellipse, opt = {}) {
5119
5124
  const {
5120
5125
  start,
5121
5126
  end,
@@ -5168,8 +5173,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5168
5173
  }
5169
5174
  });
5170
5175
  }
5171
- function _polylineWithPolyline(polyline1, polyline2) {
5172
- let opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
5176
+ function _polylineWithPolyline(polyline1, polyline2, opt = {}) {
5173
5177
  const {
5174
5178
  interior = false
5175
5179
  } = opt;
@@ -5261,80 +5265,336 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5261
5265
  return m[0][0] * m[1][1] * m[2][2] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][2] * m[1][1] * m[2][0];
5262
5266
  }
5263
5267
 
5264
- var _intersection = ({
5268
+ var _intersection = {
5269
+ __proto__: null,
5270
+ ellipseWithEllipse: ellipseWithEllipse,
5271
+ ellipseWithLine: ellipseWithLine,
5265
5272
  exists: exists,
5266
5273
  lineWithLine: lineWithLine,
5267
- ellipseWithLine: ellipseWithLine,
5268
- ellipseWithEllipse: ellipseWithEllipse,
5269
- rectWithLine: rectWithLine,
5270
- rectWithEllipse: rectWithEllipse,
5271
- rectWithRect: rectWithRect,
5272
- polylineWithLine: polylineWithLine,
5273
- polylineWithEllipse: polylineWithEllipse,
5274
- polylineWithRect: polylineWithRect,
5275
- polylineWithPolyline: polylineWithPolyline,
5276
- polygonWithLine: polygonWithLine,
5277
- polygonWithEllipse: polygonWithEllipse,
5278
- polygonWithRect: polygonWithRect,
5279
- polygonWithPolyline: polygonWithPolyline,
5280
- polygonWithPolygon: polygonWithPolygon,
5281
- pathWithLine: pathWithLine,
5282
5274
  pathWithEllipse: pathWithEllipse,
5283
- pathWithRect: pathWithRect,
5284
- pathWithPolyline: pathWithPolyline,
5275
+ pathWithLine: pathWithLine,
5276
+ pathWithPath: pathWithPath,
5285
5277
  pathWithPolygon: pathWithPolygon,
5286
- pathWithPath: pathWithPath
5287
- });
5278
+ pathWithPolyline: pathWithPolyline,
5279
+ pathWithRect: pathWithRect,
5280
+ polygonWithEllipse: polygonWithEllipse,
5281
+ polygonWithLine: polygonWithLine,
5282
+ polygonWithPolygon: polygonWithPolygon,
5283
+ polygonWithPolyline: polygonWithPolyline,
5284
+ polygonWithRect: polygonWithRect,
5285
+ polylineWithEllipse: polylineWithEllipse,
5286
+ polylineWithLine: polylineWithLine,
5287
+ polylineWithPolyline: polylineWithPolyline,
5288
+ polylineWithRect: polylineWithRect,
5289
+ rectWithEllipse: rectWithEllipse,
5290
+ rectWithLine: rectWithLine,
5291
+ rectWithRect: rectWithRect
5292
+ };
5288
5293
 
5289
5294
  // Geometry library.
5295
+ // -----------------
5296
+
5290
5297
  const intersection = _intersection;
5291
5298
 
5292
- var g = ({
5293
- intersection: intersection,
5294
- scale: scale,
5295
- normalizeAngle: normalizeAngle,
5296
- snapToGrid: snapToGrid,
5297
- toDeg: toDeg,
5298
- toRad: toRad,
5299
- random: random,
5300
- bezier: bezier,
5299
+ var g = {
5300
+ __proto__: null,
5301
5301
  Curve: Curve,
5302
5302
  Ellipse: Ellipse,
5303
- ellipse: ellipse,
5304
5303
  Line: Line,
5305
- line: line,
5306
5304
  Path: Path,
5307
5305
  Point: Point,
5308
- point: point,
5309
- Polyline: Polyline,
5310
5306
  Polygon: Polygon,
5307
+ Polyline: Polyline,
5311
5308
  Rect: Rect,
5309
+ bezier: bezier,
5310
+ ellipse: ellipse,
5311
+ intersection: intersection,
5312
+ line: line,
5313
+ normalizeAngle: normalizeAngle,
5314
+ point: point,
5315
+ random: random,
5312
5316
  rect: rect,
5317
+ scale: scale,
5318
+ snapToGrid: snapToGrid,
5319
+ toDeg: toDeg,
5320
+ toRad: toRad,
5313
5321
  types: types
5314
- });
5322
+ };
5323
+
5324
+ const svg = 'http://www.w3.org/2000/svg';
5325
+ const xmlns = 'http://www.w3.org/2000/xmlns/';
5326
+ const xml = 'http://www.w3.org/XML/1998/namespace';
5327
+ const xlink = 'http://www.w3.org/1999/xlink';
5328
+ const xhtml = 'http://www.w3.org/1999/xhtml';
5329
+
5330
+ var ns = {
5331
+ __proto__: null,
5332
+ svg: svg,
5333
+ xhtml: xhtml,
5334
+ xlink: xlink,
5335
+ xml: xml,
5336
+ xmlns: xmlns
5337
+ };
5338
+
5339
+ /**
5340
+ * @constant {boolean}
5341
+ * @description Indicates the environment supports SVG.
5342
+ */
5343
+ const isSVGSupported = typeof window === 'object' && !!window.SVGAngle;
5344
+
5345
+ /**
5346
+ * @constant {string}
5347
+ * @description The version of the SVG document.
5348
+ */
5349
+ const SVG_VERSION = '1.1';
5350
+
5351
+ /**
5352
+ * @constant {SVGSVGElement}
5353
+ * @description The detached SVG document for various internal purposes.
5354
+ * e.g. SVGMatrix has no constructor, so the only way to create it is
5355
+ * to create an SVG document and then call `createSVGMatrix()`.
5356
+ */
5357
+ const internalSVGDocument = isSVGSupported ? createSVGDocument() : null;
5358
+
5359
+ /**
5360
+ * @constant {SVGGElement}
5361
+ * @description The detached SVG group element for various internal purposes.
5362
+ */
5363
+ const internalSVGGroup = isSVGSupported ? createSVGElement('g') : null;
5364
+
5365
+ /**
5366
+ * @returns {SVGSVGElement}
5367
+ * @description Creates an SVG document.
5368
+ */
5369
+ function createSVGDocument() {
5370
+ const svg = createSVGElement('svg');
5371
+ svg.setAttributeNS(xmlns, 'xmlns:xlink', xlink);
5372
+ svg.setAttribute('version', SVG_VERSION);
5373
+ return svg;
5374
+ }
5375
+
5376
+ /**
5377
+ * @param {string} name
5378
+ * @returns {SVGElement}
5379
+ * @description Creates an SVG element with the given name.
5380
+ */
5381
+ function createSVGElement(name) {
5382
+ return document.createElementNS(svg, name);
5383
+ }
5384
+
5385
+ /**
5386
+ * @param {SVGElement} node1
5387
+ * @param {SVGElement} node2
5388
+ * @returns {SVGElement|null}
5389
+ * @description Finds the common ancestor node of two nodes.
5390
+ */
5391
+ function getCommonAncestor(node1, node2) {
5392
+ // Find the common ancestor node of two nodes.
5393
+ let parent = node1;
5394
+ do {
5395
+ if (parent.contains(node2)) return parent;
5396
+ parent = parent.parentNode;
5397
+ } while (parent);
5398
+ return null;
5399
+ }
5400
+
5401
+ /**
5402
+ * @returns {SVGMatrix}
5403
+ * @description Creates an identity matrix.
5404
+ */
5405
+ function createIdentityMatrix() {
5406
+ return internalSVGDocument.createSVGMatrix();
5407
+ }
5408
+
5409
+ /**
5410
+ * @param {Partial<SVGMatrix>} matrixInit
5411
+ * @returns {SVGMatrix}
5412
+ * @description Creates a new SVGMatrix object.
5413
+ * If no matrix is provided, it returns the identity matrix.
5414
+ * If a matrix like object is provided, it sets the matrix values.
5415
+ */
5416
+ function createMatrix(matrixInit = {}) {
5417
+ const matrix = internalSVGDocument.createSVGMatrix();
5418
+ if (!matrixInit) return matrix;
5419
+ if ('a' in matrixInit) matrix.a = matrixInit.a;
5420
+ if ('b' in matrixInit) matrix.b = matrixInit.b;
5421
+ if ('c' in matrixInit) matrix.c = matrixInit.c;
5422
+ if ('d' in matrixInit) matrix.d = matrixInit.d;
5423
+ if ('e' in matrixInit) matrix.e = matrixInit.e;
5424
+ if ('f' in matrixInit) matrix.f = matrixInit.f;
5425
+ return matrix;
5426
+ }
5427
+
5428
+ /**
5429
+ * @returns {SVGTransform}
5430
+ * @description Creates a new SVGTransform object.
5431
+ */
5432
+ function createSVGTransform() {
5433
+ return internalSVGDocument.createSVGTransform();
5434
+ }
5435
+
5436
+ /**
5437
+ * @param {SVGElement} node
5438
+ * @returns {SVGMatrix|null}
5439
+ * @description Returns the transformation matrix of the given node.
5440
+ * If the node has no transformation, it returns null.
5441
+ */
5442
+ function getNodeMatrix(node) {
5443
+ const consolidatedTransformation = node.transform.baseVal.consolidate();
5444
+ return consolidatedTransformation ? consolidatedTransformation.matrix : null;
5445
+ }
5446
+
5447
+ /**
5448
+ * @param {string} transformString
5449
+ * @returns {SVGMatrix}
5450
+ * @description Creates a matrix from the given transform string.
5451
+ */
5452
+ function createMatrixFromTransformString(transformString) {
5453
+ internalSVGGroup.setAttribute('transform', transformString);
5454
+ return getNodeMatrix(internalSVGGroup);
5455
+ }
5456
+
5457
+ /**
5458
+ * @param {SVGElement} node
5459
+ * @param {Partial<SVGMatrix>} matrixInit
5460
+ * @param {boolean} override
5461
+ * @description Sets the transformation matrix of the given node.
5462
+ * We don't use `node.transform.baseVal` here (@see `transformNode`)
5463
+ * for the following reasons:
5464
+ * - Performance: while Chrome performs slightly better, Firefox
5465
+ * and Safari are significantly slower
5466
+ * https://www.measurethat.net/Benchmarks/Show/34447/1/overriding-svg-transform-attribute
5467
+ * - Limited support: JSDOM does not support `node.transform.baseVal`
5468
+ */
5469
+ function replaceTransformNode(node, matrixInit) {
5470
+ node.setAttribute('transform', matrixToTransformString(matrixInit));
5471
+ }
5472
+
5473
+ /**
5474
+ * @param {SVGElement} node
5475
+ * @param {Partial<SVGMatrix>} matrixInit
5476
+ * @description Applies a transformation matrix to the given node.
5477
+ * If the node already has a transformation, it appends the new transformation.
5478
+ * If the node has no transformation, it creates a new one.
5479
+ */
5480
+ function transformNode(node, matrixInit) {
5481
+ const transform = createSVGTransform();
5482
+ const matrix = isSVGMatrix(matrixInit) ? matrixInit : createMatrix(matrixInit);
5483
+ transform.setMatrix(matrix);
5484
+ node.transform.baseVal.appendItem(transform);
5485
+ }
5486
+ const MATRIX_TYPE = '[object SVGMatrix]';
5487
+
5488
+ /**
5489
+ * @param {any} obj
5490
+ * @returns {boolean}
5491
+ * @description Checks if the given object is an SVGMatrix.
5492
+ */
5493
+ function isSVGMatrix(obj) {
5494
+ return Object.prototype.toString.call(obj) === MATRIX_TYPE;
5495
+ }
5496
+
5497
+ /**
5498
+ * @param {Partial<SVGMatrix>} matrixInit
5499
+ * @returns {string}
5500
+ * @description Converts a matrix to a transform string.
5501
+ * If no matrix is provided, it returns the identity matrix string.
5502
+ */
5503
+ function matrixToTransformString(matrixInit = {}) {
5504
+ const {
5505
+ a = 1,
5506
+ b = 0,
5507
+ c = 0,
5508
+ d = 1,
5509
+ e = 0,
5510
+ f = 0
5511
+ } = matrixInit;
5512
+ return `matrix(${a},${b},${c},${d},${e},${f})`;
5513
+ }
5514
+
5515
+ /**
5516
+ *
5517
+ * @param {SVGElement} a
5518
+ * @param {SVGElement} b
5519
+ * @returns {SVGMatrix|null}
5520
+ * @description Finds the transformation matrix from `a` to `b`.
5521
+ * It requires that both elements to be visible (in the render tree)
5522
+ * in order to calculate the correct transformation matrix.
5523
+ */
5524
+ function getRelativeTransformation(a, b) {
5525
+ // Different SVG elements, no transformation possible
5526
+ // Note: SVGSVGElement has no `ownerSVGElement`
5527
+ if ((a.ownerSVGElement || a) !== (b.ownerSVGElement || b)) return null;
5528
+ // Get the transformation matrix from `a` to `b`.
5529
+ const am = b.getScreenCTM();
5530
+ if (!am) return null;
5531
+ const bm = a.getScreenCTM();
5532
+ if (!bm) return null;
5533
+ return am.inverse().multiply(bm);
5534
+ }
5535
+
5536
+ /**
5537
+ * @param {SVGElement} a
5538
+ * @param {SVGElement} b
5539
+ * @returns {SVGMatrix|null}
5540
+ * @description Finds the transformation matrix from `a` to `b`.
5541
+ * A safe way to calculate the transformation matrix between two elements.
5542
+ * It does not require the elements to be visible (in the render tree).
5543
+ */
5544
+ function getRelativeTransformationSafe(a, b) {
5545
+ if (a === b) {
5546
+ // No transformation needed
5547
+ return createIdentityMatrix();
5548
+ }
5549
+ const position = a.compareDocumentPosition(b);
5550
+ if (position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
5551
+ // `b` is a descendant of `a`
5552
+ return getLinealTransformation(a, b).inverse();
5553
+ } else if (position & Node.DOCUMENT_POSITION_CONTAINS) {
5554
+ // `a` is a descendant of `b`
5555
+ return getLinealTransformation(b, a);
5556
+ }
5557
+ const c = getCommonAncestor(a, b);
5558
+ if (!c) {
5559
+ // No common ancestor
5560
+ return null;
5561
+ }
5562
+ const mca = getLinealTransformation(c, a);
5563
+ const mcb = getLinealTransformation(c, b);
5564
+ return mcb.inverse().multiply(mca);
5565
+ }
5566
+
5567
+ /**
5568
+ * @param {SVGElement} descendant
5569
+ * @param {SVGElement} ancestor
5570
+ * @returns {SVGMatrix}
5571
+ * @description Finds the transformation matrix between the `ancestor` and `descendant`.
5572
+ */
5573
+ function getLinealTransformation(ancestor, descendant) {
5574
+ const transformations = [];
5575
+ let n = descendant;
5576
+ while (n && n.nodeType === Node.ELEMENT_NODE && n !== ancestor) {
5577
+ const nm = getNodeMatrix(n);
5578
+ if (nm) {
5579
+ transformations.unshift(nm);
5580
+ }
5581
+ n = n.parentNode;
5582
+ }
5583
+ return transformations.reduce((m, t) => m.multiply(t), createIdentityMatrix());
5584
+ }
5315
5585
 
5316
5586
  // Vectorizer.
5317
- const V = function () {
5318
- var hasSvg = typeof window === 'object' && !!window.SVGAngle;
5587
+ // -----------
5319
5588
 
5589
+ const V = function () {
5320
5590
  // SVG support is required.
5321
- if (!hasSvg) {
5591
+ if (!isSVGSupported) {
5322
5592
  // Return a function that throws an error when it is used.
5323
5593
  return function () {
5324
5594
  throw new Error('SVG is required to use Vectorizer.');
5325
5595
  };
5326
5596
  }
5327
5597
 
5328
- // XML namespaces.
5329
- var ns = {
5330
- svg: 'http://www.w3.org/2000/svg',
5331
- xmlns: 'http://www.w3.org/2000/xmlns/',
5332
- xml: 'http://www.w3.org/XML/1998/namespace',
5333
- xlink: 'http://www.w3.org/1999/xlink',
5334
- xhtml: 'http://www.w3.org/1999/xhtml'
5335
- };
5336
- var SVGVersion = '1.1';
5337
-
5338
5598
  // Declare shorthands to the most used math functions.
5339
5599
  var math = Math;
5340
5600
  var PI = math.PI;
@@ -5379,7 +5639,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5379
5639
  }
5380
5640
  el = document.importNode(svgDoc.firstChild, true);
5381
5641
  } else {
5382
- el = document.createElementNS(ns.svg, el);
5642
+ el = createSVGElement(el);
5383
5643
  }
5384
5644
  V.ensureId(el);
5385
5645
  }
@@ -5402,20 +5662,25 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5402
5662
  });
5403
5663
 
5404
5664
  /**
5405
- * @param {SVGGElement} toElem
5406
- * @returns {SVGMatrix}
5665
+ * Calculates the transformation matrix from this element to the target element.
5666
+ * @param {SVGElement|V} target - The target element.
5667
+ * @param {Object} [opt] - Options object for transformation calculation.
5668
+ * @param {boolean} [opt.safe] - Use a safe traversal method to compute the matrix.
5669
+ * @returns {DOMMatrix} The transformation matrix from this element to the target element.
5407
5670
  */
5408
- VPrototype.getTransformToElement = function (target) {
5409
- var node = this.node;
5410
- if (V.isSVGGraphicsElement(target) && V.isSVGGraphicsElement(node)) {
5411
- var targetCTM = V.toNode(target).getScreenCTM();
5412
- var nodeCTM = node.getScreenCTM();
5413
- if (targetCTM && nodeCTM) {
5414
- return targetCTM.inverse().multiply(nodeCTM);
5671
+ VPrototype.getTransformToElement = function (target, opt) {
5672
+ const node = this.node;
5673
+ const targetNode = V.toNode(target);
5674
+ let m;
5675
+ if (V.isSVGGraphicsElement(targetNode) && V.isSVGGraphicsElement(node)) {
5676
+ if (opt && opt.safe) {
5677
+ // Use the traversal method to get the transformation matrix.
5678
+ m = getRelativeTransformationSafe(node, targetNode);
5679
+ } else {
5680
+ m = getRelativeTransformation(node, targetNode);
5415
5681
  }
5416
5682
  }
5417
- // Could not get actual transformation matrix
5418
- return V.createSVGMatrix();
5683
+ return m || createIdentityMatrix();
5419
5684
  };
5420
5685
 
5421
5686
  /**
@@ -5424,15 +5689,19 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5424
5689
  * @returns {Vectorizer|SVGMatrix} Setter / Getter
5425
5690
  */
5426
5691
  VPrototype.transform = function (matrix, opt) {
5427
- var node = this.node;
5692
+ const node = this.node;
5693
+
5694
+ // Getter
5428
5695
  if (V.isUndefined(matrix)) {
5429
- return V.transformStringToMatrix(this.attr('transform'));
5696
+ return getNodeMatrix(node) || createIdentityMatrix();
5430
5697
  }
5698
+
5699
+ // Setter
5431
5700
  if (opt && opt.absolute) {
5432
- return this.attr('transform', V.matrixToTransformString(matrix));
5701
+ replaceTransformNode(node, matrix);
5702
+ } else {
5703
+ transformNode(node, matrix);
5433
5704
  }
5434
- var svgTransform = V.createSVGTransform(matrix);
5435
- node.transform.baseVal.appendItem(svgTransform);
5436
5705
  return this;
5437
5706
  };
5438
5707
  VPrototype.translate = function (tx, ty, opt) {
@@ -5506,7 +5775,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5506
5775
  }
5507
5776
  try {
5508
5777
  box = node.getBBox();
5509
- } catch (e) {
5778
+ } catch {
5510
5779
  // Fallback for IE.
5511
5780
  box = {
5512
5781
  x: node.clientLeft,
@@ -5552,7 +5821,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5552
5821
  if (!options.recursive) {
5553
5822
  try {
5554
5823
  outputBBox = node.getBBox();
5555
- } catch (e) {
5824
+ } catch {
5556
5825
  // Fallback for IE.
5557
5826
  outputBBox = {
5558
5827
  x: node.clientLeft,
@@ -5730,11 +5999,18 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5730
5999
  }
5731
6000
  VPrototype.text = function (content, opt) {
5732
6001
  if (content && typeof content !== 'string') throw new Error('Vectorizer: text() expects the first argument to be a string.');
5733
-
5734
- // Replace all spaces with the Unicode No-break space (http://www.fileformat.info/info/unicode/char/a0/index.htm).
5735
- // IE would otherwise collapse all spaces into one.
5736
- content = V.sanitizeText(content);
5737
6002
  opt || (opt = {});
6003
+
6004
+ // Backwards-compatibility: if no content was provided, treat it as an
6005
+ // empty string so that subsequent string operations (e.g. split) do
6006
+ // not throw and behaviour matches the previous implementation that
6007
+ // always sanitised the input.
6008
+ if (content == null) content = '';
6009
+ if (opt.useNoBreakSpace) {
6010
+ // Replace all spaces with the Unicode No-break space (http://www.fileformat.info/info/unicode/char/a0/index.htm).
6011
+ // IE would otherwise collapse all spaces into one.
6012
+ content = V.sanitizeText(content);
6013
+ }
5738
6014
  // Should we allow the text to be selected?
5739
6015
  var displayEmpty = opt.displayEmpty;
5740
6016
  // End of Line character
@@ -5790,7 +6066,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
5790
6066
  for (var i = 0, lastI = lines.length - 1; i <= lastI; i++) {
5791
6067
  var dy = lineHeight;
5792
6068
  var lineClassName = 'v-line';
5793
- var lineNode = doc.createElementNS(ns.svg, 'tspan');
6069
+ var lineNode = doc.createElementNS(svg, 'tspan');
5794
6070
  var line = lines[i];
5795
6071
  var lineMetrics;
5796
6072
  if (line) {
@@ -6104,9 +6380,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6104
6380
  try {
6105
6381
  var globalPoint = p.matrixTransform(svg.getScreenCTM().inverse());
6106
6382
  var globalToLocalMatrix = this.getTransformToElement(svg).inverse();
6107
- } catch (e) {
6383
+ } catch {
6108
6384
  // IE9 throws an exception in odd cases. (`Unexpected call to method or property access`)
6109
- // We have to make do with the original coordianates.
6385
+ // We have to make do with the original coordinates.
6110
6386
  return p;
6111
6387
  }
6112
6388
  return globalPoint.matrixTransform(globalToLocalMatrix);
@@ -6160,7 +6436,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6160
6436
  // 5. Apply transformations and the scale
6161
6437
  var transform = V.createSVGTransform();
6162
6438
  transform.setMatrix(translateFromOrigin.matrix.multiply(rotateAroundOrigin.matrix.multiply(translateToOrigin.matrix.multiply(ctm.scale(scale.sx, scale.sy)))));
6163
- this.attr('transform', V.matrixToTransformString(transform.matrix));
6439
+ this.attr('transform', matrixToTransformString(transform.matrix));
6164
6440
  return this;
6165
6441
  };
6166
6442
  VPrototype.animateAlongPath = function (attrs, path) {
@@ -6174,7 +6450,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6174
6450
  this.append(animateMotion);
6175
6451
  try {
6176
6452
  animateMotion.node.beginElement();
6177
- } catch (e) {
6453
+ } catch {
6178
6454
  // Fallback for IE 9.
6179
6455
  // Run the animation programmatically if FakeSmile (`http://leunen.me/fakesmile/`) present
6180
6456
  if (document.documentElement.getAttribute('smiling') === 'fake') {
@@ -6437,7 +6713,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6437
6713
  // If `content` is passed, it will be used as the SVG content of the `<svg>` root element.
6438
6714
  V.createSvgDocument = function (content) {
6439
6715
  if (content) {
6440
- const XMLString = `<svg xmlns="${ns.svg}" xmlns:xlink="${ns.xlink}" version="${SVGVersion}">${content}</svg>`;
6716
+ const XMLString = `<svg xmlns="${svg}" xmlns:xlink="${xlink}" version="${SVG_VERSION}">${content}</svg>`;
6441
6717
  const {
6442
6718
  documentElement
6443
6719
  } = V.parseXML(XMLString, {
@@ -6445,10 +6721,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6445
6721
  });
6446
6722
  return documentElement;
6447
6723
  }
6448
- const svg = document.createElementNS(ns.svg, 'svg');
6449
- svg.setAttributeNS(ns.xmlns, 'xmlns:xlink', ns.xlink);
6450
- svg.setAttribute('version', SVGVersion);
6451
- return svg;
6724
+ return createSVGDocument();
6452
6725
  };
6453
6726
  V.createSVGStyle = function (stylesheet) {
6454
6727
  const {
@@ -6457,8 +6730,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6457
6730
  type: 'text/css'
6458
6731
  }, [V.createCDATASection(stylesheet)]);
6459
6732
  return node;
6460
- }, V.createCDATASection = function () {
6461
- let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
6733
+ }, V.createCDATASection = function (data = '') {
6462
6734
  const xml = document.implementation.createDocument(null, 'xml', null);
6463
6735
  return xml.createCDATASection(data);
6464
6736
  };
@@ -6481,6 +6753,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6481
6753
  // also exposed so that the programmer can use it in case he needs to. This is useful e.g. in tests
6482
6754
  // when you want to compare the actual DOM text content without having to add the unicode character in
6483
6755
  // the place of all spaces.
6756
+ /**
6757
+ * @deprecated Use regular spaces and rely on xml:space="preserve" instead.
6758
+ */
6484
6759
  V.sanitizeText = function (text) {
6485
6760
  return (text || '').replace(/ /g, '\u00A0');
6486
6761
  };
@@ -6503,7 +6778,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6503
6778
  parser.async = opt.async;
6504
6779
  }
6505
6780
  xml = parser.parseFromString(data, 'text/xml');
6506
- } catch (error) {
6781
+ } catch {
6507
6782
  xml = undefined;
6508
6783
  }
6509
6784
  if (!xml || xml.getElementsByTagName('parsererror').length) {
@@ -6519,9 +6794,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6519
6794
 
6520
6795
  // List of attributes for which not to split camel case words.
6521
6796
  // It contains known SVG attribute names and may be extended with user-defined attribute names.
6522
- ['baseFrequency', 'baseProfile', 'clipPathUnits', 'contentScriptType', 'contentStyleType', 'diffuseConstant', 'edgeMode', 'externalResourcesRequired', 'filterRes',
6797
+ ['attributeName', 'baseFrequency', 'baseProfile', 'clipPathUnits', 'contentScriptType', 'contentStyleType', 'diffuseConstant', 'edgeMode', 'externalResourcesRequired', 'filterRes',
6523
6798
  // deprecated
6524
- 'filterUnits', 'gradientTransform', 'gradientUnits', 'kernelMatrix', 'kernelUnitLength', 'keyPoints', 'lengthAdjust', 'limitingConeAngle', 'markerHeight', 'markerUnits', 'markerWidth', 'maskContentUnits', 'maskUnits', 'numOctaves', 'pathLength', 'patternContentUnits', 'patternTransform', 'patternUnits', 'pointsAtX', 'pointsAtY', 'pointsAtZ', 'preserveAlpha', 'preserveAspectRatio', 'primitiveUnits', 'refX', 'refY', 'requiredExtensions', 'requiredFeatures', 'specularConstant', 'specularExponent', 'spreadMethod', 'startOffset', 'stdDeviation', 'stitchTiles', 'surfaceScale', 'systemLanguage', 'tableValues', 'targetX', 'targetY', 'textLength', 'viewBox', 'viewTarget',
6799
+ 'filterUnits', 'gradientTransform', 'gradientUnits', 'kernelMatrix', 'kernelUnitLength', 'keyPoints', 'lengthAdjust', 'limitingConeAngle', 'markerHeight', 'markerUnits', 'markerWidth', 'maskContentUnits', 'maskUnits', 'numOctaves', 'pathLength', 'patternContentUnits', 'patternTransform', 'patternUnits', 'pointsAtX', 'pointsAtY', 'pointsAtZ', 'preserveAlpha', 'preserveAspectRatio', 'primitiveUnits', 'refX', 'refY', 'requiredExtensions', 'requiredFeatures', 'repeatCount', 'specularConstant', 'specularExponent', 'spreadMethod', 'startOffset', 'stdDeviation', 'stitchTiles', 'surfaceScale', 'systemLanguage', 'tableValues', 'targetX', 'targetY', 'textLength', 'viewBox', 'viewTarget',
6525
6800
  // deprecated
6526
6801
  'xChannelSelector', 'yChannelSelector', 'zoomAndPan' // deprecated
6527
6802
  ].forEach(name => _attributeNames[name] = name);
@@ -6588,86 +6863,19 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6588
6863
  // ReDoS mitigation: Use an anchor at the beginning of the match
6589
6864
  // ReDoS mitigation: Avoid backtracking (uses `[^()]+` instead of `.*?`)
6590
6865
  // ReDoS mitigation: Don't match initial `(` inside repeated part
6591
- // The following regex needs to use /g (= cannot use capturing groups)
6592
- V.transformRegex = /\b\w+\([^()]+\)/g;
6593
6866
  // The following regexes need to use capturing groups (= cannot use /g)
6594
6867
  V.transformFunctionRegex = /\b(\w+)\(([^()]+)\)/;
6595
6868
  V.transformTranslateRegex = /\btranslate\(([^()]+)\)/;
6596
6869
  V.transformRotateRegex = /\brotate\(([^()]+)\)/;
6597
6870
  V.transformScaleRegex = /\bscale\(([^()]+)\)/;
6598
6871
  V.transformStringToMatrix = function (transform) {
6599
- // Initialize result matrix as identity matrix
6600
- let transformationMatrix = V.createSVGMatrix();
6601
-
6602
- // Note: Multiple transform functions are allowed in `transform` string
6603
- // `match()` returns `null` if none found
6604
- const transformMatches = transform && transform.match(V.transformRegex);
6605
- if (!transformMatches) {
6606
- // Return identity matrix
6607
- return transformationMatrix;
6608
- }
6609
- const numMatches = transformMatches.length;
6610
- for (let i = 0; i < numMatches; i++) {
6611
- const transformMatch = transformMatches[i];
6612
- // Use same regex as above, but with capturing groups
6613
- // `match()` returns values of capturing groups as `[1]`, `[2]`
6614
- const transformFunctionMatch = transformMatch.match(V.transformFunctionRegex);
6615
- if (transformFunctionMatch) {
6616
- let sx, sy, tx, ty, angle;
6617
- let ctm = V.createSVGMatrix();
6618
- const transformFunction = transformFunctionMatch[1].toLowerCase();
6619
- const args = transformFunctionMatch[2].split(V.transformSeparatorRegex);
6620
- switch (transformFunction) {
6621
- case 'scale':
6622
- sx = parseFloat(args[0]);
6623
- sy = args[1] === undefined ? sx : parseFloat(args[1]);
6624
- ctm = ctm.scaleNonUniform(sx, sy);
6625
- break;
6626
- case 'translate':
6627
- tx = parseFloat(args[0]);
6628
- ty = parseFloat(args[1]);
6629
- ctm = ctm.translate(tx, ty);
6630
- break;
6631
- case 'rotate':
6632
- angle = parseFloat(args[0]);
6633
- tx = parseFloat(args[1]) || 0;
6634
- ty = parseFloat(args[2]) || 0;
6635
- if (tx !== 0 || ty !== 0) {
6636
- ctm = ctm.translate(tx, ty).rotate(angle).translate(-tx, -ty);
6637
- } else {
6638
- ctm = ctm.rotate(angle);
6639
- }
6640
- break;
6641
- case 'skewx':
6642
- angle = parseFloat(args[0]);
6643
- ctm = ctm.skewX(angle);
6644
- break;
6645
- case 'skewy':
6646
- angle = parseFloat(args[0]);
6647
- ctm = ctm.skewY(angle);
6648
- break;
6649
- case 'matrix':
6650
- ctm.a = parseFloat(args[0]);
6651
- ctm.b = parseFloat(args[1]);
6652
- ctm.c = parseFloat(args[2]);
6653
- ctm.d = parseFloat(args[3]);
6654
- ctm.e = parseFloat(args[4]);
6655
- ctm.f = parseFloat(args[5]);
6656
- break;
6657
- default:
6658
- continue;
6659
- }
6660
-
6661
- // Multiply current transformation into result matrix
6662
- transformationMatrix = transformationMatrix.multiply(ctm);
6663
- }
6872
+ let matrix;
6873
+ if (V.isString(transform)) {
6874
+ matrix = createMatrixFromTransformString(transform);
6664
6875
  }
6665
- return transformationMatrix;
6666
- };
6667
- V.matrixToTransformString = function (matrix) {
6668
- matrix || (matrix = true);
6669
- return 'matrix(' + (matrix.a !== undefined ? matrix.a : 1) + ',' + (matrix.b !== undefined ? matrix.b : 0) + ',' + (matrix.c !== undefined ? matrix.c : 0) + ',' + (matrix.d !== undefined ? matrix.d : 1) + ',' + (matrix.e !== undefined ? matrix.e : 0) + ',' + (matrix.f !== undefined ? matrix.f : 0) + ')';
6876
+ return matrix || createIdentityMatrix();
6670
6877
  };
6878
+ V.matrixToTransformString = matrixToTransformString;
6671
6879
  V.parseTransformString = function (transform) {
6672
6880
  var translate, rotate, scale;
6673
6881
  if (transform) {
@@ -6825,31 +7033,24 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
6825
7033
  // IE/Edge does not implement SVGGraphicsElement interface, thus check for `getScreenCTM` below
6826
7034
  return node instanceof SVGElement && typeof node.getScreenCTM === 'function';
6827
7035
  };
6828
- var svgDocument = V('svg').node;
6829
- V.createSVGMatrix = function (matrix) {
6830
- var svgMatrix = svgDocument.createSVGMatrix();
6831
- for (var component in matrix) {
6832
- svgMatrix[component] = matrix[component];
6833
- }
6834
- return svgMatrix;
6835
- };
7036
+ V.createSVGMatrix = createMatrix;
6836
7037
  V.createSVGTransform = function (matrix) {
6837
7038
  if (!V.isUndefined(matrix)) {
6838
- if (!(matrix instanceof SVGMatrix)) {
6839
- matrix = V.createSVGMatrix(matrix);
7039
+ if (!isSVGMatrix(matrix)) {
7040
+ matrix = createMatrix(matrix);
6840
7041
  }
6841
- return svgDocument.createSVGTransformFromMatrix(matrix);
7042
+ return internalSVGDocument.createSVGTransformFromMatrix(matrix);
6842
7043
  }
6843
- return svgDocument.createSVGTransform();
7044
+ return internalSVGDocument.createSVGTransform();
6844
7045
  };
6845
7046
  V.createSVGPoint = function (x, y) {
6846
- var p = svgDocument.createSVGPoint();
7047
+ var p = internalSVGDocument.createSVGPoint();
6847
7048
  p.x = x;
6848
7049
  p.y = y;
6849
7050
  return p;
6850
7051
  };
6851
7052
  V.transformRect = function (r, matrix) {
6852
- var p = svgDocument.createSVGPoint();
7053
+ var p = internalSVGDocument.createSVGPoint();
6853
7054
  p.x = r.x;
6854
7055
  p.y = r.y;
6855
7056
  var corner1 = p.matrixTransform(matrix);
@@ -7041,7 +7242,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
7041
7242
  };
7042
7243
  V.convertLineToPathData = function (line) {
7043
7244
  line = V(line);
7044
- var d = ['M', line.attr('x1'), line.attr('y1'), 'L', line.attr('x2'), line.attr('y2')].join(' ');
7245
+ var d = ['M', line.attr('x1') || '0', line.attr('y1') || '0', 'L', line.attr('x2') || '0', line.attr('y2') || '0'].join(' ');
7045
7246
  return d;
7046
7247
  };
7047
7248
  V.convertPolygonToPathData = function (polygon) {
@@ -7451,10 +7652,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
7451
7652
  case 'V':
7452
7653
  path = ['L'].concat(d.x, path[1]);
7453
7654
  break;
7454
- case 'L':
7455
- break;
7456
- case 'Z':
7457
- break;
7458
7655
  }
7459
7656
  return path;
7460
7657
  }
@@ -7509,7 +7706,20 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
7509
7706
  return normalize(pathData).join(',').split(',').join(' ');
7510
7707
  };
7511
7708
  }();
7512
- V.namespace = ns;
7709
+
7710
+ /**
7711
+ *
7712
+ * @param {SVGElement|V} node1
7713
+ * @param {SVGElement|V} node2
7714
+ * @returns {SVGElement|null}
7715
+ */
7716
+ V.getCommonAncestor = function (node1, node2) {
7717
+ if (!node1 || !node2) return null;
7718
+ return getCommonAncestor(V.toNode(node1), V.toNode(node2));
7719
+ };
7720
+ V.namespace = {
7721
+ ...ns
7722
+ };
7513
7723
  V.g = g;
7514
7724
  return V;
7515
7725
  }();