modern-path2d 0.1.18 → 0.2.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.
- package/README.md +2 -2
- package/dist/index.cjs +364 -145
- package/dist/index.d.cts +67 -46
- package/dist/index.d.mts +67 -46
- package/dist/index.d.ts +67 -46
- package/dist/index.js +1 -1
- package/dist/index.mjs +364 -146
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -60,6 +60,34 @@ class Vector2 {
|
|
|
60
60
|
this.y -= vec.y;
|
|
61
61
|
return this;
|
|
62
62
|
}
|
|
63
|
+
multiply(vec) {
|
|
64
|
+
this.x *= vec.x;
|
|
65
|
+
this.y *= vec.y;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
divide(vec) {
|
|
69
|
+
this.x /= vec.x;
|
|
70
|
+
this.y /= vec.y;
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
dot(vec) {
|
|
74
|
+
return this.x * vec.x + this.y * vec.y;
|
|
75
|
+
}
|
|
76
|
+
cross(vec) {
|
|
77
|
+
return this.x * vec.y - this.y * vec.x;
|
|
78
|
+
}
|
|
79
|
+
rotate(a, target = { x: 0, y: 0 }) {
|
|
80
|
+
const rotation = -a / 180 * Math.PI;
|
|
81
|
+
const x = this.x - target.x;
|
|
82
|
+
const y = -(this.y - target.y);
|
|
83
|
+
const sin = Math.sin(rotation);
|
|
84
|
+
const cos = Math.cos(rotation);
|
|
85
|
+
this.set(
|
|
86
|
+
target.x + (x * cos - y * sin),
|
|
87
|
+
target.y - (x * sin + y * cos)
|
|
88
|
+
);
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
63
91
|
distanceTo(vec) {
|
|
64
92
|
return Math.sqrt(this.distanceToSquared(vec));
|
|
65
93
|
}
|
|
@@ -68,24 +96,48 @@ class Vector2 {
|
|
|
68
96
|
const dy = this.y - vec.y;
|
|
69
97
|
return dx * dx + dy * dy;
|
|
70
98
|
}
|
|
99
|
+
lengthSquared() {
|
|
100
|
+
return this.x * this.x + this.y * this.y;
|
|
101
|
+
}
|
|
71
102
|
length() {
|
|
72
|
-
return Math.sqrt(this.
|
|
103
|
+
return Math.sqrt(this.lengthSquared());
|
|
73
104
|
}
|
|
74
|
-
|
|
75
|
-
this.x
|
|
76
|
-
this.y
|
|
105
|
+
scale(sx, sy = sx, target = { x: 0, y: 0 }) {
|
|
106
|
+
const x = sx < 0 ? target.x - this.x + target.x : this.x;
|
|
107
|
+
const y = sy < 0 ? target.y - this.y + target.y : this.y;
|
|
108
|
+
this.x = x * Math.abs(sx);
|
|
109
|
+
this.y = y * Math.abs(sy);
|
|
77
110
|
return this;
|
|
78
111
|
}
|
|
79
|
-
|
|
80
|
-
|
|
112
|
+
skew(ax, ay = 0, target = { x: 0, y: 0 }) {
|
|
113
|
+
const dx = this.x - target.x;
|
|
114
|
+
const dy = this.y - target.y;
|
|
115
|
+
this.x = target.x + (dx + Math.tan(ax) * dy);
|
|
116
|
+
this.y = target.y + (dy + Math.tan(ay) * dx);
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
normalize() {
|
|
120
|
+
return this.scale(1 / (this.length() || 1));
|
|
121
|
+
}
|
|
122
|
+
addVectors(a, b) {
|
|
123
|
+
this.x = a.x + b.x;
|
|
124
|
+
this.y = a.y + b.y;
|
|
125
|
+
return this;
|
|
81
126
|
}
|
|
82
127
|
subVectors(a, b) {
|
|
83
128
|
this.x = a.x - b.x;
|
|
84
129
|
this.y = a.y - b.y;
|
|
85
130
|
return this;
|
|
86
131
|
}
|
|
87
|
-
|
|
88
|
-
|
|
132
|
+
multiplyVectors(a, b) {
|
|
133
|
+
this.x = a.x * b.x;
|
|
134
|
+
this.y = a.y * b.y;
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
divideVectors(a, b) {
|
|
138
|
+
this.x = a.x / b.x;
|
|
139
|
+
this.y = a.y / b.y;
|
|
140
|
+
return this;
|
|
89
141
|
}
|
|
90
142
|
lerpVectors(v1, v2, alpha) {
|
|
91
143
|
this.x = v1.x + (v2.x - v1.x) * alpha;
|
|
@@ -913,8 +965,14 @@ class Curve {
|
|
|
913
965
|
__publicField$5(this, "_cacheArcLengths");
|
|
914
966
|
__publicField$5(this, "_needsUpdate", false);
|
|
915
967
|
}
|
|
968
|
+
isClockwise() {
|
|
969
|
+
const prev = this.getPoint(1);
|
|
970
|
+
const cur = this.getPoint(0.5);
|
|
971
|
+
const next = this.getPoint(1);
|
|
972
|
+
return (cur.x - prev.x) * (next.y - cur.y) - (cur.y - prev.y) * (next.x - cur.x) < 0;
|
|
973
|
+
}
|
|
916
974
|
getPointAt(u, output = new Vector2()) {
|
|
917
|
-
return this.getPoint(this.
|
|
975
|
+
return this.getPoint(this.getUToTMapping(u), output);
|
|
918
976
|
}
|
|
919
977
|
getPoints(divisions = 5) {
|
|
920
978
|
const points = [];
|
|
@@ -923,6 +981,10 @@ class Curve {
|
|
|
923
981
|
}
|
|
924
982
|
return points;
|
|
925
983
|
}
|
|
984
|
+
forEachControlPoints(cb) {
|
|
985
|
+
this.getControlPoints().forEach(cb);
|
|
986
|
+
return this;
|
|
987
|
+
}
|
|
926
988
|
getSpacedPoints(divisions = 5) {
|
|
927
989
|
const points = [];
|
|
928
990
|
for (let i = 0; i <= divisions; i++) {
|
|
@@ -957,22 +1019,22 @@ class Curve {
|
|
|
957
1019
|
this._needsUpdate = true;
|
|
958
1020
|
this.getLengths();
|
|
959
1021
|
}
|
|
960
|
-
|
|
961
|
-
const
|
|
1022
|
+
getUToTMapping(u, distance) {
|
|
1023
|
+
const lengths = this.getLengths();
|
|
962
1024
|
let i = 0;
|
|
963
|
-
const
|
|
964
|
-
let
|
|
1025
|
+
const lengthsLen = lengths.length;
|
|
1026
|
+
let targetLength;
|
|
965
1027
|
if (distance) {
|
|
966
|
-
|
|
1028
|
+
targetLength = distance;
|
|
967
1029
|
} else {
|
|
968
|
-
|
|
1030
|
+
targetLength = u * lengths[lengthsLen - 1];
|
|
969
1031
|
}
|
|
970
1032
|
let low = 0;
|
|
971
|
-
let high =
|
|
1033
|
+
let high = lengthsLen - 1;
|
|
972
1034
|
let comparison;
|
|
973
1035
|
while (low <= high) {
|
|
974
1036
|
i = Math.floor(low + (high - low) / 2);
|
|
975
|
-
comparison =
|
|
1037
|
+
comparison = lengths[i] - targetLength;
|
|
976
1038
|
if (comparison < 0) {
|
|
977
1039
|
low = i + 1;
|
|
978
1040
|
} else if (comparison > 0) {
|
|
@@ -983,14 +1045,14 @@ class Curve {
|
|
|
983
1045
|
}
|
|
984
1046
|
}
|
|
985
1047
|
i = high;
|
|
986
|
-
if (
|
|
987
|
-
return i / (
|
|
1048
|
+
if (lengths[i] === targetLength) {
|
|
1049
|
+
return i / (lengthsLen - 1);
|
|
988
1050
|
}
|
|
989
|
-
const lengthBefore =
|
|
990
|
-
const lengthAfter =
|
|
1051
|
+
const lengthBefore = lengths[i];
|
|
1052
|
+
const lengthAfter = lengths[i + 1];
|
|
991
1053
|
const segmentLength = lengthAfter - lengthBefore;
|
|
992
|
-
const segmentFraction = (
|
|
993
|
-
return (i + segmentFraction) / (
|
|
1054
|
+
const segmentFraction = (targetLength - lengthBefore) / segmentLength;
|
|
1055
|
+
return (i + segmentFraction) / (lengthsLen - 1);
|
|
994
1056
|
}
|
|
995
1057
|
getTangent(t, output = new Vector2()) {
|
|
996
1058
|
const delta = 1e-4;
|
|
@@ -999,15 +1061,36 @@ class Curve {
|
|
|
999
1061
|
return output.copy(this.getPoint(t2).sub(this.getPoint(t1)).normalize());
|
|
1000
1062
|
}
|
|
1001
1063
|
getTangentAt(u, output) {
|
|
1002
|
-
return this.getTangent(this.
|
|
1064
|
+
return this.getTangent(this.getUToTMapping(u), output);
|
|
1003
1065
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1066
|
+
getNormal(t, output = new Vector2()) {
|
|
1067
|
+
this.getTangent(t, output);
|
|
1068
|
+
return output.set(-output.y, output.x).normalize();
|
|
1069
|
+
}
|
|
1070
|
+
getNormalAt(u, output) {
|
|
1071
|
+
return this.getNormal(this.getUToTMapping(u), output);
|
|
1008
1072
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1073
|
+
getTForPoint(target, epsilon = 1e-3) {
|
|
1074
|
+
let low = 0;
|
|
1075
|
+
let high = 1;
|
|
1076
|
+
let mid = (low + high) / 2;
|
|
1077
|
+
while (high - low > epsilon) {
|
|
1078
|
+
mid = (low + high) / 2;
|
|
1079
|
+
const point = this.getPoint(mid);
|
|
1080
|
+
const distance = point.distanceTo(target);
|
|
1081
|
+
if (distance < epsilon) {
|
|
1082
|
+
return mid;
|
|
1083
|
+
}
|
|
1084
|
+
if (point.x < target.x) {
|
|
1085
|
+
low = mid;
|
|
1086
|
+
} else {
|
|
1087
|
+
high = mid;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
return mid;
|
|
1091
|
+
}
|
|
1092
|
+
matrix(matrix) {
|
|
1093
|
+
this.forEachControlPoints((point) => point.applyMatrix3(matrix));
|
|
1011
1094
|
return this;
|
|
1012
1095
|
}
|
|
1013
1096
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
@@ -1023,7 +1106,7 @@ class Curve {
|
|
|
1023
1106
|
const { min, max } = this.getMinMax();
|
|
1024
1107
|
return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
1025
1108
|
}
|
|
1026
|
-
|
|
1109
|
+
toCommands() {
|
|
1027
1110
|
return this.getPoints().map((point, i) => {
|
|
1028
1111
|
if (i === 0) {
|
|
1029
1112
|
return { type: "M", x: point.x, y: point.y };
|
|
@@ -1032,12 +1115,20 @@ class Curve {
|
|
|
1032
1115
|
}
|
|
1033
1116
|
});
|
|
1034
1117
|
}
|
|
1035
|
-
|
|
1036
|
-
return pathCommandsToPathData(this.
|
|
1118
|
+
toData() {
|
|
1119
|
+
return pathCommandsToPathData(this.toCommands());
|
|
1037
1120
|
}
|
|
1038
|
-
/** overrideable */
|
|
1039
|
-
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
1040
1121
|
drawTo(ctx) {
|
|
1122
|
+
this.toCommands().forEach((cmd) => {
|
|
1123
|
+
switch (cmd.type) {
|
|
1124
|
+
case "M":
|
|
1125
|
+
ctx.moveTo(cmd.x, cmd.y);
|
|
1126
|
+
break;
|
|
1127
|
+
case "L":
|
|
1128
|
+
ctx.lineTo(cmd.x, cmd.y);
|
|
1129
|
+
break;
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1041
1132
|
return this;
|
|
1042
1133
|
}
|
|
1043
1134
|
copy(source) {
|
|
@@ -1059,20 +1150,19 @@ class CircleCurve extends Curve {
|
|
|
1059
1150
|
}
|
|
1060
1151
|
getPoint(t) {
|
|
1061
1152
|
const { radius, center } = this;
|
|
1062
|
-
return center.clone().add(this.getNormal(t).clone().
|
|
1153
|
+
return center.clone().add(this.getNormal(t).clone().scale(radius));
|
|
1063
1154
|
}
|
|
1064
|
-
getTangent(t) {
|
|
1155
|
+
getTangent(t, output = new Vector2()) {
|
|
1065
1156
|
const { x, y } = this.getNormal(t);
|
|
1066
|
-
return
|
|
1157
|
+
return output.set(-y, x);
|
|
1067
1158
|
}
|
|
1068
|
-
getNormal(t) {
|
|
1159
|
+
getNormal(t, output = new Vector2()) {
|
|
1069
1160
|
const { start, end } = this;
|
|
1070
1161
|
const _t = t * (end - start) + start - 0.5 * Math.PI;
|
|
1071
|
-
return
|
|
1162
|
+
return output.set(Math.cos(_t), Math.sin(_t));
|
|
1072
1163
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
return this;
|
|
1164
|
+
getControlPoints() {
|
|
1165
|
+
return [this.center];
|
|
1076
1166
|
}
|
|
1077
1167
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
1078
1168
|
min.x = Math.min(min.x, this.center.x - this.radius);
|
|
@@ -1131,18 +1221,18 @@ class CubicBezierCurve extends Curve {
|
|
|
1131
1221
|
}
|
|
1132
1222
|
getPoint(t, output = new Vector2()) {
|
|
1133
1223
|
const { start, startControl, endControl, end } = this;
|
|
1134
|
-
output.set(
|
|
1224
|
+
return output.set(
|
|
1135
1225
|
cubicBezier(t, start.x, startControl.x, endControl.x, end.x),
|
|
1136
1226
|
cubicBezier(t, start.y, startControl.y, endControl.y, end.y)
|
|
1137
1227
|
);
|
|
1138
|
-
return output;
|
|
1139
1228
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1229
|
+
getControlPoints() {
|
|
1230
|
+
return [
|
|
1231
|
+
this.start,
|
|
1232
|
+
this.startControl,
|
|
1233
|
+
this.endControl,
|
|
1234
|
+
this.end
|
|
1235
|
+
];
|
|
1146
1236
|
}
|
|
1147
1237
|
_solveQuadratic(a, b, c) {
|
|
1148
1238
|
const discriminant = b * b - 4 * a * c;
|
|
@@ -1185,7 +1275,7 @@ class CubicBezierCurve extends Curve {
|
|
|
1185
1275
|
samplePoints(tValues, 10);
|
|
1186
1276
|
return { min, max };
|
|
1187
1277
|
}
|
|
1188
|
-
|
|
1278
|
+
toCommands() {
|
|
1189
1279
|
const { start, startControl, endControl, end } = this;
|
|
1190
1280
|
return [
|
|
1191
1281
|
{ type: "M", x: start.x, y: start.y },
|
|
@@ -1193,7 +1283,8 @@ class CubicBezierCurve extends Curve {
|
|
|
1193
1283
|
];
|
|
1194
1284
|
}
|
|
1195
1285
|
drawTo(ctx) {
|
|
1196
|
-
const { startControl, endControl, end } = this;
|
|
1286
|
+
const { start, startControl, endControl, end } = this;
|
|
1287
|
+
ctx.lineTo(start.x, start.y);
|
|
1197
1288
|
ctx.bezierCurveTo(startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y);
|
|
1198
1289
|
return this;
|
|
1199
1290
|
}
|
|
@@ -1222,6 +1313,9 @@ class EllipseCurve extends Curve {
|
|
|
1222
1313
|
this.endAngle = endAngle;
|
|
1223
1314
|
this.clockwise = clockwise;
|
|
1224
1315
|
}
|
|
1316
|
+
isClockwise() {
|
|
1317
|
+
return this.clockwise;
|
|
1318
|
+
}
|
|
1225
1319
|
getPoint(t, output = new Vector2()) {
|
|
1226
1320
|
const twoPi = Math.PI * 2;
|
|
1227
1321
|
let deltaAngle = this.endAngle - this.startAngle;
|
|
@@ -1257,7 +1351,7 @@ class EllipseCurve extends Curve {
|
|
|
1257
1351
|
}
|
|
1258
1352
|
return output.set(_x, _y);
|
|
1259
1353
|
}
|
|
1260
|
-
|
|
1354
|
+
toCommands() {
|
|
1261
1355
|
const { center, radiusX: rx, radiusY: ry, startAngle, endAngle, clockwise, rotation } = this;
|
|
1262
1356
|
const { x: cx, y: cy } = center;
|
|
1263
1357
|
const startX = cx + rx * Math.cos(startAngle) * Math.cos(rotation) - ry * Math.sin(startAngle) * Math.sin(rotation);
|
|
@@ -1298,7 +1392,7 @@ class EllipseCurve extends Curve {
|
|
|
1298
1392
|
);
|
|
1299
1393
|
return this;
|
|
1300
1394
|
}
|
|
1301
|
-
|
|
1395
|
+
matrix(matrix) {
|
|
1302
1396
|
tempV2.set(this.center.x, this.center.y);
|
|
1303
1397
|
tempV2.applyMatrix3(matrix);
|
|
1304
1398
|
this.center.x = tempV2.x;
|
|
@@ -1310,9 +1404,8 @@ class EllipseCurve extends Curve {
|
|
|
1310
1404
|
}
|
|
1311
1405
|
return this;
|
|
1312
1406
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
return this;
|
|
1407
|
+
getControlPoints() {
|
|
1408
|
+
return [this.center];
|
|
1316
1409
|
}
|
|
1317
1410
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
1318
1411
|
const { center, radiusX: rx, radiusY: ry, rotation: theta } = this;
|
|
@@ -1494,7 +1587,7 @@ class LineCurve extends Curve {
|
|
|
1494
1587
|
if (t === 1) {
|
|
1495
1588
|
output.copy(this.end);
|
|
1496
1589
|
} else {
|
|
1497
|
-
output.copy(this.end).sub(this.start).
|
|
1590
|
+
output.copy(this.end).sub(this.start).scale(t).add(this.start);
|
|
1498
1591
|
}
|
|
1499
1592
|
return output;
|
|
1500
1593
|
}
|
|
@@ -1507,14 +1600,11 @@ class LineCurve extends Curve {
|
|
|
1507
1600
|
getTangentAt(u, output = new Vector2()) {
|
|
1508
1601
|
return this.getTangent(u, output);
|
|
1509
1602
|
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
cb(this.start);
|
|
1516
|
-
cb(this.end);
|
|
1517
|
-
return this;
|
|
1603
|
+
getControlPoints() {
|
|
1604
|
+
return [
|
|
1605
|
+
this.start,
|
|
1606
|
+
this.end
|
|
1607
|
+
];
|
|
1518
1608
|
}
|
|
1519
1609
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
1520
1610
|
const { start, end } = this;
|
|
@@ -1524,7 +1614,7 @@ class LineCurve extends Curve {
|
|
|
1524
1614
|
max.y = Math.max(max.y, start.y, end.y);
|
|
1525
1615
|
return { min, max };
|
|
1526
1616
|
}
|
|
1527
|
-
|
|
1617
|
+
toCommands() {
|
|
1528
1618
|
const { start, end } = this;
|
|
1529
1619
|
return [
|
|
1530
1620
|
{ type: "M", x: start.x, y: start.y },
|
|
@@ -1532,7 +1622,8 @@ class LineCurve extends Curve {
|
|
|
1532
1622
|
];
|
|
1533
1623
|
}
|
|
1534
1624
|
drawTo(ctx) {
|
|
1535
|
-
const { end } = this;
|
|
1625
|
+
const { start, end } = this;
|
|
1626
|
+
ctx.lineTo(start.x, start.y);
|
|
1536
1627
|
ctx.lineTo(end.x, end.y);
|
|
1537
1628
|
return this;
|
|
1538
1629
|
}
|
|
@@ -1608,22 +1699,21 @@ class HeartCurve extends Curve {
|
|
|
1608
1699
|
}
|
|
1609
1700
|
return this.curves[index];
|
|
1610
1701
|
}
|
|
1611
|
-
getTangent(t) {
|
|
1612
|
-
return this.getCurve(t).getTangent(this.curveT);
|
|
1702
|
+
getTangent(t, output) {
|
|
1703
|
+
return this.getCurve(t).getTangent(this.curveT, output);
|
|
1613
1704
|
}
|
|
1614
|
-
getNormal(t) {
|
|
1615
|
-
return this.getCurve(t).getNormal(this.curveT);
|
|
1705
|
+
getNormal(t, output) {
|
|
1706
|
+
return this.getCurve(t).getNormal(this.curveT, output);
|
|
1616
1707
|
}
|
|
1617
|
-
|
|
1618
|
-
this.curves.
|
|
1619
|
-
return this;
|
|
1708
|
+
getControlPoints() {
|
|
1709
|
+
return this.curves.flatMap((curve) => curve.getControlPoints());
|
|
1620
1710
|
}
|
|
1621
1711
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
1622
1712
|
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
1623
1713
|
return { min, max };
|
|
1624
1714
|
}
|
|
1625
|
-
|
|
1626
|
-
return this.curves.flatMap((curve) => curve.
|
|
1715
|
+
toCommands() {
|
|
1716
|
+
return this.curves.flatMap((curve) => curve.toCommands());
|
|
1627
1717
|
}
|
|
1628
1718
|
drawTo(ctx) {
|
|
1629
1719
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
@@ -1686,16 +1776,15 @@ class PloygonCurve extends Curve {
|
|
|
1686
1776
|
getNormal(t, output) {
|
|
1687
1777
|
return this.getCurve(t).getNormal(this.curveT, output);
|
|
1688
1778
|
}
|
|
1689
|
-
|
|
1690
|
-
this.curves.
|
|
1691
|
-
return this;
|
|
1779
|
+
getControlPoints() {
|
|
1780
|
+
return this.curves.flatMap((curve) => curve.getControlPoints());
|
|
1692
1781
|
}
|
|
1693
1782
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
1694
1783
|
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
1695
1784
|
return { min, max };
|
|
1696
1785
|
}
|
|
1697
|
-
|
|
1698
|
-
return this.curves.flatMap((curve) => curve.
|
|
1786
|
+
toCommands() {
|
|
1787
|
+
return this.curves.flatMap((curve) => curve.toCommands());
|
|
1699
1788
|
}
|
|
1700
1789
|
drawTo(ctx) {
|
|
1701
1790
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
@@ -1718,11 +1807,12 @@ class QuadraticBezierCurve extends Curve {
|
|
|
1718
1807
|
);
|
|
1719
1808
|
return output;
|
|
1720
1809
|
}
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1810
|
+
getControlPoints() {
|
|
1811
|
+
return [
|
|
1812
|
+
this.start,
|
|
1813
|
+
this.control,
|
|
1814
|
+
this.end
|
|
1815
|
+
];
|
|
1726
1816
|
}
|
|
1727
1817
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
1728
1818
|
const { start, control, end } = this;
|
|
@@ -1736,7 +1826,7 @@ class QuadraticBezierCurve extends Curve {
|
|
|
1736
1826
|
max.y = Math.max(max.y, start.y, end.y, y1, y2);
|
|
1737
1827
|
return { min, max };
|
|
1738
1828
|
}
|
|
1739
|
-
|
|
1829
|
+
toCommands() {
|
|
1740
1830
|
const { start, control, end } = this;
|
|
1741
1831
|
return [
|
|
1742
1832
|
{ type: "M", x: start.x, y: start.y },
|
|
@@ -1744,7 +1834,8 @@ class QuadraticBezierCurve extends Curve {
|
|
|
1744
1834
|
];
|
|
1745
1835
|
}
|
|
1746
1836
|
drawTo(ctx) {
|
|
1747
|
-
const { control, end } = this;
|
|
1837
|
+
const { start, control, end } = this;
|
|
1838
|
+
ctx.lineTo(start.x, start.y);
|
|
1748
1839
|
ctx.quadraticCurveTo(control.x, control.y, end.x, end.y);
|
|
1749
1840
|
return this;
|
|
1750
1841
|
}
|
|
@@ -1834,16 +1925,15 @@ class RectangularCurve extends Curve {
|
|
|
1834
1925
|
getNormal(t, output) {
|
|
1835
1926
|
return this.getCurve(t).getNormal(this.curveT, output);
|
|
1836
1927
|
}
|
|
1837
|
-
|
|
1838
|
-
this.curves.
|
|
1839
|
-
return this;
|
|
1928
|
+
getControlPoints() {
|
|
1929
|
+
return this.curves.flatMap((curve) => curve.getControlPoints());
|
|
1840
1930
|
}
|
|
1841
1931
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
1842
1932
|
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
1843
1933
|
return { min, max };
|
|
1844
1934
|
}
|
|
1845
|
-
|
|
1846
|
-
return this.curves.flatMap((curve) => curve.
|
|
1935
|
+
toCommands() {
|
|
1936
|
+
return this.curves.flatMap((curve) => curve.toCommands());
|
|
1847
1937
|
}
|
|
1848
1938
|
drawTo(ctx) {
|
|
1849
1939
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
@@ -1871,9 +1961,8 @@ class SplineCurve extends Curve {
|
|
|
1871
1961
|
);
|
|
1872
1962
|
return output;
|
|
1873
1963
|
}
|
|
1874
|
-
|
|
1875
|
-
this.points
|
|
1876
|
-
return this;
|
|
1964
|
+
getControlPoints() {
|
|
1965
|
+
return this.points;
|
|
1877
1966
|
}
|
|
1878
1967
|
copy(source) {
|
|
1879
1968
|
super.copy(source);
|
|
@@ -1938,6 +2027,9 @@ class CurvePath extends Curve {
|
|
|
1938
2027
|
}
|
|
1939
2028
|
return output;
|
|
1940
2029
|
}
|
|
2030
|
+
getControlPoints() {
|
|
2031
|
+
return this.curves.flatMap((curve) => curve.getControlPoints());
|
|
2032
|
+
}
|
|
1941
2033
|
getLength() {
|
|
1942
2034
|
const lengths = this.getCurveLengths();
|
|
1943
2035
|
return lengths[lengths.length - 1];
|
|
@@ -2109,10 +2201,6 @@ class CurvePath extends Curve {
|
|
|
2109
2201
|
this._setCurrentPoint(points[points.length - 1]);
|
|
2110
2202
|
return this;
|
|
2111
2203
|
}
|
|
2112
|
-
transformPoint(cb) {
|
|
2113
|
-
this.curves.forEach((curve) => curve.transformPoint(cb));
|
|
2114
|
-
return this;
|
|
2115
|
-
}
|
|
2116
2204
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
2117
2205
|
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
2118
2206
|
return { min, max };
|
|
@@ -2121,8 +2209,8 @@ class CurvePath extends Curve {
|
|
|
2121
2209
|
const { min, max } = this.getMinMax();
|
|
2122
2210
|
return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
2123
2211
|
}
|
|
2124
|
-
|
|
2125
|
-
return this.curves.flatMap((curve) => curve.
|
|
2212
|
+
toCommands() {
|
|
2213
|
+
return this.curves.flatMap((curve) => curve.toCommands());
|
|
2126
2214
|
}
|
|
2127
2215
|
drawTo(ctx) {
|
|
2128
2216
|
const point = this.curves[0]?.getPoint(0);
|
|
@@ -2150,6 +2238,29 @@ class CurvePath extends Curve {
|
|
|
2150
2238
|
function toKebabCase(str) {
|
|
2151
2239
|
return str.replace(/[^a-z0-9]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
|
|
2152
2240
|
}
|
|
2241
|
+
function getIntersectionPoint(p1, p2, q1, q2) {
|
|
2242
|
+
const r = p2.clone().sub(p1);
|
|
2243
|
+
const s = q2.clone().sub(q1);
|
|
2244
|
+
const q1p1 = q1.clone().sub(p1);
|
|
2245
|
+
const crossRS = r.cross(s);
|
|
2246
|
+
if (crossRS === 0) {
|
|
2247
|
+
return new Vector2(
|
|
2248
|
+
(p1.x + q1.x) / 2,
|
|
2249
|
+
(p1.y + q1.y) / 2
|
|
2250
|
+
);
|
|
2251
|
+
}
|
|
2252
|
+
const t = q1p1.cross(s) / crossRS;
|
|
2253
|
+
if (Math.abs(t) > 1) {
|
|
2254
|
+
return new Vector2(
|
|
2255
|
+
(p1.x + q1.x) / 2,
|
|
2256
|
+
(p1.y + q1.y) / 2
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
return new Vector2(
|
|
2260
|
+
p1.x + t * r.x,
|
|
2261
|
+
p1.y + t * r.y
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2153
2264
|
|
|
2154
2265
|
var __defProp = Object.defineProperty;
|
|
2155
2266
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -2252,20 +2363,93 @@ class Path2D {
|
|
|
2252
2363
|
this.currentPath.splineThru(points);
|
|
2253
2364
|
return this;
|
|
2254
2365
|
}
|
|
2255
|
-
|
|
2256
|
-
this.paths.
|
|
2366
|
+
getControlPoints() {
|
|
2367
|
+
return this.paths.flatMap((path) => path.getControlPoints());
|
|
2368
|
+
}
|
|
2369
|
+
getCurves() {
|
|
2370
|
+
return this.paths.flatMap((path) => path.curves);
|
|
2371
|
+
}
|
|
2372
|
+
scale(sx, sy = sx, target = { x: 0, y: 0 }) {
|
|
2373
|
+
this.getControlPoints().forEach((point) => {
|
|
2374
|
+
point.scale(sx, sy, target);
|
|
2375
|
+
});
|
|
2257
2376
|
return this;
|
|
2258
2377
|
}
|
|
2259
|
-
|
|
2260
|
-
this.
|
|
2378
|
+
skew(ax, ay = 0, target = { x: 0, y: 0 }) {
|
|
2379
|
+
this.getControlPoints().forEach((point) => {
|
|
2380
|
+
point.skew(ax, ay, target);
|
|
2381
|
+
});
|
|
2261
2382
|
return this;
|
|
2262
2383
|
}
|
|
2263
|
-
|
|
2264
|
-
this.
|
|
2384
|
+
rotate(a, target = { x: 0, y: 0 }) {
|
|
2385
|
+
this.getControlPoints().forEach((point) => {
|
|
2386
|
+
point.rotate(a, target);
|
|
2387
|
+
});
|
|
2388
|
+
return this;
|
|
2389
|
+
}
|
|
2390
|
+
bold(b) {
|
|
2391
|
+
if (b === 0) {
|
|
2392
|
+
return this;
|
|
2393
|
+
}
|
|
2394
|
+
const curves = this.getCurves();
|
|
2395
|
+
const _list = [];
|
|
2396
|
+
const _isClockwise = [];
|
|
2397
|
+
const _points = [];
|
|
2398
|
+
curves.forEach((curve, index) => {
|
|
2399
|
+
const points = curve.getControlPoints();
|
|
2400
|
+
const isClockwise = curve.isClockwise();
|
|
2401
|
+
_points[index] = points;
|
|
2402
|
+
_isClockwise[index] = isClockwise;
|
|
2403
|
+
const start = points[0];
|
|
2404
|
+
const end = points[points.length - 1] ?? start;
|
|
2405
|
+
_list.push({
|
|
2406
|
+
start: isClockwise ? end : start,
|
|
2407
|
+
end: isClockwise ? start : end,
|
|
2408
|
+
index
|
|
2409
|
+
});
|
|
2410
|
+
});
|
|
2411
|
+
const list = [];
|
|
2412
|
+
_list.forEach((itemA, indexA) => {
|
|
2413
|
+
list[indexA] = [];
|
|
2414
|
+
_list.forEach((itemB, indexB) => {
|
|
2415
|
+
if (indexB !== indexA && itemB.start.equals(itemA.end)) {
|
|
2416
|
+
list[indexA].push(itemB.index);
|
|
2417
|
+
}
|
|
2418
|
+
});
|
|
2419
|
+
});
|
|
2420
|
+
curves.forEach((curve, index) => {
|
|
2421
|
+
const isClockwise = _isClockwise[index];
|
|
2422
|
+
const points = _points[index];
|
|
2423
|
+
points.forEach((point) => {
|
|
2424
|
+
const t = curve.getTForPoint(point);
|
|
2425
|
+
const dist = curve.getNormal(t).scale(isClockwise ? b : -b);
|
|
2426
|
+
point.add(dist);
|
|
2427
|
+
});
|
|
2428
|
+
});
|
|
2429
|
+
list.forEach((indexes, indexA) => {
|
|
2430
|
+
const pointsA = _points[indexA];
|
|
2431
|
+
indexes.forEach((indexB) => {
|
|
2432
|
+
const pointsB = _points[indexB];
|
|
2433
|
+
const point = getIntersectionPoint(
|
|
2434
|
+
pointsA[pointsA.length - 1],
|
|
2435
|
+
pointsA[pointsA.length - 2] ?? pointsA[pointsA.length - 1],
|
|
2436
|
+
pointsB[0],
|
|
2437
|
+
pointsB[1] ?? pointsB[0]
|
|
2438
|
+
);
|
|
2439
|
+
if (point) {
|
|
2440
|
+
pointsA[pointsA.length - 1].copy(point);
|
|
2441
|
+
pointsB[0].copy(point);
|
|
2442
|
+
}
|
|
2443
|
+
});
|
|
2444
|
+
});
|
|
2445
|
+
return this;
|
|
2446
|
+
}
|
|
2447
|
+
matrix(matrix) {
|
|
2448
|
+
this.getCurves().forEach((curve) => curve.matrix(matrix));
|
|
2265
2449
|
return this;
|
|
2266
2450
|
}
|
|
2267
2451
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN, withStyle = true) {
|
|
2268
|
-
this.
|
|
2452
|
+
this.getCurves().forEach((curve) => curve.getMinMax(min, max));
|
|
2269
2453
|
if (withStyle) {
|
|
2270
2454
|
const strokeHalfWidth = this.strokeWidth / 2;
|
|
2271
2455
|
min.x -= strokeHalfWidth;
|
|
@@ -2279,13 +2463,50 @@ class Path2D {
|
|
|
2279
2463
|
const { min, max } = this.getMinMax(void 0, void 0, withStyle);
|
|
2280
2464
|
return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
2281
2465
|
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2466
|
+
drawTo(ctx, style = {}) {
|
|
2467
|
+
style = { ...this.style, ...style };
|
|
2468
|
+
const { fill = "#000", stroke = "none" } = style;
|
|
2469
|
+
ctx.beginPath();
|
|
2470
|
+
ctx.save();
|
|
2471
|
+
setCanvasContext(ctx, style);
|
|
2472
|
+
this.paths.forEach((path) => {
|
|
2473
|
+
path.drawTo(ctx);
|
|
2474
|
+
});
|
|
2475
|
+
if (fill !== "none") {
|
|
2476
|
+
ctx.fill();
|
|
2477
|
+
}
|
|
2478
|
+
if (stroke !== "none") {
|
|
2479
|
+
ctx.stroke();
|
|
2480
|
+
}
|
|
2481
|
+
ctx.restore();
|
|
2482
|
+
return this;
|
|
2284
2483
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2484
|
+
drawControlPointsTo(ctx, style = {}) {
|
|
2485
|
+
style = { ...this.style, ...style };
|
|
2486
|
+
const { fill = "#000", stroke = "none" } = style;
|
|
2487
|
+
ctx.beginPath();
|
|
2488
|
+
ctx.save();
|
|
2489
|
+
setCanvasContext(ctx, style);
|
|
2490
|
+
this.getControlPoints().forEach((point) => {
|
|
2491
|
+
ctx.moveTo(point.x, point.y);
|
|
2492
|
+
ctx.arc(point.x, point.y, 4, 0, Math.PI * 2);
|
|
2493
|
+
});
|
|
2494
|
+
if (fill !== "none") {
|
|
2495
|
+
ctx.fill();
|
|
2496
|
+
}
|
|
2497
|
+
if (stroke !== "none") {
|
|
2498
|
+
ctx.stroke();
|
|
2499
|
+
}
|
|
2500
|
+
ctx.restore();
|
|
2501
|
+
return this;
|
|
2502
|
+
}
|
|
2503
|
+
toCommands() {
|
|
2504
|
+
return this.paths.flatMap((path) => path.toCommands());
|
|
2287
2505
|
}
|
|
2288
|
-
|
|
2506
|
+
toData() {
|
|
2507
|
+
return this.paths.map((path) => path.toData()).join(" ");
|
|
2508
|
+
}
|
|
2509
|
+
toSvgPathString() {
|
|
2289
2510
|
const style = {
|
|
2290
2511
|
...this.style,
|
|
2291
2512
|
fill: this.style.fill ?? "#000",
|
|
@@ -2306,40 +2527,21 @@ class Path2D {
|
|
|
2306
2527
|
cssText += `${key}:${cssStyle[key]};`;
|
|
2307
2528
|
}
|
|
2308
2529
|
}
|
|
2309
|
-
return `<path d="${this.
|
|
2530
|
+
return `<path d="${this.toData()}" style="${cssText}"></path>`;
|
|
2310
2531
|
}
|
|
2311
|
-
|
|
2532
|
+
toSvgString() {
|
|
2312
2533
|
const { x, y, width, height } = this.getBoundingBox();
|
|
2313
|
-
const path = this.
|
|
2534
|
+
const path = this.toSvgPathString();
|
|
2314
2535
|
return `<svg viewBox="${x} ${y} ${width} ${height}" width="${width}px" height="${height}px" xmlns="http://www.w3.org/2000/svg">${path}</svg>`;
|
|
2315
2536
|
}
|
|
2316
|
-
|
|
2317
|
-
return `data:image/svg+xml;base64,${btoa(this.
|
|
2318
|
-
}
|
|
2319
|
-
drawTo(ctx, style = {}) {
|
|
2320
|
-
style = { ...this.style, ...style };
|
|
2321
|
-
const { fill = "#000", stroke = "none" } = style;
|
|
2322
|
-
setCanvasContext(ctx, style);
|
|
2323
|
-
this.paths.forEach((path) => {
|
|
2324
|
-
path.drawTo(ctx);
|
|
2325
|
-
});
|
|
2326
|
-
if (fill !== "none") {
|
|
2327
|
-
ctx.fill();
|
|
2328
|
-
}
|
|
2329
|
-
if (stroke !== "none") {
|
|
2330
|
-
ctx.stroke();
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
copy(source) {
|
|
2334
|
-
this.currentPath = source.currentPath.clone();
|
|
2335
|
-
this.paths = source.paths.map((path) => path.clone());
|
|
2336
|
-
this.style = { ...source.style };
|
|
2337
|
-
return this;
|
|
2537
|
+
toSvgUrl() {
|
|
2538
|
+
return `data:image/svg+xml;base64,${btoa(this.toSvgString())}`;
|
|
2338
2539
|
}
|
|
2339
2540
|
toSvg() {
|
|
2340
|
-
return new DOMParser().parseFromString(this.
|
|
2541
|
+
return new DOMParser().parseFromString(this.toSvgString(), "image/svg+xml").documentElement;
|
|
2341
2542
|
}
|
|
2342
|
-
toCanvas(
|
|
2543
|
+
toCanvas(options = {}) {
|
|
2544
|
+
const { pixelRatio = 2, ...style } = options;
|
|
2343
2545
|
const { left, top, width, height } = this.getBoundingBox();
|
|
2344
2546
|
const canvas = document.createElement("canvas");
|
|
2345
2547
|
canvas.width = width * pixelRatio;
|
|
@@ -2350,10 +2552,16 @@ class Path2D {
|
|
|
2350
2552
|
if (ctx) {
|
|
2351
2553
|
ctx.scale(pixelRatio, pixelRatio);
|
|
2352
2554
|
ctx.translate(-left, -top);
|
|
2353
|
-
this.drawTo(ctx);
|
|
2555
|
+
this.drawTo(ctx, style);
|
|
2354
2556
|
}
|
|
2355
2557
|
return canvas;
|
|
2356
2558
|
}
|
|
2559
|
+
copy(source) {
|
|
2560
|
+
this.currentPath = source.currentPath.clone();
|
|
2561
|
+
this.paths = source.paths.map((path) => path.clone());
|
|
2562
|
+
this.style = { ...source.style };
|
|
2563
|
+
return this;
|
|
2564
|
+
}
|
|
2357
2565
|
clone() {
|
|
2358
2566
|
return new this.constructor().copy(this);
|
|
2359
2567
|
}
|
|
@@ -2830,7 +3038,7 @@ function parseNode(node, style, paths = []) {
|
|
|
2830
3038
|
const transformStack = [];
|
|
2831
3039
|
const transform = getNodeTransform(node, currentTransform, transformStack);
|
|
2832
3040
|
if (path) {
|
|
2833
|
-
path.
|
|
3041
|
+
path.matrix(currentTransform);
|
|
2834
3042
|
paths.push(path);
|
|
2835
3043
|
path.style = style;
|
|
2836
3044
|
}
|
|
@@ -2879,4 +3087,14 @@ function parseSvg(svg) {
|
|
|
2879
3087
|
return parseNode(parseSvgToDom(svg), {});
|
|
2880
3088
|
}
|
|
2881
3089
|
|
|
2882
|
-
|
|
3090
|
+
function getPathsBoundingBox(paths) {
|
|
3091
|
+
if (!paths.length) {
|
|
3092
|
+
return void 0;
|
|
3093
|
+
}
|
|
3094
|
+
const min = Vector2.MAX;
|
|
3095
|
+
const max = Vector2.MIN;
|
|
3096
|
+
paths.forEach((path) => path.getMinMax(min, max));
|
|
3097
|
+
return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
export { BoundingBox, CircleCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, HeartCurve, LineCurve, Matrix3, Path2D, PloygonCurve, QuadraticBezierCurve, RectangularCurve, SplineCurve, Vector2, addPathCommandsToPath2D, getPathsBoundingBox, parseArcCommand, parsePathDataArgs, parseSvg, parseSvgToDom, pathCommandsToPathData, pathDataToPathCommands, setCanvasContext };
|