modern-path2d 0.0.2 → 0.0.4
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.cjs +202 -45
- package/dist/index.d.cts +70 -19
- package/dist/index.d.mts +70 -19
- package/dist/index.d.ts +70 -19
- package/dist/index.js +1 -1
- package/dist/index.mjs +202 -45
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3,6 +3,12 @@ class Point2D {
|
|
|
3
3
|
this.x = x;
|
|
4
4
|
this.y = y;
|
|
5
5
|
}
|
|
6
|
+
static get MAX() {
|
|
7
|
+
return new Point2D(Infinity, Infinity);
|
|
8
|
+
}
|
|
9
|
+
static get MIN() {
|
|
10
|
+
return new Point2D(-Infinity, -Infinity);
|
|
11
|
+
}
|
|
6
12
|
set(x, y) {
|
|
7
13
|
this.x = x;
|
|
8
14
|
this.y = y;
|
|
@@ -75,6 +81,9 @@ class Curve {
|
|
|
75
81
|
__publicField$5(this, "_cacheArcLengths");
|
|
76
82
|
__publicField$5(this, "_needsUpdate", false);
|
|
77
83
|
}
|
|
84
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
85
|
+
return { min, max };
|
|
86
|
+
}
|
|
78
87
|
getDivisions(divisions) {
|
|
79
88
|
return divisions;
|
|
80
89
|
}
|
|
@@ -170,6 +179,26 @@ class Curve {
|
|
|
170
179
|
getTangentAt(u, output = new Point2D()) {
|
|
171
180
|
return this.getTangent(this.getUtoTmapping(u), output);
|
|
172
181
|
}
|
|
182
|
+
getData() {
|
|
183
|
+
return this.getCommands().map((cmd) => {
|
|
184
|
+
switch (cmd.type) {
|
|
185
|
+
case "M":
|
|
186
|
+
return `M ${cmd.x} ${cmd.y}`;
|
|
187
|
+
case "L":
|
|
188
|
+
return `L ${cmd.x} ${cmd.y}`;
|
|
189
|
+
case "C":
|
|
190
|
+
return `C ${cmd.x1} ${cmd.y1} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`;
|
|
191
|
+
case "Q":
|
|
192
|
+
return `Q ${cmd.x1} ${cmd.y1} ${cmd.x} ${cmd.y}`;
|
|
193
|
+
case "A":
|
|
194
|
+
return `A ${cmd.rx} ${cmd.ry} ${cmd.xAxisRotation} ${cmd.largeArcFlag} ${cmd.sweepFlag} ${cmd.x} ${cmd.y}`;
|
|
195
|
+
case "Z":
|
|
196
|
+
return "Z";
|
|
197
|
+
default:
|
|
198
|
+
return "";
|
|
199
|
+
}
|
|
200
|
+
}).join(" ");
|
|
201
|
+
}
|
|
173
202
|
clone() {
|
|
174
203
|
return new this.constructor().copy(this);
|
|
175
204
|
}
|
|
@@ -187,26 +216,27 @@ class CircleCurve extends Curve {
|
|
|
187
216
|
this.start = start;
|
|
188
217
|
this.end = end;
|
|
189
218
|
}
|
|
190
|
-
|
|
219
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
191
220
|
min.x = Math.min(min.x, this.center.x - this.radius);
|
|
192
221
|
min.y = Math.min(min.y, this.center.y - this.radius);
|
|
193
222
|
max.x = Math.max(max.x, this.center.x + this.radius);
|
|
194
223
|
max.y = Math.max(max.y, this.center.y + this.radius);
|
|
224
|
+
return { min, max };
|
|
195
225
|
}
|
|
196
|
-
getPoint(
|
|
226
|
+
getPoint(t) {
|
|
197
227
|
const { radius, center } = this;
|
|
198
|
-
return center.clone().add(this.getNormal(
|
|
228
|
+
return center.clone().add(this.getNormal(t).clone().multiplyScalar(radius));
|
|
199
229
|
}
|
|
200
|
-
getTangent(
|
|
201
|
-
const { x, y } = this.getNormal(
|
|
230
|
+
getTangent(t) {
|
|
231
|
+
const { x, y } = this.getNormal(t);
|
|
202
232
|
return new Point2D(-y, x);
|
|
203
233
|
}
|
|
204
|
-
getNormal(
|
|
234
|
+
getNormal(t) {
|
|
205
235
|
const { start, end } = this;
|
|
206
|
-
const
|
|
207
|
-
return new Point2D(Math.cos(
|
|
236
|
+
const _t = t * (end - start) + start - 0.5 * Math.PI;
|
|
237
|
+
return new Point2D(Math.cos(_t), Math.sin(_t));
|
|
208
238
|
}
|
|
209
|
-
|
|
239
|
+
getCommands() {
|
|
210
240
|
return [];
|
|
211
241
|
}
|
|
212
242
|
drawTo(_ctx) {
|
|
@@ -267,8 +297,20 @@ class CubicBezierCurve extends Curve {
|
|
|
267
297
|
);
|
|
268
298
|
return output;
|
|
269
299
|
}
|
|
270
|
-
|
|
271
|
-
|
|
300
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
301
|
+
const { v0, v1, v2, v3 } = this;
|
|
302
|
+
min.x = Math.min(min.x, v0.x, v1.x, v2.x, v3.x);
|
|
303
|
+
min.y = Math.min(min.y, v0.y, v1.y, v2.y, v3.y);
|
|
304
|
+
max.x = Math.max(max.x, v0.x, v1.x, v2.x, v3.x);
|
|
305
|
+
max.y = Math.max(max.y, v0.y, v1.y, v2.y, v3.y);
|
|
306
|
+
return { min, max };
|
|
307
|
+
}
|
|
308
|
+
getCommands() {
|
|
309
|
+
const { v0, v1, v2, v3 } = this;
|
|
310
|
+
return [
|
|
311
|
+
{ type: "M", x: v0.x, y: v0.y },
|
|
312
|
+
{ type: "C", x1: v1.x, y1: v1.y, x2: v2.x, y2: v2.y, x: v3.x, y: v3.y }
|
|
313
|
+
];
|
|
272
314
|
}
|
|
273
315
|
drawTo(ctx) {
|
|
274
316
|
const { v0, v1, v2, v3 } = this;
|
|
@@ -335,18 +377,30 @@ class EllipseCurve extends Curve {
|
|
|
335
377
|
}
|
|
336
378
|
return output.set(_x, _y);
|
|
337
379
|
}
|
|
338
|
-
|
|
380
|
+
getCommands() {
|
|
339
381
|
const { x, y, rx, ry, startAngle, endAngle, clockwise } = this;
|
|
382
|
+
const anticlockwise = !clockwise;
|
|
340
383
|
const startX = x + rx * Math.cos(startAngle);
|
|
341
384
|
const startY = y + ry * Math.sin(startAngle);
|
|
342
385
|
const endX = x + rx * Math.cos(endAngle);
|
|
343
386
|
const endY = y + ry * Math.sin(endAngle);
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
387
|
+
const angleDiff = Math.abs(startAngle - endAngle);
|
|
388
|
+
const largeArcFlag = angleDiff > Math.PI ? 1 : 0;
|
|
389
|
+
const sweepFlag = anticlockwise ? 0 : 1;
|
|
390
|
+
const midX = x + rx * Math.cos(startAngle + (endAngle - startAngle) / 2);
|
|
391
|
+
const midY = y + ry * Math.sin(startAngle + (endAngle - startAngle) / 2);
|
|
392
|
+
if (angleDiff >= 2 * Math.PI) {
|
|
393
|
+
return [
|
|
394
|
+
{ type: "M", x: startX, y: startY },
|
|
395
|
+
{ type: "A", rx, ry, xAxisRotation: 0, largeArcFlag: 1, sweepFlag, x: midX, y: midY },
|
|
396
|
+
{ type: "A", rx, ry, xAxisRotation: 0, largeArcFlag: 1, sweepFlag, x: startX, y: startY }
|
|
397
|
+
];
|
|
398
|
+
} else {
|
|
399
|
+
return [
|
|
400
|
+
{ type: "M", x: startX, y: startY },
|
|
401
|
+
{ type: "A", rx, ry, xAxisRotation: 0, largeArcFlag, sweepFlag, x: endX, y: endY }
|
|
402
|
+
];
|
|
403
|
+
}
|
|
350
404
|
}
|
|
351
405
|
drawTo(ctx) {
|
|
352
406
|
const { x, y, rx, ry, startAngle } = this;
|
|
@@ -403,12 +457,21 @@ class LineCurve extends Curve {
|
|
|
403
457
|
getTangentAt(u, output = new Point2D()) {
|
|
404
458
|
return this.getTangent(u, output);
|
|
405
459
|
}
|
|
406
|
-
|
|
460
|
+
getCommands() {
|
|
461
|
+
const { v1, v2 } = this;
|
|
407
462
|
return [
|
|
408
|
-
{ type: "M", x:
|
|
409
|
-
{ type: "L", x:
|
|
463
|
+
{ type: "M", x: v1.x, y: v1.y },
|
|
464
|
+
{ type: "L", x: v2.x, y: v2.y }
|
|
410
465
|
];
|
|
411
466
|
}
|
|
467
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
468
|
+
const { v1, v2 } = this;
|
|
469
|
+
min.x = Math.min(min.x, v1.x, v2.x);
|
|
470
|
+
min.y = Math.min(min.y, v1.y, v2.y);
|
|
471
|
+
max.x = Math.max(max.x, v1.x, v2.x);
|
|
472
|
+
max.y = Math.max(max.y, v1.y, v2.y);
|
|
473
|
+
return { min, max };
|
|
474
|
+
}
|
|
412
475
|
drawTo(ctx) {
|
|
413
476
|
const { v1, v2 } = this;
|
|
414
477
|
ctx.moveTo(v1.x, v1.y);
|
|
@@ -490,8 +553,8 @@ class HeartCurve extends Curve {
|
|
|
490
553
|
const line = this.getCurrentLine(value);
|
|
491
554
|
return new Point2D(line.v2.y - line.v1.y, -(line.v2.x - line.v1.x)).normalize();
|
|
492
555
|
}
|
|
493
|
-
|
|
494
|
-
return this.curves.flatMap((curve) => curve.
|
|
556
|
+
getCommands() {
|
|
557
|
+
return this.curves.flatMap((curve) => curve.getCommands());
|
|
495
558
|
}
|
|
496
559
|
drawTo(ctx) {
|
|
497
560
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
@@ -548,8 +611,12 @@ class PloygonCurve extends Curve {
|
|
|
548
611
|
const line = this.getCurrentLine(value);
|
|
549
612
|
return new Point2D(line.v2.y - line.v1.y, -(line.v2.x - line.v1.x)).normalize();
|
|
550
613
|
}
|
|
551
|
-
|
|
552
|
-
return this.curves.flatMap((curve) => curve.
|
|
614
|
+
getCommands() {
|
|
615
|
+
return this.curves.flatMap((curve) => curve.getCommands());
|
|
616
|
+
}
|
|
617
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
618
|
+
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
619
|
+
return { min, max };
|
|
553
620
|
}
|
|
554
621
|
drawTo(ctx) {
|
|
555
622
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
@@ -571,8 +638,24 @@ class QuadraticBezierCurve extends Curve {
|
|
|
571
638
|
);
|
|
572
639
|
return output;
|
|
573
640
|
}
|
|
574
|
-
|
|
575
|
-
|
|
641
|
+
getCommands() {
|
|
642
|
+
const { v0, v1, v2 } = this;
|
|
643
|
+
return [
|
|
644
|
+
{ type: "M", x: v0.x, y: v0.y },
|
|
645
|
+
{ type: "Q", x1: v1.x, y1: v1.y, x: v2.x, y: v2.y }
|
|
646
|
+
];
|
|
647
|
+
}
|
|
648
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
649
|
+
const { v0, v1, v2 } = this;
|
|
650
|
+
const x1 = 0.5 * (v0.x + v1.x);
|
|
651
|
+
const y1 = 0.5 * (v0.y + v1.y);
|
|
652
|
+
const x2 = 0.5 * (v0.x + v2.x);
|
|
653
|
+
const y2 = 0.5 * (v0.y + v2.y);
|
|
654
|
+
min.x = Math.min(min.x, v0.x, v2.x, x1, x2);
|
|
655
|
+
min.y = Math.min(min.y, v0.y, v2.y, y1, y2);
|
|
656
|
+
max.x = Math.max(max.x, v0.x, v2.x, x1, x2);
|
|
657
|
+
max.y = Math.max(max.y, v0.y, v2.y, y1, y2);
|
|
658
|
+
return { min, max };
|
|
576
659
|
}
|
|
577
660
|
drawTo(ctx) {
|
|
578
661
|
const { v0, v1, v2 } = this;
|
|
@@ -662,8 +745,12 @@ class RectangularCurve extends Curve {
|
|
|
662
745
|
const { v1, v2 } = this.getCurrentLine(value);
|
|
663
746
|
return new Point2D(v2.y - v1.y, -(v2.x - v1.x)).normalize();
|
|
664
747
|
}
|
|
665
|
-
|
|
666
|
-
return this.curves.flatMap((curve) => curve.
|
|
748
|
+
getCommands() {
|
|
749
|
+
return this.curves.flatMap((curve) => curve.getCommands());
|
|
750
|
+
}
|
|
751
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
752
|
+
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
753
|
+
return { min, max };
|
|
667
754
|
}
|
|
668
755
|
drawTo(ctx) {
|
|
669
756
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
@@ -693,7 +780,7 @@ class SplineCurve extends Curve {
|
|
|
693
780
|
);
|
|
694
781
|
return output;
|
|
695
782
|
}
|
|
696
|
-
|
|
783
|
+
getCommands() {
|
|
697
784
|
return [];
|
|
698
785
|
}
|
|
699
786
|
drawTo(_ctx) {
|
|
@@ -701,9 +788,8 @@ class SplineCurve extends Curve {
|
|
|
701
788
|
copy(source) {
|
|
702
789
|
super.copy(source);
|
|
703
790
|
this.points = [];
|
|
704
|
-
for (let i = 0,
|
|
705
|
-
|
|
706
|
-
this.points.push(point.clone());
|
|
791
|
+
for (let i = 0, len = source.points.length; i < len; i++) {
|
|
792
|
+
this.points.push(source.points[i].clone());
|
|
707
793
|
}
|
|
708
794
|
return this;
|
|
709
795
|
}
|
|
@@ -887,8 +973,12 @@ class CurvePath extends Curve {
|
|
|
887
973
|
this.currentPoint.copy(curve.getPoint(1));
|
|
888
974
|
return this;
|
|
889
975
|
}
|
|
890
|
-
|
|
891
|
-
return this.curves.flatMap((curve) => curve.
|
|
976
|
+
getCommands() {
|
|
977
|
+
return this.curves.flatMap((curve) => curve.getCommands());
|
|
978
|
+
}
|
|
979
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
980
|
+
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
981
|
+
return { min, max };
|
|
892
982
|
}
|
|
893
983
|
drawTo(ctx) {
|
|
894
984
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
@@ -917,16 +1007,12 @@ class Path2D {
|
|
|
917
1007
|
__publicField(this, "currentPath", new CurvePath());
|
|
918
1008
|
__publicField(this, "paths", [this.currentPath]);
|
|
919
1009
|
}
|
|
920
|
-
|
|
921
|
-
this.
|
|
922
|
-
return this;
|
|
923
|
-
}
|
|
924
|
-
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
925
|
-
this.currentPath.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
|
1010
|
+
addPath(path) {
|
|
1011
|
+
this.paths.push(...path.paths.map((v) => v.clone()));
|
|
926
1012
|
return this;
|
|
927
1013
|
}
|
|
928
|
-
|
|
929
|
-
this.currentPath.
|
|
1014
|
+
closePath() {
|
|
1015
|
+
this.currentPath.closePath();
|
|
930
1016
|
return this;
|
|
931
1017
|
}
|
|
932
1018
|
moveTo(x, y) {
|
|
@@ -935,10 +1021,56 @@ class Path2D {
|
|
|
935
1021
|
this.currentPath.moveTo(x, y);
|
|
936
1022
|
return this;
|
|
937
1023
|
}
|
|
1024
|
+
lineTo(x, y) {
|
|
1025
|
+
this.currentPath.lineTo(x, y);
|
|
1026
|
+
return this;
|
|
1027
|
+
}
|
|
1028
|
+
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
1029
|
+
this.currentPath.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
|
1030
|
+
return this;
|
|
1031
|
+
}
|
|
938
1032
|
quadraticCurveTo(cpx, cpy, x, y) {
|
|
939
1033
|
this.currentPath.quadraticCurveTo(cpx, cpy, x, y);
|
|
940
1034
|
return this;
|
|
941
1035
|
}
|
|
1036
|
+
arc(x, y, radius, startAngle, endAngle, counterclockwise) {
|
|
1037
|
+
this.currentPath.absarc(x, y, radius, startAngle, endAngle, !counterclockwise);
|
|
1038
|
+
return this;
|
|
1039
|
+
}
|
|
1040
|
+
arcTo(x1, y1, x2, y2, radius) {
|
|
1041
|
+
const point = this.currentPath.currentPoint;
|
|
1042
|
+
const currentX = point.x;
|
|
1043
|
+
const currentY = point.y;
|
|
1044
|
+
const dx1 = x1 - currentX;
|
|
1045
|
+
const dy1 = y1 - currentY;
|
|
1046
|
+
const dx2 = x2 - x1;
|
|
1047
|
+
const dy2 = y2 - y1;
|
|
1048
|
+
const len1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
1049
|
+
const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
|
|
1050
|
+
if (len1 < radius || len2 < radius) {
|
|
1051
|
+
this.lineTo(x2, y2);
|
|
1052
|
+
return this;
|
|
1053
|
+
}
|
|
1054
|
+
const unitV1 = { x: dx1 / len1, y: dy1 / len1 };
|
|
1055
|
+
const unitV2 = { x: dx2 / len2, y: dy2 / len2 };
|
|
1056
|
+
const centerX = x1 - unitV1.y * radius;
|
|
1057
|
+
const centerY = y1 + unitV1.x * radius;
|
|
1058
|
+
const startAngle = Math.atan2(unitV1.y, unitV1.x);
|
|
1059
|
+
const endAngle = Math.atan2(unitV2.y, unitV2.x);
|
|
1060
|
+
let angleDiff = endAngle - startAngle;
|
|
1061
|
+
if (angleDiff > Math.PI) {
|
|
1062
|
+
angleDiff -= 2 * Math.PI;
|
|
1063
|
+
} else if (angleDiff < -Math.PI) {
|
|
1064
|
+
angleDiff += 2 * Math.PI;
|
|
1065
|
+
}
|
|
1066
|
+
this.arc(centerX, centerY, radius, startAngle, startAngle + angleDiff, false);
|
|
1067
|
+
this.lineTo(x2, y2);
|
|
1068
|
+
return this;
|
|
1069
|
+
}
|
|
1070
|
+
ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) {
|
|
1071
|
+
this.currentPath.absellipse(x, y, radiusX, radiusY, startAngle, endAngle, !counterclockwise, rotation);
|
|
1072
|
+
return this;
|
|
1073
|
+
}
|
|
942
1074
|
rect(x, y, w, h) {
|
|
943
1075
|
this.currentPath.rect(x, y, w, h);
|
|
944
1076
|
return this;
|
|
@@ -947,8 +1079,33 @@ class Path2D {
|
|
|
947
1079
|
this.currentPath.splineThru(points);
|
|
948
1080
|
return this;
|
|
949
1081
|
}
|
|
950
|
-
|
|
951
|
-
|
|
1082
|
+
getMinMax(min = new Point2D(), max = new Point2D()) {
|
|
1083
|
+
this.paths.forEach((path) => path.curves.forEach((curve) => curve.getMinMax(min, max)));
|
|
1084
|
+
return { min, max };
|
|
1085
|
+
}
|
|
1086
|
+
getCommands() {
|
|
1087
|
+
return this.paths.flatMap((path) => path.curves.flatMap((curve) => curve.getCommands()));
|
|
1088
|
+
}
|
|
1089
|
+
getData() {
|
|
1090
|
+
return this.paths.map((path) => path.getData()).join(" ");
|
|
1091
|
+
}
|
|
1092
|
+
getBoundingBox() {
|
|
1093
|
+
const min = Point2D.MAX;
|
|
1094
|
+
const max = Point2D.MIN;
|
|
1095
|
+
this.paths.forEach((path) => path.getMinMax(min, max));
|
|
1096
|
+
return {
|
|
1097
|
+
x: min.x,
|
|
1098
|
+
y: min.y,
|
|
1099
|
+
width: max.x - min.x,
|
|
1100
|
+
height: max.y - min.y
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
getSvgString() {
|
|
1104
|
+
const { x, y, width, height } = this.getBoundingBox();
|
|
1105
|
+
return `<svg viewBox="${x} ${y} ${width} ${height}" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="currentColor" d="${this.getData()}"></path></svg>`;
|
|
1106
|
+
}
|
|
1107
|
+
getSvgDataUri() {
|
|
1108
|
+
return `data:image/svg+xml;base64,${btoa(this.getSvgString())}`;
|
|
952
1109
|
}
|
|
953
1110
|
drawTo(ctx) {
|
|
954
1111
|
this.paths.forEach((path) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modern-path2d",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"packageManager": "pnpm@9.9.0",
|
|
6
6
|
"description": "A modern Path2D library, fully compatible with Web Path2D, with additional support for path animation, path deformation, path playback, etc.",
|
|
7
7
|
"author": "wxm",
|