@oh-just-another/scene 0.57.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/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/a11y.d.ts +23 -0
- package/dist/a11y.d.ts.map +1 -0
- package/dist/a11y.js +37 -0
- package/dist/a11y.js.map +1 -0
- package/dist/anchors.d.ts +120 -0
- package/dist/anchors.d.ts.map +1 -0
- package/dist/anchors.js +322 -0
- package/dist/anchors.js.map +1 -0
- package/dist/annotation-geometry.d.ts +11 -0
- package/dist/annotation-geometry.d.ts.map +1 -0
- package/dist/annotation-geometry.js +19 -0
- package/dist/annotation-geometry.js.map +1 -0
- package/dist/annotation.d.ts +32 -0
- package/dist/annotation.d.ts.map +1 -0
- package/dist/annotation.js +2 -0
- package/dist/annotation.js.map +1 -0
- package/dist/constants.d.ts +186 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +186 -0
- package/dist/constants.js.map +1 -0
- package/dist/container.d.ts +112 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +227 -0
- package/dist/container.js.map +1 -0
- package/dist/diff.d.ts +22 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +18 -0
- package/dist/diff.js.map +1 -0
- package/dist/edge-curve.d.ts +37 -0
- package/dist/edge-curve.d.ts.map +1 -0
- package/dist/edge-curve.js +72 -0
- package/dist/edge-curve.js.map +1 -0
- package/dist/edge-geometry.d.ts +96 -0
- package/dist/edge-geometry.d.ts.map +1 -0
- package/dist/edge-geometry.js +467 -0
- package/dist/edge-geometry.js.map +1 -0
- package/dist/edge.d.ts +206 -0
- package/dist/edge.d.ts.map +1 -0
- package/dist/edge.js +2 -0
- package/dist/edge.js.map +1 -0
- package/dist/elbow-link.d.ts +23 -0
- package/dist/elbow-link.d.ts.map +1 -0
- package/dist/elbow-link.js +419 -0
- package/dist/elbow-link.js.map +1 -0
- package/dist/elbow-router.d.ts +20 -0
- package/dist/elbow-router.d.ts.map +1 -0
- package/dist/elbow-router.js +218 -0
- package/dist/elbow-router.js.map +1 -0
- package/dist/file.d.ts +41 -0
- package/dist/file.d.ts.map +1 -0
- package/dist/file.js +13 -0
- package/dist/file.js.map +1 -0
- package/dist/heading.d.ts +42 -0
- package/dist/heading.d.ts.map +1 -0
- package/dist/heading.js +77 -0
- package/dist/heading.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/layer.d.ts +18 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +2 -0
- package/dist/layer.js.map +1 -0
- package/dist/layout-registry.d.ts +35 -0
- package/dist/layout-registry.d.ts.map +1 -0
- package/dist/layout-registry.js +13 -0
- package/dist/layout-registry.js.map +1 -0
- package/dist/layout.d.ts +128 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +453 -0
- package/dist/layout.js.map +1 -0
- package/dist/operations.d.ts +32 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +105 -0
- package/dist/operations.js.map +1 -0
- package/dist/outline.d.ts +36 -0
- package/dist/outline.d.ts.map +1 -0
- package/dist/outline.js +129 -0
- package/dist/outline.js.map +1 -0
- package/dist/patch.d.ts +57 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +47 -0
- package/dist/patch.js.map +1 -0
- package/dist/queries.d.ts +115 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +403 -0
- package/dist/queries.js.map +1 -0
- package/dist/render-bounds.d.ts +36 -0
- package/dist/render-bounds.d.ts.map +1 -0
- package/dist/render-bounds.js +36 -0
- package/dist/render-bounds.js.map +1 -0
- package/dist/scene.d.ts +80 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +129 -0
- package/dist/scene.js.map +1 -0
- package/dist/shape.d.ts +306 -0
- package/dist/shape.d.ts.map +1 -0
- package/dist/shape.js +192 -0
- package/dist/shape.js.map +1 -0
- package/dist/snap.d.ts +88 -0
- package/dist/snap.d.ts.map +1 -0
- package/dist/snap.js +128 -0
- package/dist/snap.js.map +1 -0
- package/dist/spatial.d.ts +38 -0
- package/dist/spatial.d.ts.map +1 -0
- package/dist/spatial.js +95 -0
- package/dist/spatial.js.map +1 -0
- package/dist/style.d.ts +87 -0
- package/dist/style.d.ts.map +1 -0
- package/dist/style.js +43 -0
- package/dist/style.js.map +1 -0
- package/dist/text-measure.d.ts +29 -0
- package/dist/text-measure.d.ts.map +1 -0
- package/dist/text-measure.js +8 -0
- package/dist/text-measure.js.map +1 -0
- package/dist/three-way-merge.d.ts +59 -0
- package/dist/three-way-merge.d.ts.map +1 -0
- package/dist/three-way-merge.js +108 -0
- package/dist/three-way-merge.js.map +1 -0
- package/dist/viewport.d.ts +78 -0
- package/dist/viewport.d.ts.map +1 -0
- package/dist/viewport.js +62 -0
- package/dist/viewport.js.map +1 -0
- package/package.json +54 -0
package/dist/queries.js
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { bounds as B } from "@oh-just-another/math";
|
|
2
|
+
import { getElementWorldBounds, getElementLocalBounds, isPolygon, isEllipse, isRectangle, isImage, isText, isPath, isGroup, } from "./shape.js";
|
|
3
|
+
import { getCornerRadius } from "./style.js";
|
|
4
|
+
import { SpatialGrid } from "./spatial.js";
|
|
5
|
+
// --- direct lookups ---
|
|
6
|
+
export const getElement = (scene, id) => scene.elements.get(id);
|
|
7
|
+
export const getLink = (scene, id) => scene.links.get(id);
|
|
8
|
+
export const getLayer = (scene, id) => scene.layers.get(id);
|
|
9
|
+
// --- iteration in z-order ---
|
|
10
|
+
/**
|
|
11
|
+
* Layers sorted bottom-to-top by their `order` field. Stable for equal orders
|
|
12
|
+
* (which should not happen in practice with fractional indices).
|
|
13
|
+
*/
|
|
14
|
+
export const getLayersInOrder = (scene) => [...scene.layers.values()].sort((a, b) => (a.order < b.order ? -1 : a.order > b.order ? 1 : 0));
|
|
15
|
+
/** Shapes in `layerId`, sorted bottom-to-top by `order`. */
|
|
16
|
+
export const getElementsInLayer = (scene, layerId) => [...scene.elements.values()]
|
|
17
|
+
.filter((s) => s.layerId === layerId)
|
|
18
|
+
.sort((a, b) => (a.order < b.order ? -1 : a.order > b.order ? 1 : 0));
|
|
19
|
+
export const getLinksInLayer = (scene, layerId) => [...scene.links.values()]
|
|
20
|
+
.filter((e) => e.layerId === layerId)
|
|
21
|
+
.sort((a, b) => (a.order < b.order ? -1 : a.order > b.order ? 1 : 0));
|
|
22
|
+
// --- selection outline (contour) ---
|
|
23
|
+
/** Number of samples for an ellipse's outline polyline. */
|
|
24
|
+
const ELLIPSE_OUTLINE_SAMPLES = 48;
|
|
25
|
+
/** Samples per Q/C path segment when flattening to a polyline. */
|
|
26
|
+
const PATH_CURVE_SAMPLES = 10;
|
|
27
|
+
/** Apply a shape's local→world transform (scale → rotate → translate). */
|
|
28
|
+
const toWorld = (shape, p) => {
|
|
29
|
+
const sx = p.x * shape.scale.x;
|
|
30
|
+
const sy = p.y * shape.scale.y;
|
|
31
|
+
const cos = Math.cos(shape.rotation);
|
|
32
|
+
const sin = Math.sin(shape.rotation);
|
|
33
|
+
return {
|
|
34
|
+
x: shape.position.x + (sx * cos - sy * sin),
|
|
35
|
+
y: shape.position.y + (sx * sin + sy * cos),
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const rectLoop = (b) => [
|
|
39
|
+
{ x: b.x, y: b.y },
|
|
40
|
+
{ x: b.x + b.width, y: b.y },
|
|
41
|
+
{ x: b.x + b.width, y: b.y + b.height },
|
|
42
|
+
{ x: b.x, y: b.y + b.height },
|
|
43
|
+
];
|
|
44
|
+
/** Samples per rounded-rect corner arc. */
|
|
45
|
+
const CORNER_ARC_SAMPLES = 6;
|
|
46
|
+
/** Rounded-rect outline as a polyline — straight edges + sampled corner arcs. */
|
|
47
|
+
const roundedRectLoop = (b, r) => {
|
|
48
|
+
const { x, y, width: w, height: h } = b;
|
|
49
|
+
const arc = (cx, cy, from, to) => {
|
|
50
|
+
const pts = [];
|
|
51
|
+
for (let i = 0; i <= CORNER_ARC_SAMPLES; i++) {
|
|
52
|
+
const a = from + (to - from) * (i / CORNER_ARC_SAMPLES);
|
|
53
|
+
pts.push({ x: cx + r * Math.cos(a), y: cy + r * Math.sin(a) });
|
|
54
|
+
}
|
|
55
|
+
return pts;
|
|
56
|
+
};
|
|
57
|
+
const HALF_PI = Math.PI / 2;
|
|
58
|
+
return [
|
|
59
|
+
// top-left → top-right → bottom-right → bottom-left corners (clockwise).
|
|
60
|
+
...arc(x + r, y + r, Math.PI, Math.PI + HALF_PI),
|
|
61
|
+
...arc(x + w - r, y + r, -HALF_PI, 0),
|
|
62
|
+
...arc(x + w - r, y + h - r, 0, HALF_PI),
|
|
63
|
+
...arc(x + r, y + h - r, HALF_PI, Math.PI),
|
|
64
|
+
];
|
|
65
|
+
};
|
|
66
|
+
const flattenPath = (commands) => {
|
|
67
|
+
const pts = [];
|
|
68
|
+
let cur = { x: 0, y: 0 };
|
|
69
|
+
for (const c of commands) {
|
|
70
|
+
if (c.kind === "M" || c.kind === "L") {
|
|
71
|
+
cur = c.to;
|
|
72
|
+
pts.push({ x: cur.x, y: cur.y });
|
|
73
|
+
}
|
|
74
|
+
else if (c.kind === "Q") {
|
|
75
|
+
for (let i = 1; i <= PATH_CURVE_SAMPLES; i++) {
|
|
76
|
+
const t = i / PATH_CURVE_SAMPLES;
|
|
77
|
+
const u = 1 - t;
|
|
78
|
+
pts.push({
|
|
79
|
+
x: u * u * cur.x + 2 * u * t * c.control.x + t * t * c.to.x,
|
|
80
|
+
y: u * u * cur.y + 2 * u * t * c.control.y + t * t * c.to.y,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
cur = c.to;
|
|
84
|
+
}
|
|
85
|
+
else if (c.kind === "C") {
|
|
86
|
+
for (let i = 1; i <= PATH_CURVE_SAMPLES; i++) {
|
|
87
|
+
const t = i / PATH_CURVE_SAMPLES;
|
|
88
|
+
const u = 1 - t;
|
|
89
|
+
pts.push({
|
|
90
|
+
x: u ** 3 * cur.x + 3 * u * u * t * c.control1.x + 3 * u * t * t * c.control2.x + t ** 3 * c.to.x,
|
|
91
|
+
y: u ** 3 * cur.y + 3 * u * u * t * c.control1.y + 3 * u * t * t * c.control2.y + t ** 3 * c.to.y,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
cur = c.to;
|
|
95
|
+
}
|
|
96
|
+
// "Z" closes implicitly (the halo renderer closes each loop).
|
|
97
|
+
}
|
|
98
|
+
return pts;
|
|
99
|
+
};
|
|
100
|
+
const outlineProviders = new Map();
|
|
101
|
+
/** Register a multi-loop outline provider for a custom element `type`. */
|
|
102
|
+
export const registerElementOutline = (type, provider) => {
|
|
103
|
+
outlineProviders.set(type, provider);
|
|
104
|
+
};
|
|
105
|
+
/** Local-space outline loop(s) for a single (non-group) shape, or `null`. */
|
|
106
|
+
const localOutlineLoops = (shape) => {
|
|
107
|
+
if (isPolygon(shape))
|
|
108
|
+
return [shape.points.map((p) => ({ x: p.x, y: p.y }))];
|
|
109
|
+
if (isEllipse(shape)) {
|
|
110
|
+
const b = getElementLocalBounds(shape);
|
|
111
|
+
const cx = b.x + b.width / 2;
|
|
112
|
+
const cy = b.y + b.height / 2;
|
|
113
|
+
const rx = b.width / 2;
|
|
114
|
+
const ry = b.height / 2;
|
|
115
|
+
const pts = [];
|
|
116
|
+
for (let i = 0; i < ELLIPSE_OUTLINE_SAMPLES; i++) {
|
|
117
|
+
const a = (i / ELLIPSE_OUTLINE_SAMPLES) * Math.PI * 2 - Math.PI / 2;
|
|
118
|
+
pts.push({ x: cx + rx * Math.cos(a), y: cy + ry * Math.sin(a) });
|
|
119
|
+
}
|
|
120
|
+
return [pts];
|
|
121
|
+
}
|
|
122
|
+
if (isRectangle(shape)) {
|
|
123
|
+
const b = getElementLocalBounds(shape);
|
|
124
|
+
const r = getCornerRadius(shape.style.roundness, b.width, b.height);
|
|
125
|
+
return [r > 0 ? roundedRectLoop(b, r) : rectLoop(b)];
|
|
126
|
+
}
|
|
127
|
+
if (isImage(shape) || isText(shape)) {
|
|
128
|
+
return [rectLoop(getElementLocalBounds(shape))];
|
|
129
|
+
}
|
|
130
|
+
if (isPath(shape))
|
|
131
|
+
return [flattenPath(shape.commands)];
|
|
132
|
+
// group handled by the caller; brush / template / custom → bbox fallback.
|
|
133
|
+
return null;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* World-space outline loop(s) tracing a shape's actual contour, for the
|
|
137
|
+
* selection halo. polygon (star / diamond / hexagon) is exact; ellipse and
|
|
138
|
+
* path are sampled; a group returns one loop per descendant (handles
|
|
139
|
+
* visually-disconnected figures). Shapes without known geometry (composite
|
|
140
|
+
* template, brush, custom) fall back to their world bounding box. Cheap
|
|
141
|
+
* enough to recompute every frame — no baking needed.
|
|
142
|
+
*/
|
|
143
|
+
export const getElementOutline = (scene, shape) => {
|
|
144
|
+
if (isGroup(shape)) {
|
|
145
|
+
const loops = [];
|
|
146
|
+
for (const child of getChildrenOf(scene, shape.id))
|
|
147
|
+
loops.push(...getElementOutline(scene, child));
|
|
148
|
+
return loops;
|
|
149
|
+
}
|
|
150
|
+
const local = localOutlineLoops(shape);
|
|
151
|
+
if (local)
|
|
152
|
+
return local.map((loop) => loop.map((p) => toWorld(shape, p)));
|
|
153
|
+
// Custom / composite type with a registered outline provider (multi-loop).
|
|
154
|
+
const provider = outlineProviders.get(shape.type);
|
|
155
|
+
if (provider) {
|
|
156
|
+
const loops = provider(shape).filter((loop) => loop.length >= 2);
|
|
157
|
+
if (loops.length > 0)
|
|
158
|
+
return loops.map((loop) => loop.map((p) => toWorld(shape, p)));
|
|
159
|
+
}
|
|
160
|
+
// Fallback: axis-aligned world bounding box.
|
|
161
|
+
const b = getElementWorldBounds(shape);
|
|
162
|
+
return [rectLoop(b)];
|
|
163
|
+
};
|
|
164
|
+
// --- group queries (parentId chain) ---
|
|
165
|
+
/**
|
|
166
|
+
* Direct children of `parentId` — every shape whose `parentId` equals
|
|
167
|
+
* the argument, in z-order. Linear in scene size; for groups inside the
|
|
168
|
+
* editor's hot path, cache the result by `(scene, parentId)`.
|
|
169
|
+
*/
|
|
170
|
+
export const getChildrenOf = (scene, parentId) => {
|
|
171
|
+
const out = [];
|
|
172
|
+
for (const s of scene.elements.values()) {
|
|
173
|
+
if (s.parentId === parentId)
|
|
174
|
+
out.push(s);
|
|
175
|
+
}
|
|
176
|
+
out.sort((a, b) => (a.order < b.order ? -1 : a.order > b.order ? 1 : 0));
|
|
177
|
+
return out;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* `true` when the shape (or any of its ancestors via `parentId`) has
|
|
181
|
+
* `locked: true`. Walks the parent chain bounded by
|
|
182
|
+
* `MAX_PARENT_DEPTH` so the answer stays O(depth) for a freshly
|
|
183
|
+
* grouped scene. Independent from `Layer.locked` — callers that need
|
|
184
|
+
* the combined interactivity gate should `||` both flags.
|
|
185
|
+
*/
|
|
186
|
+
export const isElementLocked = (scene, shape) => {
|
|
187
|
+
let current = shape;
|
|
188
|
+
for (let i = 0; current && i < MAX_PARENT_DEPTH; i++) {
|
|
189
|
+
if (current.locked === true)
|
|
190
|
+
return true;
|
|
191
|
+
if (!current.parentId)
|
|
192
|
+
return false;
|
|
193
|
+
current = scene.elements.get(current.parentId);
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* `true` when the shape (or any of its ancestors via `parentId`) has
|
|
199
|
+
* `hidden: true`. Same propagation semantics as `isElementLocked`.
|
|
200
|
+
*/
|
|
201
|
+
export const isElementHidden = (scene, shape) => {
|
|
202
|
+
let current = shape;
|
|
203
|
+
for (let i = 0; current && i < MAX_PARENT_DEPTH; i++) {
|
|
204
|
+
if (current.hidden === true)
|
|
205
|
+
return true;
|
|
206
|
+
if (!current.parentId)
|
|
207
|
+
return false;
|
|
208
|
+
current = scene.elements.get(current.parentId);
|
|
209
|
+
}
|
|
210
|
+
return false;
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Walks the `parentId` chain starting from `elementId` and returns the
|
|
214
|
+
* topmost ancestor (the root). Returns the shape itself when it has no
|
|
215
|
+
* parent, or `undefined` when the shape (or any ancestor) is missing.
|
|
216
|
+
* Cycle-safe — bails after `MAX_PARENT_DEPTH` hops.
|
|
217
|
+
*/
|
|
218
|
+
export const getRootSelf = (scene, elementId) => {
|
|
219
|
+
let current = scene.elements.get(elementId);
|
|
220
|
+
for (let i = 0; current?.parentId && i < MAX_PARENT_DEPTH; i++) {
|
|
221
|
+
const parent = scene.elements.get(current.parentId);
|
|
222
|
+
if (!parent)
|
|
223
|
+
break;
|
|
224
|
+
current = parent;
|
|
225
|
+
}
|
|
226
|
+
return current;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Every descendant of `parentId`, recursive, including the root itself.
|
|
230
|
+
* Order: parent first, then a depth-first walk. Cycle-safe via the
|
|
231
|
+
* `visited` set.
|
|
232
|
+
*/
|
|
233
|
+
export const getDescendantsOf = (scene, parentId) => {
|
|
234
|
+
const root = scene.elements.get(parentId);
|
|
235
|
+
if (!root)
|
|
236
|
+
return [];
|
|
237
|
+
const visited = new Set([parentId]);
|
|
238
|
+
const out = [root];
|
|
239
|
+
const stack = [parentId];
|
|
240
|
+
while (stack.length > 0) {
|
|
241
|
+
const cur = stack.pop();
|
|
242
|
+
if (cur === undefined)
|
|
243
|
+
break;
|
|
244
|
+
for (const child of getChildrenOf(scene, cur)) {
|
|
245
|
+
if (visited.has(child.id))
|
|
246
|
+
continue;
|
|
247
|
+
visited.add(child.id);
|
|
248
|
+
out.push(child);
|
|
249
|
+
stack.push(child.id);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return out;
|
|
253
|
+
};
|
|
254
|
+
const MAX_PARENT_DEPTH = 64;
|
|
255
|
+
// --- spatial queries (linear scan) ---
|
|
256
|
+
/**
|
|
257
|
+
* Shapes whose world AABB intersects `range`. Linear in the number of shapes.
|
|
258
|
+
* For large scenes use `buildSpatialIndex` once and query the index.
|
|
259
|
+
*/
|
|
260
|
+
export const getElementsInBounds = (scene, range) => {
|
|
261
|
+
const out = [];
|
|
262
|
+
for (const s of scene.elements.values()) {
|
|
263
|
+
if (B.intersects(getElementWorldBounds(s), range))
|
|
264
|
+
out.push(s);
|
|
265
|
+
}
|
|
266
|
+
return out;
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Shapes whose world-AABB is at least `minCoverageRatio` covered by
|
|
270
|
+
* `range`. `1` requires full containment (containment-style lasso);
|
|
271
|
+
* `0.5` selects when at least half of the element sits inside the
|
|
272
|
+
* box — friendlier than pure intersection because brushing past an
|
|
273
|
+
* edge doesn't accidentally grab the shape.
|
|
274
|
+
*
|
|
275
|
+
* Always selects shapes that fully contain the lasso (small lasso
|
|
276
|
+
* inside a big shape) — same affordance as bidirectional containment.
|
|
277
|
+
* Zero-area shapes (groups, brushes-with-one-vertex) fall back to a
|
|
278
|
+
* plain intersection test.
|
|
279
|
+
*/
|
|
280
|
+
export const getElementsCoveredByBounds = (scene, range, minCoverageRatio = 0.5) => {
|
|
281
|
+
const out = [];
|
|
282
|
+
for (const s of scene.elements.values()) {
|
|
283
|
+
const b = getElementWorldBounds(s);
|
|
284
|
+
if (!B.intersects(b, range))
|
|
285
|
+
continue;
|
|
286
|
+
const area = b.width * b.height;
|
|
287
|
+
if (area <= 0) {
|
|
288
|
+
out.push(s);
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const ix = Math.max(b.x, range.x);
|
|
292
|
+
const iy = Math.max(b.y, range.y);
|
|
293
|
+
const ix2 = Math.min(b.x + b.width, range.x + range.width);
|
|
294
|
+
const iy2 = Math.min(b.y + b.height, range.y + range.height);
|
|
295
|
+
const iw = ix2 - ix;
|
|
296
|
+
const ih = iy2 - iy;
|
|
297
|
+
if (iw <= 0 || ih <= 0)
|
|
298
|
+
continue;
|
|
299
|
+
const coverage = (iw * ih) / area;
|
|
300
|
+
if (coverage >= minCoverageRatio) {
|
|
301
|
+
out.push(s);
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
// Bidirectional: tiny lasso inside a big shape still picks it.
|
|
305
|
+
const lassoArea = range.width * range.height;
|
|
306
|
+
if (lassoArea > 0 && (iw * ih) / lassoArea >= minCoverageRatio) {
|
|
307
|
+
out.push(s);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return out;
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Topmost shape containing `point`. Iterates layers top-to-bottom, then shapes
|
|
314
|
+
* within each layer top-to-bottom; returns the first hit. Hit-test here is the
|
|
315
|
+
* conservative AABB test; renderer-specific shape-precise hit-tests belong
|
|
316
|
+
* with the renderer.
|
|
317
|
+
*/
|
|
318
|
+
export const getElementAt = (scene, point) => {
|
|
319
|
+
const layers = getLayersInOrder(scene);
|
|
320
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
321
|
+
const layer = layers[i];
|
|
322
|
+
if (!layer?.visible)
|
|
323
|
+
continue;
|
|
324
|
+
const shapes = getElementsInLayer(scene, layer.id);
|
|
325
|
+
for (let j = shapes.length - 1; j >= 0; j--) {
|
|
326
|
+
const s = shapes[j];
|
|
327
|
+
if (s === undefined)
|
|
328
|
+
continue;
|
|
329
|
+
if (B.contains(getElementWorldBounds(s), point))
|
|
330
|
+
return s;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return undefined;
|
|
334
|
+
};
|
|
335
|
+
// --- spatial index helpers ---
|
|
336
|
+
/**
|
|
337
|
+
* Build a `SpatialGrid` from the current scene. Re-build (or update
|
|
338
|
+
* incrementally) when shapes change — the grid is not auto-synced with the
|
|
339
|
+
* scene. The default cell size is tuned for typical editor scenes; pass an
|
|
340
|
+
* explicit value if your shapes are much larger or smaller.
|
|
341
|
+
*/
|
|
342
|
+
export const buildSpatialIndex = (scene, cellSize) => {
|
|
343
|
+
const grid = new SpatialGrid(cellSize);
|
|
344
|
+
for (const shape of scene.elements.values()) {
|
|
345
|
+
grid.insert(shape.id, getElementWorldBounds(shape));
|
|
346
|
+
}
|
|
347
|
+
return grid;
|
|
348
|
+
};
|
|
349
|
+
/**
|
|
350
|
+
* Range query backed by the index. Returns shapes (not just ids) whose AABB
|
|
351
|
+
* actually intersects `range`. The grid pre-filters by cell overlap; this
|
|
352
|
+
* function does the precise AABB filter.
|
|
353
|
+
*/
|
|
354
|
+
export const queryByIndex = (scene, grid, range) => {
|
|
355
|
+
const candidates = grid.query(range);
|
|
356
|
+
const out = [];
|
|
357
|
+
for (const id of candidates) {
|
|
358
|
+
const shape = scene.elements.get(id);
|
|
359
|
+
if (!shape)
|
|
360
|
+
continue;
|
|
361
|
+
if (B.intersects(getElementWorldBounds(shape), range))
|
|
362
|
+
out.push(shape);
|
|
363
|
+
}
|
|
364
|
+
return out;
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* Point hit-test backed by a SpatialGrid. Equivalent to `getElementAt` but
|
|
368
|
+
* pre-filters candidates through `grid.query` — O(k) where k is the
|
|
369
|
+
* shapes overlapping the point's cell. Walks layers top-to-bottom for
|
|
370
|
+
* stable z-order; within a layer picks the highest-`order` shape that
|
|
371
|
+
* actually contains the point.
|
|
372
|
+
*/
|
|
373
|
+
export const getElementAtIndexed = (scene, grid, point) => {
|
|
374
|
+
const pointRange = { x: point.x, y: point.y, width: 0, height: 0 };
|
|
375
|
+
const candidates = grid.query(pointRange);
|
|
376
|
+
if (candidates.size === 0)
|
|
377
|
+
return undefined;
|
|
378
|
+
let best;
|
|
379
|
+
let bestLayerOrder = "";
|
|
380
|
+
let bestElementOrder = "";
|
|
381
|
+
let bestSet = false;
|
|
382
|
+
for (const id of candidates) {
|
|
383
|
+
const shape = scene.elements.get(id);
|
|
384
|
+
if (!shape)
|
|
385
|
+
continue;
|
|
386
|
+
if (!B.contains(getElementWorldBounds(shape), point))
|
|
387
|
+
continue;
|
|
388
|
+
const layer = scene.layers.get(shape.layerId);
|
|
389
|
+
if (!layer?.visible)
|
|
390
|
+
continue;
|
|
391
|
+
const layerOrder = layer.order;
|
|
392
|
+
if (!bestSet ||
|
|
393
|
+
layerOrder > bestLayerOrder ||
|
|
394
|
+
(layerOrder === bestLayerOrder && shape.order > bestElementOrder)) {
|
|
395
|
+
best = shape;
|
|
396
|
+
bestLayerOrder = layerOrder;
|
|
397
|
+
bestElementOrder = shape.order;
|
|
398
|
+
bestSet = true;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return best;
|
|
402
|
+
};
|
|
403
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Bounds } from "@oh-just-another/types";
|
|
2
|
+
import { type ElementBase } from "./shape.js";
|
|
3
|
+
/**
|
|
4
|
+
* Some elements PAINT beyond their geometric bounds — a frame draws its
|
|
5
|
+
* header strip above the rectangle, a confetti box throws particles past
|
|
6
|
+
* its edges. The dirty-rect / tile invalidation must clear that overspill
|
|
7
|
+
* too, otherwise deleting (or moving without a full repaint) leaves a
|
|
8
|
+
* "ghost" of the overpainted region.
|
|
9
|
+
*
|
|
10
|
+
* `RenderOverflow` is the per-side extra paint margin (world units) an
|
|
11
|
+
* element type bleeds past `getElementWorldBounds`. Providers are keyed by
|
|
12
|
+
* element `type` and may inspect the shape (e.g. only confetti-tagged
|
|
13
|
+
* rectangles overflow). All sides default to 0.
|
|
14
|
+
*/
|
|
15
|
+
export interface RenderOverflow {
|
|
16
|
+
readonly top?: number;
|
|
17
|
+
readonly right?: number;
|
|
18
|
+
readonly bottom?: number;
|
|
19
|
+
readonly left?: number;
|
|
20
|
+
}
|
|
21
|
+
type RenderOverflowProvider = (shape: ElementBase) => RenderOverflow;
|
|
22
|
+
/**
|
|
23
|
+
* Register how far an element type paints past its bounds. The renderer
|
|
24
|
+
* that draws the overspill owns this (it knows the header height /
|
|
25
|
+
* particle spread). Idempotent per type — last registration wins.
|
|
26
|
+
*/
|
|
27
|
+
export declare const registerRenderOverflow: (type: string, fn: RenderOverflowProvider) => void;
|
|
28
|
+
/**
|
|
29
|
+
* World bounds expanded by the element type's registered paint overflow —
|
|
30
|
+
* the region that must be invalidated/cleared when the element changes or
|
|
31
|
+
* is removed. Falls back to the plain world bounds when no overflow is
|
|
32
|
+
* registered (the common case).
|
|
33
|
+
*/
|
|
34
|
+
export declare const getElementRenderBounds: (shape: ElementBase) => Bounds;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=render-bounds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-bounds.d.ts","sourceRoot":"","sources":["../src/render-bounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAyB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,KAAK,sBAAsB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,cAAc,CAAC;AAIrE;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,MAAM,EAAE,IAAI,sBAAsB,KAAG,IAEjF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,WAAW,KAAG,MAgB3D,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getElementWorldBounds } from "./shape.js";
|
|
2
|
+
const providers = new Map();
|
|
3
|
+
/**
|
|
4
|
+
* Register how far an element type paints past its bounds. The renderer
|
|
5
|
+
* that draws the overspill owns this (it knows the header height /
|
|
6
|
+
* particle spread). Idempotent per type — last registration wins.
|
|
7
|
+
*/
|
|
8
|
+
export const registerRenderOverflow = (type, fn) => {
|
|
9
|
+
providers.set(type, fn);
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* World bounds expanded by the element type's registered paint overflow —
|
|
13
|
+
* the region that must be invalidated/cleared when the element changes or
|
|
14
|
+
* is removed. Falls back to the plain world bounds when no overflow is
|
|
15
|
+
* registered (the common case).
|
|
16
|
+
*/
|
|
17
|
+
export const getElementRenderBounds = (shape) => {
|
|
18
|
+
const b = getElementWorldBounds(shape);
|
|
19
|
+
const fn = providers.get(shape.type);
|
|
20
|
+
if (!fn)
|
|
21
|
+
return b;
|
|
22
|
+
const o = fn(shape);
|
|
23
|
+
const top = o.top ?? 0;
|
|
24
|
+
const right = o.right ?? 0;
|
|
25
|
+
const bottom = o.bottom ?? 0;
|
|
26
|
+
const left = o.left ?? 0;
|
|
27
|
+
if (top === 0 && right === 0 && bottom === 0 && left === 0)
|
|
28
|
+
return b;
|
|
29
|
+
return {
|
|
30
|
+
x: b.x - left,
|
|
31
|
+
y: b.y - top,
|
|
32
|
+
width: b.width + left + right,
|
|
33
|
+
height: b.height + top + bottom,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=render-bounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-bounds.js","sourceRoot":"","sources":["../src/render-bounds.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAoB,MAAM,YAAY,CAAC;AAuBrE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkC,CAAC;AAE5D;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAAY,EAAE,EAA0B,EAAQ,EAAE;IACvF,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAkB,EAAU,EAAE;IACnE,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,CAAC;IAClB,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;IACpB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IACzB,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACrE,OAAO;QACL,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;QACb,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,GAAG,KAAK;QAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,MAAM;KAChC,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/scene.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type AnnotationId, type LinkId, type FileId, type LayerId, type ElementId } from "@oh-just-another/types";
|
|
2
|
+
import { type FractionalIndex } from "fractional-keys";
|
|
3
|
+
import type { Annotation } from "./annotation.js";
|
|
4
|
+
import type { Link } from "./edge.js";
|
|
5
|
+
import type { BinaryFile } from "./file.js";
|
|
6
|
+
import { type Layer } from "./layer.js";
|
|
7
|
+
import type { Patch } from "./patch.js";
|
|
8
|
+
import type { Element } from "./shape.js";
|
|
9
|
+
import { type Viewport } from "./viewport.js";
|
|
10
|
+
/**
|
|
11
|
+
* Whole-scene container. Entities are stored in immutable `ReadonlyMap`s for
|
|
12
|
+
* O(1) lookup; z-order is computed by sorting on the `order` field. The maps
|
|
13
|
+
* are replaced wholesale on every operation, but only the touched entries are
|
|
14
|
+
* actually reallocated (structural sharing).
|
|
15
|
+
*/
|
|
16
|
+
export interface Scene {
|
|
17
|
+
readonly elements: ReadonlyMap<ElementId, Element>;
|
|
18
|
+
readonly links: ReadonlyMap<LinkId, Link>;
|
|
19
|
+
readonly layers: ReadonlyMap<LayerId, Layer>;
|
|
20
|
+
/**
|
|
21
|
+
* Threaded comments anchored to either a shape (id) or a free
|
|
22
|
+
* world-space position. Separate from shapes/edges because they
|
|
23
|
+
* are not part of the diagram's structure — they're meta-content
|
|
24
|
+
* that hosts may toggle on/off without affecting render output.
|
|
25
|
+
*/
|
|
26
|
+
readonly annotations: ReadonlyMap<AnnotationId, Annotation>;
|
|
27
|
+
/**
|
|
28
|
+
* Binary file registry. Shapes that carry bitmaps —
|
|
29
|
+
* `ImageElement.fileId` is the typical case — reference entries
|
|
30
|
+
* here instead of embedding `src` as a dataURL. Keeps the
|
|
31
|
+
* shape-graph small (so scene.json stays human-grep-able) and
|
|
32
|
+
* lets the host transport the bytes once, regardless of how
|
|
33
|
+
* many shapes reference them.
|
|
34
|
+
*
|
|
35
|
+
* Optional (defaults to empty) so scenes without file entries
|
|
36
|
+
* keep loading: `ImageElement.src` remains the fallback when
|
|
37
|
+
* `fileId` is unset.
|
|
38
|
+
*/
|
|
39
|
+
readonly files: ReadonlyMap<FileId, BinaryFile>;
|
|
40
|
+
readonly viewport: Viewport;
|
|
41
|
+
}
|
|
42
|
+
export declare const DEFAULT_LAYER_ID: LayerId;
|
|
43
|
+
/** Empty scene with a single default layer and a zero-size viewport. */
|
|
44
|
+
export declare const emptyScene: () => Scene;
|
|
45
|
+
/**
|
|
46
|
+
* Idempotent add: writes the file under its id, replacing any
|
|
47
|
+
* previous entry with the same id. Returns a fresh Scene with
|
|
48
|
+
* the new `files` map. Pure.
|
|
49
|
+
*/
|
|
50
|
+
export declare const addBinaryFile: (scene: Scene, file: BinaryFile) => Scene;
|
|
51
|
+
/**
|
|
52
|
+
* Remove a binary file by id. No-op when the id isn't present.
|
|
53
|
+
* Doesn't garbage-collect references — callers that delete shapes
|
|
54
|
+
* pointing at the file should remove the file separately when
|
|
55
|
+
* they're certain no other shape still references it.
|
|
56
|
+
*/
|
|
57
|
+
export declare const removeBinaryFile: (scene: Scene, id: FileId) => Scene;
|
|
58
|
+
/** Lookup helper — mirrors `getElement` / `getLink` style. */
|
|
59
|
+
export declare const getBinaryFile: (scene: Scene, id: FileId) => BinaryFile | undefined;
|
|
60
|
+
/** Apply a patch to a scene, returning a new scene. Pure. */
|
|
61
|
+
export declare const apply: (scene: Scene, patch: Patch) => Scene;
|
|
62
|
+
/**
|
|
63
|
+
* Pick an `order` key that places the new entity above every existing one in
|
|
64
|
+
* `layerId`. O(n) in the number of entities in that layer. For bulk inserts,
|
|
65
|
+
* compute once and chain manually.
|
|
66
|
+
*/
|
|
67
|
+
export declare const orderForTop: (existing: Iterable<FractionalIndex>) => FractionalIndex;
|
|
68
|
+
/** Mirror of `orderForTop` for placing below everything. */
|
|
69
|
+
export declare const orderForBottom: (existing: Iterable<FractionalIndex>) => FractionalIndex;
|
|
70
|
+
/** Pick an `order` that places strictly between two neighbors. */
|
|
71
|
+
export declare const orderBetween: (a: FractionalIndex | null, b: FractionalIndex | null) => FractionalIndex;
|
|
72
|
+
/**
|
|
73
|
+
* Generate `n` evenly-spaced fractional indices strictly between `a` and
|
|
74
|
+
* `b`. Useful for compaction passes that rewrite a whole layer's
|
|
75
|
+
* z-order back to short balanced strings (`"a0"`, `"a1"`, `"a2"`, …)
|
|
76
|
+
* after a burst of insert-in-the-middle operations has lengthened the
|
|
77
|
+
* existing keys.
|
|
78
|
+
*/
|
|
79
|
+
export declare const orderBetweenMany: (a: FractionalIndex | null, b: FractionalIndex | null, n: number) => readonly FractionalIndex[];
|
|
80
|
+
//# sourceMappingURL=scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,OAAO,EACZ,KAAK,SAAS,EACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA4C,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAoB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC5D;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED,eAAO,MAAM,gBAAgB,EAAE,OAAgC,CAAC;AAUhE,wEAAwE;AACxE,eAAO,MAAM,UAAU,QAAO,KAO5B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,EAAE,MAAM,UAAU,KAAG,KAI9D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,EAAE,IAAI,MAAM,KAAG,KAK3D,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,EAAE,IAAI,MAAM,KAAG,UAAU,GAAG,SACjD,CAAC;AAEtB,6DAA6D;AAC7D,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,EAAE,OAAO,KAAK,KAAG,KAqClD,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,UAAU,QAAQ,CAAC,eAAe,CAAC,KAAG,eAMjE,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,cAAc,GAAI,UAAU,QAAQ,CAAC,eAAe,CAAC,KAAG,eAMpE,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,YAAY,GACvB,GAAG,eAAe,GAAG,IAAI,EACzB,GAAG,eAAe,GAAG,IAAI,KACxB,eAA2C,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,GAAG,eAAe,GAAG,IAAI,EACzB,GAAG,eAAe,GAAG,IAAI,EACzB,GAAG,MAAM,KACR,SAAS,eAAe,EAAmC,CAAC"}
|