modern-path2d 0.1.9 → 0.1.11

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/dist/index.mjs CHANGED
@@ -1,3 +1,31 @@
1
+ const lineJoinMap = {
2
+ "arcs": "bevel",
3
+ "bevel": "bevel",
4
+ "miter": "miter",
5
+ "miter-clip": "miter",
6
+ "round": "round"
7
+ };
8
+ function setCanvasContextByPath(ctx, path) {
9
+ const {
10
+ fill = "#000",
11
+ stroke = "none",
12
+ strokeWidth = stroke === "none" ? 0 : 1,
13
+ strokeLinecap = "round",
14
+ strokeLinejoin = "miter",
15
+ strokeMiterlimit = 0,
16
+ strokeDasharray,
17
+ strokeDashoffset = 0
18
+ } = path.style;
19
+ ctx.fillStyle = fill;
20
+ ctx.strokeStyle = stroke;
21
+ ctx.lineWidth = strokeWidth;
22
+ ctx.lineCap = strokeLinecap;
23
+ ctx.lineJoin = lineJoinMap[strokeLinejoin];
24
+ ctx.miterLimit = strokeMiterlimit;
25
+ ctx.lineDashOffset = strokeDashoffset;
26
+ strokeDasharray && ctx.setLineDash(strokeDasharray);
27
+ }
28
+
1
29
  class Vector2 {
2
30
  constructor(x = 0, y = 0) {
3
31
  this.x = x;
@@ -382,221 +410,175 @@ function parseArcCommand(path, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, s
382
410
  const cy = Math.sin(xAxisRotation) * cxp + Math.cos(xAxisRotation) * cyp + (start.y + end.y) / 2;
383
411
  const theta = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
384
412
  const delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry) % (Math.PI * 2);
385
- path.currentPath.absellipse(cx, cy, rx, ry, theta, theta + delta, sweepFlag === 0, xAxisRotation);
413
+ path.ellipse(cx, cy, rx, ry, xAxisRotation, theta, theta + delta, sweepFlag === 1);
386
414
  }
387
415
 
388
416
  function getReflection(a, b) {
389
417
  return a - (b - a);
390
418
  }
391
419
  function addPathCommandsToPath2D(commands, path) {
392
- const point = new Vector2();
420
+ const current = new Vector2();
393
421
  const control = new Vector2();
394
- const firstPoint = new Vector2();
395
- let isFirstPoint = true;
396
- let doSetFirstPoint = false;
397
422
  for (let i = 0, l = commands.length; i < l; i++) {
398
- const command = commands[i];
399
- if (isFirstPoint) {
400
- doSetFirstPoint = true;
401
- isFirstPoint = false;
402
- }
403
- if (command.type === "m" || command.type === "M") {
404
- if (command.type === "m") {
405
- point.x += command.x;
406
- point.y += command.y;
423
+ const cmd = commands[i];
424
+ if (cmd.type === "m" || cmd.type === "M") {
425
+ if (cmd.type === "m") {
426
+ current.add(cmd);
407
427
  } else {
408
- point.x = command.x;
409
- point.y = command.y;
428
+ current.copy(cmd);
410
429
  }
411
- control.x = point.x;
412
- control.y = point.y;
413
- path.moveTo(point.x, point.y);
414
- firstPoint.copy(point);
415
- } else if (command.type === "h" || command.type === "H") {
416
- if (command.type === "h") {
417
- point.x += command.x;
430
+ path.moveTo(current.x, current.y);
431
+ control.copy(current);
432
+ } else if (cmd.type === "h" || cmd.type === "H") {
433
+ if (cmd.type === "h") {
434
+ current.x += cmd.x;
418
435
  } else {
419
- point.x = command.x;
436
+ current.x = cmd.x;
420
437
  }
421
- control.x = point.x;
422
- control.y = point.y;
423
- path.lineTo(point.x, point.y);
424
- if (doSetFirstPoint)
425
- firstPoint.copy(point);
426
- } else if (command.type === "v" || command.type === "V") {
427
- if (command.type === "v") {
428
- point.y += command.y;
438
+ path.lineTo(current.x, current.y);
439
+ control.copy(current);
440
+ } else if (cmd.type === "v" || cmd.type === "V") {
441
+ if (cmd.type === "v") {
442
+ current.y += cmd.y;
429
443
  } else {
430
- point.y = command.y;
444
+ current.y = cmd.y;
431
445
  }
432
- control.x = point.x;
433
- control.y = point.y;
434
- path.lineTo(point.x, point.y);
435
- if (doSetFirstPoint)
436
- firstPoint.copy(point);
437
- } else if (command.type === "l" || command.type === "L") {
438
- if (command.type === "l") {
439
- point.x += command.x;
440
- point.y += command.y;
446
+ path.lineTo(current.x, current.y);
447
+ control.copy(current);
448
+ } else if (cmd.type === "l" || cmd.type === "L") {
449
+ if (cmd.type === "l") {
450
+ current.add(cmd);
441
451
  } else {
442
- point.x = command.x;
443
- point.y = command.y;
452
+ current.copy(cmd);
444
453
  }
445
- control.x = point.x;
446
- control.y = point.y;
447
- path.lineTo(point.x, point.y);
448
- if (doSetFirstPoint)
449
- firstPoint.copy(point);
450
- } else if (command.type === "c" || command.type === "C") {
451
- if (command.type === "c") {
454
+ path.lineTo(current.x, current.y);
455
+ control.copy(current);
456
+ } else if (cmd.type === "c" || cmd.type === "C") {
457
+ if (cmd.type === "c") {
452
458
  path.bezierCurveTo(
453
- point.x + command.x1,
454
- point.y + command.y1,
455
- point.x + command.x2,
456
- point.y + command.y2,
457
- point.x + command.x,
458
- point.y + command.y
459
+ current.x + cmd.x1,
460
+ current.y + cmd.y1,
461
+ current.x + cmd.x2,
462
+ current.y + cmd.y2,
463
+ current.x + cmd.x,
464
+ current.y + cmd.y
459
465
  );
460
- control.x = point.x + command.x2;
461
- control.y = point.y + command.y2;
462
- point.x += command.x;
463
- point.y += command.y;
466
+ control.x = current.x + cmd.x2;
467
+ control.y = current.y + cmd.y2;
468
+ current.add(cmd);
464
469
  } else {
465
470
  path.bezierCurveTo(
466
- command.x1,
467
- command.y1,
468
- command.x2,
469
- command.y2,
470
- command.x,
471
- command.y
471
+ cmd.x1,
472
+ cmd.y1,
473
+ cmd.x2,
474
+ cmd.y2,
475
+ cmd.x,
476
+ cmd.y
472
477
  );
473
- control.x = command.x2;
474
- control.y = command.y2;
475
- point.x = command.x;
476
- point.y = command.y;
478
+ control.x = cmd.x2;
479
+ control.y = cmd.y2;
480
+ current.copy(cmd);
477
481
  }
478
- if (doSetFirstPoint)
479
- firstPoint.copy(point);
480
- } else if (command.type === "s" || command.type === "S") {
481
- if (command.type === "s") {
482
+ } else if (cmd.type === "s" || cmd.type === "S") {
483
+ if (cmd.type === "s") {
482
484
  path.bezierCurveTo(
483
- getReflection(point.x, control.x),
484
- getReflection(point.y, control.y),
485
- point.x + command.x2,
486
- point.y + command.y2,
487
- point.x + command.x,
488
- point.y + command.y
485
+ getReflection(current.x, control.x),
486
+ getReflection(current.y, control.y),
487
+ current.x + cmd.x2,
488
+ current.y + cmd.y2,
489
+ current.x + cmd.x,
490
+ current.y + cmd.y
489
491
  );
490
- control.x = point.x + command.x2;
491
- control.y = point.y + command.y2;
492
- point.x += command.x;
493
- point.y += command.y;
492
+ control.x = current.x + cmd.x2;
493
+ control.y = current.y + cmd.y2;
494
+ current.add(cmd);
494
495
  } else {
495
496
  path.bezierCurveTo(
496
- getReflection(point.x, control.x),
497
- getReflection(point.y, control.y),
498
- command.x2,
499
- command.y2,
500
- command.x,
501
- command.y
497
+ getReflection(current.x, control.x),
498
+ getReflection(current.y, control.y),
499
+ cmd.x2,
500
+ cmd.y2,
501
+ cmd.x,
502
+ cmd.y
502
503
  );
503
- control.x = command.x2;
504
- control.y = command.y2;
505
- point.x = command.x;
506
- point.y = command.y;
504
+ control.x = cmd.x2;
505
+ control.y = cmd.y2;
506
+ current.copy(cmd);
507
507
  }
508
- if (doSetFirstPoint)
509
- firstPoint.copy(point);
510
- } else if (command.type === "q" || command.type === "Q") {
511
- if (command.type === "q") {
508
+ } else if (cmd.type === "q" || cmd.type === "Q") {
509
+ if (cmd.type === "q") {
512
510
  path.quadraticCurveTo(
513
- point.x + command.x1,
514
- point.y + command.y1,
515
- point.x + command.x,
516
- point.y + command.y
511
+ current.x + cmd.x1,
512
+ current.y + cmd.y1,
513
+ current.x + cmd.x,
514
+ current.y + cmd.y
517
515
  );
518
- control.x = point.x + command.x1;
519
- control.y = point.y + command.y1;
520
- point.x += command.x;
521
- point.y += command.y;
516
+ control.x = current.x + cmd.x1;
517
+ control.y = current.y + cmd.y1;
518
+ current.add(cmd);
522
519
  } else {
523
520
  path.quadraticCurveTo(
524
- command.x1,
525
- command.y1,
526
- command.x,
527
- command.y
521
+ cmd.x1,
522
+ cmd.y1,
523
+ cmd.x,
524
+ cmd.y
528
525
  );
529
- control.x = command.x1;
530
- control.y = command.y1;
531
- point.x = command.x;
532
- point.y = command.y;
526
+ control.x = cmd.x1;
527
+ control.y = cmd.y1;
528
+ current.copy(cmd);
533
529
  }
534
- if (doSetFirstPoint)
535
- firstPoint.copy(point);
536
- } else if (command.type === "t" || command.type === "T") {
537
- const rx = getReflection(point.x, control.x);
538
- const ry = getReflection(point.y, control.y);
530
+ } else if (cmd.type === "t" || cmd.type === "T") {
531
+ const rx = getReflection(current.x, control.x);
532
+ const ry = getReflection(current.y, control.y);
539
533
  control.x = rx;
540
534
  control.y = ry;
541
- if (command.type === "t") {
535
+ if (cmd.type === "t") {
542
536
  path.quadraticCurveTo(
543
537
  rx,
544
538
  ry,
545
- point.x + command.x,
546
- point.y + command.y
539
+ current.x + cmd.x,
540
+ current.y + cmd.y
547
541
  );
548
- point.x += command.x;
549
- point.y += command.y;
542
+ current.add(cmd);
550
543
  } else {
551
544
  path.quadraticCurveTo(
552
545
  rx,
553
546
  ry,
554
- command.x,
555
- command.y
547
+ cmd.x,
548
+ cmd.y
556
549
  );
557
- point.x = command.x;
558
- point.y = command.y;
550
+ current.copy(cmd);
559
551
  }
560
- if (doSetFirstPoint)
561
- firstPoint.copy(point);
562
- } else if (command.type === "a" || command.type === "A") {
563
- if (command.type === "a") {
564
- if (command.x === 0 && command.y === 0)
552
+ } else if (cmd.type === "a" || cmd.type === "A") {
553
+ const start = current.clone();
554
+ if (cmd.type === "a") {
555
+ if (cmd.x === 0 && cmd.y === 0)
565
556
  continue;
566
- point.x += command.x;
567
- point.y += command.y;
557
+ current.add(cmd);
568
558
  } else {
569
- if (command.x === point.x && command.y === point.y)
559
+ if (current.equals(cmd))
570
560
  continue;
571
- point.x = command.x;
572
- point.y = command.y;
561
+ current.copy(cmd);
573
562
  }
574
- const start = point.clone();
575
- control.x = point.x;
576
- control.y = point.y;
563
+ control.copy(current);
577
564
  parseArcCommand(
578
565
  path,
579
- command.rx,
580
- command.ry,
581
- command.angle,
582
- command.largeArcFlag,
583
- command.sweepFlag,
566
+ cmd.rx,
567
+ cmd.ry,
568
+ cmd.angle,
569
+ cmd.largeArcFlag,
570
+ cmd.sweepFlag,
584
571
  start,
585
- point
572
+ current
586
573
  );
587
- if (doSetFirstPoint)
588
- firstPoint.copy(point);
589
- } else if (command.type === "z" || command.type === "Z") {
590
- path.currentPath.autoClose = true;
591
- if (path.currentPath.curves.length > 0) {
592
- point.copy(firstPoint);
593
- path.currentPath.currentPoint.copy(point);
594
- isFirstPoint = true;
574
+ } else if (cmd.type === "z" || cmd.type === "Z") {
575
+ if (path.startPoint) {
576
+ current.copy(path.startPoint);
595
577
  }
578
+ path.closePath();
596
579
  } else {
597
- console.warn("Unsupported commands", command);
580
+ console.warn("Unsupported commands", cmd);
598
581
  }
599
- doSetFirstPoint = false;
600
582
  }
601
583
  }
602
584
 
@@ -1187,15 +1169,15 @@ const tempTransform1$1 = new Matrix3();
1187
1169
  const tempTransform2$1 = new Matrix3();
1188
1170
  const tempV2 = new Vector2();
1189
1171
  class EllipseCurve extends Curve {
1190
- constructor(center = new Vector2(), radiusX = 1, radiusY = 1, startAngle = 0, endAngle = Math.PI * 2, clockwise = false, rotation = 0) {
1172
+ constructor(center = new Vector2(), radiusX = 1, radiusY = 1, rotation = 0, startAngle = 0, endAngle = Math.PI * 2, clockwise = false) {
1191
1173
  super();
1192
1174
  this.center = center;
1193
1175
  this.radiusX = radiusX;
1194
1176
  this.radiusY = radiusY;
1177
+ this.rotation = rotation;
1195
1178
  this.startAngle = startAngle;
1196
1179
  this.endAngle = endAngle;
1197
1180
  this.clockwise = clockwise;
1198
- this.rotation = rotation;
1199
1181
  }
1200
1182
  getPoint(t, output = new Vector2()) {
1201
1183
  const twoPi = Math.PI * 2;
@@ -1879,27 +1861,36 @@ class CurvePath extends Curve {
1879
1861
  constructor(points) {
1880
1862
  super();
1881
1863
  __publicField$1(this, "curves", []);
1864
+ __publicField$1(this, "startPoint");
1882
1865
  __publicField$1(this, "currentPoint", new Vector2());
1883
1866
  __publicField$1(this, "autoClose", false);
1884
1867
  __publicField$1(this, "_cacheLengths", []);
1885
1868
  if (points) {
1886
- this.setFromPoints(points);
1869
+ this.addPoints(points);
1887
1870
  }
1888
1871
  }
1889
1872
  addCurve(curve) {
1890
1873
  this.curves.push(curve);
1891
1874
  return this;
1892
1875
  }
1893
- closePath() {
1894
- const start = this.curves[0].getPoint(0);
1895
- const end = this.curves[this.curves.length - 1].getPoint(1);
1896
- if (!start.equals(end)) {
1897
- this.curves.push(new LineCurve(end, start));
1876
+ addPoints(points) {
1877
+ this.moveTo(points[0].x, points[0].y);
1878
+ for (let i = 1, len = points.length; i < len; i++) {
1879
+ const { x, y } = points[i];
1880
+ this.lineTo(x, y);
1898
1881
  }
1899
1882
  return this;
1900
1883
  }
1901
- getPoint(position, output = new Vector2()) {
1902
- const d = position * this.getLength();
1884
+ addCommands(commands) {
1885
+ addPathCommandsToPath2D(commands, this);
1886
+ return this;
1887
+ }
1888
+ addData(data) {
1889
+ this.addCommands(pathDataToPathCommands(data));
1890
+ return this;
1891
+ }
1892
+ getPoint(t, output = new Vector2()) {
1893
+ const d = t * this.getLength();
1903
1894
  const curveLengths = this.getCurveLengths();
1904
1895
  let i = 0;
1905
1896
  while (i < curveLengths.length) {
@@ -1964,23 +1955,28 @@ class CurvePath extends Curve {
1964
1955
  }
1965
1956
  return points;
1966
1957
  }
1967
- setFromPoints(points) {
1968
- this.moveTo(points[0].x, points[0].y);
1969
- for (let i = 1, l = points.length; i < l; i++) {
1970
- this.lineTo(points[i].x, points[i].y);
1958
+ _setCurrentPoint(point) {
1959
+ this.currentPoint.copy(point);
1960
+ if (!this.startPoint) {
1961
+ this.startPoint = this.currentPoint.clone();
1971
1962
  }
1972
1963
  return this;
1973
1964
  }
1974
- bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
1975
- this.curves.push(
1976
- new CubicBezierCurve(
1977
- this.currentPoint.clone(),
1978
- new Vector2(cp1x, cp1y),
1979
- new Vector2(cp2x, cp2y),
1980
- new Vector2(x, y)
1981
- )
1982
- );
1965
+ closePath() {
1966
+ const start = this.startPoint;
1967
+ if (start) {
1968
+ const end = this.currentPoint;
1969
+ if (!start.equals(end)) {
1970
+ this.curves.push(new LineCurve(end, start));
1971
+ this.currentPoint.copy(start);
1972
+ }
1973
+ this.startPoint = void 0;
1974
+ }
1975
+ return this;
1976
+ }
1977
+ moveTo(x, y) {
1983
1978
  this.currentPoint.set(x, y);
1979
+ this.startPoint = this.currentPoint.clone();
1984
1980
  return this;
1985
1981
  }
1986
1982
  lineTo(x, y) {
@@ -1990,64 +1986,56 @@ class CurvePath extends Curve {
1990
1986
  new Vector2(x, y)
1991
1987
  )
1992
1988
  );
1993
- this.currentPoint.set(x, y);
1994
- return this;
1995
- }
1996
- moveTo(x, y) {
1997
- this.currentPoint.set(x, y);
1989
+ this._setCurrentPoint({ x, y });
1998
1990
  return this;
1999
1991
  }
2000
- quadraticCurveTo(cpx, cpy, x, y) {
1992
+ bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
2001
1993
  this.curves.push(
2002
- new QuadraticBezierCurve(
1994
+ new CubicBezierCurve(
2003
1995
  this.currentPoint.clone(),
2004
- new Vector2(cpx, cpy),
1996
+ new Vector2(cp1x, cp1y),
1997
+ new Vector2(cp2x, cp2y),
2005
1998
  new Vector2(x, y)
2006
1999
  )
2007
2000
  );
2008
- this.currentPoint.set(x, y);
2001
+ this._setCurrentPoint({ x, y });
2009
2002
  return this;
2010
2003
  }
2011
- rect(x, y, w, h) {
2004
+ quadraticCurveTo(cpx, cpy, x, y) {
2012
2005
  this.curves.push(
2013
- new RectangularCurve(
2014
- new Vector2(x + w / 2, y + h / 2),
2015
- w / 2,
2016
- w / h
2006
+ new QuadraticBezierCurve(
2007
+ this.currentPoint.clone(),
2008
+ new Vector2(cpx, cpy),
2009
+ new Vector2(x, y)
2017
2010
  )
2018
2011
  );
2019
- this.currentPoint.set(x, y);
2012
+ this._setCurrentPoint({ x, y });
2020
2013
  return this;
2021
2014
  }
2022
- splineThru(points) {
2023
- const npts = [this.currentPoint.clone()].concat(points);
2024
- this.curves.push(new SplineCurve(npts));
2025
- this.currentPoint.copy(points[points.length - 1]);
2015
+ arc(x, y, radius, startAngle, endAngle, counterclockwise) {
2016
+ this.ellipse(x, y, radius, radius, 0, startAngle, endAngle, counterclockwise);
2026
2017
  return this;
2027
2018
  }
2028
- arc(x, y, radius, startAngle, endAngle, clockwise = false) {
2019
+ relativeArc(x, y, radius, startAngle, endAngle, counterclockwise) {
2029
2020
  const point = this.currentPoint;
2030
- this.absarc(x + point.x, y + point.y, radius, startAngle, endAngle, clockwise);
2031
- return this;
2032
- }
2033
- absarc(x, y, radius, startAngle, endAngle, clockwise = false) {
2034
- this.absellipse(x, y, radius, radius, startAngle, endAngle, clockwise);
2021
+ this.arc(x + point.x, y + point.y, radius, startAngle, endAngle, counterclockwise);
2035
2022
  return this;
2036
2023
  }
2037
- ellipse(x, y, radiusX, radiusY, startAngle, endAngle, clockwise = false, rotation = 0) {
2038
- const point = this.currentPoint;
2039
- this.absellipse(x + point.x, y + point.y, radiusX, radiusY, startAngle, endAngle, clockwise, rotation);
2024
+ // TODO
2025
+ // eslint-disable-next-line unused-imports/no-unused-vars
2026
+ arcTo(x1, y1, x2, y2, radius) {
2027
+ console.warn("Method arcTo not supported yet");
2040
2028
  return this;
2041
2029
  }
2042
- absellipse(x, y, radiusX, radiusY, startAngle, endAngle, clockwise = false, rotation = 0) {
2030
+ ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise = true) {
2043
2031
  const curve = new EllipseCurve(
2044
2032
  new Vector2(x, y),
2045
2033
  radiusX,
2046
2034
  radiusY,
2035
+ rotation,
2047
2036
  startAngle,
2048
2037
  endAngle,
2049
- clockwise,
2050
- rotation
2038
+ !counterclockwise
2051
2039
  );
2052
2040
  if (this.curves.length > 0) {
2053
2041
  const first = curve.getPoint(0);
@@ -2056,16 +2044,45 @@ class CurvePath extends Curve {
2056
2044
  }
2057
2045
  }
2058
2046
  this.curves.push(curve);
2059
- this.currentPoint.copy(curve.getPoint(1));
2047
+ this._setCurrentPoint(curve.getPoint(1));
2060
2048
  return this;
2061
2049
  }
2062
- getCommands() {
2063
- return this.curves.flatMap((curve) => curve.getCommands());
2050
+ relativeEllipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) {
2051
+ const point = this.currentPoint;
2052
+ this.ellipse(x + point.x, y + point.y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise);
2053
+ return this;
2054
+ }
2055
+ rect(x, y, w, h) {
2056
+ this.curves.push(
2057
+ new RectangularCurve(
2058
+ new Vector2(x + w / 2, y + h / 2),
2059
+ w / 2,
2060
+ w / h
2061
+ )
2062
+ );
2063
+ this._setCurrentPoint({ x, y });
2064
+ return this;
2065
+ }
2066
+ splineThru(points) {
2067
+ this.curves.push(new SplineCurve([this.currentPoint.clone()].concat(points)));
2068
+ this._setCurrentPoint(points[points.length - 1]);
2069
+ return this;
2070
+ }
2071
+ transformPoint(cb) {
2072
+ this.curves.forEach((curve) => curve.transformPoint(cb));
2073
+ return this;
2064
2074
  }
2065
2075
  getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
2066
2076
  this.curves.forEach((curve) => curve.getMinMax(min, max));
2067
2077
  return { min, max };
2068
2078
  }
2079
+ getBoundingBox() {
2080
+ const { min, max } = this.getMinMax();
2081
+ return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
2082
+ }
2083
+ getCommands() {
2084
+ return this.curves.flatMap((curve) => curve.getCommands());
2085
+ }
2069
2086
  drawTo(ctx) {
2070
2087
  const point = this.curves[0]?.getPoint(0);
2071
2088
  if (point) {
@@ -2089,6 +2106,10 @@ class CurvePath extends Curve {
2089
2106
  }
2090
2107
  }
2091
2108
 
2109
+ function toKebabCase(str) {
2110
+ return str.replace(/[^a-z0-9]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
2111
+ }
2112
+
2092
2113
  var __defProp = Object.defineProperty;
2093
2114
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2094
2115
  var __publicField = (obj, key, value) => {
@@ -2099,7 +2120,7 @@ class Path2D {
2099
2120
  constructor(path) {
2100
2121
  __publicField(this, "currentPath", new CurvePath());
2101
2122
  __publicField(this, "paths", [this.currentPath]);
2102
- __publicField(this, "userData");
2123
+ __publicField(this, "style", {});
2103
2124
  if (path) {
2104
2125
  if (path instanceof Path2D) {
2105
2126
  this.addPath(path);
@@ -2110,6 +2131,15 @@ class Path2D {
2110
2131
  }
2111
2132
  }
2112
2133
  }
2134
+ get startPoint() {
2135
+ return this.currentPath.startPoint;
2136
+ }
2137
+ get currentPoint() {
2138
+ return this.currentPath.currentPoint;
2139
+ }
2140
+ get strokeWidth() {
2141
+ return this.style.strokeWidth ?? ((this.style.stroke ?? "none") === "none" ? 0 : 1);
2142
+ }
2113
2143
  addPath(path) {
2114
2144
  if (path instanceof Path2D) {
2115
2145
  this.paths.push(...path.paths.map((v) => v.clone()));
@@ -2119,12 +2149,19 @@ class Path2D {
2119
2149
  return this;
2120
2150
  }
2121
2151
  closePath() {
2122
- this.currentPath.closePath();
2152
+ const startPoint = this.startPoint;
2153
+ if (startPoint) {
2154
+ this.currentPath.closePath();
2155
+ if (this.currentPath.curves.length > 0) {
2156
+ this.currentPath = new CurvePath().moveTo(startPoint.x, startPoint.y);
2157
+ this.paths.push(this.currentPath);
2158
+ }
2159
+ }
2123
2160
  return this;
2124
2161
  }
2125
2162
  moveTo(x, y) {
2126
2163
  const { currentPoint, curves } = this.currentPath;
2127
- if (currentPoint.x !== x || currentPoint.y !== y) {
2164
+ if (!currentPoint.equals({ x, y })) {
2128
2165
  if (curves.length) {
2129
2166
  this.currentPath = new CurvePath().moveTo(x, y);
2130
2167
  this.paths.push(this.currentPath);
@@ -2147,17 +2184,15 @@ class Path2D {
2147
2184
  return this;
2148
2185
  }
2149
2186
  arc(x, y, radius, startAngle, endAngle, counterclockwise) {
2150
- this.currentPath.absarc(x, y, radius, startAngle, endAngle, !counterclockwise);
2187
+ this.currentPath.arc(x, y, radius, startAngle, endAngle, counterclockwise);
2151
2188
  return this;
2152
2189
  }
2153
- // TODO
2154
- // eslint-disable-next-line unused-imports/no-unused-vars
2155
2190
  arcTo(x1, y1, x2, y2, radius) {
2156
- console.warn("Method arcTo not supported yet");
2191
+ this.currentPath.arcTo(x1, y1, x2, y2, radius);
2157
2192
  return this;
2158
2193
  }
2159
2194
  ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) {
2160
- this.currentPath.absellipse(x, y, radiusX, radiusY, startAngle, endAngle, !counterclockwise, rotation);
2195
+ this.currentPath.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise);
2161
2196
  return this;
2162
2197
  }
2163
2198
  rect(x, y, w, h) {
@@ -2192,56 +2227,92 @@ class Path2D {
2192
2227
  this.forEachCurve((curve) => curve.getMinMax(min, max));
2193
2228
  return { min, max };
2194
2229
  }
2195
- getBoundingBox() {
2230
+ getBoundingBox(withStrokeWidth = true) {
2196
2231
  const { min, max } = this.getMinMax();
2197
- return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
2232
+ const bbox = new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
2233
+ if (withStrokeWidth) {
2234
+ const strokeWidth = this.strokeWidth;
2235
+ bbox.left -= strokeWidth / 2;
2236
+ bbox.top -= strokeWidth / 2;
2237
+ bbox.width += strokeWidth;
2238
+ bbox.height += strokeWidth;
2239
+ }
2240
+ return bbox;
2198
2241
  }
2199
2242
  getCommands() {
2200
- return this.paths.flatMap((path) => path.curves.flatMap((curve) => curve.getCommands()));
2243
+ return this.paths.flatMap((path) => path.getCommands());
2201
2244
  }
2202
2245
  getData() {
2203
2246
  return this.paths.map((path) => path.getData()).join(" ");
2204
2247
  }
2205
- getSvgString() {
2248
+ getSvgPathXml() {
2249
+ const style = {
2250
+ ...this.style,
2251
+ fill: this.style.fill ?? "#000",
2252
+ stroke: this.style.stroke ?? "none"
2253
+ };
2254
+ const cssStyle = {};
2255
+ for (const key in style) {
2256
+ if (style[key] !== void 0) {
2257
+ cssStyle[toKebabCase(key)] = style[key];
2258
+ }
2259
+ }
2260
+ Object.assign(cssStyle, {
2261
+ "stroke-width": `${this.strokeWidth}px`
2262
+ });
2263
+ let cssText = "";
2264
+ for (const key in cssStyle) {
2265
+ if (cssStyle[key] !== void 0) {
2266
+ cssText += `${key}:${cssStyle[key]};`;
2267
+ }
2268
+ }
2269
+ return `<path d="${this.getData()}" style="${cssText}"></path>`;
2270
+ }
2271
+ getSvgXml() {
2206
2272
  const { x, y, width, height } = this.getBoundingBox();
2207
- const strokeWidth = 1;
2208
- return `<svg viewBox="${x - strokeWidth} ${y - strokeWidth} ${width + strokeWidth * 2} ${height + strokeWidth * 2}" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="currentColor" d="${this.getData()}"></path></svg>`;
2273
+ const path = this.getSvgPathXml();
2274
+ return `<svg viewBox="${x} ${y} ${width} ${height}" width="${width}px" height="${height}px" xmlns="http://www.w3.org/2000/svg">${path}</svg>`;
2209
2275
  }
2210
2276
  getSvgDataUri() {
2211
- return `data:image/svg+xml;base64,${btoa(this.getSvgString())}`;
2277
+ return `data:image/svg+xml;base64,${btoa(this.getSvgXml())}`;
2212
2278
  }
2213
2279
  drawTo(ctx) {
2280
+ const {
2281
+ fill = "#000",
2282
+ stroke = "none"
2283
+ } = this.style;
2284
+ setCanvasContextByPath(ctx, this);
2214
2285
  this.paths.forEach((path) => {
2215
2286
  path.drawTo(ctx);
2216
2287
  });
2217
- }
2218
- strokeTo(ctx) {
2219
- this.drawTo(ctx);
2220
- ctx.stroke();
2221
- }
2222
- fillTo(ctx) {
2223
- this.drawTo(ctx);
2224
- ctx.fill();
2288
+ if (fill !== "none") {
2289
+ ctx.fill();
2290
+ }
2291
+ if (stroke !== "none") {
2292
+ ctx.stroke();
2293
+ }
2225
2294
  }
2226
2295
  copy(source) {
2227
2296
  this.currentPath = source.currentPath.clone();
2228
2297
  this.paths = source.paths.map((path) => path.clone());
2229
- this.userData = source.userData;
2298
+ this.style = { ...source.style };
2230
2299
  return this;
2231
2300
  }
2232
- toCanvas(fill = true) {
2233
- const canvas = document.createElement("canvas");
2301
+ toSvg() {
2302
+ return new DOMParser().parseFromString(this.getSvgXml(), "image/svg+xml").documentElement;
2303
+ }
2304
+ toCanvas(pixelRatio = 2) {
2234
2305
  const { left, top, width, height } = this.getBoundingBox();
2235
- canvas.width = width;
2236
- canvas.height = height;
2306
+ const canvas = document.createElement("canvas");
2307
+ canvas.width = width * pixelRatio;
2308
+ canvas.height = height * pixelRatio;
2309
+ canvas.style.width = `${width}px`;
2310
+ canvas.style.height = `${height}px`;
2237
2311
  const ctx = canvas.getContext("2d");
2238
2312
  if (ctx) {
2313
+ ctx.scale(pixelRatio, pixelRatio);
2239
2314
  ctx.translate(-left, -top);
2240
- if (fill) {
2241
- this.fillTo(ctx);
2242
- } else {
2243
- this.strokeTo(ctx);
2244
- }
2315
+ this.drawTo(ctx);
2245
2316
  }
2246
2317
  return canvas;
2247
2318
  }
@@ -2450,7 +2521,7 @@ function parseNodeTransform(node) {
2450
2521
 
2451
2522
  function parseCircleNode(node) {
2452
2523
  return new Path2D().addPath(
2453
- new CurvePath().absarc(
2524
+ new CurvePath().arc(
2454
2525
  parseFloatWithUnits(node.getAttribute("cx") || 0),
2455
2526
  parseFloatWithUnits(node.getAttribute("cy") || 0),
2456
2527
  parseFloatWithUnits(node.getAttribute("r") || 0),
@@ -2482,12 +2553,13 @@ function parseCSSStylesheet(node, stylesheets) {
2482
2553
 
2483
2554
  function parseEllipseNode(node) {
2484
2555
  return new Path2D().addPath(
2485
- new CurvePath().absellipse(
2556
+ new CurvePath().ellipse(
2486
2557
  parseFloatWithUnits(node.getAttribute("cx") || 0),
2487
2558
  parseFloatWithUnits(node.getAttribute("cy") || 0),
2488
2559
  parseFloatWithUnits(node.getAttribute("rx") || 0),
2489
2560
  parseFloatWithUnits(node.getAttribute("ry") || 0),
2490
2561
  0,
2562
+ 0,
2491
2563
  Math.PI * 2
2492
2564
  )
2493
2565
  );
@@ -2633,18 +2705,21 @@ function parseStyle(node, style, stylesheets) {
2633
2705
  function positive(v) {
2634
2706
  return Math.max(0, parseFloatWithUnits(v));
2635
2707
  }
2708
+ function array(v) {
2709
+ return v.split(" ").filter((v2) => v2 !== "").map((v2) => parseFloatWithUnits(v2));
2710
+ }
2636
2711
  addStyle("fill", "fill");
2637
2712
  addStyle("fill-opacity", "fillOpacity", clamp);
2638
2713
  addStyle("fill-rule", "fillRule");
2639
2714
  addStyle("opacity", "opacity", clamp);
2640
2715
  addStyle("stroke", "stroke");
2641
- addStyle("stroke-dashoffset", "strokeDashoffset");
2642
- addStyle("stroke-dasharray", "strokeDasharray");
2643
- addStyle("stroke-linecap", "strokeLineCap");
2644
- addStyle("stroke-linejoin", "strokeLineJoin");
2645
- addStyle("stroke-miterlimit", "strokeMiterLimit", positive);
2646
2716
  addStyle("stroke-opacity", "strokeOpacity", clamp);
2647
2717
  addStyle("stroke-width", "strokeWidth", positive);
2718
+ addStyle("stroke-linecap", "strokeLinecap");
2719
+ addStyle("stroke-linejoin", "strokeLinejoin");
2720
+ addStyle("stroke-miterlimit", "strokeMiterlimit", positive);
2721
+ addStyle("stroke-dasharray", "strokeDasharray", array);
2722
+ addStyle("stroke-dashoffset", "strokeDashoffset", parseFloatWithUnits);
2648
2723
  addStyle("visibility", "visibility");
2649
2724
  return style;
2650
2725
  }
@@ -2719,7 +2794,7 @@ function parseNode(node, style, paths = []) {
2719
2794
  if (path) {
2720
2795
  path.transform(currentTransform);
2721
2796
  paths.push(path);
2722
- path.userData = { node, style };
2797
+ path.style = style;
2723
2798
  }
2724
2799
  const childNodes = node.childNodes;
2725
2800
  for (let i = 0, len = childNodes.length; i < len; i++) {
@@ -2763,15 +2838,7 @@ function parseSvgToDom(svg) {
2763
2838
  }
2764
2839
  }
2765
2840
  function parseSvg(svg) {
2766
- return parseNode(parseSvgToDom(svg), {
2767
- fill: "#000",
2768
- fillOpacity: 1,
2769
- strokeOpacity: 1,
2770
- strokeWidth: 1,
2771
- strokeLineJoin: "miter",
2772
- strokeLineCap: "butt",
2773
- strokeMiterLimit: 4
2774
- });
2841
+ return parseNode(parseSvgToDom(svg), {});
2775
2842
  }
2776
2843
 
2777
- export { BoundingBox, CircleCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, HeartCurve, LineCurve, Matrix3, Path2D, PloygonCurve, QuadraticBezierCurve, RectangularCurve, SplineCurve, Vector2, parseSvg, parseSvgToDom };
2844
+ export { BoundingBox, CircleCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, HeartCurve, LineCurve, Matrix3, Path2D, PloygonCurve, QuadraticBezierCurve, RectangularCurve, SplineCurve, Vector2, addPathCommandsToPath2D, parseArcCommand, parsePathDataArgs, parseSvg, parseSvgToDom, pathCommandsToPathData, pathDataToPathCommands, setCanvasContextByPath };