@mocanvas/mocanvas 1.0.0 → 4.0.0
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/ARCHITECTURE.md +421 -0
- package/BENCHMARK.md +519 -0
- package/CLEAN_ROOM.md +50 -0
- package/COMPAT.md +282 -0
- package/CUSTOM_SHAPES.md +880 -0
- package/LICENSE +110 -16
- package/MIGRATION.md +807 -0
- package/README.md +122 -6
- package/UI.md +256 -0
- package/dist/chunk-DMCI6V5Y.js +3370 -0
- package/dist/chunk-DMCI6V5Y.js.map +1 -0
- package/dist/chunk-GYF6AY4N.js +54 -0
- package/dist/chunk-GYF6AY4N.js.map +1 -0
- package/dist/chunk-OCYJAMXT.js +1117 -0
- package/dist/chunk-OCYJAMXT.js.map +1 -0
- package/dist/chunk-OMUOD53T.js +370 -0
- package/dist/chunk-OMUOD53T.js.map +1 -0
- package/dist/chunk-QDUQZXE4.js +1340 -0
- package/dist/chunk-QDUQZXE4.js.map +1 -0
- package/dist/chunk-TWCVRVK2.js +296 -0
- package/dist/chunk-TWCVRVK2.js.map +1 -0
- package/dist/export-VQGOVONC.js +5 -0
- package/dist/export-VQGOVONC.js.map +1 -0
- package/dist/file-GEHTVI2G.js +3 -0
- package/dist/file-GEHTVI2G.js.map +1 -0
- package/dist/index.d.ts +9593 -1659
- package/dist/index.js +9005 -6114
- package/dist/index.js.map +1 -1
- package/dist/panel-shortcuts-R2PDTDUN.js +4 -0
- package/dist/panel-shortcuts-R2PDTDUN.js.map +1 -0
- package/dist/{ui-62NV5N7K.css → ui-4C5V5GYT.css} +385 -0
- package/dist/urlContent-GC44EU52.js +4 -0
- package/dist/urlContent-GC44EU52.js.map +1 -0
- package/package.json +17 -16
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { PATH_OP, Vec, Mat, Polygon2d, Group2d, Polyline2d, CubicSpline2d, Ellipse2d } from '@mocanvas/editor';
|
|
2
|
+
|
|
3
|
+
// src/shapes/spline-helpers.ts
|
|
4
|
+
function lineSegment(a, b) {
|
|
5
|
+
return { p0: a, c1: Vec.Lrp(a, b, 1 / 3), c2: Vec.Lrp(a, b, 2 / 3), p1: b };
|
|
6
|
+
}
|
|
7
|
+
function arcToCubicSegments(center, radius, startAngle, sweep, count = 2) {
|
|
8
|
+
const n = Math.max(1, Math.floor(count));
|
|
9
|
+
const step = sweep / n;
|
|
10
|
+
const k = 4 / 3 * Math.tan(step / 4) * radius;
|
|
11
|
+
const out = [];
|
|
12
|
+
for (let i = 0; i < n; i++) {
|
|
13
|
+
const a0 = startAngle + step * i;
|
|
14
|
+
const a1 = a0 + step;
|
|
15
|
+
const p0 = { x: center.x + radius * Math.cos(a0), y: center.y + radius * Math.sin(a0) };
|
|
16
|
+
const p1 = { x: center.x + radius * Math.cos(a1), y: center.y + radius * Math.sin(a1) };
|
|
17
|
+
out.push({
|
|
18
|
+
p0,
|
|
19
|
+
c1: { x: p0.x - k * Math.sin(a0), y: p0.y + k * Math.cos(a0) },
|
|
20
|
+
c2: { x: p1.x + k * Math.sin(a1), y: p1.y - k * Math.cos(a1) },
|
|
21
|
+
p1
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
function catmullRomToBezier(points, closed = false) {
|
|
27
|
+
const n = points.length;
|
|
28
|
+
if (n < 2) return [];
|
|
29
|
+
const at = (i) => {
|
|
30
|
+
if (closed) return points[(i % n + n) % n];
|
|
31
|
+
return points[Math.max(0, Math.min(n - 1, i))];
|
|
32
|
+
};
|
|
33
|
+
const segCount = closed ? n : n - 1;
|
|
34
|
+
const out = [];
|
|
35
|
+
for (let i = 0; i < segCount; i++) {
|
|
36
|
+
const p0 = at(i - 1);
|
|
37
|
+
const p1 = at(i);
|
|
38
|
+
const p2 = at(i + 1);
|
|
39
|
+
const p3 = at(i + 2);
|
|
40
|
+
out.push({
|
|
41
|
+
p0: p1,
|
|
42
|
+
c1: { x: p1.x + (p2.x - p0.x) / 6, y: p1.y + (p2.y - p0.y) / 6 },
|
|
43
|
+
c2: { x: p2.x - (p3.x - p1.x) / 6, y: p2.y - (p3.y - p1.y) / 6 },
|
|
44
|
+
p1: p2
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
function pointOnCubic(s, t) {
|
|
50
|
+
const u = 1 - t;
|
|
51
|
+
return new Vec(
|
|
52
|
+
u * u * u * s.p0.x + 3 * u * u * t * s.c1.x + 3 * u * t * t * s.c2.x + t * t * t * s.p1.x,
|
|
53
|
+
u * u * u * s.p0.y + 3 * u * u * t * s.c1.y + 3 * u * t * t * s.c2.y + t * t * t * s.p1.y
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
var PATH_OP_PAIRS = {
|
|
57
|
+
[PATH_OP.MOVE]: 1,
|
|
58
|
+
[PATH_OP.LINE]: 1,
|
|
59
|
+
[PATH_OP.QUAD]: 2,
|
|
60
|
+
[PATH_OP.CUBIC]: 3,
|
|
61
|
+
[PATH_OP.CLOSE]: 0
|
|
62
|
+
};
|
|
63
|
+
function num(v) {
|
|
64
|
+
const n = v ?? 0;
|
|
65
|
+
return String(Math.round(n * 100) / 100);
|
|
66
|
+
}
|
|
67
|
+
function pathWordsToSvgD(words) {
|
|
68
|
+
const parts = [];
|
|
69
|
+
let i = 0;
|
|
70
|
+
while (i < words.length) {
|
|
71
|
+
const op = words[i];
|
|
72
|
+
switch (op) {
|
|
73
|
+
case PATH_OP.MOVE:
|
|
74
|
+
parts.push(`M${num(words[i + 1])} ${num(words[i + 2])}`);
|
|
75
|
+
i += 3;
|
|
76
|
+
break;
|
|
77
|
+
case PATH_OP.LINE:
|
|
78
|
+
parts.push(`L${num(words[i + 1])} ${num(words[i + 2])}`);
|
|
79
|
+
i += 3;
|
|
80
|
+
break;
|
|
81
|
+
case PATH_OP.QUAD:
|
|
82
|
+
parts.push(`Q${num(words[i + 1])} ${num(words[i + 2])} ${num(words[i + 3])} ${num(words[i + 4])}`);
|
|
83
|
+
i += 5;
|
|
84
|
+
break;
|
|
85
|
+
case PATH_OP.CUBIC:
|
|
86
|
+
parts.push(
|
|
87
|
+
`C${num(words[i + 1])} ${num(words[i + 2])} ${num(words[i + 3])} ${num(words[i + 4])} ${num(words[i + 5])} ${num(words[i + 6])}`
|
|
88
|
+
);
|
|
89
|
+
i += 7;
|
|
90
|
+
break;
|
|
91
|
+
case PATH_OP.CLOSE:
|
|
92
|
+
parts.push("Z");
|
|
93
|
+
i += 1;
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
return parts.join(" ");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return parts.join(" ");
|
|
100
|
+
}
|
|
101
|
+
function transformPathWords(words, mat) {
|
|
102
|
+
const m = mat instanceof Mat ? mat : Mat.From(mat);
|
|
103
|
+
const out = [];
|
|
104
|
+
let i = 0;
|
|
105
|
+
while (i < words.length) {
|
|
106
|
+
const op = words[i];
|
|
107
|
+
const pairs = PATH_OP_PAIRS[op];
|
|
108
|
+
if (pairs === void 0 || i + 1 + pairs * 2 > words.length) return out;
|
|
109
|
+
out.push(op);
|
|
110
|
+
for (let pair = 0; pair < pairs; pair++) {
|
|
111
|
+
const p = m.applyToPoint({ x: words[i + 1 + pair * 2], y: words[i + 2 + pair * 2] });
|
|
112
|
+
out.push(p.x, p.y);
|
|
113
|
+
}
|
|
114
|
+
i += 1 + pairs * 2;
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
var TAU = Math.PI * 2;
|
|
119
|
+
var STAR_INNER_RATIO = 0.5;
|
|
120
|
+
var HEXAGON_START_ANGLE = -Math.PI / 2;
|
|
121
|
+
var HEXAGON_FLAT_SIDE_SPAN = 0.5;
|
|
122
|
+
function fitPointsToBox(points, w, h) {
|
|
123
|
+
if (points.length === 0) return [];
|
|
124
|
+
let minX = Infinity;
|
|
125
|
+
let minY = Infinity;
|
|
126
|
+
let maxX = -Infinity;
|
|
127
|
+
let maxY = -Infinity;
|
|
128
|
+
for (const p of points) {
|
|
129
|
+
if (p.x < minX) minX = p.x;
|
|
130
|
+
if (p.y < minY) minY = p.y;
|
|
131
|
+
if (p.x > maxX) maxX = p.x;
|
|
132
|
+
if (p.y > maxY) maxY = p.y;
|
|
133
|
+
}
|
|
134
|
+
const sx = maxX - minX > 0 ? w / (maxX - minX) : 0;
|
|
135
|
+
const sy = maxY - minY > 0 ? h / (maxY - minY) : 0;
|
|
136
|
+
return points.map((p) => ({ x: (p.x - minX) * sx, y: (p.y - minY) * sy }));
|
|
137
|
+
}
|
|
138
|
+
function regularPolygon(sides, startAngle, w, h, innerRatio) {
|
|
139
|
+
const count = innerRatio === void 0 ? sides : sides * 2;
|
|
140
|
+
const raw = [];
|
|
141
|
+
for (let i = 0; i < count; i++) {
|
|
142
|
+
const a = startAngle + i / count * TAU;
|
|
143
|
+
const r = innerRatio !== void 0 && i % 2 === 1 ? innerRatio : 1;
|
|
144
|
+
raw.push({ x: Math.cos(a) * r, y: Math.sin(a) * r });
|
|
145
|
+
}
|
|
146
|
+
return fitPointsToBox(raw, w, h);
|
|
147
|
+
}
|
|
148
|
+
function blockArrowRight(w, h) {
|
|
149
|
+
const headLen = Math.min(w / 2, h / 2);
|
|
150
|
+
const shaftTop = h / 4;
|
|
151
|
+
const shaftBottom = 3 * h / 4;
|
|
152
|
+
return [
|
|
153
|
+
{ x: 0, y: shaftTop },
|
|
154
|
+
{ x: w - headLen, y: shaftTop },
|
|
155
|
+
{ x: w - headLen, y: 0 },
|
|
156
|
+
{ x: w, y: h / 2 },
|
|
157
|
+
{ x: w - headLen, y: h },
|
|
158
|
+
{ x: w - headLen, y: shaftBottom },
|
|
159
|
+
{ x: 0, y: shaftBottom }
|
|
160
|
+
];
|
|
161
|
+
}
|
|
162
|
+
function getGeoPolygonPoints(kind, w, h) {
|
|
163
|
+
switch (kind) {
|
|
164
|
+
case "rectangle":
|
|
165
|
+
case "x-box":
|
|
166
|
+
case "check-box":
|
|
167
|
+
return [
|
|
168
|
+
{ x: 0, y: 0 },
|
|
169
|
+
{ x: w, y: 0 },
|
|
170
|
+
{ x: w, y: h },
|
|
171
|
+
{ x: 0, y: h }
|
|
172
|
+
];
|
|
173
|
+
case "triangle":
|
|
174
|
+
return [
|
|
175
|
+
{ x: w / 2, y: 0 },
|
|
176
|
+
{ x: w, y: h },
|
|
177
|
+
{ x: 0, y: h }
|
|
178
|
+
];
|
|
179
|
+
case "diamond":
|
|
180
|
+
return [
|
|
181
|
+
{ x: w / 2, y: 0 },
|
|
182
|
+
{ x: w, y: h / 2 },
|
|
183
|
+
{ x: w / 2, y: h },
|
|
184
|
+
{ x: 0, y: h / 2 }
|
|
185
|
+
];
|
|
186
|
+
case "pentagon":
|
|
187
|
+
return regularPolygon(5, -Math.PI / 2, w, h);
|
|
188
|
+
case "hexagon":
|
|
189
|
+
return regularPolygon(6, HEXAGON_START_ANGLE, w, h);
|
|
190
|
+
case "octagon":
|
|
191
|
+
return regularPolygon(8, Math.PI / 8, w, h);
|
|
192
|
+
case "star":
|
|
193
|
+
return regularPolygon(5, -Math.PI / 2, w, h, STAR_INNER_RATIO);
|
|
194
|
+
case "rhombus": {
|
|
195
|
+
const off = Math.min(w / 3, h);
|
|
196
|
+
return [
|
|
197
|
+
{ x: off, y: 0 },
|
|
198
|
+
{ x: w, y: 0 },
|
|
199
|
+
{ x: w - off, y: h },
|
|
200
|
+
{ x: 0, y: h }
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
case "rhombus-2": {
|
|
204
|
+
const off = Math.min(w / 3, h);
|
|
205
|
+
return [
|
|
206
|
+
{ x: 0, y: 0 },
|
|
207
|
+
{ x: w - off, y: 0 },
|
|
208
|
+
{ x: w, y: h },
|
|
209
|
+
{ x: off, y: h }
|
|
210
|
+
];
|
|
211
|
+
}
|
|
212
|
+
case "trapezoid": {
|
|
213
|
+
const off = Math.min(w / 4, h / 2);
|
|
214
|
+
return [
|
|
215
|
+
{ x: off, y: 0 },
|
|
216
|
+
{ x: w - off, y: 0 },
|
|
217
|
+
{ x: w, y: h },
|
|
218
|
+
{ x: 0, y: h }
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
case "arrow-right":
|
|
222
|
+
return blockArrowRight(w, h);
|
|
223
|
+
case "arrow-left":
|
|
224
|
+
return blockArrowRight(w, h).map((p) => ({ x: w - p.x, y: p.y }));
|
|
225
|
+
case "arrow-down":
|
|
226
|
+
return blockArrowRight(h, w).map((p) => ({ x: p.y, y: p.x }));
|
|
227
|
+
case "arrow-up":
|
|
228
|
+
return blockArrowRight(h, w).map((p) => ({ x: p.y, y: h - p.x }));
|
|
229
|
+
case "ellipse":
|
|
230
|
+
case "oval":
|
|
231
|
+
case "cloud":
|
|
232
|
+
case "heart":
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function getGeoDecorations(kind, w, h, strokeWidth = 0) {
|
|
237
|
+
switch (kind) {
|
|
238
|
+
case "x-box": {
|
|
239
|
+
const d = Math.hypot(w, h);
|
|
240
|
+
const t = d > 0 ? Math.min(strokeWidth / 2 / d, 0.4) : 0;
|
|
241
|
+
const [dx, dy] = [w * t, h * t];
|
|
242
|
+
return [
|
|
243
|
+
[
|
|
244
|
+
{ x: dx, y: dy },
|
|
245
|
+
{ x: w - dx, y: h - dy }
|
|
246
|
+
],
|
|
247
|
+
[
|
|
248
|
+
{ x: w - dx, y: dy },
|
|
249
|
+
{ x: dx, y: h - dy }
|
|
250
|
+
]
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
case "check-box":
|
|
254
|
+
return [
|
|
255
|
+
[
|
|
256
|
+
{ x: w * 0.25, y: h * 0.52 },
|
|
257
|
+
{ x: w * 0.43, y: h * 0.72 },
|
|
258
|
+
{ x: w * 0.76, y: h * 0.3 }
|
|
259
|
+
]
|
|
260
|
+
];
|
|
261
|
+
default:
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function getStadiumSegments(w, h) {
|
|
266
|
+
if (w >= h) {
|
|
267
|
+
const r2 = h / 2;
|
|
268
|
+
return [
|
|
269
|
+
lineSegment({ x: r2, y: 0 }, { x: w - r2, y: 0 }),
|
|
270
|
+
...arcToCubicSegments({ x: w - r2, y: r2 }, r2, -Math.PI / 2, Math.PI, 2),
|
|
271
|
+
lineSegment({ x: w - r2, y: h }, { x: r2, y: h }),
|
|
272
|
+
...arcToCubicSegments({ x: r2, y: r2 }, r2, Math.PI / 2, Math.PI, 2)
|
|
273
|
+
];
|
|
274
|
+
}
|
|
275
|
+
const r = w / 2;
|
|
276
|
+
return [
|
|
277
|
+
...arcToCubicSegments({ x: r, y: r }, r, Math.PI, Math.PI, 2),
|
|
278
|
+
lineSegment({ x: w, y: r }, { x: w, y: h - r }),
|
|
279
|
+
...arcToCubicSegments({ x: r, y: h - r }, r, 0, Math.PI, 2),
|
|
280
|
+
lineSegment({ x: 0, y: h - r }, { x: 0, y: r })
|
|
281
|
+
];
|
|
282
|
+
}
|
|
283
|
+
function fitSegmentsToBox(segments, w, h) {
|
|
284
|
+
const b = new CubicSpline2d({ segments, isClosed: true }).bounds;
|
|
285
|
+
const sx = b.w > 0 ? w / b.w : 0;
|
|
286
|
+
const sy = b.h > 0 ? h / b.h : 0;
|
|
287
|
+
const map = (p) => ({ x: (p.x - b.x) * sx, y: (p.y - b.y) * sy });
|
|
288
|
+
return segments.map((s) => ({ p0: map(s.p0), c1: map(s.c1), c2: map(s.c2), p1: map(s.p1) }));
|
|
289
|
+
}
|
|
290
|
+
function getCloudSegments(w, h) {
|
|
291
|
+
const bumps = Math.max(5, Math.min(12, Math.round((w + h) / 40)));
|
|
292
|
+
const center = { x: w / 2, y: h / 2 };
|
|
293
|
+
const rx = w / 2 * 0.75;
|
|
294
|
+
const ry = h / 2 * 0.7;
|
|
295
|
+
const anchors = [];
|
|
296
|
+
for (let i = 0; i < bumps; i++) {
|
|
297
|
+
const a = -Math.PI / 2 + i / bumps * TAU;
|
|
298
|
+
anchors.push({ x: center.x + rx * Math.cos(a), y: center.y + ry * Math.sin(a) });
|
|
299
|
+
}
|
|
300
|
+
const segments = [];
|
|
301
|
+
for (let i = 0; i < bumps; i++) {
|
|
302
|
+
const a = anchors[i];
|
|
303
|
+
const b = anchors[(i + 1) % bumps];
|
|
304
|
+
const chord = Vec.Sub(b, a);
|
|
305
|
+
const len = Vec.Len(chord);
|
|
306
|
+
const mid = Vec.Lrp(a, b, 0.5);
|
|
307
|
+
let outward = Vec.Per(Vec.Uni(chord));
|
|
308
|
+
if (Vec.Dot(outward, Vec.Sub(mid, center)) < 0) outward = Vec.Mul(outward, -1);
|
|
309
|
+
const k = len * 0.55;
|
|
310
|
+
segments.push({
|
|
311
|
+
p0: a,
|
|
312
|
+
c1: Vec.Add(a, Vec.Mul(outward, k)),
|
|
313
|
+
c2: Vec.Add(b, Vec.Mul(outward, k)),
|
|
314
|
+
p1: b
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
return fitSegmentsToBox(segments, w, h);
|
|
318
|
+
}
|
|
319
|
+
function getHeartSegments(w, h) {
|
|
320
|
+
const P = (x, y) => ({ x: x * w, y: y * h });
|
|
321
|
+
return [
|
|
322
|
+
{ p0: P(0.5, 0.25), c1: P(0.5, 0.1), c2: P(0.35, 0), p1: P(0.25, 0) },
|
|
323
|
+
{ p0: P(0.25, 0), c1: P(0.1, 0), c2: P(0, 0.15), p1: P(0, 0.3) },
|
|
324
|
+
{ p0: P(0, 0.3), c1: P(0, 0.55), c2: P(0.25, 0.75), p1: P(0.5, 1) },
|
|
325
|
+
{ p0: P(0.5, 1), c1: P(0.75, 0.75), c2: P(1, 0.55), p1: P(1, 0.3) },
|
|
326
|
+
{ p0: P(1, 0.3), c1: P(1, 0.15), c2: P(0.9, 0), p1: P(0.75, 0) },
|
|
327
|
+
{ p0: P(0.75, 0), c1: P(0.65, 0), c2: P(0.5, 0.1), p1: P(0.5, 0.25) }
|
|
328
|
+
];
|
|
329
|
+
}
|
|
330
|
+
function hasGeoFlip(flip) {
|
|
331
|
+
return flip !== void 0 && (flip.flipX === true || flip.flipY === true);
|
|
332
|
+
}
|
|
333
|
+
function mirrorPointsInBox(points, w, h, flip) {
|
|
334
|
+
if (!hasGeoFlip(flip)) return points.map((p) => ({ x: p.x, y: p.y }));
|
|
335
|
+
const fx = flip.flipX === true;
|
|
336
|
+
const fy = flip.flipY === true;
|
|
337
|
+
return points.map((p) => ({ x: fx ? w - p.x : p.x, y: fy ? h - p.y : p.y }));
|
|
338
|
+
}
|
|
339
|
+
function mirrorSegmentsInBox(segments, w, h, flip) {
|
|
340
|
+
if (!hasGeoFlip(flip)) return segments.map((s) => ({ ...s }));
|
|
341
|
+
const fx = flip.flipX === true;
|
|
342
|
+
const fy = flip.flipY === true;
|
|
343
|
+
const map = (p) => ({ x: fx ? w - p.x : p.x, y: fy ? h - p.y : p.y });
|
|
344
|
+
return segments.map((s) => ({ p0: map(s.p0), c1: map(s.c1), c2: map(s.c2), p1: map(s.p1) }));
|
|
345
|
+
}
|
|
346
|
+
function getGeoGeometry(kind, w, h, isFilled, flip, strokeWidth = 0) {
|
|
347
|
+
switch (kind) {
|
|
348
|
+
case "ellipse":
|
|
349
|
+
return new Ellipse2d({ width: w, height: h, isFilled });
|
|
350
|
+
case "oval":
|
|
351
|
+
return new CubicSpline2d({ segments: mirrorSegmentsInBox(getStadiumSegments(w, h), w, h, flip), isClosed: true, isFilled });
|
|
352
|
+
case "cloud":
|
|
353
|
+
return new CubicSpline2d({ segments: mirrorSegmentsInBox(getCloudSegments(w, h), w, h, flip), isClosed: true, isFilled });
|
|
354
|
+
case "heart":
|
|
355
|
+
return new CubicSpline2d({ segments: mirrorSegmentsInBox(getHeartSegments(w, h), w, h, flip), isClosed: true, isFilled });
|
|
356
|
+
default: {
|
|
357
|
+
const points = mirrorPointsInBox(getGeoPolygonPoints(kind, w, h) ?? [], w, h, flip);
|
|
358
|
+
const body = new Polygon2d({ points, isFilled });
|
|
359
|
+
const decorations = getGeoDecorations(kind, w, h, strokeWidth);
|
|
360
|
+
if (decorations.length === 0) return body;
|
|
361
|
+
return new Group2d({
|
|
362
|
+
children: [body, ...decorations.map((points2) => new Polyline2d({ points: mirrorPointsInBox(points2, w, h, flip) }))]
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export { HEXAGON_FLAT_SIDE_SPAN, STAR_INNER_RATIO, arcToCubicSegments, catmullRomToBezier, fitPointsToBox, getCloudSegments, getGeoDecorations, getGeoGeometry, getGeoPolygonPoints, getHeartSegments, getStadiumSegments, hasGeoFlip, lineSegment, mirrorPointsInBox, mirrorSegmentsInBox, pathWordsToSvgD, pointOnCubic, transformPathWords };
|
|
369
|
+
//# sourceMappingURL=chunk-OMUOD53T.js.map
|
|
370
|
+
//# sourceMappingURL=chunk-OMUOD53T.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shapes/spline-helpers.ts","../src/shapes/svg-path.ts","../src/shapes/geo-helpers.ts"],"names":["r","Vec","points"],"mappings":"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","file":"chunk-OMUOD53T.js","sourcesContent":["/** Curve construction shared by the line, arrow and geo shapes. */\nimport { Vec, type VecLike } from \"@mocanvas/editor\"\n\nexport interface CubicSegment {\n p0: VecLike\n c1: VecLike\n c2: VecLike\n p1: VecLike\n}\n\n/** A straight line expressed as a cubic (control points at 1/3 and 2/3). */\nexport function lineSegment(a: VecLike, b: VecLike): CubicSegment {\n return { p0: a, c1: Vec.Lrp(a, b, 1 / 3), c2: Vec.Lrp(a, b, 2 / 3), p1: b }\n}\n\n/**\n * Approximate a circular arc with `count` cubic béziers.\n * `sweep` is signed: positive sweeps toward increasing angle (clockwise in\n * screen space where +y points down).\n */\nexport function arcToCubicSegments(\n center: VecLike,\n radius: number,\n startAngle: number,\n sweep: number,\n count = 2,\n): CubicSegment[] {\n const n = Math.max(1, Math.floor(count))\n const step = sweep / n\n // Tangent handle length for a cubic approximating an arc of `step` radians.\n const k = (4 / 3) * Math.tan(step / 4) * radius\n const out: CubicSegment[] = []\n for (let i = 0; i < n; i++) {\n const a0 = startAngle + step * i\n const a1 = a0 + step\n const p0 = { x: center.x + radius * Math.cos(a0), y: center.y + radius * Math.sin(a0) }\n const p1 = { x: center.x + radius * Math.cos(a1), y: center.y + radius * Math.sin(a1) }\n out.push({\n p0,\n c1: { x: p0.x - k * Math.sin(a0), y: p0.y + k * Math.cos(a0) },\n c2: { x: p1.x + k * Math.sin(a1), y: p1.y - k * Math.cos(a1) },\n p1,\n })\n }\n return out\n}\n\n/**\n * Convert a polyline into a smooth cubic spline that passes through every\n * point (uniform Catmull-Rom, tension 0.5, converted to bézier handles).\n * Endpoints are clamped so the curve starts and ends exactly on the first and\n * last points.\n */\nexport function catmullRomToBezier(points: readonly VecLike[], closed = false): CubicSegment[] {\n const n = points.length\n if (n < 2) return []\n const at = (i: number): VecLike => {\n if (closed) return points[((i % n) + n) % n]!\n return points[Math.max(0, Math.min(n - 1, i))]!\n }\n const segCount = closed ? n : n - 1\n const out: CubicSegment[] = []\n for (let i = 0; i < segCount; i++) {\n const p0 = at(i - 1)\n const p1 = at(i)\n const p2 = at(i + 1)\n const p3 = at(i + 2)\n out.push({\n p0: p1,\n c1: { x: p1.x + (p2.x - p0.x) / 6, y: p1.y + (p2.y - p0.y) / 6 },\n c2: { x: p2.x - (p3.x - p1.x) / 6, y: p2.y - (p3.y - p1.y) / 6 },\n p1: p2,\n })\n }\n return out\n}\n\n/** Evaluate a cubic segment at `t`. */\nexport function pointOnCubic(s: CubicSegment, t: number): Vec {\n const u = 1 - t\n return new Vec(\n u * u * u * s.p0.x + 3 * u * u * t * s.c1.x + 3 * u * t * t * s.c2.x + t * t * t * s.p1.x,\n u * u * u * s.p0.y + 3 * u * u * t * s.c1.y + 3 * u * t * t * s.c2.y + t * t * t * s.p1.y,\n )\n}\n","import { Mat, PATH_OP, type MatLike } from \"@mocanvas/editor\"\n\n/** How many x/y pairs follow each op word; the one table the path walk needs. */\nconst PATH_OP_PAIRS: Readonly<Record<number, number>> = {\n [PATH_OP.MOVE]: 1,\n [PATH_OP.LINE]: 1,\n [PATH_OP.QUAD]: 2,\n [PATH_OP.CUBIC]: 3,\n [PATH_OP.CLOSE]: 0,\n}\n\nfunction num(v: number | undefined): string {\n const n = v ?? 0\n return String(Math.round(n * 100) / 100)\n}\n\n/** Convert the engine's flat path encoding to an SVG `d` attribute (for indicators). */\nexport function pathWordsToSvgD(words: readonly number[]): string {\n const parts: string[] = []\n let i = 0\n while (i < words.length) {\n const op = words[i]\n switch (op) {\n case PATH_OP.MOVE:\n parts.push(`M${num(words[i + 1])} ${num(words[i + 2])}`)\n i += 3\n break\n case PATH_OP.LINE:\n parts.push(`L${num(words[i + 1])} ${num(words[i + 2])}`)\n i += 3\n break\n case PATH_OP.QUAD:\n parts.push(`Q${num(words[i + 1])} ${num(words[i + 2])} ${num(words[i + 3])} ${num(words[i + 4])}`)\n i += 5\n break\n case PATH_OP.CUBIC:\n parts.push(\n `C${num(words[i + 1])} ${num(words[i + 2])} ${num(words[i + 3])} ${num(words[i + 4])} ${num(words[i + 5])} ${num(words[i + 6])}`,\n )\n i += 7\n break\n case PATH_OP.CLOSE:\n parts.push(\"Z\")\n i += 1\n break\n default:\n // Malformed stream: stop rather than emit garbage.\n return parts.join(\" \")\n }\n }\n return parts.join(\" \")\n}\n\n/**\n * A copy of a flat path with `mat` applied to every point.\n *\n * mocanvas has no `PathBuilder`: a shape's outline is a `Geometry2d`,\n * and the *encoded* form every consumer of an outline shares is the engine's\n * flat word stream (`geometry.toPathWords()`), which is what\n * {@link pathWordsToSvgD} serializes and what the indicator layer strokes. So\n * this is where a path transform belongs — one function, applied to the one\n * encoding, rather than a second path abstraction that would have to be kept\n * in step with the first.\n *\n * ```ts\n * const flipped = transformPathWords(geometry.toPathWords(), Mat.Identity().translate(w, 0).scale(-1, 1))\n * const d = pathWordsToSvgD(flipped)\n * ```\n *\n * The input is never mutated. Control points transform with their anchors, so\n * a curve stays a curve (an affine map takes a cubic bézier to a cubic\n * bézier); a malformed stream is truncated at the bad word, exactly as\n * {@link pathWordsToSvgD} truncates it.\n */\nexport function transformPathWords(words: readonly number[], mat: MatLike): number[] {\n const m = mat instanceof Mat ? mat : Mat.From(mat)\n const out: number[] = []\n let i = 0\n while (i < words.length) {\n const op = words[i]!\n const pairs = PATH_OP_PAIRS[op]\n if (pairs === undefined || i + 1 + pairs * 2 > words.length) return out\n out.push(op)\n for (let pair = 0; pair < pairs; pair++) {\n const p = m.applyToPoint({ x: words[i + 1 + pair * 2]!, y: words[i + 2 + pair * 2]! })\n out.push(p.x, p.y)\n }\n i += 1 + pairs * 2\n }\n return out\n}\n","/**\n * Outline math for the `geo` shape. Every polygon is inscribed in the w×h box\n * so that its bounds are exactly the shape's bounds.\n */\nimport {\n CubicSpline2d,\n Ellipse2d,\n Group2d,\n Polygon2d,\n Polyline2d,\n Vec,\n type GeoShapeKind,\n type Geometry2d,\n type VecLike,\n} from \"@mocanvas/editor\"\nimport { arcToCubicSegments, lineSegment, type CubicSegment } from \"./spline-helpers\"\n\nconst TAU = Math.PI * 2\n\n/**\n * Inner radius of the five-pointed star, as a fraction of the outer radius.\n * Measured off a reference render (interior-IoU and outline least-squares fits\n * of the same star both put it at 0.51 ± 0.02, calibrated against a render of\n * known ratio); a plain half reads the same to well under a pixel at any\n * sensible size. A smaller ratio makes the arms too thin.\n */\nexport const STAR_INNER_RATIO = 0.5\n\n/**\n * Angle of the hexagon's first vertex. A vertex sits at the top and one at the\n * bottom, which leaves the left and right sides vertical and running the full\n * width of the box — that is the orientation the reference draws, and it is\n * what `HEXAGON_FLAT_SIDE_SPAN` describes.\n */\nconst HEXAGON_START_ANGLE = -Math.PI / 2\n\n/**\n * Fraction of the box height spanned by the hexagon's two vertical sides. They\n * are centred, so they run from `(1 - span) / 2` to `(1 + span) / 2` of the\n * height, and the distance across them is the full box width.\n */\nexport const HEXAGON_FLAT_SIDE_SPAN = 0.5\n\n/** Affinely stretch points so their bounding box becomes exactly [0,w]×[0,h]. */\nexport function fitPointsToBox(points: readonly VecLike[], w: number, h: number): VecLike[] {\n if (points.length === 0) return []\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const p of points) {\n if (p.x < minX) minX = p.x\n if (p.y < minY) minY = p.y\n if (p.x > maxX) maxX = p.x\n if (p.y > maxY) maxY = p.y\n }\n const sx = maxX - minX > 0 ? w / (maxX - minX) : 0\n const sy = maxY - minY > 0 ? h / (maxY - minY) : 0\n return points.map((p) => ({ x: (p.x - minX) * sx, y: (p.y - minY) * sy }))\n}\n\n/**\n * Regular polygon (or star when `innerRatio` is given) with `sides` outer\n * vertices, first vertex at `startAngle`, stretched to fill the box.\n */\nfunction regularPolygon(sides: number, startAngle: number, w: number, h: number, innerRatio?: number): VecLike[] {\n const count = innerRatio === undefined ? sides : sides * 2\n const raw: VecLike[] = []\n for (let i = 0; i < count; i++) {\n const a = startAngle + (i / count) * TAU\n const r = innerRatio !== undefined && i % 2 === 1 ? innerRatio : 1\n raw.push({ x: Math.cos(a) * r, y: Math.sin(a) * r })\n }\n return fitPointsToBox(raw, w, h)\n}\n\n/** Block arrow pointing +x inside a w×h box (7 vertices). */\nfunction blockArrowRight(w: number, h: number): VecLike[] {\n const headLen = Math.min(w / 2, h / 2)\n const shaftTop = h / 4\n const shaftBottom = (3 * h) / 4\n return [\n { x: 0, y: shaftTop },\n { x: w - headLen, y: shaftTop },\n { x: w - headLen, y: 0 },\n { x: w, y: h / 2 },\n { x: w - headLen, y: h },\n { x: w - headLen, y: shaftBottom },\n { x: 0, y: shaftBottom },\n ]\n}\n\n/**\n * Polygon vertices for the polygonal geo kinds, or `null` for the curved kinds\n * (ellipse, oval, cloud, heart). `x-box` and `check-box` return their frame;\n * see `getGeoDecorations` for the marks inside.\n */\nexport function getGeoPolygonPoints(kind: GeoShapeKind, w: number, h: number): VecLike[] | null {\n switch (kind) {\n case \"rectangle\":\n case \"x-box\":\n case \"check-box\":\n return [\n { x: 0, y: 0 },\n { x: w, y: 0 },\n { x: w, y: h },\n { x: 0, y: h },\n ]\n case \"triangle\":\n return [\n { x: w / 2, y: 0 },\n { x: w, y: h },\n { x: 0, y: h },\n ]\n case \"diamond\":\n return [\n { x: w / 2, y: 0 },\n { x: w, y: h / 2 },\n { x: w / 2, y: h },\n { x: 0, y: h / 2 },\n ]\n case \"pentagon\":\n return regularPolygon(5, -Math.PI / 2, w, h)\n case \"hexagon\":\n return regularPolygon(6, HEXAGON_START_ANGLE, w, h)\n case \"octagon\":\n return regularPolygon(8, Math.PI / 8, w, h)\n case \"star\":\n return regularPolygon(5, -Math.PI / 2, w, h, STAR_INNER_RATIO)\n case \"rhombus\": {\n const off = Math.min(w / 3, h)\n return [\n { x: off, y: 0 },\n { x: w, y: 0 },\n { x: w - off, y: h },\n { x: 0, y: h },\n ]\n }\n case \"rhombus-2\": {\n const off = Math.min(w / 3, h)\n return [\n { x: 0, y: 0 },\n { x: w - off, y: 0 },\n { x: w, y: h },\n { x: off, y: h },\n ]\n }\n case \"trapezoid\": {\n const off = Math.min(w / 4, h / 2)\n return [\n { x: off, y: 0 },\n { x: w - off, y: 0 },\n { x: w, y: h },\n { x: 0, y: h },\n ]\n }\n case \"arrow-right\":\n return blockArrowRight(w, h)\n case \"arrow-left\":\n return blockArrowRight(w, h).map((p) => ({ x: w - p.x, y: p.y }))\n case \"arrow-down\":\n return blockArrowRight(h, w).map((p) => ({ x: p.y, y: p.x }))\n case \"arrow-up\":\n return blockArrowRight(h, w).map((p) => ({ x: p.y, y: h - p.x }))\n case \"ellipse\":\n case \"oval\":\n case \"cloud\":\n case \"heart\":\n return null\n }\n}\n\n/**\n * Open polylines drawn inside the outline (the X of an x-box, the tick of a\n * check-box).\n *\n * `strokeWidth` shortens the marks that end *on* the outline. A stroke is\n * centred on its path and its round cap reaches half a width beyond the last\n * point, so diagonals running corner to corner of the box came out as four\n * spikes sticking through the very outline they belong inside. Pulling each end\n * back by half a width lands the cap on the corner instead of past it. The\n * check-box's tick sits well clear of the edge and is left alone.\n */\nexport function getGeoDecorations(kind: GeoShapeKind, w: number, h: number, strokeWidth = 0): VecLike[][] {\n switch (kind) {\n case \"x-box\": {\n // Along the diagonal, not along an axis: the cap sticks out the way the\n // line is pointing.\n const d = Math.hypot(w, h)\n const t = d > 0 ? Math.min(strokeWidth / 2 / d, 0.4) : 0\n const [dx, dy] = [w * t, h * t]\n return [\n [\n { x: dx, y: dy },\n { x: w - dx, y: h - dy },\n ],\n [\n { x: w - dx, y: dy },\n { x: dx, y: h - dy },\n ],\n ]\n }\n case \"check-box\":\n return [\n [\n { x: w * 0.25, y: h * 0.52 },\n { x: w * 0.43, y: h * 0.72 },\n { x: w * 0.76, y: h * 0.3 },\n ],\n ]\n default:\n return []\n }\n}\n\n/** Stadium / capsule: two semicircles joined by straight sides. */\nexport function getStadiumSegments(w: number, h: number): CubicSegment[] {\n if (w >= h) {\n const r = h / 2\n return [\n lineSegment({ x: r, y: 0 }, { x: w - r, y: 0 }),\n ...arcToCubicSegments({ x: w - r, y: r }, r, -Math.PI / 2, Math.PI, 2),\n lineSegment({ x: w - r, y: h }, { x: r, y: h }),\n ...arcToCubicSegments({ x: r, y: r }, r, Math.PI / 2, Math.PI, 2),\n ]\n }\n const r = w / 2\n return [\n ...arcToCubicSegments({ x: r, y: r }, r, Math.PI, Math.PI, 2),\n lineSegment({ x: w, y: r }, { x: w, y: h - r }),\n ...arcToCubicSegments({ x: r, y: h - r }, r, 0, Math.PI, 2),\n lineSegment({ x: 0, y: h - r }, { x: 0, y: r }),\n ]\n}\n\n/** Stretch closed spline control points so the sampled outline fills [0,w]×[0,h]. */\nfunction fitSegmentsToBox(segments: CubicSegment[], w: number, h: number): CubicSegment[] {\n const b = new CubicSpline2d({ segments, isClosed: true }).bounds\n const sx = b.w > 0 ? w / b.w : 0\n const sy = b.h > 0 ? h / b.h : 0\n const map = (p: VecLike): VecLike => ({ x: (p.x - b.x) * sx, y: (p.y - b.y) * sy })\n return segments.map((s) => ({ p0: map(s.p0), c1: map(s.c1), c2: map(s.c2), p1: map(s.p1) }))\n}\n\n/** A ring of round bumps around an inner ellipse, fitted to the box. */\nexport function getCloudSegments(w: number, h: number): CubicSegment[] {\n const bumps = Math.max(5, Math.min(12, Math.round((w + h) / 40)))\n const center = { x: w / 2, y: h / 2 }\n const rx = (w / 2) * 0.75\n const ry = (h / 2) * 0.7\n const anchors: VecLike[] = []\n for (let i = 0; i < bumps; i++) {\n const a = -Math.PI / 2 + (i / bumps) * TAU\n anchors.push({ x: center.x + rx * Math.cos(a), y: center.y + ry * Math.sin(a) })\n }\n const segments: CubicSegment[] = []\n for (let i = 0; i < bumps; i++) {\n const a = anchors[i]!\n const b = anchors[(i + 1) % bumps]!\n const chord = Vec.Sub(b, a)\n const len = Vec.Len(chord)\n const mid = Vec.Lrp(a, b, 0.5)\n let outward = Vec.Per(Vec.Uni(chord))\n if (Vec.Dot(outward, Vec.Sub(mid, center)) < 0) outward = Vec.Mul(outward, -1)\n const k = len * 0.55\n segments.push({\n p0: a,\n c1: Vec.Add(a, Vec.Mul(outward, k)),\n c2: Vec.Add(b, Vec.Mul(outward, k)),\n p1: b,\n })\n }\n return fitSegmentsToBox(segments, w, h)\n}\n\n/** Classic two-lobed heart, six cubics, bounds exactly w×h. */\nexport function getHeartSegments(w: number, h: number): CubicSegment[] {\n const P = (x: number, y: number): VecLike => ({ x: x * w, y: y * h })\n return [\n { p0: P(0.5, 0.25), c1: P(0.5, 0.1), c2: P(0.35, 0), p1: P(0.25, 0) },\n { p0: P(0.25, 0), c1: P(0.1, 0), c2: P(0, 0.15), p1: P(0, 0.3) },\n { p0: P(0, 0.3), c1: P(0, 0.55), c2: P(0.25, 0.75), p1: P(0.5, 1) },\n { p0: P(0.5, 1), c1: P(0.75, 0.75), c2: P(1, 0.55), p1: P(1, 0.3) },\n { p0: P(1, 0.3), c1: P(1, 0.15), c2: P(0.9, 0), p1: P(0.75, 0) },\n { p0: P(0.75, 0), c1: P(0.65, 0), c2: P(0.5, 0.1), p1: P(0.5, 0.25) },\n ]\n}\n\n/**\n * Which axes a silhouette is mirrored about, inside its own `w × h` box.\n *\n * A flip is a property of the *outline*, not of the shape's transform: the box\n * and the label stay where they are, and only the drawing inside them turns\n * over. That is what makes a flipped triangle still occupy exactly its own\n * bounds, and what keeps its label upright.\n */\nexport interface GeoFlip {\n flipX?: boolean | undefined\n flipY?: boolean | undefined\n}\n\n/** Whether `flip` asks for anything at all. */\nexport function hasGeoFlip(flip: GeoFlip | undefined): boolean {\n return flip !== undefined && (flip.flipX === true || flip.flipY === true)\n}\n\n/** Mirror `points` about the centre of the `w × h` box on the requested axes. */\nexport function mirrorPointsInBox(points: readonly VecLike[], w: number, h: number, flip: GeoFlip | undefined): VecLike[] {\n if (!hasGeoFlip(flip)) return points.map((p) => ({ x: p.x, y: p.y }))\n const fx = flip!.flipX === true\n const fy = flip!.flipY === true\n return points.map((p) => ({ x: fx ? w - p.x : p.x, y: fy ? h - p.y : p.y }))\n}\n\n/** {@link mirrorPointsInBox} for cubic segments: every control point moves with its anchors. */\nexport function mirrorSegmentsInBox(segments: readonly CubicSegment[], w: number, h: number, flip: GeoFlip | undefined): CubicSegment[] {\n if (!hasGeoFlip(flip)) return segments.map((s) => ({ ...s }))\n const fx = flip!.flipX === true\n const fy = flip!.flipY === true\n const map = (p: VecLike): VecLike => ({ x: fx ? w - p.x : p.x, y: fy ? h - p.y : p.y })\n return segments.map((s) => ({ p0: map(s.p0), c1: map(s.c1), c2: map(s.c2), p1: map(s.p1) }))\n}\n\n/**\n * Build the outline geometry for a geo kind inside a w×h box.\n *\n * `flip` mirrors the silhouette in place — see {@link GeoFlip}. It is applied\n * to the *source* points and control points rather than to the finished\n * geometry, so a curved outline keeps its curves instead of being flattened\n * into a mirrored polygon.\n */\nexport function getGeoGeometry(kind: GeoShapeKind, w: number, h: number, isFilled: boolean, flip?: GeoFlip, strokeWidth = 0): Geometry2d {\n switch (kind) {\n case \"ellipse\":\n // An axis-aligned ellipse is its own mirror image on both axes.\n return new Ellipse2d({ width: w, height: h, isFilled })\n case \"oval\":\n // As is a stadium — but it is built from segments, so it goes through the\n // same path as the rest for the sake of one behaviour rather than two.\n return new CubicSpline2d({ segments: mirrorSegmentsInBox(getStadiumSegments(w, h), w, h, flip), isClosed: true, isFilled })\n case \"cloud\":\n return new CubicSpline2d({ segments: mirrorSegmentsInBox(getCloudSegments(w, h), w, h, flip), isClosed: true, isFilled })\n case \"heart\":\n return new CubicSpline2d({ segments: mirrorSegmentsInBox(getHeartSegments(w, h), w, h, flip), isClosed: true, isFilled })\n default: {\n const points = mirrorPointsInBox(getGeoPolygonPoints(kind, w, h) ?? [], w, h, flip)\n const body = new Polygon2d({ points, isFilled })\n const decorations = getGeoDecorations(kind, w, h, strokeWidth)\n if (decorations.length === 0) return body\n return new Group2d({\n children: [body, ...decorations.map((points) => new Polyline2d({ points: mirrorPointsInBox(points, w, h, flip) }))],\n })\n }\n }\n}\n"]}
|