@elaraai/east-ui-components 1.0.12 → 1.0.14
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/collections/schematic/camera.d.ts +175 -0
- package/dist/collections/schematic/camera.d.ts.map +1 -0
- package/dist/collections/schematic/index.d.ts +2 -0
- package/dist/collections/schematic/index.d.ts.map +1 -1
- package/dist/collections/schematic/paint.d.ts +174 -0
- package/dist/collections/schematic/paint.d.ts.map +1 -0
- package/dist/collections/schematic/theme.d.ts +9 -0
- package/dist/collections/schematic/theme.d.ts.map +1 -0
- package/dist/index.cjs +1030 -247
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1030 -247
- package/dist/index.js.map +1 -1
- package/dist/theme/global-css.d.ts.map +1 -1
- package/dist/theme/slot-recipes/schematic.d.ts +1 -1
- package/dist/theme/slot-recipes/schematic.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Pure camera maths for the Schematic renderer — the single source of truth for
|
|
7
|
+
* the pan/zoom transform, the interaction-mode machine, viewport culling
|
|
8
|
+
* geometry, and the `requestAnimationFrame` coalescer. Kept free of React,
|
|
9
|
+
* Chakra, and Canvas2D so every piece is unit-testable in a `node` environment
|
|
10
|
+
* and so the **same** world→screen projection is shared by the Canvas2D painter
|
|
11
|
+
* ({@link ../paint}) and the DOM card layer — the two surfaces can never use a
|
|
12
|
+
* different transform and drift apart (issue #57, P1).
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
/** The pan/zoom state: `screen = world × fit × zoom + t`. */
|
|
17
|
+
export interface Viewport {
|
|
18
|
+
zoom: number;
|
|
19
|
+
tx: number;
|
|
20
|
+
ty: number;
|
|
21
|
+
}
|
|
22
|
+
/** The identity camera — fully zoomed out, no pan. */
|
|
23
|
+
export declare const IDENTITY: Viewport;
|
|
24
|
+
/**
|
|
25
|
+
* The transform in CSS pixels with `ppu` (pixels-per-world-unit) already
|
|
26
|
+
* folded in: `screen = world × ppu + t`. Mirrors {@link ../paint!PaintCamera}.
|
|
27
|
+
*/
|
|
28
|
+
export interface ScreenCamera {
|
|
29
|
+
ppu: number;
|
|
30
|
+
tx: number;
|
|
31
|
+
ty: number;
|
|
32
|
+
}
|
|
33
|
+
/** An axis-aligned bounding box (world or screen space). */
|
|
34
|
+
export interface Bbox {
|
|
35
|
+
minX: number;
|
|
36
|
+
minY: number;
|
|
37
|
+
maxX: number;
|
|
38
|
+
maxY: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Project a world point to screen space (`x × ppu + tx`, `y × ppu + ty`). The
|
|
42
|
+
* one projector shared by the painter and the card layer; the DOM cards apply
|
|
43
|
+
* the identical arithmetic in CSS via {@link cardTranslateCss}.
|
|
44
|
+
*
|
|
45
|
+
* @param x - world x
|
|
46
|
+
* @param y - world y
|
|
47
|
+
* @param cam - the screen camera (ppu + translation)
|
|
48
|
+
* @returns the screen-space point
|
|
49
|
+
*/
|
|
50
|
+
export declare function project(x: number, y: number, cam: ScreenCamera): {
|
|
51
|
+
sx: number;
|
|
52
|
+
sy: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The CSS `translate(...)` a DOM card uses to sit on its world anchor, reading
|
|
56
|
+
* the live camera from the `--cam-ppu` / `--cam-tx` / `--cam-ty` custom
|
|
57
|
+
* properties set on the card layer. The arithmetic is identical to
|
|
58
|
+
* {@link project} (`ppu × coord + t`), so card and canvas-drawn footprint
|
|
59
|
+
* resolve to the same screen point. The string is **camera-independent** (it
|
|
60
|
+
* only embeds the item's world `x`/`y`), so a camera change is a single set of
|
|
61
|
+
* custom-property writes on the parent — no per-card React re-layout.
|
|
62
|
+
*
|
|
63
|
+
* @param x - world x of the item anchor
|
|
64
|
+
* @param y - world y of the item anchor
|
|
65
|
+
* @returns a CSS `translate()` expression referencing the `--cam-*` vars
|
|
66
|
+
*/
|
|
67
|
+
export declare function cardTranslateCss(x: number, y: number): string;
|
|
68
|
+
/**
|
|
69
|
+
* The CSS length a DOM card uses for an explicit world-space `width`, reading
|
|
70
|
+
* the live `--cam-ppu`. Expressing the width through the var (not a
|
|
71
|
+
* render-time `width × ppu`) keeps an explicit-width card's box sized from the
|
|
72
|
+
* **same** live ppu the canvas footprint is drawn from, so box and footprint
|
|
73
|
+
* never diverge in size during a zoom (issue #57, Phase 2 invariant 6).
|
|
74
|
+
*
|
|
75
|
+
* @param width - the item's world-space width
|
|
76
|
+
* @returns a CSS `calc()` length referencing `--cam-ppu`
|
|
77
|
+
*/
|
|
78
|
+
export declare function cardWidthCss(width: number): string;
|
|
79
|
+
/**
|
|
80
|
+
* The world-space rectangle currently visible — the inverse projection of the
|
|
81
|
+
* canvas corners. Used to cull off-screen zones / links (issue #57, P6).
|
|
82
|
+
*
|
|
83
|
+
* @param cam - the screen camera
|
|
84
|
+
* @param width - canvas width in CSS px
|
|
85
|
+
* @param height - canvas height in CSS px
|
|
86
|
+
* @returns the visible world bbox
|
|
87
|
+
*/
|
|
88
|
+
export declare function viewportWorldBbox(cam: ScreenCamera, width: number, height: number): Bbox;
|
|
89
|
+
/**
|
|
90
|
+
* Whether two axis-aligned bounding boxes overlap (inclusive edges). Off-screen
|
|
91
|
+
* shapes whose bbox misses the viewport bbox are culled.
|
|
92
|
+
*
|
|
93
|
+
* @param a - first bbox
|
|
94
|
+
* @param b - second bbox
|
|
95
|
+
* @returns `true` when the boxes touch or overlap
|
|
96
|
+
*/
|
|
97
|
+
export declare function bboxOverlaps(a: Bbox, b: Bbox): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* The world-space AABB over a set of points. For a link this is taken over
|
|
100
|
+
* **all** anchors (endpoints + waypoints), so a trunk whose two ends sit
|
|
101
|
+
* off-screen but whose segment crosses the viewport is not wrongly culled
|
|
102
|
+
* (issue #57, 1e).
|
|
103
|
+
*
|
|
104
|
+
* @param pts - the points to bound (world coords)
|
|
105
|
+
* @returns the AABB, or `null` when the list is empty
|
|
106
|
+
*/
|
|
107
|
+
export declare function pointsBbox(pts: readonly {
|
|
108
|
+
x: number;
|
|
109
|
+
y: number;
|
|
110
|
+
}[]): Bbox | null;
|
|
111
|
+
/**
|
|
112
|
+
* Apply a multiplicative zoom about a screen-space focal point, keeping that
|
|
113
|
+
* point fixed on screen (cursor-anchored wheel zoom, centre-anchored button
|
|
114
|
+
* zoom). Clamps to `[min, max]`; snapping to `min === 1` returns
|
|
115
|
+
* {@link IDENTITY} so a full zoom-out also recentres.
|
|
116
|
+
*
|
|
117
|
+
* @param prev - the current camera
|
|
118
|
+
* @param factor - multiply `zoom` by this
|
|
119
|
+
* @param px - screen-x to keep fixed
|
|
120
|
+
* @param py - screen-y to keep fixed
|
|
121
|
+
* @param min - minimum zoom
|
|
122
|
+
* @param max - maximum zoom
|
|
123
|
+
* @returns the next camera
|
|
124
|
+
*/
|
|
125
|
+
export declare function zoomAbout(prev: Viewport, factor: number, px: number, py: number, min: number, max: number): Viewport;
|
|
126
|
+
/** The interaction modes the camera can be in at any instant. */
|
|
127
|
+
export type CameraMode = "idle" | "panning" | "wheeling" | "flying";
|
|
128
|
+
/** The inputs that drive {@link nextMode} transitions. */
|
|
129
|
+
export type CameraEvent = "pointerDown" | "wheel" | "zoom" | "flyStart" | "pointerUp" | "flyEnd" | "cancel";
|
|
130
|
+
/**
|
|
131
|
+
* The camera interaction-mode transition. Entering an input mode
|
|
132
|
+
* (`pointerDown` / `wheel` / `zoom`) supersedes a running fly — see
|
|
133
|
+
* {@link cancelsFly} for the companion side-effect predicate — so a user
|
|
134
|
+
* gesture always wins over an animation rather than racing it (issue #57, P4 /
|
|
135
|
+
* Phase 2 invariant 5).
|
|
136
|
+
*
|
|
137
|
+
* @param mode - the current mode
|
|
138
|
+
* @param event - the input event
|
|
139
|
+
* @returns the next mode
|
|
140
|
+
*/
|
|
141
|
+
export declare function nextMode(mode: CameraMode, event: CameraEvent): CameraMode;
|
|
142
|
+
/**
|
|
143
|
+
* Whether processing `event` in `mode` must cancel a running fly animation.
|
|
144
|
+
* Pairs with {@link nextMode}: the reducer names the next mode, this names the
|
|
145
|
+
* side-effect (cancel the in-flight `flyTo` rAF) the transition implies. Every
|
|
146
|
+
* event that moves the machine OUT of `flying` (a user gesture, an explicit
|
|
147
|
+
* `cancel`/`reset`) must cancel the rAF, so the mode and the live `animRef` can
|
|
148
|
+
* never disagree — `flyEnd` is the sole exception (the rAF has already ended).
|
|
149
|
+
*
|
|
150
|
+
* @param mode - the current mode
|
|
151
|
+
* @param event - the input event
|
|
152
|
+
* @returns `true` when a fly animation is in progress and is being superseded
|
|
153
|
+
*/
|
|
154
|
+
export declare function cancelsFly(mode: CameraMode, event: CameraEvent): boolean;
|
|
155
|
+
/** A frame-coalesced render scheduler — see {@link makeRafCoalescer}. */
|
|
156
|
+
export interface RafCoalescer {
|
|
157
|
+
/** Schedule `run` for the next frame; repeat calls before it fires are no-ops. */
|
|
158
|
+
request(run: () => void): void;
|
|
159
|
+
/** Cancel a pending frame (teardown). */
|
|
160
|
+
cancel(): void;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Coalesce many `request` calls within a single frame down to **one** scheduled
|
|
164
|
+
* callback. Pointer-move / wheel handlers mutate the live camera synchronously
|
|
165
|
+
* and call `request` on every event; this guarantees at most one paint +
|
|
166
|
+
* snapshot per frame, keeping the hot pan path off the per-event path (issue
|
|
167
|
+
* #57, Phase 2 invariant 2). Injecting `schedule` / `cancel` (rather than
|
|
168
|
+
* closing over `requestAnimationFrame`) keeps the coalescer unit-testable.
|
|
169
|
+
*
|
|
170
|
+
* @param schedule - schedules a callback for the next frame, returns a handle
|
|
171
|
+
* @param cancel - cancels a scheduled callback by handle
|
|
172
|
+
* @returns a {@link RafCoalescer}
|
|
173
|
+
*/
|
|
174
|
+
export declare function makeRafCoalescer(schedule: (cb: () => void) => number, cancel: (handle: number) => void): RafCoalescer;
|
|
175
|
+
//# sourceMappingURL=camera.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../../../src/collections/schematic/camera.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;GAUG;AAEH,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACd;AAED,sDAAsD;AACtD,eAAO,MAAM,QAAQ,EAAE,QAAoC,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACd;AAED,4DAA4D;AAC5D,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAE3F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOxF;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,OAAO,CAEtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,IAAI,GAAG,IAAI,CAUhF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,CAKpH;AAED,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEpE,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5G;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,UAAU,CAUzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAGxE;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY;IACzB,kFAAkF;IAClF,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC/B,yCAAyC;IACzC,MAAM,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,MAAM,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,YAAY,CAiBrH"}
|
|
@@ -6,6 +6,8 @@ export type SchematicValue = ValueTypeOf<typeof Schematic.Types.Schematic>;
|
|
|
6
6
|
export type SchematicItemValue = ValueTypeOf<typeof Schematic.Types.Item>;
|
|
7
7
|
/** East Schematic zone value type. */
|
|
8
8
|
export type SchematicZoneValue = ValueTypeOf<typeof Schematic.Types.Zone>;
|
|
9
|
+
/** East Schematic shape-geometry value type (`rect` / `circle` / `polyline` / `polygon`). */
|
|
10
|
+
export type SchematicGeometryValue = ValueTypeOf<typeof Schematic.Types.Geometry>;
|
|
9
11
|
export interface EastChakraSchematicProps {
|
|
10
12
|
value: SchematicValue;
|
|
11
13
|
storageKey: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/collections/schematic/index.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/collections/schematic/index.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAetD,iCAAiC;AACjC,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAE3E,sCAAsC;AACtC,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAE1E,sCAAsC;AACtC,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAE1E,6FAA6F;AAC7F,MAAM,MAAM,sBAAsB,GAAG,WAAW,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAElF,MAAM,WAAW,wBAAwB;IACrC,KAAK,EAAE,cAAc,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACtB;AAgKD;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,gEA4zBiE,CAAC"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { ValueTypeOf } from '@elaraai/east';
|
|
2
|
+
import { Schematic } from '@elaraai/east-ui/internal';
|
|
3
|
+
import { ScreenCamera } from './camera';
|
|
4
|
+
type SchematicValue = ValueTypeOf<typeof Schematic.Types.Schematic>;
|
|
5
|
+
type SchematicItemValue = ValueTypeOf<typeof Schematic.Types.Item>;
|
|
6
|
+
type Pt = {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
};
|
|
10
|
+
/** Per-item LOD tier (mirrors the React layer). */
|
|
11
|
+
export type LodTier = "card" | "label" | "dot";
|
|
12
|
+
/** An `[r, g, b]` triple in 0–255. */
|
|
13
|
+
export type RGB = [number, number, number];
|
|
14
|
+
/**
|
|
15
|
+
* Theme-resolved colours the paint layer needs. The React layer resolves these
|
|
16
|
+
* from Chakra semantic tokens (CSS custom properties) once per theme; the paint
|
|
17
|
+
* layer is colour-system-agnostic and just consumes RGB.
|
|
18
|
+
*/
|
|
19
|
+
export interface SchematicPalette {
|
|
20
|
+
/** Brand teal (links, `info` status). */
|
|
21
|
+
brand600: RGB;
|
|
22
|
+
brand500: RGB;
|
|
23
|
+
/** Foreground ink (`ink` tone). */
|
|
24
|
+
fg: RGB;
|
|
25
|
+
fgMuted: RGB;
|
|
26
|
+
fgSubtle: RGB;
|
|
27
|
+
/** Zone `muted` stroke. */
|
|
28
|
+
borderStrong: RGB;
|
|
29
|
+
borderSubtle: RGB;
|
|
30
|
+
/** Card / pin background, and the eyebrow-label halo. */
|
|
31
|
+
bgSurface: RGB;
|
|
32
|
+
bgPanel: RGB;
|
|
33
|
+
/** Status tones. */
|
|
34
|
+
statusOk: RGB;
|
|
35
|
+
statusWarn: RGB;
|
|
36
|
+
statusBad: RGB;
|
|
37
|
+
/** Dot ring. */
|
|
38
|
+
white: RGB;
|
|
39
|
+
}
|
|
40
|
+
/** The pan/zoom transform in CSS pixels: `screen = world × ppu + t`. */
|
|
41
|
+
export interface PaintCamera {
|
|
42
|
+
ppu: number;
|
|
43
|
+
tx: number;
|
|
44
|
+
ty: number;
|
|
45
|
+
}
|
|
46
|
+
/** Everything {@link paintSchematic} needs for one frame. */
|
|
47
|
+
export interface PaintInput {
|
|
48
|
+
ctx: CanvasRenderingContext2D;
|
|
49
|
+
value: SchematicValue;
|
|
50
|
+
cam: PaintCamera;
|
|
51
|
+
/** Canvas size in CSS px (the ctx is pre-scaled by devicePixelRatio). */
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
/** Viewport-culled items (the React layer's `visibleItems`). */
|
|
55
|
+
visibleItems: readonly SchematicItemValue[];
|
|
56
|
+
/** Per-item LOD tier after declutter. */
|
|
57
|
+
tiers: ReadonlyMap<string, LodTier>;
|
|
58
|
+
selected: string | null;
|
|
59
|
+
/** Item key → world centre, for link endpoints. */
|
|
60
|
+
centers: ReadonlyMap<string, Pt>;
|
|
61
|
+
palette: SchematicPalette;
|
|
62
|
+
}
|
|
63
|
+
/** Centre / radius / sweep of a DXF bulge arc, ready for `CanvasRenderingContext2D.arc`. */
|
|
64
|
+
export interface BulgeArc {
|
|
65
|
+
cx: number;
|
|
66
|
+
cy: number;
|
|
67
|
+
radius: number;
|
|
68
|
+
startAngle: number;
|
|
69
|
+
endAngle: number;
|
|
70
|
+
anticlockwise: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Pure geometry of the circular arc a DXF `bulge` encodes for the edge
|
|
74
|
+
* `p1`→`p2` (`bulge = tan(includedAngle / 4)`; sign = turn direction). Returns
|
|
75
|
+
* `null` for a straight or degenerate edge (`|bulge|` ~ 0, or a zero-length
|
|
76
|
+
* chord). Screen space: the caller has already transformed the vertices, and
|
|
77
|
+
* the uniform camera scale preserves the bulge (it is the tangent of an angle).
|
|
78
|
+
* Exported so the arc maths is unit-testable without a Canvas2D context.
|
|
79
|
+
*/
|
|
80
|
+
export declare function arcFromBulge(p1: Pt, p2: Pt, bulge: number): BulgeArc | null;
|
|
81
|
+
/** Font the labelled-pin marker is drawn with; the pick must measure label
|
|
82
|
+
* widths with the SAME font so its hitbox matches the drawn pill. */
|
|
83
|
+
export declare const MARKER_LABEL_FONT = "600 10px ui-monospace, \"SF Mono\", Menlo, monospace";
|
|
84
|
+
/** Drawn radius of a `dot`-tier marker, in screen px. */
|
|
85
|
+
export declare const MARKER_DOT_RADIUS = 5;
|
|
86
|
+
/** Hit radius of a `dot`-tier marker, in screen px — comfortably over the
|
|
87
|
+
* drawn dot (5) and its selected ring (7.5) for touch slop (issue #57, P11). */
|
|
88
|
+
export declare const MARKER_DOT_HIT_RADIUS = 10;
|
|
89
|
+
/** The screen-space hitbox of a non-card LOD marker — a circle for a `dot`, the
|
|
90
|
+
* rounded-pill rect for a `label`. */
|
|
91
|
+
export type MarkerHitbox = {
|
|
92
|
+
kind: "circle";
|
|
93
|
+
cx: number;
|
|
94
|
+
cy: number;
|
|
95
|
+
r: number;
|
|
96
|
+
} | {
|
|
97
|
+
kind: "rect";
|
|
98
|
+
left: number;
|
|
99
|
+
top: number;
|
|
100
|
+
w: number;
|
|
101
|
+
h: number;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* The screen-space hitbox of an item's LOD marker at `tier`. The single source
|
|
105
|
+
* of truth used by **both** {@link paintSchematic} (to draw the pill) and the
|
|
106
|
+
* React layer's pick (to hit-test), so the clickable area always equals the
|
|
107
|
+
* drawn area and the two cannot silently drift (issue #57, P11). A `dot` is a
|
|
108
|
+
* circle of {@link MARKER_DOT_HIT_RADIUS}; a `label` is the rounded pill whose
|
|
109
|
+
* width is `pad + dot + gap + textWidth + pad` — the text measured by `measure`
|
|
110
|
+
* (the caller sets the context font to {@link MARKER_LABEL_FONT} first).
|
|
111
|
+
*
|
|
112
|
+
* @param item - the item's world anchor and label
|
|
113
|
+
* @param tier - the LOD tier (`dot` or `label`; `card` markers are DOM)
|
|
114
|
+
* @param cam - the screen camera
|
|
115
|
+
* @param measure - measures a string's width in px under the pin font
|
|
116
|
+
* @returns the marker's screen-space hitbox
|
|
117
|
+
*/
|
|
118
|
+
export declare function markerHitbox(item: {
|
|
119
|
+
x: number;
|
|
120
|
+
y: number;
|
|
121
|
+
label: string;
|
|
122
|
+
}, tier: "dot" | "label", cam: ScreenCamera, measure: (text: string) => number): MarkerHitbox;
|
|
123
|
+
/**
|
|
124
|
+
* Whether the screen point `(sx, sy)` falls inside `box` (see
|
|
125
|
+
* {@link markerHitbox}).
|
|
126
|
+
*
|
|
127
|
+
* @param box - a marker hitbox
|
|
128
|
+
* @param sx - screen x
|
|
129
|
+
* @param sy - screen y
|
|
130
|
+
* @returns `true` when the point is inside the hitbox
|
|
131
|
+
*/
|
|
132
|
+
export declare function markerHit(box: MarkerHitbox, sx: number, sy: number): boolean;
|
|
133
|
+
/** Clamp a hatch `spacing` to a positive, finite minimum so the line sweep
|
|
134
|
+
* always advances and terminates — a `0` / negative / NaN spacing would
|
|
135
|
+
* otherwise hard-hang or stall the render thread (issue #57, P3). */
|
|
136
|
+
export declare function hatchSpacing(rawSpacing: number): number;
|
|
137
|
+
/**
|
|
138
|
+
* The bounded offset range `[oStart, oEnd)` for the diagonal hatch sweep of a
|
|
139
|
+
* zone whose screen rect is `(x, y, w, h)` on an `width × height` canvas, for a
|
|
140
|
+
* line family of direction `(dx, dy)` spaced `spacing` apart, with `diag` the
|
|
141
|
+
* sweep half-length. The full sweep is `-diag … diag`; this narrows it to the
|
|
142
|
+
* offsets whose line can reach the on-screen portion of the zone, so the step
|
|
143
|
+
* count is O(visible area / spacing) not O(zone area / spacing) (issue #57,
|
|
144
|
+
* 1e). `oStart` is snapped onto the SAME `{ -diag + k·spacing }` phase grid the
|
|
145
|
+
* full sweep uses, so the bounded sweep draws the identical lines — fewer of
|
|
146
|
+
* them, never phase-shifted. A horizontal family (`dy ≈ 0`, so the line normal
|
|
147
|
+
* has no x-component) can't be solved this way and falls back to the full
|
|
148
|
+
* `-diag … diag` range: fully off-screen zones are already culled upstream, so
|
|
149
|
+
* the only cost case is an on-screen zone far taller than the viewport, which
|
|
150
|
+
* then pays the full-height sweep (it still terminates — `spacing ≥ 1`; this
|
|
151
|
+
* degenerate orientation renders as collinear lines and is rarely authored).
|
|
152
|
+
*
|
|
153
|
+
* @returns the inclusive-exclusive offset range to sweep
|
|
154
|
+
*/
|
|
155
|
+
export declare function hatchSweepBounds(x: number, y: number, w: number, h: number, width: number, height: number, dx: number, dy: number, diag: number, spacing: number): {
|
|
156
|
+
oStart: number;
|
|
157
|
+
oEnd: number;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* An upper bound on the number of hatch lines swept across an `w × h` (screen
|
|
161
|
+
* px) region at `rawSpacing`. Finite for any input because {@link hatchSpacing}
|
|
162
|
+
* floors the spacing at 1 (issue #57, P3); the painter further bounds the sweep
|
|
163
|
+
* to the on-screen portion of the zone (1e).
|
|
164
|
+
*
|
|
165
|
+
* @param w - region width in screen px
|
|
166
|
+
* @param h - region height in screen px
|
|
167
|
+
* @param rawSpacing - the raw (possibly zero/negative) spacing
|
|
168
|
+
* @returns a finite line-count upper bound
|
|
169
|
+
*/
|
|
170
|
+
export declare function hatchLineCount(w: number, h: number, rawSpacing: number): number;
|
|
171
|
+
/** Draw the schematic's bulk-shape layer for one frame. Clears first. */
|
|
172
|
+
export declare function paintSchematic(input: PaintInput): void;
|
|
173
|
+
export {};
|
|
174
|
+
//# sourceMappingURL=paint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint.d.ts","sourceRoot":"","sources":["../../../src/collections/schematic/paint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SchematicPalette } from './paint';
|
|
2
|
+
/**
|
|
3
|
+
* Renders a visually-hidden set of themed probes and reports the resolved
|
|
4
|
+
* {@link SchematicPalette} to `onResolve` on mount and on every theme change.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SchematicPaletteProbe: import('react').NamedExoticComponent<{
|
|
7
|
+
onResolve: (palette: SchematicPalette) => void;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/collections/schematic/theme.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,OAAO,EAAE,KAAK,gBAAgB,EAAY,MAAM,SAAS,CAAC;AA2B1D;;;GAGG;AACH,eAAO,MAAM,qBAAqB;eACF,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI;EAyBjE,CAAC"}
|