/** * Clip box controller (spec: issue #34 §"Cutting / Clipping" — visible, * draggable box). `clip-box.ts` owns the pure shader/patch math; this file * owns the DOM-touching half: a wireframe box + 6 face-handle gizmos so the * box is something you can SEE and GRAB, not just type numbers into. Same * architecture as `measure-controller.ts`'s volume-mode height gizmo (real * `` elements driven by `core.patchAnimatedProps` on the per-frame * channel) — generalized from that gizmo's one hardcoded vertical axis to 6 * axis-constrained handles (one per box face), since a face can move along * lng, lat, OR elevation depending on which one it is. * * Owned per `` (the draw/measure precedent) and kept alive for as * long as a clip box is configured, independent of whether the `clip-box` * widget is even mounted — set clip-box-min/max programmatically and the * wireframe still shows up, the same way the box itself still clips content * with no widget present. */ import type { PickingInfo } from "@deck.gl/core"; import type { RuntimeCore, GizmoDragEvent } from "./runtime-core"; export declare class ClipBoxController { private readonly mapEl; private readonly core; private grab; /** * Whether the visual box + drag handles are showing. OFF by default and * OFF whenever a drag/hover isn't in progress — the box's CLIPPING effect * is entirely independent of this (that's driven straight off the * clip-box-min/max attributes, always active once set). This is purely * about the interactive gizmo: reported that its handles — always * pickable once rendered, several of them sitting right around screen * center where a normal pan gesture naturally starts — were hijacking * ordinary map panning. Gating them behind an explicit "Edit box" toggle * (see the clip-box-edit action) means panning is never at risk, and the * gizmo only exists on screen when someone actually asked to adjust it. */ private editing; constructor(mapEl: Element, core: RuntimeCore); setEditing(active: boolean): void; isEditing(): boolean; /** Re-reads the current box from `core` and repaints the wireframe + handles — call after ANY change, drag or attribute. */ syncVisuals(): void; /** * Repaints the wireframe + handles for a GIVEN box — factored out of * `syncVisuals()` so `handleGizmoDrag` can drive this every mousemove * frame from its own LOCAL `grab.liveBox` without going anywhere near * `core.setClipBox`/DOM attributes (see that method's own doc comment). * `patchAnimatedProps` is cheap and frame-rate-safe (patches within one JS turn coalesce into a single scene rebuild); this is the * same reason `measure-controller.ts`'s volume gizmo redraws through * `patchAnimatedProps` on every drag frame instead of writing anything * to the DOM until the gesture actually ends. */ private renderBox; /** * Grab a face handle. Computes a LOCAL screen-space drag basis for this * handle's axis by projecting a known small step (`AXIS_EPSILON`) along * it — the same linearization trick `measure-controller.ts`'s height * gizmo uses for its one hardcoded vertical axis, generalized to a full * 2D screen vector so it's correct for lng/lat faces too (which project * to some diagonal screen direction depending on the camera's bearing/ * pitch, not a pure vertical like elevation). */ handleGizmoDragStart(info: PickingInfo, event: GizmoDragEvent): void; /** * Every mousemove during a drag updates ONLY `grab.liveBox` and repaints * the gizmo via `renderBox` (the cheap `patchAnimatedProps` channel) — * it does NOT write clip-box-min/max attributes or call * `core.setClipBox` per frame. Those go through `RuntimeCore.applyLayers`, * which rebuilds the ENTIRE layer list (every layer, not just this box) — * fine for an occasional attribute change, but firing it on every one of * a mousemove's ~60 frames/sec froze the whole map (reported: "dragging * the gizmos ... the whole map just hangs"). The real content stays * clipped to the box's PRE-drag position for the gesture's duration and * catches up in ONE `applyLayers` pass at `handleGizmoDragEnd` — the same * "cheap live preview, expensive commit once at the end" split the proven * volume-measurement gizmo already uses (it never touches the DOM mid- * drag either). */ handleGizmoDrag(info: PickingInfo): void; /** * The ONE expensive commit for the whole gesture: write the final * min/max to the authored attributes — same channel the widget's own * number inputs use, so the drag is undoable (history.ts's 500ms * coalesce window merges it with any other same-attribute writes into a * single step) and reflects live in the widget. The map's own * MutationObserver picks this up and calls core.setClipBox, which * re-applies the ACTUAL clip to real layers and (via that same observer * hook) resyncs this controller's own gizmo from the now-authoritative * state. */ handleGizmoDragEnd(): void; private ensureLayers; } export declare function getClipBoxController(mapEl: Element, core: RuntimeCore): ClipBoxController; export declare function peekClipBoxController(mapEl: Element): ClipBoxController | undefined;