import type { Client, View } from "@perspective-dev/client"; import type { FacetConfig, PluginConfig } from "../charts/chart"; import type { InteractionEvent } from "./protocol"; /** * Unified host-side driver for the chart renderer. Owns one of two * handle shapes: * * - **Worker mode**: a real `Worker` running the same module. The * handle posts `ControlMsg`s over `Worker.postMessage`. * - **In-process mode**: a `MessageChannel` whose `port2` is owned * by an in-thread `WorkerRenderer` instantiated via * `await import(workerURL)`. Same module bytes, different host. * * Both modes go through the same control channel, the same * `ProxySession` proxy port, and the same `OffscreenCanvas` transfer * — `MessageChannel` and `transferControlToOffscreen` work in-realm * just as well as cross-thread. The only branching is at construction * (handle creation) and bootstrap (worker scope sets up its own * `Client`; in-process reuses the host's). */ export declare class RendererTransport { private _handle; private _proxyChannel; private _proxySession; private _client; private _view; private _tableName; private _clientWorkerURL; private _clientWasm; private _chartTag; private _maxCells; private _precompileShaders; private _ready; private _resolveReady; private _rejectReady; /** * Pending request/reply promises across all worker round-trips — * `saveZoom`, `uploadChunk` ACKs, and `snapshotPng`. Each entry * carries its `kind` so `destroy()` can apply per-kind teardown * semantics (uploadChunk resolves silently, the rest reject with * a teardown error). * * Keyed by a single monotonic counter; the worker's reply messages * carry that id back verbatim. One counter for all kinds is safe * because the host's switch already keys on `msg.kind` before * resolving. */ private _pending; private _pendingCounter; private _onZoomChanged; /** * Cached zoom-default flag pushed by the renderer after each zoom * mutation. Surfaced sync via `allZoomsDefault()`; updates between * calls are best-effort. */ private _allZoomsDefault; private _hostGlCanvas; /** * Blit-mode only: the visible `.webgl-canvas`'s 2D context. The * worker emits each completed GL frame as a `FrameBitmapMsg`; on * receipt we `drawImage` the bitmap into this context and `close()` * it to release the GPU surface. Null in direct mode (the visible * canvas's drawing buffer is the worker's transferred GL canvas). */ private _displayCtx; /** * Host-side sink for tooltip + cursor side-effects. The chart * inside the renderer calls into a `MessageHostSink` that posts * `pinTooltip` / `dismissTooltip` / `setCursor` over the control * channel; this sink applies them to the DOM. Initialized lazily * on first signal so we don't pay for the parent-style lookup * unless a user interacts. */ private _hostSink; /** * Last `insertConfig` accepted by a `userSelect { selected: true }` * message. Used to populate `removeConfigs` on the next * `selected: false` (unpin / drill-up / view-change) — mirrors * datagrid's `model._last_insert_configs` so coordinated-filter * consumers can roll back the previous select when a new one * supplants it. */ private _lastInsertConfig; constructor(opts: { client: Client; view: View; tableName?: string; clientWasm: WebAssembly.Module; clientWorkerURL: URL; chartTag: string; maxCells: number; precompileShaders?: boolean; onZoomChanged?: (isDefault: boolean) => void; }); init(opts: { gl: HTMLCanvasElement; gridlines: HTMLCanvasElement; chrome: HTMLCanvasElement; facetConfig: FacetConfig; pluginConfig: PluginConfig; defaultChartType?: string; renderBlitMode: "blit" | "direct"; }): Promise; /** * Construct the underlying transport. Worker mode wraps the * module-shared `Worker` (lazy, page-singleton) and tags every * message with a unique `sessionId`. In-process mode pairs a * `MessageChannel` with a dynamically-imported * {@link bootstrapInProcess}. */ private _createHandle; setView(view: View): void; setColumnsConfig(cfg: Record): void; setPluginConfig(cfg: PluginConfig): void; setBufferMaxCapacity(n: number): void; /** * Trigger a worker-side data fetch + render cycle. The worker * resolves all schema / row-count metadata against its own `View` * and `Table`, runs `view.with_typed_arrays`, and pipes the * resulting `ColumnDataMap` directly into `chartImpl.uploadAndRender` * — no host-side `Client`/`Table`/`View` await, no `postMessage` of * column buffers. * * The returned promise resolves when the worker replies with * `loadAndRenderAck`. Per the worker's "resolve on stale" * contract, a mid-flight cancellation (a newer `loadAndRender` * superseding this one) still acks — the host's awaiter just * resolves quietly. */ loadAndRender(opts: { viewerConfig: { group_by: string[]; split_by: string[]; columns: (string | null)[]; }; options?: { float32?: boolean; }; }): Promise; redraw(): void; resize(): void; clear(): void; invalidateTheme(): void; saveZoom(): Promise; /** * Allocate a pending request slot of the given `kind`. Returns the * id (encoded into the outgoing `ControlMsg`) and a promise that * resolves / rejects when the matching reply arrives or * `destroy()` drains the table. */ private _allocPending; restoreZoom(state: any): void; allZoomsDefault(): boolean; resetAllZooms(): void; resetExpandedDomain(): void; /** * Request a PNG snapshot of the current frame. The worker flushes a * synchronous render across the GL + gridlines + chrome layers, * composites them into a single `OffscreenCanvas`, fills the theme * background, and replies with the `convertToBlob` result. */ snapshotPng(): Promise; forwardInteraction(event: InteractionEvent): void; destroy(): void; private _post; private _postRaw; private _handleRendererMsg; /** * Look up a pending request by id, verify the recorded kind * matches the inbound reply, resolve, and remove. Mismatches are * silently dropped — they would only fire if the worker echoed * the wrong kind for a given id, which would itself be a bug * worth catching at the worker side. */ private _resolvePending; /** * Blit-mode handler: draw a renderer-emitted frame into the * visible 2D-context display canvas, then close the bitmap so its * GPU-backed surface is released. Resizes the visible canvas's * drawing buffer to the bitmap dimensions on first frame and * after any worker-side resize — the host doesn't directly * control GL canvas size in blit mode, so we follow whatever the * renderer emits. */ private _drawFrameBitmap; /** * Dispatch a `CustomEvent` on the `` ancestor * of this transport's GL canvas. Walks the parent chain so the * event bubbles from the viewer (matching where datagrid * dispatches its `perspective-click` / `perspective-global-filter` * events). No-op when the canvas is detached or no viewer ancestor * exists (test harnesses, snapshot mode). */ private _dispatchOnViewer; /** * Lazily construct a `DomHostSink` rooted at the host GL canvas * (cursor mutations) and its parent (pinned-tooltip `
`). * Returns `null` if the canvas has been detached. */ private _ensureHostSink; }