@weasel-js/guides 1.14.2 → 1.15.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/README.md +17 -1
- package/dist/index.d.ts +196 -102
- package/dist/index.js +322 -204
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,12 +1,197 @@
|
|
|
1
1
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
|
-
import { sceneBoxFrames, scenePoseFrame,
|
|
3
|
-
import { pointInPolygon, invert,
|
|
2
|
+
import { sceneBoxFrames, scenePoseFrame, useLatest, viewportWorldRect, tickedSegment, measuredSegmentCommands, AUTO_POSE_DESCRIPTOR, visualBoundsViaDescriptor, rectFromPlane, unionAABB, createTransformOp, asNodeId, sceneUnitScopes, screenToWorld, nodeGates, resolveStrokeWidth, resolveUnit, axisUnits, resolveScoped } from '@weasel-js/core';
|
|
3
|
+
import { pointInPolygon, invert, mat3, applyToPoint, pxExtent, PATH_M, PATH_L, PATH_Z, pxExtentInFrame } from '@weasel-js/geom';
|
|
4
4
|
|
|
5
5
|
// src/grid/roundToCell.ts
|
|
6
6
|
function roundToCell(value, cellSize) {
|
|
7
7
|
return Math.round(value / cellSize) * cellSize || 0;
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
// src/grid/axes.ts
|
|
11
|
+
function isGridLength(v) {
|
|
12
|
+
return typeof v === "number" || typeof v === "object" && v !== null && "value" in v;
|
|
13
|
+
}
|
|
14
|
+
function resolveGridLines(spacing, read) {
|
|
15
|
+
const on = (axis) => {
|
|
16
|
+
const a = isGridLength(spacing) ? spacing : spacing[axis];
|
|
17
|
+
if (a === void 0) return null;
|
|
18
|
+
try {
|
|
19
|
+
return resolveAxis(a, (v) => read(v, axis));
|
|
20
|
+
} catch (e) {
|
|
21
|
+
throw new Error(`${axis} axis: ${e instanceof Error ? e.message : String(e)}`);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return { x: on("x"), y: on("y") };
|
|
25
|
+
}
|
|
26
|
+
function resolveAxis(a, read) {
|
|
27
|
+
if (isGridLength(a)) return periodic(read(a), 0, -Infinity, Infinity);
|
|
28
|
+
if ("at" in a) {
|
|
29
|
+
const at = [...new Set(a.at.map(read))].filter(Number.isFinite).sort((p, q) => p - q);
|
|
30
|
+
return at.length ? { at } : null;
|
|
31
|
+
}
|
|
32
|
+
return periodic(
|
|
33
|
+
read(a.pitch),
|
|
34
|
+
a.offset === void 0 ? 0 : read(a.offset),
|
|
35
|
+
a.from === void 0 ? -Infinity : read(a.from),
|
|
36
|
+
a.to === void 0 ? Infinity : read(a.to)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
function periodic(pitch, offset, from, to) {
|
|
40
|
+
return pitch > 0 && Number.isFinite(pitch) && from <= to ? { pitch, offset, from, to } : null;
|
|
41
|
+
}
|
|
42
|
+
var EPS = 1e-9;
|
|
43
|
+
function indexRange(a) {
|
|
44
|
+
return [Math.ceil((a.from - a.offset) / a.pitch - EPS), Math.floor((a.to - a.offset) / a.pitch + EPS)];
|
|
45
|
+
}
|
|
46
|
+
function linesNear(a, v) {
|
|
47
|
+
let pair;
|
|
48
|
+
if ("at" in a) {
|
|
49
|
+
const i = Math.min(Math.max(0, lastAtOrBefore(a.at, v)), Math.max(0, a.at.length - 2));
|
|
50
|
+
pair = a.at.slice(i, i + 2);
|
|
51
|
+
} else {
|
|
52
|
+
const [lo3, hi3] = indexRange(a);
|
|
53
|
+
if (lo3 > hi3) return [];
|
|
54
|
+
const k = Math.min(Math.max(Math.floor((v - a.offset) / a.pitch), lo3), Math.max(lo3, hi3 - 1));
|
|
55
|
+
pair = k + 1 <= hi3 ? [a.offset + k * a.pitch, a.offset + (k + 1) * a.pitch] : [a.offset + k * a.pitch];
|
|
56
|
+
}
|
|
57
|
+
return pair.length === 2 && v - pair[0] >= pair[1] - v ? [pair[1], pair[0]] : pair;
|
|
58
|
+
}
|
|
59
|
+
function nearestLine(a, v) {
|
|
60
|
+
let best = null;
|
|
61
|
+
for (const l of linesNear(a, v)) if (best === null || Math.abs(l - v) < Math.abs(best - v)) best = l;
|
|
62
|
+
return best;
|
|
63
|
+
}
|
|
64
|
+
function linesIn(a, lo3, hi3) {
|
|
65
|
+
if ("at" in a) return a.at.filter((l) => l >= lo3 - EPS && l <= hi3 + EPS);
|
|
66
|
+
const [k0, k1] = indexRange({ ...a, from: Math.max(a.from, lo3), to: Math.min(a.to, hi3) });
|
|
67
|
+
const out = [];
|
|
68
|
+
for (let k = k0; k <= k1; k++) out.push(a.offset + k * a.pitch);
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
function cellOf(a, v) {
|
|
72
|
+
if (!a) return { index: 0, lo: -Infinity, hi: Infinity };
|
|
73
|
+
if ("at" in a) {
|
|
74
|
+
const i = lastAtOrBefore(a.at, v);
|
|
75
|
+
return i >= 0 && i < a.at.length - 1 ? { index: i, lo: a.at[i], hi: a.at[i + 1] } : null;
|
|
76
|
+
}
|
|
77
|
+
const [lo3, hi3] = indexRange(a);
|
|
78
|
+
const k = Math.floor((v - a.offset) / a.pitch);
|
|
79
|
+
if (k < lo3 || k >= hi3) return null;
|
|
80
|
+
return { index: k, lo: a.offset + k * a.pitch, hi: a.offset + (k + 1) * a.pitch };
|
|
81
|
+
}
|
|
82
|
+
function mapLines(a, scale, shift) {
|
|
83
|
+
const m = (p) => p * scale + shift;
|
|
84
|
+
if ("at" in a) return { at: a.at.map(m).sort((p, q) => p - q) };
|
|
85
|
+
const [from, to] = [m(a.from), m(a.to)].sort((p, q) => p - q);
|
|
86
|
+
return { pitch: Math.abs(a.pitch * scale), offset: m(a.offset), from: Number.isNaN(from) ? -Infinity : from, to: Number.isNaN(to) ? Infinity : to };
|
|
87
|
+
}
|
|
88
|
+
function lastAtOrBefore(at, v) {
|
|
89
|
+
let lo3 = 0;
|
|
90
|
+
let hi3 = at.length - 1;
|
|
91
|
+
let found = -1;
|
|
92
|
+
while (lo3 <= hi3) {
|
|
93
|
+
const mid2 = lo3 + hi3 >> 1;
|
|
94
|
+
if (at[mid2] <= v + EPS) {
|
|
95
|
+
found = mid2;
|
|
96
|
+
lo3 = mid2 + 1;
|
|
97
|
+
} else hi3 = mid2 - 1;
|
|
98
|
+
}
|
|
99
|
+
return found;
|
|
100
|
+
}
|
|
101
|
+
var MIN_SCREEN_SPACING = 4;
|
|
102
|
+
function hasArea(r) {
|
|
103
|
+
return r.width > 0 && r.height > 0 && Number.isFinite(r.width) && Number.isFinite(r.height);
|
|
104
|
+
}
|
|
105
|
+
var other = (axis) => axis === "x" ? "y" : "x";
|
|
106
|
+
function lattice(b, lines, shape, view, styles, frame) {
|
|
107
|
+
const px = frame ? pxExtentInFrame(1, view.scale, frame) : pxExtent(1, view.scale);
|
|
108
|
+
const span2 = { x: [b.x, b.x + b.width], y: [b.y, b.y + b.height] };
|
|
109
|
+
const children = [];
|
|
110
|
+
const across = (axis) => {
|
|
111
|
+
const a = lines[axis];
|
|
112
|
+
const [lo3, hi3] = span2[axis];
|
|
113
|
+
return a && "pitch" in a ? [Math.max(lo3, a.from), Math.min(hi3, a.to)] : [lo3, hi3];
|
|
114
|
+
};
|
|
115
|
+
const draw = (axis, at, s) => {
|
|
116
|
+
const [lo3, hi3] = across(other(axis));
|
|
117
|
+
if (!(hi3 > lo3)) return;
|
|
118
|
+
const width = resolveStrokeWidth(s.width ?? 1, 1) * px[axis];
|
|
119
|
+
for (const p of at) {
|
|
120
|
+
const coords = axis === "x" ? [p, lo3, p, hi3] : [lo3, p, hi3, p];
|
|
121
|
+
const path = {
|
|
122
|
+
kind: "polygon",
|
|
123
|
+
commands: new Uint8Array([PATH_M, PATH_L]),
|
|
124
|
+
coords: new Float32Array(coords),
|
|
125
|
+
fillRule: "nonzero"
|
|
126
|
+
};
|
|
127
|
+
children.push({ kind: "path", path, stroke: { ...s, width } });
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const periodic2 = (axis, a, step, skipEvery, s) => {
|
|
131
|
+
if (!(step / px[axis] >= MIN_SCREEN_SPACING)) return;
|
|
132
|
+
const at = linesIn({ ...a, pitch: step }, ...span2[axis]);
|
|
133
|
+
draw(axis, skipEvery > 0 ? at.filter((p) => Math.round((p - a.offset) / step) % skipEvery !== 0) : at, s);
|
|
134
|
+
};
|
|
135
|
+
const { accentEvery, subdivisions } = shape;
|
|
136
|
+
const accentOn = accentEvery !== void 0 && accentEvery > 0;
|
|
137
|
+
const passes = [
|
|
138
|
+
// Sub-lines first so cell lines paint on top, accents last of all.
|
|
139
|
+
(axis, a) => {
|
|
140
|
+
if (subdivisions && subdivisions > 1) periodic2(axis, a, a.pitch / subdivisions, subdivisions, styles.sub);
|
|
141
|
+
},
|
|
142
|
+
(axis, a) => periodic2(axis, a, a.pitch, accentOn ? accentEvery : 0, styles.line),
|
|
143
|
+
(axis, a) => {
|
|
144
|
+
if (accentOn) periodic2(axis, a, a.pitch * accentEvery, 0, styles.accent);
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
for (const pass of passes) {
|
|
148
|
+
for (const axis of ["x", "y"]) {
|
|
149
|
+
const a = lines[axis];
|
|
150
|
+
if (a && "pitch" in a) pass(axis, a);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const axis of ["x", "y"]) {
|
|
154
|
+
const a = lines[axis];
|
|
155
|
+
if (a && "at" in a) draw(axis, thinned(linesIn(a, ...span2[axis]), px[axis] * MIN_SCREEN_SPACING), styles.line);
|
|
156
|
+
}
|
|
157
|
+
return children;
|
|
158
|
+
}
|
|
159
|
+
function thinned(at, gap) {
|
|
160
|
+
const out = [];
|
|
161
|
+
for (const p of at) if (out.length === 0 || p - out[out.length - 1] >= gap) out.push(p);
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
function outlineBox(outline) {
|
|
165
|
+
const xs = outline.map((p) => p.x);
|
|
166
|
+
const ys = outline.map((p) => p.y);
|
|
167
|
+
const x = Math.min(...xs);
|
|
168
|
+
const y = Math.min(...ys);
|
|
169
|
+
return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };
|
|
170
|
+
}
|
|
171
|
+
function intersect(a, b) {
|
|
172
|
+
const x = Math.max(a.x, b.x);
|
|
173
|
+
const y = Math.max(a.y, b.y);
|
|
174
|
+
return { x, y, width: Math.min(end(a.x, a.width), end(b.x, b.width)) - x, height: Math.min(end(a.y, a.height), end(b.y, b.height)) - y };
|
|
175
|
+
}
|
|
176
|
+
var end = (start, size) => size === Infinity ? Infinity : start + size;
|
|
177
|
+
function span(v, chain) {
|
|
178
|
+
const zero = typeof v === "number" ? 0 : { ...v, value: 0 };
|
|
179
|
+
return resolveScoped(v, chain) - resolveScoped(zero, chain);
|
|
180
|
+
}
|
|
181
|
+
function gridLines(spacing, unitSystem, scopes, chain) {
|
|
182
|
+
if (!scopes) return resolveGridLines(spacing, (v, axis) => resolveUnit(v, axisUnits(unitSystem, axis)));
|
|
183
|
+
const at = chain ?? [scopes.root];
|
|
184
|
+
return resolveGridLines(spacing, (v) => span(v, at));
|
|
185
|
+
}
|
|
186
|
+
function scopeSpacing(spacing, scopes, chain) {
|
|
187
|
+
const inner = chain && chain.length > 1 ? chain[chain.length - 1] : null;
|
|
188
|
+
return inner && scopes?.spacing ? scopes.spacing(inner) : spacing;
|
|
189
|
+
}
|
|
190
|
+
function containerLines(own, spacing, unitSystem, scopes, chain) {
|
|
191
|
+
if (own === null) return null;
|
|
192
|
+
return gridLines(own ?? scopeSpacing(spacing, scopes, chain), unitSystem, scopes, chain);
|
|
193
|
+
}
|
|
194
|
+
function sceneGridRegions(scene, owners, outlineOf) {
|
|
10
195
|
const frames = sceneBoxFrames(scene);
|
|
11
196
|
const poses = scenePoseFrame(scene);
|
|
12
197
|
const boxOutline = (id, frame) => {
|
|
@@ -18,8 +203,8 @@ function sceneGridRegions(scene, root, outlineOf) {
|
|
|
18
203
|
};
|
|
19
204
|
const children = /* @__PURE__ */ new Map();
|
|
20
205
|
for (const id of scene.nodes.keys()) {
|
|
21
|
-
if (scene
|
|
22
|
-
const parent =
|
|
206
|
+
if (!ownsGrid(scene, id, owners)) continue;
|
|
207
|
+
const parent = gridOwner(scene, id, owners);
|
|
23
208
|
children.set(parent, [...children.get(parent) ?? [], id]);
|
|
24
209
|
}
|
|
25
210
|
const build = (parent) => {
|
|
@@ -29,9 +214,11 @@ function sceneGridRegions(scene, root, outlineOf) {
|
|
|
29
214
|
const outline = outlineOf ? outlineOf(id) : frame && boxOutline(id, frame);
|
|
30
215
|
if (!outline) continue;
|
|
31
216
|
const inner = build(id);
|
|
217
|
+
const own = owners.gridOf?.(id);
|
|
32
218
|
out.push({
|
|
33
219
|
outline,
|
|
34
|
-
chain: sceneUnitScopes(scene, id, root, { inclusive: true }),
|
|
220
|
+
...owners.root ? { chain: sceneUnitScopes(scene, id, owners.root, { inclusive: true }) } : {},
|
|
221
|
+
...own !== void 0 ? { spacing: own } : {},
|
|
35
222
|
...inner.length ? { regions: inner } : {},
|
|
36
223
|
...frame ? { frame } : {}
|
|
37
224
|
});
|
|
@@ -40,9 +227,12 @@ function sceneGridRegions(scene, root, outlineOf) {
|
|
|
40
227
|
};
|
|
41
228
|
return build(null);
|
|
42
229
|
}
|
|
43
|
-
function
|
|
230
|
+
function ownsGrid(scene, id, owners) {
|
|
231
|
+
return owners.gridOf?.(id) !== void 0 || owners.root !== void 0 && scene.get(id)?.units !== void 0;
|
|
232
|
+
}
|
|
233
|
+
function gridOwner(scene, id, owners, inclusive = false) {
|
|
44
234
|
for (let at = inclusive ? id : scene.get(id)?.parent ?? null; at !== null; at = scene.get(at)?.parent ?? null) {
|
|
45
|
-
if (scene
|
|
235
|
+
if (ownsGrid(scene, at, owners)) return at;
|
|
46
236
|
}
|
|
47
237
|
return null;
|
|
48
238
|
}
|
|
@@ -53,48 +243,41 @@ function regionAt(regions, point) {
|
|
|
53
243
|
}
|
|
54
244
|
return null;
|
|
55
245
|
}
|
|
56
|
-
function span(v, chain) {
|
|
57
|
-
const zero = typeof v === "number" ? 0 : { ...v, value: 0 };
|
|
58
|
-
return resolveScoped(v, chain) - resolveScoped(zero, chain);
|
|
59
|
-
}
|
|
60
|
-
function scopedGridPitch(spacing, scopes, chain) {
|
|
61
|
-
const inner = chain.length > 1 ? chain[chain.length - 1] : null;
|
|
62
|
-
const v = inner && scopes.spacing ? scopes.spacing(inner) : spacing;
|
|
63
|
-
const on = (axis) => {
|
|
64
|
-
const a = typeof v === "object" && "x" in v ? v[axis] : v;
|
|
65
|
-
try {
|
|
66
|
-
return span(a, chain);
|
|
67
|
-
} catch (e) {
|
|
68
|
-
throw new Error(`${axis} axis: ${e instanceof Error ? e.message : String(e)}`);
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
return { x: on("x"), y: on("y") };
|
|
72
|
-
}
|
|
73
|
-
function gridPitch(spacing, unitSystem, scopes, chain) {
|
|
74
|
-
return scopes ? scopedGridPitch(spacing, scopes, chain ?? [scopes.root]) : resolveAxes(spacing, unitSystem);
|
|
75
|
-
}
|
|
76
246
|
|
|
77
247
|
// src/grid/pointToGridCell.ts
|
|
78
248
|
function pointToGridCell(point, spacing, unitSystem, origin = { x: 0, y: 0 }, scoped) {
|
|
79
|
-
const region =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const [x, y] = applyToPoint(back, point.x, point.y);
|
|
84
|
-
return { col: Math.floor(x / s.x), row: Math.floor(y / s.y), pitch: s, frame: region.frame };
|
|
249
|
+
const region = regionAt(scoped?.regions, point);
|
|
250
|
+
if (!region) {
|
|
251
|
+
const cell2 = cellIn(gridLines(spacing, unitSystem, scoped?.scopes), point.x - origin.x, point.y - origin.y);
|
|
252
|
+
return cell2 && { ...cell2, box: { ...cell2.box, x: cell2.box.x + origin.x, y: cell2.box.y + origin.y } };
|
|
85
253
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
254
|
+
const lines = containerLines(region.spacing, spacing, unitSystem, scoped?.scopes, region.chain);
|
|
255
|
+
if (!lines) return null;
|
|
256
|
+
const back = region.frame && invert(region.frame);
|
|
257
|
+
if (region.frame && !back) return null;
|
|
258
|
+
const local = (p) => {
|
|
259
|
+
if (!back) return p;
|
|
260
|
+
const [x, y] = applyToPoint(back, p.x, p.y);
|
|
261
|
+
return { x, y };
|
|
90
262
|
};
|
|
263
|
+
const at = local(point);
|
|
264
|
+
const cell = cellIn(lines, at.x, at.y, outlineBox(region.outline.map(local)));
|
|
265
|
+
return cell && (region.frame ? { ...cell, frame: region.frame } : cell);
|
|
266
|
+
}
|
|
267
|
+
function cellIn(lines, x, y, within) {
|
|
268
|
+
const cx = cellOf(lines.x, x);
|
|
269
|
+
const cy = cellOf(lines.y, y);
|
|
270
|
+
if (!cx || !cy) return null;
|
|
271
|
+
const [x0, x1] = within && !lines.x ? [within.x, within.x + within.width] : [cx.lo, cx.hi];
|
|
272
|
+
const [y0, y1] = within && !lines.y ? [within.y, within.y + within.height] : [cy.lo, cy.hi];
|
|
273
|
+
return { col: cx.index, row: cy.index, box: { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } };
|
|
91
274
|
}
|
|
92
275
|
|
|
93
276
|
// src/grid/useGridCellHover.ts
|
|
94
277
|
function cellsEqual(a, b) {
|
|
95
278
|
if (a === b) return true;
|
|
96
279
|
if (a === null || b === null) return false;
|
|
97
|
-
return a.col === b.col && a.row === b.row && a.
|
|
280
|
+
return a.col === b.col && a.row === b.row && a.box.x === b.box.x && a.box.y === b.box.y && a.box.width === b.box.width && a.box.height === b.box.height && (a.frame === b.frame || !!a.frame && !!b.frame && a.frame.every((v, i) => v === b.frame[i]));
|
|
98
281
|
}
|
|
99
282
|
function useGridCellHover(opts) {
|
|
100
283
|
const [cell, setCell] = useState(null);
|
|
@@ -118,7 +301,7 @@ function useGridCellHover(opts) {
|
|
|
118
301
|
const sx = e.clientX - rect.left;
|
|
119
302
|
const sy = e.clientY - rect.top;
|
|
120
303
|
const [wx, wy] = screenToWorld(sx, sy, o.view());
|
|
121
|
-
const scoped = o.scopes ? { scopes: o.scopes, ...o.regions ? { regions: o.regions() } : {} }
|
|
304
|
+
const scoped = { ...o.scopes ? { scopes: o.scopes } : {}, ...o.regions ? { regions: o.regions() } : {} };
|
|
122
305
|
update(pointToGridCell({ x: wx, y: wy }, o.spacing, o.unitSystem, o.origin, scoped));
|
|
123
306
|
};
|
|
124
307
|
const onLeave = () => update(null);
|
|
@@ -133,66 +316,6 @@ function useGridCellHover(opts) {
|
|
|
133
316
|
}, [enabled, opts.ref, optsRef]);
|
|
134
317
|
return { cell, getCell };
|
|
135
318
|
}
|
|
136
|
-
var MIN_SCREEN_SPACING = 4;
|
|
137
|
-
function hasArea(r) {
|
|
138
|
-
return r.width > 0 && r.height > 0 && Number.isFinite(r.width) && Number.isFinite(r.height);
|
|
139
|
-
}
|
|
140
|
-
function lattice(b, spacing, shape, view, styles, frame) {
|
|
141
|
-
const { accentEvery, subdivisions } = shape;
|
|
142
|
-
const x0 = b.x;
|
|
143
|
-
const y0 = b.y;
|
|
144
|
-
const x1 = b.x + b.width;
|
|
145
|
-
const y1 = b.y + b.height;
|
|
146
|
-
const px = frame ? pxExtentInFrame(1, view.scale, frame) : pxExtent(1, view.scale);
|
|
147
|
-
const children = [];
|
|
148
|
-
const pushSegment = (sx, sy, ex, ey, s) => {
|
|
149
|
-
const path = {
|
|
150
|
-
kind: "polygon",
|
|
151
|
-
commands: new Uint8Array([PATH_M, PATH_L]),
|
|
152
|
-
coords: new Float32Array([sx, sy, ex, ey]),
|
|
153
|
-
fillRule: "nonzero"
|
|
154
|
-
};
|
|
155
|
-
const across = sx === ex ? px.x : px.y;
|
|
156
|
-
children.push({
|
|
157
|
-
kind: "path",
|
|
158
|
-
path,
|
|
159
|
-
stroke: { ...s, width: resolveStrokeWidth(s.width ?? 1, 1) * across }
|
|
160
|
-
});
|
|
161
|
-
};
|
|
162
|
-
const family = (axis, step, skipEvery, s) => {
|
|
163
|
-
if (!(step / px[axis] >= MIN_SCREEN_SPACING)) return;
|
|
164
|
-
const [from, to] = axis === "x" ? [x0, x1] : [y0, y1];
|
|
165
|
-
for (let k = 0; from + k * step <= to + 1e-9; k++) {
|
|
166
|
-
if (skipEvery > 0 && k % skipEvery === 0) continue;
|
|
167
|
-
const at = from + k * step;
|
|
168
|
-
if (axis === "x") pushSegment(at, y0, at, y1, s);
|
|
169
|
-
else pushSegment(x0, at, x1, at, s);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
const accentOn = accentEvery !== void 0 && accentEvery > 0;
|
|
173
|
-
for (const axis of ["x", "y"]) {
|
|
174
|
-
if (subdivisions && subdivisions > 1) family(axis, spacing[axis] / subdivisions, subdivisions, styles.sub);
|
|
175
|
-
}
|
|
176
|
-
for (const axis of ["x", "y"]) family(axis, spacing[axis], accentOn ? accentEvery : 0, styles.line);
|
|
177
|
-
if (accentOn) {
|
|
178
|
-
for (const axis of ["x", "y"]) family(axis, spacing[axis] * accentEvery, 0, styles.accent);
|
|
179
|
-
}
|
|
180
|
-
return children;
|
|
181
|
-
}
|
|
182
|
-
function onLattice(r, spacing, accentEvery, anchor) {
|
|
183
|
-
const px = spacing.x * accentEvery;
|
|
184
|
-
const py = spacing.y * accentEvery;
|
|
185
|
-
const x = anchor.x + Math.floor((r.x - anchor.x) / px) * px;
|
|
186
|
-
const y = anchor.y + Math.floor((r.y - anchor.y) / py) * py;
|
|
187
|
-
return {
|
|
188
|
-
x,
|
|
189
|
-
y,
|
|
190
|
-
width: anchor.x + Math.ceil((r.x + r.width - anchor.x) / px) * px - x,
|
|
191
|
-
height: anchor.y + Math.ceil((r.y + r.height - anchor.y) / py) * py - y
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// src/grid/layer.ts
|
|
196
319
|
var DEFAULT_LINE = {
|
|
197
320
|
paint: { kind: "solid", color: "rgba(255, 255, 255, 0.08)" },
|
|
198
321
|
width: 1
|
|
@@ -215,20 +338,16 @@ function createGridLayer(opts) {
|
|
|
215
338
|
id: "grid",
|
|
216
339
|
label: "Grid",
|
|
217
340
|
draw: (_data, view, dims) => {
|
|
218
|
-
const
|
|
219
|
-
const spacing = gridPitch(opts.spacing, opts.unitSystem, opts.scopes);
|
|
220
|
-
const shown = viewportWorldRect(view, dims);
|
|
221
|
-
const b = opts.bounds ? opts.bounds(view, dims) : onLattice(shown, spacing, every, { x: 0, y: 0 });
|
|
341
|
+
const b = opts.bounds ? opts.bounds(view, dims) : padded(viewportWorldRect(view, dims), view);
|
|
222
342
|
if (!hasArea(b)) return [];
|
|
223
|
-
const root = lattice(b, spacing, opts, view, styles);
|
|
224
|
-
const regions = opts.scopes && opts.regions ? opts.regions() : [];
|
|
225
|
-
if (regions.length === 0) return root;
|
|
226
343
|
const anchor = opts.bounds ? { x: b.x, y: b.y } : { x: 0, y: 0 };
|
|
227
|
-
const
|
|
344
|
+
const root = lattice(b, placed(gridLines(opts.spacing, opts.unitSystem, opts.scopes), anchor), opts, view, styles);
|
|
345
|
+
const regions = opts.regions?.() ?? [];
|
|
346
|
+
if (regions.length === 0) return root;
|
|
228
347
|
const children = [{ kind: "group", clip: withHoles(rectOutline(b), regions), children: root }];
|
|
229
348
|
const visit = (r) => {
|
|
230
|
-
const
|
|
231
|
-
const lines = regionLattice(r,
|
|
349
|
+
const own = containerLines(r.spacing, opts.spacing, opts.unitSystem, opts.scopes, r.chain);
|
|
350
|
+
const lines = own ? regionLattice(r, b, (box, frame) => lattice(box, placed(own, frame ? { x: 0, y: 0 } : anchor), opts, view, styles, frame)) : [];
|
|
232
351
|
if (lines.length) children.push({ kind: "group", clip: withHoles(r.outline, r.regions ?? []), children: lines });
|
|
233
352
|
for (const inner of r.regions ?? []) visit(inner);
|
|
234
353
|
};
|
|
@@ -237,6 +356,14 @@ function createGridLayer(opts) {
|
|
|
237
356
|
}
|
|
238
357
|
};
|
|
239
358
|
}
|
|
359
|
+
function padded(r, view) {
|
|
360
|
+
const px = 1 / Math.abs(view.scale.x);
|
|
361
|
+
const py = 1 / Math.abs(view.scale.y);
|
|
362
|
+
return { x: r.x - px, y: r.y - py, width: r.width + 2 * px, height: r.height + 2 * py };
|
|
363
|
+
}
|
|
364
|
+
function placed(lines, anchor) {
|
|
365
|
+
return { x: lines.x && mapLines(lines.x, 1, anchor.x), y: lines.y && mapLines(lines.y, 1, anchor.y) };
|
|
366
|
+
}
|
|
240
367
|
function rectOutline(r) {
|
|
241
368
|
return [
|
|
242
369
|
{ x: r.x, y: r.y },
|
|
@@ -273,51 +400,36 @@ function regionLattice(r, area, draw) {
|
|
|
273
400
|
const lines = draw(box, r.frame);
|
|
274
401
|
return lines.length ? [{ kind: "group", transform: mat3.fromAffine(r.frame), children: lines }] : [];
|
|
275
402
|
}
|
|
276
|
-
function outlineBox(outline) {
|
|
277
|
-
const xs = outline.map((p) => p.x);
|
|
278
|
-
const ys = outline.map((p) => p.y);
|
|
279
|
-
const x = Math.min(...xs);
|
|
280
|
-
const y = Math.min(...ys);
|
|
281
|
-
return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };
|
|
282
|
-
}
|
|
283
|
-
function intersect(a, b) {
|
|
284
|
-
const x = Math.max(a.x, b.x);
|
|
285
|
-
const y = Math.max(a.y, b.y);
|
|
286
|
-
return { x, y, width: Math.min(a.x + a.width, b.x + b.width) - x, height: Math.min(a.y + a.height, b.y + b.height) - y };
|
|
287
|
-
}
|
|
288
403
|
var DEFAULT_FILL = { paint: { kind: "solid", color: "rgba(127,176,105,0.15)" } };
|
|
289
404
|
function createCellHighlightLayer(opts) {
|
|
290
405
|
const fill = opts.fill ?? DEFAULT_FILL;
|
|
291
406
|
return {
|
|
292
407
|
id: "cell-highlight",
|
|
293
408
|
label: "Cell highlight",
|
|
294
|
-
draw: () => {
|
|
409
|
+
draw: (_data, view, dims) => {
|
|
295
410
|
const cell = opts.getCell();
|
|
296
411
|
if (!cell) return [];
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
const y = o.y + cell.row * spacing.y;
|
|
301
|
-
const children = [
|
|
302
|
-
{
|
|
303
|
-
kind: "path",
|
|
304
|
-
path: { kind: "rect", x, y, width: spacing.x, height: spacing.y },
|
|
305
|
-
fill
|
|
306
|
-
}
|
|
307
|
-
];
|
|
412
|
+
const box = cell.frame ? cell.box : intersect(cell.box, viewportWorldRect(view, dims));
|
|
413
|
+
if (!hasArea(box)) return [];
|
|
414
|
+
const children = [{ kind: "path", path: { kind: "rect", ...box }, fill }];
|
|
308
415
|
return cell.frame ? [{ kind: "group", transform: mat3.fromAffine(cell.frame), children }] : children;
|
|
309
416
|
}
|
|
310
417
|
};
|
|
311
418
|
}
|
|
312
419
|
|
|
313
|
-
// src/
|
|
314
|
-
function
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
420
|
+
// src/grid/fit.ts
|
|
421
|
+
function gridFit(points, lines, tolerance = 1e-6) {
|
|
422
|
+
const misses = [];
|
|
423
|
+
points.forEach((p, index) => {
|
|
424
|
+
for (const axis of ["x", "y"]) {
|
|
425
|
+
const a = lines[axis];
|
|
426
|
+
if (!a) continue;
|
|
427
|
+
const near = nearestLine(a, p[axis]);
|
|
428
|
+
const distance = near === null ? Infinity : Math.abs(p[axis] - near);
|
|
429
|
+
if (distance > tolerance) misses.push({ index, axis, distance });
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
return { fits: misses.length === 0, misses };
|
|
321
433
|
}
|
|
322
434
|
|
|
323
435
|
// src/sources/lines.ts
|
|
@@ -345,53 +457,56 @@ function landedBox(q, delta) {
|
|
|
345
457
|
}
|
|
346
458
|
|
|
347
459
|
// src/sources/grid.ts
|
|
460
|
+
var AXES = ["x", "y"];
|
|
348
461
|
function gridSnapSource(opts) {
|
|
349
|
-
const { scopes } = opts;
|
|
350
|
-
const
|
|
462
|
+
const { scopes, gridOf } = opts;
|
|
463
|
+
const owners = { ...scopes ? { root: scopes.root } : {}, ...gridOf ? { gridOf } : {} };
|
|
464
|
+
const rootLines = gridLines(opts.spacing, opts.unitSystem, scopes);
|
|
465
|
+
const latticeOf = (q, owner) => {
|
|
466
|
+
if (owner === null) return { lines: rootLines };
|
|
467
|
+
const chain = scopes && q.scene ? sceneUnitScopes(q.scene, owner, scopes.root, { inclusive: true }) : void 0;
|
|
468
|
+
return {
|
|
469
|
+
lines: containerLines(gridOf?.(owner), opts.spacing, opts.unitSystem, scopes, chain),
|
|
470
|
+
frame: q.frameOf?.(owner)
|
|
471
|
+
};
|
|
472
|
+
};
|
|
351
473
|
const latticeFor = (q) => {
|
|
352
474
|
const scene = q.scene;
|
|
353
|
-
if (!scopes || !scene) return {
|
|
354
|
-
const within = (owner) => owner === null ? void 0 : q.frameOf?.(owner);
|
|
475
|
+
if (!scopes && !gridOf || !scene) return { lines: rootLines };
|
|
355
476
|
if (q.ids?.length) {
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
// Nodes in two containers share no one lattice, whatever their scopes.
|
|
361
|
-
frame: owners.size === 1 ? within([...owners][0]) : void 0
|
|
362
|
-
};
|
|
477
|
+
const held = [...new Set(q.ids.map((id) => gridOwner(scene, asNodeId(id), owners)))];
|
|
478
|
+
if (held.length === 1) return latticeOf(q, held[0]);
|
|
479
|
+
const each = held.map((owner) => JSON.stringify(latticeOf(q, owner).lines));
|
|
480
|
+
return { lines: each.every((l) => l === each[0]) ? latticeOf(q, held[0]).lines : null };
|
|
363
481
|
}
|
|
364
|
-
if (q.parent === void 0) return {
|
|
365
|
-
|
|
366
|
-
return {
|
|
367
|
-
pitch: scopedGridPitch(opts.spacing, scopes, sceneUnitScopes(scene, parent, scopes.root, { inclusive: true })),
|
|
368
|
-
frame: within(scopeOwner(scene, parent, true))
|
|
369
|
-
};
|
|
482
|
+
if (q.parent === void 0) return { lines: rootLines };
|
|
483
|
+
return latticeOf(q, gridOwner(scene, asNodeId(q.parent), owners, true));
|
|
370
484
|
};
|
|
371
485
|
const o = opts.origin ?? { x: 0, y: 0 };
|
|
372
|
-
const lines = (v, axis, pitch, plane) => {
|
|
373
|
-
const s = plane ? plane.scale[axis] : 1;
|
|
374
|
-
const near = roundToGridOn(v - o[axis] * s, axis, pitch[axis], plane) + o[axis] * s;
|
|
375
|
-
const step = pitch[axis] * s;
|
|
376
|
-
return [near, near + (v >= near ? step : -step)];
|
|
377
|
-
};
|
|
378
486
|
return {
|
|
379
|
-
id: "grid",
|
|
487
|
+
id: opts.id ?? "grid",
|
|
380
488
|
tier: "fallback",
|
|
381
489
|
reachPx: Infinity,
|
|
382
|
-
roles: ["box", "origin", "pointer"],
|
|
490
|
+
roles: ["box", "origin", "pointer", "anchor"],
|
|
383
491
|
*collect(q) {
|
|
384
|
-
const {
|
|
492
|
+
const { lines, frame } = latticeFor(q);
|
|
493
|
+
if (!lines) return;
|
|
385
494
|
const plane = q.plane ?? null;
|
|
495
|
+
const scale = (axis) => plane ? plane.scale[axis] : 1;
|
|
496
|
+
const anchored = q.probes.some((p) => p.role === "anchor");
|
|
386
497
|
const skip = frame && turns(frame) ? "box" : "origin";
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
498
|
+
const probes = q.probes.filter((p) => anchored ? p.role === "anchor" || p.role === "pointer" : p.role !== skip);
|
|
499
|
+
if (frame) {
|
|
500
|
+
const local = { x: lines.x && mapLines(lines.x, scale("x"), 0), y: lines.y && mapLines(lines.y, scale("y"), 0) };
|
|
501
|
+
for (const p of probes) yield* framedLines(p.id, p.at, local, frame);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const shift = (axis) => o[axis] * scale(axis) + (plane ? plane.offset[axis] : 0);
|
|
505
|
+
const world = { x: lines.x && mapLines(lines.x, scale("x"), shift("x")), y: lines.y && mapLines(lines.y, scale("y"), shift("y")) };
|
|
506
|
+
for (const p of probes) {
|
|
507
|
+
for (const axis of AXES) {
|
|
508
|
+
const a = world[axis];
|
|
509
|
+
if (a) for (const at of linesNear(a, p.at[axis])) yield { probe: p.id, locus: axisLine(axis, at, p.at) };
|
|
395
510
|
}
|
|
396
511
|
}
|
|
397
512
|
}
|
|
@@ -407,15 +522,12 @@ function turns(frame) {
|
|
|
407
522
|
};
|
|
408
523
|
return !(along(ex, "x") && along(ey, "y") || along(ex, "y") && along(ey, "x"));
|
|
409
524
|
}
|
|
410
|
-
function* framedLines(probe, at,
|
|
525
|
+
function* framedLines(probe, at, lines, frame) {
|
|
411
526
|
const local = frame.toLocal(at);
|
|
412
527
|
if (!local) return;
|
|
413
|
-
for (const axis of
|
|
414
|
-
const
|
|
415
|
-
const
|
|
416
|
-
for (const offset of [near, near + (local[axis] >= near ? step : -step)]) {
|
|
417
|
-
yield { probe, locus: frameLine(frame, axis, offset, local) };
|
|
418
|
-
}
|
|
528
|
+
for (const axis of AXES) {
|
|
529
|
+
const a = lines[axis];
|
|
530
|
+
if (a) for (const offset of linesNear(a, local[axis])) yield { probe, locus: frameLine(frame, axis, offset, local) };
|
|
419
531
|
}
|
|
420
532
|
}
|
|
421
533
|
|
|
@@ -427,6 +539,7 @@ function createGridPreset(opts) {
|
|
|
427
539
|
id,
|
|
428
540
|
layers: { grid: { layer: createGridLayer(layer) } },
|
|
429
541
|
snapSources: snap === false ? [] : [gridSnapSource({
|
|
542
|
+
id,
|
|
430
543
|
spacing,
|
|
431
544
|
...unitSystem === void 0 ? {} : { unitSystem },
|
|
432
545
|
...scopes === void 0 ? {} : { scopes },
|
|
@@ -504,7 +617,7 @@ function createGuidesLayer(opts) {
|
|
|
504
617
|
}
|
|
505
618
|
};
|
|
506
619
|
}
|
|
507
|
-
var
|
|
620
|
+
var EPS2 = 1e-3;
|
|
508
621
|
function deriveAlignmentGuides(targets, opts = {}) {
|
|
509
622
|
const d = opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR;
|
|
510
623
|
const edges = opts.edges ?? true;
|
|
@@ -513,7 +626,7 @@ function deriveAlignmentGuides(targets, opts = {}) {
|
|
|
513
626
|
const seenY = /* @__PURE__ */ new Map();
|
|
514
627
|
const add = (axis, offset, b) => {
|
|
515
628
|
const seen = axis === "x" ? seenX : seenY;
|
|
516
|
-
const key = Math.round(offset /
|
|
629
|
+
const key = Math.round(offset / EPS2);
|
|
517
630
|
const min = axis === "x" ? b.y : b.x;
|
|
518
631
|
const max = min + (axis === "x" ? b.height : b.width);
|
|
519
632
|
const prev = seen.get(key);
|
|
@@ -545,14 +658,14 @@ function deriveAlignmentGuides(targets, opts = {}) {
|
|
|
545
658
|
}
|
|
546
659
|
|
|
547
660
|
// src/guides/alignment/spacing.ts
|
|
548
|
-
var
|
|
661
|
+
var EPS3 = 1e-6;
|
|
549
662
|
var lo = (b, a) => a === "x" ? b.x : b.y;
|
|
550
663
|
var hi = (b, a) => a === "x" ? b.x + b.width : b.y + b.height;
|
|
551
664
|
var cross = (a) => a === "x" ? "y" : "x";
|
|
552
665
|
function overlap(a, b, axis) {
|
|
553
666
|
const min = Math.max(lo(a, axis), lo(b, axis));
|
|
554
667
|
const max = Math.min(hi(a, axis), hi(b, axis));
|
|
555
|
-
return max - min >
|
|
668
|
+
return max - min > EPS3 ? [min, max] : null;
|
|
556
669
|
}
|
|
557
670
|
function gapBetween(a, b, axis) {
|
|
558
671
|
const shared = overlap(a, b, cross(axis));
|
|
@@ -561,7 +674,7 @@ function gapBetween(a, b, axis) {
|
|
|
561
674
|
}
|
|
562
675
|
function hitsStrip(g, b, span2) {
|
|
563
676
|
const c = cross(g.axis);
|
|
564
|
-
return lo(b, g.axis) < g.max -
|
|
677
|
+
return lo(b, g.axis) < g.max - EPS3 && hi(b, g.axis) > g.min + EPS3 && lo(b, c) < span2[1] - EPS3 && hi(b, c) > span2[0] + EPS3;
|
|
565
678
|
}
|
|
566
679
|
function measureGaps(targets, axis) {
|
|
567
680
|
return measureGapSpans(targets, axis).map((m) => m.gap);
|
|
@@ -571,7 +684,7 @@ function measureGapSpans(targets, axis) {
|
|
|
571
684
|
for (const a of targets) {
|
|
572
685
|
let next = null;
|
|
573
686
|
for (const c of targets) {
|
|
574
|
-
if (c === a || lo(c, axis) < hi(a, axis) +
|
|
687
|
+
if (c === a || lo(c, axis) < hi(a, axis) + EPS3) continue;
|
|
575
688
|
if (overlap(a, c, cross(axis)) === null) continue;
|
|
576
689
|
if (next === null || lo(c, axis) < lo(next, axis)) next = c;
|
|
577
690
|
}
|
|
@@ -598,14 +711,14 @@ function spacingOffers(b, axis, edge, targets, refs) {
|
|
|
598
711
|
const sizes = refs.map((g) => g.max - g.min);
|
|
599
712
|
const out = [];
|
|
600
713
|
const offer = (delta, gap) => {
|
|
601
|
-
if (gap >
|
|
714
|
+
if (gap > EPS3) out.push({ delta, size: gap });
|
|
602
715
|
};
|
|
603
716
|
const L = left === null ? null : hi(left, axis);
|
|
604
717
|
const R = right === null ? null : lo(right, axis);
|
|
605
718
|
if (edge === "both") {
|
|
606
719
|
for (const g of sizes) {
|
|
607
|
-
if (L !== null && (R === null || L + g + size <= R +
|
|
608
|
-
if (R !== null && (L === null || R - g - size >= L -
|
|
720
|
+
if (L !== null && (R === null || L + g + size <= R + EPS3)) offer(L + g - bLo, g);
|
|
721
|
+
if (R !== null && (L === null || R - g - size >= L - EPS3)) offer(R - g - size - bLo, g);
|
|
609
722
|
}
|
|
610
723
|
if (L !== null && R !== null) {
|
|
611
724
|
const g = (R - L - size) / 2;
|
|
@@ -613,10 +726,10 @@ function spacingOffers(b, axis, edge, targets, refs) {
|
|
|
613
726
|
}
|
|
614
727
|
} else if (edge === "max" && R !== null) {
|
|
615
728
|
const own = L !== null ? [bLo - L] : [];
|
|
616
|
-
for (const g of [...sizes, ...own]) if (R - g > bLo +
|
|
729
|
+
for (const g of [...sizes, ...own]) if (R - g > bLo + EPS3) offer(R - g - bHi, g);
|
|
617
730
|
} else if (edge === "min" && L !== null) {
|
|
618
731
|
const own = R !== null ? [R - bHi] : [];
|
|
619
|
-
for (const g of [...sizes, ...own]) if (L + g < bHi -
|
|
732
|
+
for (const g of [...sizes, ...own]) if (L + g < bHi - EPS3) offer(L + g - bLo, g);
|
|
620
733
|
}
|
|
621
734
|
return out;
|
|
622
735
|
}
|
|
@@ -631,8 +744,8 @@ function bestAxis(b, axis, edge, targets, refs, tol) {
|
|
|
631
744
|
function equalGaps(b, axis, size, targets, refs) {
|
|
632
745
|
const eq = (g) => Math.abs(g.max - g.min - size) < 1e-3;
|
|
633
746
|
const out = refs.filter(eq);
|
|
634
|
-
const near = targets.filter((t) => hi(t, axis) > lo(b, axis) - size -
|
|
635
|
-
const own = measureGaps([...near, b], axis).filter((g) => (Math.abs(g.max - lo(b, axis)) <
|
|
747
|
+
const near = targets.filter((t) => hi(t, axis) > lo(b, axis) - size - EPS3 && lo(t, axis) < hi(b, axis) + size + EPS3);
|
|
748
|
+
const own = measureGaps([...near, b], axis).filter((g) => (Math.abs(g.max - lo(b, axis)) < EPS3 || Math.abs(g.min - hi(b, axis)) < EPS3) && eq(g));
|
|
636
749
|
return [...out, ...own];
|
|
637
750
|
}
|
|
638
751
|
function referenceGaps(bounds, measured) {
|
|
@@ -703,6 +816,11 @@ function siblingBounds(scene, ids, opts = {}) {
|
|
|
703
816
|
return worldBoundsOf(scene, siblingIds(scene, ids), opts);
|
|
704
817
|
}
|
|
705
818
|
|
|
819
|
+
// src/strategies/onPlane.ts
|
|
820
|
+
function guideOffsetOn(g, plane) {
|
|
821
|
+
return plane ? g.offset * plane.scale[g.axis] + plane.offset[g.axis] : g.offset;
|
|
822
|
+
}
|
|
823
|
+
|
|
706
824
|
// src/sources/guides.ts
|
|
707
825
|
function guideSnapSource(getGuides) {
|
|
708
826
|
return {
|
|
@@ -874,7 +992,7 @@ function spacingSnapSource(opts = {}) {
|
|
|
874
992
|
}
|
|
875
993
|
|
|
876
994
|
// src/spacingHints/distance.ts
|
|
877
|
-
var
|
|
995
|
+
var EPS4 = 1e-6;
|
|
878
996
|
var lo2 = (b, a) => a === "x" ? b.x : b.y;
|
|
879
997
|
var hi2 = (b, a) => a === "x" ? b.x + b.width : b.y + b.height;
|
|
880
998
|
var mid = (b, a) => (lo2(b, a) + hi2(b, a)) / 2;
|
|
@@ -888,15 +1006,15 @@ function measureAxis(from, to, axis, out) {
|
|
|
888
1006
|
const c = cross3(axis);
|
|
889
1007
|
const sharedMin = Math.max(lo2(from, c), lo2(to, c));
|
|
890
1008
|
const sharedMax = Math.min(hi2(from, c), hi2(to, c));
|
|
891
|
-
const shares = sharedMax - sharedMin >
|
|
1009
|
+
const shares = sharedMax - sharedMin > EPS4;
|
|
892
1010
|
const push = (min, max, at2) => {
|
|
893
|
-
if (max - min >
|
|
1011
|
+
if (max - min > EPS4) out.gaps.push({ axis, min, max, at: at2 });
|
|
894
1012
|
};
|
|
895
|
-
const before = hi2(from, axis) <= lo2(to, axis) +
|
|
896
|
-
const after = hi2(to, axis) <= lo2(from, axis) +
|
|
1013
|
+
const before = hi2(from, axis) <= lo2(to, axis) + EPS4;
|
|
1014
|
+
const after = hi2(to, axis) <= lo2(from, axis) + EPS4;
|
|
897
1015
|
if (before || after) {
|
|
898
1016
|
const [min, max] = before ? [hi2(from, axis), lo2(to, axis)] : [hi2(to, axis), lo2(from, axis)];
|
|
899
|
-
if (max - min <=
|
|
1017
|
+
if (max - min <= EPS4) return;
|
|
900
1018
|
const at2 = shares ? (sharedMin + sharedMax) / 2 : mid(from, c);
|
|
901
1019
|
push(min, max, at2);
|
|
902
1020
|
if (!shares) {
|
|
@@ -907,7 +1025,7 @@ function measureAxis(from, to, axis, out) {
|
|
|
907
1025
|
return;
|
|
908
1026
|
}
|
|
909
1027
|
if (!shares) return;
|
|
910
|
-
const [inner, outer] = lo2(from, axis) >= lo2(to, axis) -
|
|
1028
|
+
const [inner, outer] = lo2(from, axis) >= lo2(to, axis) - EPS4 && hi2(from, axis) <= hi2(to, axis) + EPS4 ? [from, to] : lo2(to, axis) >= lo2(from, axis) - EPS4 && hi2(to, axis) <= hi2(from, axis) + EPS4 ? [to, from] : [null, null];
|
|
911
1029
|
if (inner === null || outer === null) return;
|
|
912
1030
|
const at = mid(inner, c);
|
|
913
1031
|
push(lo2(outer, axis), lo2(inner, axis), at);
|
|
@@ -1787,6 +1905,6 @@ function ringSlots(opts = {}) {
|
|
|
1787
1905
|
};
|
|
1788
1906
|
}
|
|
1789
1907
|
|
|
1790
|
-
export { alignmentSnapSource, cellAt, containedThenNearest, createCellHighlightLayer, createGridLayer, createGridPreset, createGuidesLayer, createSpacingHintsPreset, deriveAlignmentGuides, distanceReadout, freeform,
|
|
1908
|
+
export { alignmentSnapSource, cellAt, cellOf, containedThenNearest, containerLines, createCellHighlightLayer, createGridLayer, createGridPreset, createGuidesLayer, createSpacingHintsPreset, deriveAlignmentGuides, distanceReadout, freeform, gridFit, gridLines, gridOwner, gridSlots, gridSnapSource, guideSnapSource, linesIn, linesNear, mapLines, matchSpacing, measureDistances, measureGaps, nearest, nearestLine, nearestWithin, none, pack, perContainer, pointToGridCell, quadtree, regionAt, resolveGridLines, ringSlots, roundToCell, rowSlots, sceneGridRegions, sequenceLayout, siblingBounds, slots, snapPoint, spacingSnapSource, tileGrid, useGridCellHover, useGuides, worldBoundsOf, worldUnionOf };
|
|
1791
1909
|
//# sourceMappingURL=index.js.map
|
|
1792
1910
|
//# sourceMappingURL=index.js.map
|