@kyralabs/m3e-shapes 1.2.0 → 1.4.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/dist/index.d.ts +95 -2
- package/dist/index.js +347 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -291,7 +291,7 @@ declare function pillStar(options?: {
|
|
|
291
291
|
centerY?: number;
|
|
292
292
|
}): RoundedPolygon;
|
|
293
293
|
|
|
294
|
-
type PathCommand = readonly ['M', number, number] | readonly ['L', number, number] | readonly ['C', number, number, number, number, number, number] | readonly ['Z'];
|
|
294
|
+
type PathCommand = readonly ['M', number, number] | readonly ['L', number, number] | readonly ['Q', number, number, number, number] | readonly ['C', number, number, number, number, number, number] | readonly ['Z'];
|
|
295
295
|
/** Compose `Path.translate(offset)`. */
|
|
296
296
|
declare const translatePath: (path: readonly PathCommand[], dx: number, dy: number) => PathCommand[];
|
|
297
297
|
/**
|
|
@@ -414,6 +414,99 @@ declare const materialShapeNames: MaterialShapeName[];
|
|
|
414
414
|
*/
|
|
415
415
|
declare function materialShape(name: MaterialShapeName): RoundedPolygon;
|
|
416
416
|
|
|
417
|
+
declare class PathMeasure {
|
|
418
|
+
#private;
|
|
419
|
+
/** Length of the first contour. */
|
|
420
|
+
readonly length: number;
|
|
421
|
+
/**
|
|
422
|
+
* Measures the first contour of `path`. With `forceClosed` (or a `Z`), a closing line back to
|
|
423
|
+
* the contour's start is part of it.
|
|
424
|
+
*/
|
|
425
|
+
constructor(path: readonly PathCommand[], forceClosed?: boolean);
|
|
426
|
+
/** Compose `PathMeasure.getSegment(startD, stopD, destination)` (moveTo first). */
|
|
427
|
+
getSegment(startD: number, stopD: number): PathCommand[];
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** Stroke widths (px) and whether the caps are round (StrokeCap.Round, the default). */
|
|
431
|
+
interface ProgressStrokes {
|
|
432
|
+
stroke: number;
|
|
433
|
+
trackStroke: number;
|
|
434
|
+
round?: boolean;
|
|
435
|
+
}
|
|
436
|
+
interface LinearWavyInput extends ProgressStrokes {
|
|
437
|
+
width: number;
|
|
438
|
+
height: number;
|
|
439
|
+
/** Wavelength in px (applies when amplitude > 0). */
|
|
440
|
+
wavelength: number;
|
|
441
|
+
/** Pairs of [start, end] fractions (0–1): one pair (determinate) or two (indeterminate). */
|
|
442
|
+
fractions: readonly number[];
|
|
443
|
+
/** 0–1 of the room the height leaves the stroke. */
|
|
444
|
+
amplitude: number;
|
|
445
|
+
/** 0–1: how far along a wavelength the wave has travelled. */
|
|
446
|
+
waveOffset: number;
|
|
447
|
+
/** Gap between the progress and the track (px). */
|
|
448
|
+
gap: number;
|
|
449
|
+
}
|
|
450
|
+
interface LinearWavyPaths {
|
|
451
|
+
track: PathCommand[];
|
|
452
|
+
/** One path per fraction pair (empty when the pair has no length). */
|
|
453
|
+
progress: PathCommand[][];
|
|
454
|
+
/** `currentStrokeCapWidth`. */
|
|
455
|
+
capWidth: number;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Linear wavy paths, LTR (Compose rotates the drawing 180° for RTL). Reuse one instance per
|
|
459
|
+
* indicator: like LinearProgressDrawingCache it caches the measured full path.
|
|
460
|
+
*/
|
|
461
|
+
declare class LinearWavyPathCache {
|
|
462
|
+
#private;
|
|
463
|
+
/** `updateDrawPaths`: the progress parts and the track for these fractions. */
|
|
464
|
+
paths(input: LinearWavyInput): LinearWavyPaths;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* The wavy linear stop indicator (`drawStopIndicator`): a dot of min(track stroke, `maxSize`) at the
|
|
468
|
+
* end of the track that shrinks away as the progress reaches it. Returns its left edge and
|
|
469
|
+
* diameter (LTR), or null when it has shrunk to nothing.
|
|
470
|
+
*/
|
|
471
|
+
declare function linearWavyStopIndicator(progressEnd: number, width: number, maxSize: number, insets: number, trackStroke: number): {
|
|
472
|
+
x: number;
|
|
473
|
+
size: number;
|
|
474
|
+
} | null;
|
|
475
|
+
/**
|
|
476
|
+
* The wave count of a circular wavy indicator: as many wavelengths as fit around the circle (its
|
|
477
|
+
* radius inset by half the stroke), at least 5 (`MinCircularVertexCount`).
|
|
478
|
+
*/
|
|
479
|
+
declare const circularWavyVertexCount: (size: number, wavelength: number, stroke: number) => number;
|
|
480
|
+
interface CircularWavyInput extends ProgressStrokes {
|
|
481
|
+
/** Square drawing size (px). */
|
|
482
|
+
size: number;
|
|
483
|
+
/** Preferred wavelength (px); the actual one fits a whole number of waves. */
|
|
484
|
+
wavelength: number;
|
|
485
|
+
start: number;
|
|
486
|
+
end: number;
|
|
487
|
+
amplitude: number;
|
|
488
|
+
waveOffset: number;
|
|
489
|
+
/** The wave offset applies (waveSpeed > 0 and a wave is drawn). */
|
|
490
|
+
motion: boolean;
|
|
491
|
+
gap: number;
|
|
492
|
+
}
|
|
493
|
+
interface CircularWavyPaths {
|
|
494
|
+
track: PathCommand[];
|
|
495
|
+
progress: PathCommand[];
|
|
496
|
+
/** Wave count, which scales the circular wave travel duration. */
|
|
497
|
+
vertexCount: number;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Circular wavy paths (CircularShapes + CircularProgressDrawingCache). Reuse one instance per
|
|
501
|
+
* indicator: it caches the polygons, the morph (created the first time the amplitude is between 0
|
|
502
|
+
* and 1, `requiresMorph`) and the measured full paths.
|
|
503
|
+
*/
|
|
504
|
+
declare class CircularWavyPathCache {
|
|
505
|
+
#private;
|
|
506
|
+
/** The paths for `input`; `requiresMorph` as the Compose node passes it. */
|
|
507
|
+
paths(input: CircularWavyInput, requiresMorph: boolean): CircularWavyPaths;
|
|
508
|
+
}
|
|
509
|
+
|
|
417
510
|
interface PathOptions {
|
|
418
511
|
/**
|
|
419
512
|
* Angle in degrees the path starts drawing from. Note that, as in Compose, the path is rotated
|
|
@@ -434,4 +527,4 @@ interface MorphPathOptions extends PathOptions {
|
|
|
434
527
|
/** Path for a [Morph] at [progress]; the start angle is measured around the rotation pivot. */
|
|
435
528
|
declare function morphToPath(morph: Morph, progress: number, options?: MorphPathOptions): PathCommand[];
|
|
436
529
|
|
|
437
|
-
export { Corner, CornerRounding, Cubic, Edge, Feature, type LoadingIndicatorFrame, LoadingIndicatorShapes, type MaterialShapeName, Morph, type MorphPathOptions, MutableCubic, type PathCommand, type PathOptions, type Point, type PointTransformer, RoundedPolygon, calculateScaleFactor, circle, determinateFrame, determinateIndicatorPolygons, indeterminateIndicatorPolygons, loadingIndicatorShapes, materialShape, materialShapeNames, morphSequence, morphToPath, pathBounds, pill, pillStar, polygonToPath, processPath, rectangle, star, toShapeOutline, toSvgPathData, translatePath };
|
|
530
|
+
export { type CircularWavyInput, CircularWavyPathCache, type CircularWavyPaths, Corner, CornerRounding, Cubic, Edge, Feature, type LinearWavyInput, LinearWavyPathCache, type LinearWavyPaths, type LoadingIndicatorFrame, LoadingIndicatorShapes, type MaterialShapeName, Morph, type MorphPathOptions, MutableCubic, type PathCommand, PathMeasure, type PathOptions, type Point, type PointTransformer, type ProgressStrokes, RoundedPolygon, calculateScaleFactor, circle, circularWavyVertexCount, determinateFrame, determinateIndicatorPolygons, indeterminateIndicatorPolygons, linearWavyStopIndicator, loadingIndicatorShapes, materialShape, materialShapeNames, morphSequence, morphToPath, pathBounds, pill, pillStar, polygonToPath, processPath, rectangle, star, toShapeOutline, toSvgPathData, translatePath };
|
package/dist/index.js
CHANGED
|
@@ -1529,33 +1529,35 @@ var Matrix = class {
|
|
|
1529
1529
|
};
|
|
1530
1530
|
|
|
1531
1531
|
// src/path.ts
|
|
1532
|
-
var mapPoints = (
|
|
1533
|
-
switch (
|
|
1532
|
+
var mapPoints = (command2, f4) => {
|
|
1533
|
+
switch (command2[0]) {
|
|
1534
1534
|
case "M":
|
|
1535
1535
|
case "L":
|
|
1536
|
-
return [
|
|
1536
|
+
return [command2[0], ...f4(command2[1], command2[2])];
|
|
1537
|
+
case "Q":
|
|
1538
|
+
return ["Q", ...f4(command2[1], command2[2]), ...f4(command2[3], command2[4])];
|
|
1537
1539
|
case "C":
|
|
1538
1540
|
return [
|
|
1539
1541
|
"C",
|
|
1540
|
-
...f4(
|
|
1541
|
-
...f4(
|
|
1542
|
-
...f4(
|
|
1542
|
+
...f4(command2[1], command2[2]),
|
|
1543
|
+
...f4(command2[3], command2[4]),
|
|
1544
|
+
...f4(command2[5], command2[6])
|
|
1543
1545
|
];
|
|
1544
1546
|
case "Z":
|
|
1545
|
-
return
|
|
1547
|
+
return command2;
|
|
1546
1548
|
}
|
|
1547
1549
|
};
|
|
1548
|
-
var transformPath = (path, matrix) => path.map((
|
|
1549
|
-
var translatePath = (path, dx, dy) => path.map((
|
|
1550
|
+
var transformPath = (path, matrix) => path.map((command2) => mapPoints(command2, (x, y) => matrix.map(x, y)));
|
|
1551
|
+
var translatePath = (path, dx, dy) => path.map((command2) => mapPoints(command2, (x, y) => [x + dx, y + dy]));
|
|
1550
1552
|
function pathBounds(path) {
|
|
1551
1553
|
let left = Infinity;
|
|
1552
1554
|
let top = Infinity;
|
|
1553
1555
|
let right = -Infinity;
|
|
1554
1556
|
let bottom = -Infinity;
|
|
1555
|
-
for (const
|
|
1556
|
-
for (let i = 1; i + 1 <
|
|
1557
|
-
const x =
|
|
1558
|
-
const y =
|
|
1557
|
+
for (const command2 of path) {
|
|
1558
|
+
for (let i = 1; i + 1 < command2.length; i += 2) {
|
|
1559
|
+
const x = command2[i];
|
|
1560
|
+
const y = command2[i + 1];
|
|
1559
1561
|
left = Math.min(left, x);
|
|
1560
1562
|
top = Math.min(top, y);
|
|
1561
1563
|
right = Math.max(right, x);
|
|
@@ -1957,23 +1959,31 @@ function processPath(path, width, height, scaleFactor) {
|
|
|
1957
1959
|
const [left, top, right, bottom] = pathBounds(scaled);
|
|
1958
1960
|
const dx = f2(f2(width / 2) - f2(left + f2(f2(right - left) / 2)));
|
|
1959
1961
|
const dy = f2(f2(height / 2) - f2(top + f2(f2(bottom - top) / 2)));
|
|
1960
|
-
return scaled.map((
|
|
1961
|
-
switch (
|
|
1962
|
+
return scaled.map((command2) => {
|
|
1963
|
+
switch (command2[0]) {
|
|
1962
1964
|
case "M":
|
|
1963
1965
|
case "L":
|
|
1964
|
-
return [
|
|
1966
|
+
return [command2[0], f2(command2[1] + dx), f2(command2[2] + dy)];
|
|
1967
|
+
case "Q":
|
|
1968
|
+
return [
|
|
1969
|
+
"Q",
|
|
1970
|
+
f2(command2[1] + dx),
|
|
1971
|
+
f2(command2[2] + dy),
|
|
1972
|
+
f2(command2[3] + dx),
|
|
1973
|
+
f2(command2[4] + dy)
|
|
1974
|
+
];
|
|
1965
1975
|
case "C":
|
|
1966
1976
|
return [
|
|
1967
1977
|
"C",
|
|
1968
|
-
f2(
|
|
1969
|
-
f2(
|
|
1970
|
-
f2(
|
|
1971
|
-
f2(
|
|
1972
|
-
f2(
|
|
1973
|
-
f2(
|
|
1978
|
+
f2(command2[1] + dx),
|
|
1979
|
+
f2(command2[2] + dy),
|
|
1980
|
+
f2(command2[3] + dx),
|
|
1981
|
+
f2(command2[4] + dy),
|
|
1982
|
+
f2(command2[5] + dx),
|
|
1983
|
+
f2(command2[6] + dy)
|
|
1974
1984
|
];
|
|
1975
1985
|
case "Z":
|
|
1976
|
-
return
|
|
1986
|
+
return command2;
|
|
1977
1987
|
}
|
|
1978
1988
|
});
|
|
1979
1989
|
}
|
|
@@ -2027,6 +2037,319 @@ function loadingIndicatorShapes(polygons, indeterminate, activeIndicatorScale) {
|
|
|
2027
2037
|
return shapes;
|
|
2028
2038
|
}
|
|
2029
2039
|
|
|
2030
|
-
|
|
2040
|
+
// src/path-measure.ts
|
|
2041
|
+
var SAMPLES = 32;
|
|
2042
|
+
function at(p, t) {
|
|
2043
|
+
let q = [...p];
|
|
2044
|
+
while (q.length > 2) {
|
|
2045
|
+
const next = [];
|
|
2046
|
+
for (let i = 0; i + 3 < q.length; i += 2) {
|
|
2047
|
+
next.push(q[i] + (q[i + 2] - q[i]) * t, q[i + 1] + (q[i + 3] - q[i + 1]) * t);
|
|
2048
|
+
}
|
|
2049
|
+
q = next;
|
|
2050
|
+
}
|
|
2051
|
+
return [q[0], q[1]];
|
|
2052
|
+
}
|
|
2053
|
+
function sub(p, t0, t1) {
|
|
2054
|
+
const left = (q, t) => {
|
|
2055
|
+
const out = [q[0], q[1]];
|
|
2056
|
+
let r = [...q];
|
|
2057
|
+
while (r.length > 2) {
|
|
2058
|
+
const next = [];
|
|
2059
|
+
for (let i = 0; i + 3 < r.length; i += 2) {
|
|
2060
|
+
next.push(r[i] + (r[i + 2] - r[i]) * t, r[i + 1] + (r[i + 3] - r[i + 1]) * t);
|
|
2061
|
+
}
|
|
2062
|
+
out.push(next[0], next[1]);
|
|
2063
|
+
r = next;
|
|
2064
|
+
}
|
|
2065
|
+
return out;
|
|
2066
|
+
};
|
|
2067
|
+
const reverse = (q) => {
|
|
2068
|
+
const out = [];
|
|
2069
|
+
for (let i = q.length - 2; i >= 0; i -= 2) out.push(q[i], q[i + 1]);
|
|
2070
|
+
return out;
|
|
2071
|
+
};
|
|
2072
|
+
const head = t1 < 1 ? left(p, t1) : [...p];
|
|
2073
|
+
const s = t1 > 0 ? t0 / t1 : 0;
|
|
2074
|
+
return s > 0 ? reverse(left(reverse(head), 1 - s)) : head;
|
|
2075
|
+
}
|
|
2076
|
+
var command = (p) => p.length === 4 ? ["L", p[2], p[3]] : p.length === 6 ? ["Q", p[2], p[3], p[4], p[5]] : ["C", p[2], p[3], p[4], p[5], p[6], p[7]];
|
|
2077
|
+
var PathMeasure = class {
|
|
2078
|
+
#segs = [];
|
|
2079
|
+
/** Length of the first contour. */
|
|
2080
|
+
length = 0;
|
|
2081
|
+
/**
|
|
2082
|
+
* Measures the first contour of `path`. With `forceClosed` (or a `Z`), a closing line back to
|
|
2083
|
+
* the contour's start is part of it.
|
|
2084
|
+
*/
|
|
2085
|
+
constructor(path, forceClosed = false) {
|
|
2086
|
+
let x = 0;
|
|
2087
|
+
let y = 0;
|
|
2088
|
+
let startX = 0;
|
|
2089
|
+
let startY = 0;
|
|
2090
|
+
let total = 0;
|
|
2091
|
+
let started = false;
|
|
2092
|
+
let closed = forceClosed;
|
|
2093
|
+
const add = (p) => {
|
|
2094
|
+
const d = [total];
|
|
2095
|
+
let [px, py] = [p[0], p[1]];
|
|
2096
|
+
for (let i = 1; i <= SAMPLES; i++) {
|
|
2097
|
+
const [qx, qy] = at(p, i / SAMPLES);
|
|
2098
|
+
total += Math.hypot(qx - px, qy - py);
|
|
2099
|
+
d.push(total);
|
|
2100
|
+
px = qx;
|
|
2101
|
+
py = qy;
|
|
2102
|
+
}
|
|
2103
|
+
if (total > d[0]) this.#segs.push({ p, d });
|
|
2104
|
+
};
|
|
2105
|
+
for (const c of path) {
|
|
2106
|
+
if (c[0] === "M") {
|
|
2107
|
+
if (started) break;
|
|
2108
|
+
started = true;
|
|
2109
|
+
[x, y, startX, startY] = [c[1], c[2], c[1], c[2]];
|
|
2110
|
+
continue;
|
|
2111
|
+
}
|
|
2112
|
+
if (c[0] === "Z") {
|
|
2113
|
+
closed = true;
|
|
2114
|
+
break;
|
|
2115
|
+
}
|
|
2116
|
+
const p = [x, y, ...c.slice(1)];
|
|
2117
|
+
add(p);
|
|
2118
|
+
x = p[p.length - 2];
|
|
2119
|
+
y = p[p.length - 1];
|
|
2120
|
+
}
|
|
2121
|
+
if (closed && (x !== startX || y !== startY)) add([x, y, startX, startY]);
|
|
2122
|
+
this.length = total;
|
|
2123
|
+
}
|
|
2124
|
+
/** The segment and its parameter at distance `d` (0 ≤ d ≤ length). */
|
|
2125
|
+
#find(d) {
|
|
2126
|
+
const segs = this.#segs;
|
|
2127
|
+
let i = 0;
|
|
2128
|
+
while (i < segs.length - 1 && segs[i].d[SAMPLES] < d) i++;
|
|
2129
|
+
const seg = segs[i];
|
|
2130
|
+
let k = 1;
|
|
2131
|
+
while (k < SAMPLES && seg.d[k] < d) k++;
|
|
2132
|
+
const d0 = seg.d[k - 1];
|
|
2133
|
+
const d1 = seg.d[k];
|
|
2134
|
+
const t = (k - 1 + (d1 > d0 ? (d - d0) / (d1 - d0) : 0)) / SAMPLES;
|
|
2135
|
+
return [seg, Math.min(1, Math.max(0, t))];
|
|
2136
|
+
}
|
|
2137
|
+
/** Compose `PathMeasure.getSegment(startD, stopD, destination)` (moveTo first). */
|
|
2138
|
+
getSegment(startD, stopD) {
|
|
2139
|
+
const start = Math.max(0, startD);
|
|
2140
|
+
const stop = Math.min(this.length, stopD);
|
|
2141
|
+
if (!(start <= stop) || this.#segs.length === 0) return [];
|
|
2142
|
+
const [seg0, t0] = this.#find(start);
|
|
2143
|
+
const [seg1, t1] = this.#find(stop);
|
|
2144
|
+
const [mx, my] = at(seg0.p, t0);
|
|
2145
|
+
const out = [["M", mx, my]];
|
|
2146
|
+
if (seg0 === seg1) {
|
|
2147
|
+
out.push(t0 === t1 ? ["L", mx, my] : command(sub(seg0.p, t0, t1)));
|
|
2148
|
+
return out;
|
|
2149
|
+
}
|
|
2150
|
+
const segs = this.#segs;
|
|
2151
|
+
out.push(command(sub(seg0.p, t0, 1)));
|
|
2152
|
+
for (let i = segs.indexOf(seg0) + 1; segs[i] !== seg1; i++) out.push(command(segs[i].p));
|
|
2153
|
+
out.push(command(sub(seg1.p, 0, t1)));
|
|
2154
|
+
return out;
|
|
2155
|
+
}
|
|
2156
|
+
};
|
|
2157
|
+
|
|
2158
|
+
// src/progress-indicator.ts
|
|
2159
|
+
var capWidth = (s, width, height) => s.round === false || height > width ? 0 : Math.max(s.stroke / 2, s.trackStroke / 2);
|
|
2160
|
+
var LinearWavyPathCache = class {
|
|
2161
|
+
#full = null;
|
|
2162
|
+
/** `updateFullPaths`: the full wave (or line, at amplitude 0), measured. */
|
|
2163
|
+
#fullPath(input) {
|
|
2164
|
+
const { width, height, wavelength, stroke } = input;
|
|
2165
|
+
const wavy = input.amplitude !== 0;
|
|
2166
|
+
const key = [width, height, wavy ? wavelength : 0, stroke].join();
|
|
2167
|
+
if (this.#full?.key === key) return this.#full;
|
|
2168
|
+
const path = [["M", 0, height / 2]];
|
|
2169
|
+
if (!wavy) {
|
|
2170
|
+
path.push(["L", width, height / 2]);
|
|
2171
|
+
} else {
|
|
2172
|
+
const half = wavelength / 2;
|
|
2173
|
+
let anchorX = half;
|
|
2174
|
+
let controlX = half / 2;
|
|
2175
|
+
let controlY = height - stroke;
|
|
2176
|
+
const end = width + wavelength * 2;
|
|
2177
|
+
while (anchorX <= end) {
|
|
2178
|
+
path.push(["Q", controlX, controlY + height / 2, anchorX, height / 2]);
|
|
2179
|
+
anchorX += half;
|
|
2180
|
+
controlX += half;
|
|
2181
|
+
controlY *= -1;
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
const measure = new PathMeasure(path, false);
|
|
2185
|
+
const [left, , right] = pathBounds(path);
|
|
2186
|
+
this.#full = { key, measure, scale: measure.length / (right - left + 1e-8) };
|
|
2187
|
+
return this.#full;
|
|
2188
|
+
}
|
|
2189
|
+
/** `updateDrawPaths`: the progress parts and the track for these fractions. */
|
|
2190
|
+
paths(input) {
|
|
2191
|
+
const { width, height, fractions, amplitude, waveOffset, gap } = input;
|
|
2192
|
+
const { measure, scale } = this.#fullPath(input);
|
|
2193
|
+
const cap = capWidth(input, width, height);
|
|
2194
|
+
const halfHeight = height / 2;
|
|
2195
|
+
const wavelength = input.wavelength;
|
|
2196
|
+
const progress = [];
|
|
2197
|
+
const track = [];
|
|
2198
|
+
let adjustedGap = gap;
|
|
2199
|
+
let activeVisible = false;
|
|
2200
|
+
let nextEnd = width - cap;
|
|
2201
|
+
track.push(["M", nextEnd, halfHeight]);
|
|
2202
|
+
for (let i = 0; i + 1 < fractions.length; i += 2) {
|
|
2203
|
+
const start = fractions[i];
|
|
2204
|
+
const end = fractions[i + 1];
|
|
2205
|
+
const barTail = start * width;
|
|
2206
|
+
const barHead = end * width;
|
|
2207
|
+
if (i === 0) {
|
|
2208
|
+
adjustedGap = barHead < cap ? 0 : Math.min(barHead - cap, gap);
|
|
2209
|
+
activeVisible = barHead >= cap;
|
|
2210
|
+
}
|
|
2211
|
+
const head = Math.min(Math.max(barHead, cap), width - cap);
|
|
2212
|
+
const tail = Math.min(Math.max(barTail, cap), width - cap);
|
|
2213
|
+
let part = [];
|
|
2214
|
+
if (Math.abs(end - start) > 0) {
|
|
2215
|
+
const shift = amplitude !== 0 ? waveOffset * wavelength : 0;
|
|
2216
|
+
part = measure.getSegment((tail + shift) * scale, (head + shift) * scale);
|
|
2217
|
+
part = part.map((c) => mapY(c, -Math.max(0, shift), amplitude, halfHeight));
|
|
2218
|
+
}
|
|
2219
|
+
progress.push(part);
|
|
2220
|
+
const spacing = activeVisible ? adjustedGap + cap * 2 : adjustedGap;
|
|
2221
|
+
if (nextEnd > head + spacing) track.push(["L", Math.max(cap, head + spacing), halfHeight]);
|
|
2222
|
+
if (barHead > barTail) {
|
|
2223
|
+
nextEnd = Math.max(cap, tail - spacing);
|
|
2224
|
+
track.push(["M", nextEnd, halfHeight]);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
if (nextEnd > cap) track.push(["L", cap, halfHeight]);
|
|
2228
|
+
return { track, progress, capWidth: cap };
|
|
2229
|
+
}
|
|
2230
|
+
};
|
|
2231
|
+
function mapY(c, dx, amplitude, halfHeight) {
|
|
2232
|
+
const y = (v) => amplitude * v + (1 - amplitude) * halfHeight;
|
|
2233
|
+
switch (c[0]) {
|
|
2234
|
+
case "M":
|
|
2235
|
+
case "L":
|
|
2236
|
+
return [c[0], c[1] + dx, y(c[2])];
|
|
2237
|
+
case "Q":
|
|
2238
|
+
return ["Q", c[1] + dx, y(c[2]), c[3] + dx, y(c[4])];
|
|
2239
|
+
case "C":
|
|
2240
|
+
return ["C", c[1] + dx, y(c[2]), c[3] + dx, y(c[4]), c[5] + dx, y(c[6])];
|
|
2241
|
+
case "Z":
|
|
2242
|
+
return c;
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
function linearWavyStopIndicator(progressEnd, width, maxSize, insets, trackStroke) {
|
|
2246
|
+
let size = Math.min(trackStroke, maxSize);
|
|
2247
|
+
const offset = size === trackStroke ? 0 : trackStroke / 4;
|
|
2248
|
+
let x = width - size - offset;
|
|
2249
|
+
const progressX = width * progressEnd + insets;
|
|
2250
|
+
if (x <= progressX) {
|
|
2251
|
+
size = Math.max(0, size - (progressX - x));
|
|
2252
|
+
x = progressX;
|
|
2253
|
+
}
|
|
2254
|
+
return size > 0 ? { x, size } : null;
|
|
2255
|
+
}
|
|
2256
|
+
var MIN_VERTICES = 5;
|
|
2257
|
+
var circularWavyVertexCount = (size, wavelength, stroke) => Math.max(MIN_VERTICES, Math.round(2 * Math.PI * (size / 2 - stroke / 2) / wavelength));
|
|
2258
|
+
var CircularWavyPathCache = class {
|
|
2259
|
+
#shapesKey = "";
|
|
2260
|
+
#vertices = -1;
|
|
2261
|
+
#trackPolygon = null;
|
|
2262
|
+
#activePolygon = null;
|
|
2263
|
+
#morph = null;
|
|
2264
|
+
#full = null;
|
|
2265
|
+
/** `CircularShapes.update`. */
|
|
2266
|
+
#update(size, wavelength, stroke, requiresMorph) {
|
|
2267
|
+
const key = [size, wavelength].join();
|
|
2268
|
+
if (key === this.#shapesKey) {
|
|
2269
|
+
if (requiresMorph && this.#morph === null)
|
|
2270
|
+
this.#morph = new Morph(this.#trackPolygon, this.#activePolygon);
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2273
|
+
const n = circularWavyVertexCount(size, wavelength, stroke);
|
|
2274
|
+
if (n !== this.#vertices) {
|
|
2275
|
+
this.#trackPolygon = circle({ numVertices: n }).normalized();
|
|
2276
|
+
this.#activePolygon = star(n, {
|
|
2277
|
+
innerRadius: 0.75,
|
|
2278
|
+
rounding: new CornerRounding(0.35, 0.4),
|
|
2279
|
+
innerRounding: new CornerRounding(0.5)
|
|
2280
|
+
}).normalized();
|
|
2281
|
+
this.#morph = requiresMorph ? new Morph(this.#trackPolygon, this.#activePolygon) : null;
|
|
2282
|
+
this.#full = null;
|
|
2283
|
+
}
|
|
2284
|
+
this.#shapesKey = key;
|
|
2285
|
+
this.#vertices = n;
|
|
2286
|
+
}
|
|
2287
|
+
/** The paths for `input`; `requiresMorph` as the Compose node passes it. */
|
|
2288
|
+
paths(input, requiresMorph) {
|
|
2289
|
+
const { size, wavelength, stroke, motion, start, end, gap } = input;
|
|
2290
|
+
this.#update(size, wavelength, stroke, requiresMorph);
|
|
2291
|
+
const full = this.#fullPaths(input);
|
|
2292
|
+
const cap = capWidth(input, size, size);
|
|
2293
|
+
const pStart = start * full.length;
|
|
2294
|
+
const pStop = end * full.length;
|
|
2295
|
+
const trackGap = Math.min(pStop, gap);
|
|
2296
|
+
const insets = Math.min(pStop, cap);
|
|
2297
|
+
const spacing = insets * 2 + trackGap;
|
|
2298
|
+
let progress;
|
|
2299
|
+
if (motion) {
|
|
2300
|
+
const offset = Math.min(Math.max(input.waveOffset, 0), 1);
|
|
2301
|
+
const shift = offset * full.length;
|
|
2302
|
+
progress = full.measure.getSegment(pStart + shift, pStop + shift);
|
|
2303
|
+
const angle2 = offset * 360 % 360;
|
|
2304
|
+
if (angle2 !== 0) {
|
|
2305
|
+
const [cx, cy] = full.center;
|
|
2306
|
+
progress = translatePath(
|
|
2307
|
+
transformPath(translatePath(progress, -cx, -cy), new Matrix().rotateZ(-angle2)),
|
|
2308
|
+
cx,
|
|
2309
|
+
cy
|
|
2310
|
+
);
|
|
2311
|
+
}
|
|
2312
|
+
} else {
|
|
2313
|
+
progress = full.measure.getSegment(pStart, pStop);
|
|
2314
|
+
}
|
|
2315
|
+
const trackLength = full.track.length;
|
|
2316
|
+
const track = trackLength > 0 ? full.track.getSegment(end * trackLength + spacing, trackLength - spacing) : [];
|
|
2317
|
+
return { track, progress, vertexCount: this.#vertices };
|
|
2318
|
+
}
|
|
2319
|
+
/** `updateFullPaths` + `getProgressPath` / `getTrackPath` + `processPath`. */
|
|
2320
|
+
#fullPaths(input) {
|
|
2321
|
+
const { size, stroke, amplitude, motion } = input;
|
|
2322
|
+
const key = [size, stroke, amplitude, motion, this.#vertices, this.#morph !== null].join();
|
|
2323
|
+
if (this.#full?.key === key) return this.#full;
|
|
2324
|
+
const pivot = { rotationPivotX: 0.5, rotationPivotY: 0.5 };
|
|
2325
|
+
const raw = this.#morph !== null ? morphToPath(this.#morph, amplitude, { startAngle: 270, repeatPath: motion, ...pivot }) : polygonToPath(amplitude === 1 ? this.#activePolygon : this.#trackPolygon, {
|
|
2326
|
+
startAngle: 270,
|
|
2327
|
+
repeatPath: motion
|
|
2328
|
+
});
|
|
2329
|
+
const progress = processPath2(raw, size, stroke);
|
|
2330
|
+
const measure = new PathMeasure(progress, true);
|
|
2331
|
+
const track = new PathMeasure(
|
|
2332
|
+
processPath2(polygonToPath(this.#trackPolygon, { startAngle: 270 }), size, stroke),
|
|
2333
|
+
true
|
|
2334
|
+
);
|
|
2335
|
+
const [left, top, right, bottom] = pathBounds(progress);
|
|
2336
|
+
this.#full = {
|
|
2337
|
+
key,
|
|
2338
|
+
progress,
|
|
2339
|
+
measure,
|
|
2340
|
+
length: motion ? measure.length / 2 : measure.length,
|
|
2341
|
+
center: [(left + right) / 2, (top + bottom) / 2],
|
|
2342
|
+
track
|
|
2343
|
+
};
|
|
2344
|
+
return this.#full;
|
|
2345
|
+
}
|
|
2346
|
+
};
|
|
2347
|
+
function processPath2(path, size, stroke) {
|
|
2348
|
+
const scaled = transformPath(path, new Matrix().scale(size - stroke, size - stroke));
|
|
2349
|
+
const [left, top, right, bottom] = pathBounds(scaled);
|
|
2350
|
+
return translatePath(scaled, size / 2 - (left + right) / 2, size / 2 - (top + bottom) / 2);
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
export { CircularWavyPathCache, Corner, CornerRounding, Cubic, Edge, Feature, LinearWavyPathCache, LoadingIndicatorShapes, Morph, MutableCubic, PathMeasure, RoundedPolygon, calculateScaleFactor, circle, circularWavyVertexCount, determinateFrame, determinateIndicatorPolygons, indeterminateIndicatorPolygons, linearWavyStopIndicator, loadingIndicatorShapes, materialShape, materialShapeNames, morphSequence, morphToPath, pathBounds, pill, pillStar, polygonToPath, processPath, rectangle, star, toShapeOutline, toSvgPathData, translatePath };
|
|
2031
2354
|
//# sourceMappingURL=index.js.map
|
|
2032
2355
|
//# sourceMappingURL=index.js.map
|