@perspective-dev/viewer-charts 4.5.0 → 4.5.2
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/LICENSE.md +193 -0
- package/dist/cdn/perspective-viewer-charts.js +2 -2
- package/dist/cdn/perspective-viewer-charts.js.map +3 -3
- package/dist/esm/axis/bar-axis.d.ts +9 -1
- package/dist/esm/axis/categorical-axis.d.ts +0 -2
- package/dist/esm/charts/cartesian/cartesian.d.ts +26 -0
- package/dist/esm/charts/common/category-axis-resolver.d.ts +43 -1
- package/dist/esm/charts/common/expand-domain.d.ts +20 -0
- package/dist/esm/charts/common/tree-chart.d.ts +7 -0
- package/dist/esm/charts/common/tree-chrome.d.ts +23 -1
- package/dist/esm/charts/common/tree-interact.d.ts +46 -0
- package/dist/esm/charts/series/glyphs/draw-lines.d.ts +11 -4
- package/dist/esm/charts/series/series-build.d.ts +38 -2
- package/dist/esm/charts/series/series-render.d.ts +1 -4
- package/dist/esm/charts/series/series-type.d.ts +19 -17
- package/dist/esm/charts/series/series.d.ts +16 -0
- package/dist/esm/charts/sunburst/sunburst-interact.d.ts +1 -1
- package/dist/esm/charts/treemap/treemap-interact.d.ts +1 -6
- package/dist/esm/config.d.ts +19 -0
- package/dist/esm/interaction/host-sink-message.d.ts +10 -28
- package/dist/esm/interaction/raw-event-forwarder.d.ts +6 -7
- package/dist/esm/interaction/zoom-controller.d.ts +31 -20
- package/dist/esm/interaction/zoom-router.d.ts +3 -26
- package/dist/esm/perspective-viewer-charts.js +2 -2
- package/dist/esm/perspective-viewer-charts.js.map +3 -3
- package/dist/esm/plugin/plugin.d.ts +15 -3
- package/dist/esm/render/scheduler.d.ts +23 -0
- package/dist/esm/theme/palette.d.ts +0 -5
- package/dist/esm/transport/protocol.d.ts +2 -7
- package/dist/esm/webgl/context-manager.d.ts +100 -117
- package/dist/esm/webgl/context-pool.d.ts +40 -0
- package/dist/esm/webgl/gl-context.d.ts +54 -0
- package/dist/esm/worker/renderer.worker.d.ts +2 -4
- package/package.json +45 -45
- package/src/ts/axis/bar-axis.ts +74 -45
- package/src/ts/axis/categorical-axis.ts +0 -2
- package/src/ts/charts/candlestick/candlestick-render.ts +10 -7
- package/src/ts/charts/candlestick/candlestick.ts +10 -29
- package/src/ts/charts/candlestick/glyphs/draw-candlesticks.ts +36 -2
- package/src/ts/charts/candlestick/glyphs/draw-ohlc.ts +36 -2
- package/src/ts/charts/cartesian/cartesian-build.ts +143 -9
- package/src/ts/charts/cartesian/cartesian-render.ts +205 -30
- package/src/ts/charts/cartesian/cartesian.ts +43 -4
- package/src/ts/charts/cartesian/glyphs/density.ts +36 -41
- package/src/ts/charts/cartesian/glyphs/lines.ts +13 -15
- package/src/ts/charts/cartesian/glyphs/points.ts +12 -17
- package/src/ts/charts/chart-base.ts +20 -6
- package/src/ts/charts/chart.ts +1 -1
- package/src/ts/charts/common/category-axis-resolver.ts +135 -1
- package/src/ts/charts/common/expand-domain.ts +40 -0
- package/src/ts/charts/common/tree-chart.ts +16 -0
- package/src/ts/charts/common/tree-chrome.ts +86 -1
- package/src/ts/charts/common/tree-interact.ts +209 -0
- package/src/ts/charts/heatmap/heatmap-render.ts +9 -11
- package/src/ts/charts/series/glyphs/draw-areas.ts +30 -1
- package/src/ts/charts/series/glyphs/draw-lines.ts +151 -76
- package/src/ts/charts/series/series-build.ts +394 -21
- package/src/ts/charts/series/series-render.ts +159 -38
- package/src/ts/charts/series/series-type.ts +37 -17
- package/src/ts/charts/series/series.ts +63 -68
- package/src/ts/charts/sunburst/sunburst-interact.ts +18 -162
- package/src/ts/charts/sunburst/sunburst-render.ts +24 -89
- package/src/ts/charts/sunburst/sunburst.ts +1 -15
- package/src/ts/charts/treemap/treemap-interact.ts +22 -189
- package/src/ts/charts/treemap/treemap-render.ts +19 -46
- package/src/ts/charts/treemap/treemap.ts +1 -16
- package/src/ts/config.ts +21 -1
- package/src/ts/interaction/host-sink-message.ts +33 -22
- package/src/ts/interaction/raw-event-forwarder.ts +10 -12
- package/src/ts/interaction/zoom-controller.ts +120 -83
- package/src/ts/interaction/zoom-router.ts +3 -126
- package/src/ts/map/tile-layer.ts +13 -13
- package/src/ts/plugin/plugin.ts +176 -196
- package/src/ts/render/scheduler.ts +125 -42
- package/src/ts/shaders/line-uniform.frag.glsl +2 -1
- package/src/ts/shaders/line-uniform.vert.glsl +19 -0
- package/src/ts/theme/palette.ts +1 -4
- package/src/ts/transport/protocol.ts +3 -8
- package/src/ts/webgl/context-manager.ts +195 -189
- package/src/ts/webgl/context-pool.ts +78 -0
- package/src/ts/webgl/gl-context.ts +191 -0
- package/src/ts/worker/dispatch.ts +0 -1
- package/src/ts/worker/renderer.worker.ts +72 -65
- package/src/ts/worker/session-host.ts +29 -0
|
@@ -11,7 +11,6 @@ export declare class HTMLPerspectiveViewerWebGLPluginElement extends HTMLElement
|
|
|
11
11
|
private _rendererPromise;
|
|
12
12
|
private _rawEventForwarder;
|
|
13
13
|
private _generation;
|
|
14
|
-
private _renderBlitMode;
|
|
15
14
|
private _resetClickAbort;
|
|
16
15
|
/**
|
|
17
16
|
* Plugin-scoped global config. Seeded lazily from
|
|
@@ -64,7 +63,21 @@ export declare class HTMLPerspectiveViewerWebGLPluginElement extends HTMLElement
|
|
|
64
63
|
*/
|
|
65
64
|
private _setupInteraction;
|
|
66
65
|
private _buildRenderer;
|
|
67
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Select the GL presentation strategy for *all* chart-type plugins
|
|
68
|
+
* in this renderer. Static + process-global: the value is shared by
|
|
69
|
+
* every per-chart-type subclass, so it must be set once before the
|
|
70
|
+
* charts that should use it build their renderers (a renderer reads
|
|
71
|
+
* {@link BLIT_MODE} at construction in `_buildRenderer`; charts
|
|
72
|
+
* already built keep their mode until torn down and rebuilt).
|
|
73
|
+
*
|
|
74
|
+
* - `"direct"` — each chart owns a GL context 1:1 with its visible
|
|
75
|
+
* canvas (lowest latency; bounded by the browser's ~16-context
|
|
76
|
+
* cap).
|
|
77
|
+
* - `"blit"` — charts render off-screen and share a pool of GL
|
|
78
|
+
* contexts ([webgl/context-pool.ts]), so a page can exceed the cap.
|
|
79
|
+
*/
|
|
80
|
+
static setBlitMode(mode: "direct" | "blit"): void;
|
|
68
81
|
get_static_config(): PluginStaticConfig;
|
|
69
82
|
column_config_schema(column_type: string, _group: string | undefined, _column_name: string, current_value: Record<string, unknown> | null, _viewer_config?: {
|
|
70
83
|
group_by?: string[];
|
|
@@ -88,7 +101,6 @@ export declare class HTMLPerspectiveViewerWebGLPluginElement extends HTMLElement
|
|
|
88
101
|
clear(): Promise<void>;
|
|
89
102
|
resize(): Promise<void>;
|
|
90
103
|
restyle(): number;
|
|
91
|
-
save(): any;
|
|
92
104
|
render(view: View): Promise<Blob>;
|
|
93
105
|
restore(config: any, columns_config?: Record<string, any>): void;
|
|
94
106
|
delete(): void;
|
|
@@ -34,6 +34,29 @@ export declare function requestRender(glManager: WebGLContextManager, fullRender
|
|
|
34
34
|
* picks it up for the next RAF.
|
|
35
35
|
*/
|
|
36
36
|
export declare function deferIfDraining(glManager: WebGLContextManager, op: () => void): void;
|
|
37
|
+
/**
|
|
38
|
+
* Drop every scheduler reference to `glManager` — called from
|
|
39
|
+
* `WebGLContextManager`'s owning renderer at teardown, *before*
|
|
40
|
+
* `glManager.destroy()` loses the GL context.
|
|
41
|
+
*
|
|
42
|
+
* Without this, a frame queued for the next RAF (an `Entry` in
|
|
43
|
+
* `pending`) or a `deferIfDraining` op still parked in `deferred`
|
|
44
|
+
* would survive the destroy and, on the next `drain()`, drive
|
|
45
|
+
* `fullRender` / `present` against a context-lost manager. In blit
|
|
46
|
+
* mode that surfaces as `endFrame`'s `transferToImageBitmap` throwing
|
|
47
|
+
* "Cannot transfer to ImageBitmap because WebGL context is lost" —
|
|
48
|
+
* logged as "scheduler: present failed". In direct mode it's a wasted
|
|
49
|
+
* paint against a dead context.
|
|
50
|
+
*
|
|
51
|
+
* Outstanding waiters for a destroyed manager are resolved (not
|
|
52
|
+
* rejected): the caller asked to tear the chart down, so its awaited
|
|
53
|
+
* `draw()` should observe a clean no-op rather than an error it would
|
|
54
|
+
* have to suppress. An in-flight `present()` (manager in `inFlight`)
|
|
55
|
+
* is left to unwind on its own — its `finally` clause will not find a
|
|
56
|
+
* `deferred` entry to flush, and the manager is already gone from
|
|
57
|
+
* `pending`, so it cannot re-enqueue.
|
|
58
|
+
*/
|
|
59
|
+
export declare function unregister(glManager: WebGLContextManager): void;
|
|
37
60
|
/**
|
|
38
61
|
* Test-only: clear pending state. Production callers must not use
|
|
39
62
|
* this — outstanding waiters are silently dropped.
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { type GradientStop } from "./gradient";
|
|
2
2
|
export type Vec3 = [number, number, number];
|
|
3
|
-
/**
|
|
4
|
-
* Build a series palette of length `count` by sampling the theme gradient
|
|
5
|
-
* at evenly-spaced offsets. For count == 1 returns the 50% stop.
|
|
6
|
-
*/
|
|
7
|
-
export declare function interpolatePalette(stops: GradientStop[], count: number): Vec3[];
|
|
8
3
|
/**
|
|
9
4
|
* Resolve a series palette: use the discrete `--psp-charts--series-N--color`
|
|
10
5
|
* palette when available, otherwise fall back to evenly-spaced samples of
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { FacetConfig, PluginConfig } from "../charts/chart";
|
|
2
2
|
import type { PerspectiveClickDetail } from "../event-detail";
|
|
3
|
+
import type { ThemeSnapshot } from "../theme/theme";
|
|
3
4
|
import type { ViewConfig } from "@perspective-dev/client";
|
|
5
|
+
export type { ThemeSnapshot };
|
|
4
6
|
/**
|
|
5
7
|
* Worker-mode control-channel messages. Distinct from the perspective
|
|
6
8
|
* `ProxySession` channel that the worker's `Client` uses to talk to the
|
|
@@ -160,13 +162,6 @@ export interface FontFaceDescriptor {
|
|
|
160
162
|
featureSettings?: string;
|
|
161
163
|
display?: string;
|
|
162
164
|
}
|
|
163
|
-
/**
|
|
164
|
-
* Theme values resolved on the host via `getComputedStyle` and shipped
|
|
165
|
-
* to the renderer scope, which has no DOM. Decoded by the chart via
|
|
166
|
-
* `theme/theme.ts::resolveThemeFromVars`. Plain map for
|
|
167
|
-
* structured-clone.
|
|
168
|
-
*/
|
|
169
|
-
export type ThemeSnapshot = Record<string, string>;
|
|
170
165
|
export interface SetViewByNameMsg {
|
|
171
166
|
kind: "setViewByName";
|
|
172
167
|
name: string;
|
|
@@ -1,62 +1,78 @@
|
|
|
1
1
|
import { ShaderRegistry } from "./shader-registry";
|
|
2
2
|
import { BufferPool } from "./buffer-pool";
|
|
3
|
-
|
|
3
|
+
import { GLContext, type WebGLCanvas } from "./gl-context";
|
|
4
|
+
export type { WebGLCanvas } from "./gl-context";
|
|
4
5
|
export interface WebGLContextManagerOptions {
|
|
5
6
|
/**
|
|
6
7
|
* If `true`, compile + link every shader in `SHADER_MANIFEST`
|
|
7
|
-
* during construction (and again after a context-loss/
|
|
8
|
-
* cycle). Trades ~30-100ms of init time for elimination of
|
|
9
|
-
* compile/link cost on the first-frame path
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* during context construction (and again after a context-loss/
|
|
9
|
+
* restore cycle). Trades ~30-100ms of init time for elimination of
|
|
10
|
+
* the compile/link cost on the first-frame path. Ignored when the
|
|
11
|
+
* manager is constructed against an already-built shared
|
|
12
|
+
* {@link GLContext} — that context owns the precompile decision.
|
|
13
|
+
* Default `false` keeps lazy-compile behavior.
|
|
13
14
|
*/
|
|
14
15
|
precompile?: boolean;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Per-chart render handle. Owns the chart's GPU **buffers** and frame
|
|
19
|
+
* bookkeeping, but only *borrows* its GL **context** — either a private
|
|
20
|
+
* one it constructs (the default 1:1 mode, where the manager is handed a
|
|
21
|
+
* raw canvas) or a shared {@link GLContext} from the
|
|
22
|
+
* [ContextPool](./context-pool.ts) (pooled blit mode, where many
|
|
23
|
+
* managers share K contexts to stay under the browser's per-agent
|
|
24
|
+
* context cap).
|
|
25
|
+
*
|
|
26
|
+
* Buffers are always per-manager: {@link BufferPool} keys buffers by
|
|
27
|
+
* name, so two charts sharing one pool would stomp each other's `"x"` /
|
|
28
|
+
* `"y"` / `"color"`. Shaders, the GL context, and the canvas drawing
|
|
29
|
+
* buffer are shared per {@link GLContext}; the scheduler serializes
|
|
30
|
+
* renders of managers that share a context so the shared drawing buffer
|
|
31
|
+
* only ever holds one chart's frame at a time (see {@link beginFrame}).
|
|
32
|
+
*/
|
|
16
33
|
export declare class WebGLContextManager {
|
|
17
|
-
private
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
private _shaders;
|
|
34
|
+
private _ctx;
|
|
35
|
+
private _ownsCtx;
|
|
36
|
+
private _disposeRestore;
|
|
21
37
|
private _buffers;
|
|
22
38
|
private _uploadedCount;
|
|
23
39
|
private _cssWidth;
|
|
24
40
|
private _cssHeight;
|
|
25
41
|
private _dpr;
|
|
26
|
-
private
|
|
42
|
+
private _destroyed;
|
|
27
43
|
private _frameCallback;
|
|
28
44
|
/**
|
|
29
45
|
* Per-instance `MessageChannel` used by `_yieldToTask` to resume a
|
|
30
|
-
* polling `awaitGpuFence` loop on the next task. Allocated lazily
|
|
31
|
-
* the polling path is rarely hit when the GPU is idle, and many
|
|
32
|
-
* `WebGLContextManager` instances never need one.
|
|
33
|
-
*
|
|
46
|
+
* polling `awaitGpuFence` loop on the next task. Allocated lazily.
|
|
34
47
|
* Must be per-instance: a module-level singleton races when two
|
|
35
|
-
* managers poll concurrently
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* scheduler's `present` → `uploadAndRender` → the worker's
|
|
40
|
-
* `uploadChunkAck` → the host's `with_typed_arrays` callback,
|
|
41
|
-
* stalling `draw()` indefinitely. (Now that fence waits across
|
|
42
|
-
* different `WebGLContextManager`s run in parallel inside one
|
|
43
|
-
* scheduler drain, the per-instance discipline matters even
|
|
44
|
-
* more — concurrent poll loops are the common case, not the
|
|
45
|
-
* exception.)
|
|
46
|
-
*
|
|
47
|
-
* Cost of per-instance allocation: one extra `MessageChannel` (two
|
|
48
|
-
* `MessagePort`s, ~negligible bytes, zero idle CPU) per chart on
|
|
49
|
-
* top of the per-chart proxy channel that the transport already
|
|
50
|
-
* holds. Bounded by chart count; safe even for pathological pages
|
|
51
|
-
* with hundreds of charts. The alternative — allocating a fresh
|
|
52
|
-
* channel on every `_yieldToTask` call — would churn ports on every
|
|
53
|
-
* fence poll (potentially many per frame on slow GPUs), which is
|
|
54
|
-
* far worse for the structured-clone subsystem than holding one
|
|
55
|
-
* port pair for the manager's lifetime.
|
|
48
|
+
* managers poll concurrently (the second `onmessage` assignment
|
|
49
|
+
* clobbers the first's resolver, hanging that fence wait). Now that
|
|
50
|
+
* fence waits across managers run in parallel within one scheduler
|
|
51
|
+
* drain, concurrent poll loops are the common case.
|
|
56
52
|
*/
|
|
57
53
|
private _yieldChannel;
|
|
58
|
-
|
|
54
|
+
private _pendingYieldResolve;
|
|
55
|
+
/**
|
|
56
|
+
* @param source A raw canvas (manager constructs and **owns** a
|
|
57
|
+
* private {@link GLContext}) or an existing shared `GLContext`
|
|
58
|
+
* (manager borrows it; the pool owns its lifecycle).
|
|
59
|
+
*/
|
|
60
|
+
constructor(source: WebGLCanvas | GLContext, options?: WebGLContextManagerOptions);
|
|
59
61
|
get gl(): WebGL2RenderingContext | WebGLRenderingContext;
|
|
62
|
+
/**
|
|
63
|
+
* Identifies the shared GL context behind this manager. The
|
|
64
|
+
* scheduler groups pending renders by this id: managers on the same
|
|
65
|
+
* backend serialize (they share one drawing buffer); managers on
|
|
66
|
+
* different backends render in parallel. In the default 1:1 mode
|
|
67
|
+
* every manager has its own backend, so every render is independent
|
|
68
|
+
* — identical to the pre-pooling behavior.
|
|
69
|
+
*/
|
|
70
|
+
get backendId(): number;
|
|
71
|
+
/**
|
|
72
|
+
* True once this manager's context has been lost — its own
|
|
73
|
+
* {@link destroy}, or a browser eviction of the shared context.
|
|
74
|
+
*/
|
|
75
|
+
isContextLost(): boolean;
|
|
60
76
|
get isWebGL2(): boolean;
|
|
61
77
|
get shaders(): ShaderRegistry;
|
|
62
78
|
get bufferPool(): BufferPool;
|
|
@@ -64,11 +80,10 @@ export declare class WebGLContextManager {
|
|
|
64
80
|
set uploadedCount(count: number);
|
|
65
81
|
/**
|
|
66
82
|
* Resize the GL canvas's bitmap to match the host's CSS layout. The
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* `OffscreenCanvas` (in-process via transfer, or in a worker).
|
|
83
|
+
* host measures the DOM element and DPR — the manager never touches
|
|
84
|
+
* DOM, so the same path works for an `HTMLCanvasElement`
|
|
85
|
+
* (in-process), a transferred `OffscreenCanvas` (direct/worker), or
|
|
86
|
+
* a pool-shared `OffscreenCanvas` (pooled blit).
|
|
72
87
|
*/
|
|
73
88
|
resize(cssWidth: number, cssHeight: number, dpr: number): void;
|
|
74
89
|
/**
|
|
@@ -78,106 +93,74 @@ export declare class WebGLContextManager {
|
|
|
78
93
|
*/
|
|
79
94
|
private _pendingResize;
|
|
80
95
|
/**
|
|
81
|
-
* Record a dimension change to be applied at the start of the
|
|
82
|
-
*
|
|
83
|
-
* `canvas.width = N` assignment (which clears the drawing buffer
|
|
84
|
-
*
|
|
85
|
-
* paired in the same synchronous task as the
|
|
86
|
-
* the new buffer
|
|
96
|
+
* Record a dimension change to be applied at the start of the next
|
|
97
|
+
* render's Phase 1, before `_fullRender` runs. The actual
|
|
98
|
+
* `canvas.width = N` assignment (which clears the drawing buffer per
|
|
99
|
+
* the WebGL spec) happens inside {@link applyPendingResize} /
|
|
100
|
+
* {@link beginFrame}, paired in the same synchronous task as the
|
|
101
|
+
* paint that fills the new buffer — eliminating the one-frame blank
|
|
102
|
+
* the compositor would otherwise show in direct/in-process modes
|
|
103
|
+
* (where the GL canvas IS the visible canvas).
|
|
87
104
|
*
|
|
88
|
-
*
|
|
89
|
-
* {@link resize} method: in direct / in-process modes the
|
|
90
|
-
* GL canvas IS the host's visible canvas, and `canvas.width = N`
|
|
91
|
-
* is immediately observable to the browser's compositor as a
|
|
92
|
-
* cleared buffer. If the resize lands in the message handler
|
|
93
|
-
* (one task) but the matching `_fullRender` lands in the next
|
|
94
|
-
* RAF (a later task), the compositor cycles between them and
|
|
95
|
-
* presents one full frame of empty canvas — visible flicker.
|
|
96
|
-
* Deferring the dimension change to the same RAF as the paint
|
|
97
|
-
* eliminates the inter-frame gap; both happen inside Phase 1's
|
|
98
|
-
* un-yielded loop.
|
|
99
|
-
*
|
|
100
|
-
* Multiple `requestResize` calls before the next render coalesce
|
|
101
|
-
* to last-write-wins — five rapid width changes from a window
|
|
102
|
-
* drag produce one resize+paint, not five.
|
|
105
|
+
* Multiple calls before the next render coalesce to last-write-wins.
|
|
103
106
|
*/
|
|
104
107
|
requestResize(cssWidth: number, cssHeight: number, dpr: number): void;
|
|
105
108
|
/**
|
|
106
109
|
* Apply any pending dimension change recorded by
|
|
107
|
-
* {@link requestResize}.
|
|
108
|
-
* (immediately before each entry's `fullRender`) and by the
|
|
109
|
-
* `snapshotPng` bypass path. Returns `true` when a resize was
|
|
110
|
-
* applied, `false` when there was nothing pending — useful for
|
|
111
|
-
* callers that want to skip a no-op render.
|
|
110
|
+
* {@link requestResize}. Returns `true` when a resize was applied.
|
|
112
111
|
*/
|
|
113
112
|
applyPendingResize(): boolean;
|
|
114
113
|
/**
|
|
115
|
-
*
|
|
114
|
+
* Prepare the shared GL surface for *this* manager's render. Called
|
|
115
|
+
* by the scheduler immediately before `_fullRender` (and by the
|
|
116
|
+
* `snapshotPng` bypass).
|
|
117
|
+
*
|
|
118
|
+
* - **Own context (1:1):** identical to the old Phase-1 step — apply
|
|
119
|
+
* only a *pending* resize. The context isn't shared, so there is
|
|
120
|
+
* no sibling state to reset and no need to touch the canvas when
|
|
121
|
+
* dimensions are unchanged.
|
|
122
|
+
* - **Shared context (pooled):** a co-tenant chart rendered last and
|
|
123
|
+
* left the shared canvas at *its* dimensions with *its* GL state.
|
|
124
|
+
* Force the canvas to this manager's dimensions and reset the
|
|
125
|
+
* global GL state a sibling might have left dirty (bound
|
|
126
|
+
* framebuffer, viewport, scissor/depth enables) so frames can't
|
|
127
|
+
* bleed across charts. Per-frame draw state (blend, clear) is
|
|
128
|
+
* re-established by the chart's `clearAndSetupFrame`.
|
|
116
129
|
*/
|
|
130
|
+
beginFrame(): void;
|
|
117
131
|
get cssWidth(): number;
|
|
118
|
-
/**
|
|
119
|
-
* Last CSS height passed to `resize()`.
|
|
120
|
-
*/
|
|
121
132
|
get cssHeight(): number;
|
|
122
|
-
/**
|
|
123
|
-
* Last device pixel ratio passed to `resize()`.
|
|
124
|
-
*/
|
|
125
133
|
get dpr(): number;
|
|
126
134
|
clear(): void;
|
|
127
135
|
/**
|
|
128
136
|
* Register a per-frame hook invoked at the end of each render. In
|
|
129
|
-
* blit-mode rendering
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* no-op.
|
|
134
|
-
*
|
|
135
|
-
* Pass `null` to detach.
|
|
137
|
+
* blit-mode rendering the worker installs a callback that transfers
|
|
138
|
+
* an `ImageBitmap` from the canvas back to the host. In direct mode
|
|
139
|
+
* the callback is null and `endFrame` is a no-op. Pass `null` to
|
|
140
|
+
* detach.
|
|
136
141
|
*/
|
|
137
142
|
setFrameCallback(cb: ((bitmap: ImageBitmap) => void) | null): void;
|
|
138
143
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* `ImageBitmap` to the host. Otherwise no-op — direct-mode
|
|
144
|
-
* rendering has nothing to ship; the visible canvas already holds
|
|
145
|
-
* the drawing buffer.
|
|
144
|
+
* Ship the current canvas contents as an `ImageBitmap` to the host
|
|
145
|
+
* when a frame callback is registered and the surface is an
|
|
146
|
+
* `OffscreenCanvas`. Otherwise no-op (direct mode paints straight to
|
|
147
|
+
* the visible drawing buffer).
|
|
146
148
|
*/
|
|
147
149
|
endFrame(): void;
|
|
148
150
|
/**
|
|
149
151
|
* Resolve when every GL command submitted up to this call has been
|
|
150
|
-
* executed by the GPU.
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* and polls `clientWaitSync` with a zero timeout, yielding to the
|
|
154
|
-
* task queue between polls. The first poll passes
|
|
155
|
-
* `SYNC_FLUSH_COMMANDS_BIT` so the fence becomes reachable without
|
|
156
|
-
* a separate `gl.flush()`.
|
|
157
|
-
*
|
|
158
|
-
* On WebGL1 there is no fenceSync; we fall back to the blocking
|
|
159
|
-
* `gl.finish()`. This is acceptable in a worker — never call this
|
|
160
|
-
* from the main thread on a heavy frame.
|
|
161
|
-
*
|
|
162
|
-
* Used as a per-frame "GPU is idle" barrier so callers can serialize
|
|
163
|
-
* follow-on work (`endFrame` snapshot, present roundtrip, the next
|
|
164
|
-
* chunk upload) against actual GPU completion instead of the
|
|
165
|
-
* implicit, implementation-defined timing of `transferToImageBitmap`.
|
|
152
|
+
* executed by the GPU. WebGL2 issues a `fenceSync` and polls
|
|
153
|
+
* `clientWaitSync` (yielding to the task queue between polls); WebGL1
|
|
154
|
+
* falls back to a blocking `gl.finish()` (acceptable in a worker).
|
|
166
155
|
*/
|
|
167
156
|
awaitGpuFence(): Promise<void>;
|
|
168
157
|
ensureBufferCapacity(totalRows: number): void;
|
|
169
158
|
/**
|
|
170
|
-
* Yield to the task queue between fence polls.
|
|
171
|
-
*
|
|
172
|
-
* ~4ms
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* `addEventListener(..., { once: true })` is used over
|
|
177
|
-
* `port1.onmessage = ...` so concurrent in-flight resumes (should
|
|
178
|
-
* any path ever introduce them) cannot clobber each other's
|
|
179
|
-
* resolvers — the previous module-level singleton lost a resolver
|
|
180
|
-
* on every overlap and hung one chart's `draw()` indefinitely.
|
|
159
|
+
* Yield to the task queue between fence polls. `setTimeout(0)` is
|
|
160
|
+
* avoided because Chromium clamps nested worker `setTimeout` to
|
|
161
|
+
* ~4ms; a reused per-instance `MessageChannel` resumes in the next
|
|
162
|
+
* task with sub-ms latency. `{ once: true }` over `onmessage = ...`
|
|
163
|
+
* so concurrent resumes can't clobber each other's resolvers.
|
|
181
164
|
*/
|
|
182
165
|
private _yieldToTask;
|
|
183
166
|
destroy(): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { GLContext } from "./gl-context";
|
|
2
|
+
/**
|
|
3
|
+
* Renderer-scope pool of shared {@link GLContext}s for pooled blit mode.
|
|
4
|
+
*
|
|
5
|
+
* The browser caps live WebGL contexts per agent (~16 in Chromium) and
|
|
6
|
+
* force-loses the oldest past that cap. A page with more than ~16 charts
|
|
7
|
+
* therefore can't give each its own context. This pool caps the number
|
|
8
|
+
* of live contexts at `size`, distributing renderers across them
|
|
9
|
+
* round-robin (sticky for a renderer's lifetime — a renderer keeps the
|
|
10
|
+
* same context so its resident GPU buffers and any cached textures/FBOs
|
|
11
|
+
* stay valid frame to frame). N charts render through K = `size`
|
|
12
|
+
* contexts; the scheduler serializes renders that land on the same
|
|
13
|
+
* context.
|
|
14
|
+
*
|
|
15
|
+
* Pooling applies to blit mode only: direct mode renders into the host's
|
|
16
|
+
* transferred visible canvas, which is permanently 1:1 with a context.
|
|
17
|
+
*
|
|
18
|
+
* One pool per renderer scope (the worker, or the main thread in
|
|
19
|
+
* in-process mode). Contexts are created lazily on first `acquire` and
|
|
20
|
+
* live until renderer-scope teardown — like the contexts they replace,
|
|
21
|
+
* they are not refcounted, because a shared context outlives any single
|
|
22
|
+
* borrowing renderer.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ContextPool {
|
|
25
|
+
private _size;
|
|
26
|
+
private _precompile;
|
|
27
|
+
private _contexts;
|
|
28
|
+
private _next;
|
|
29
|
+
constructor(size: number, options?: {
|
|
30
|
+
precompile?: boolean;
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Borrow a context for a new renderer. Fills the pool to `size`
|
|
34
|
+
* before reusing, then round-robins. A dead context (browser
|
|
35
|
+
* eviction) is replaced in place so a borrower never receives a lost
|
|
36
|
+
* context.
|
|
37
|
+
*/
|
|
38
|
+
acquire(): GLContext;
|
|
39
|
+
private _make;
|
|
40
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ShaderRegistry } from "./shader-registry";
|
|
2
|
+
export type WebGLCanvas = HTMLCanvasElement | OffscreenCanvas;
|
|
3
|
+
export declare class GLContext {
|
|
4
|
+
readonly id: number;
|
|
5
|
+
readonly canvas: WebGLCanvas;
|
|
6
|
+
readonly gl: WebGL2RenderingContext | WebGLRenderingContext;
|
|
7
|
+
readonly isWebGL2: boolean;
|
|
8
|
+
shaders: ShaderRegistry;
|
|
9
|
+
private _maxVertexAttribs;
|
|
10
|
+
private _angle;
|
|
11
|
+
private _precompile;
|
|
12
|
+
private _destroyed;
|
|
13
|
+
/**
|
|
14
|
+
* Per-tenant hooks fired after a `webglcontextrestored`. Each
|
|
15
|
+
* {@link WebGLContextManager} on this context registers one that
|
|
16
|
+
* rebuilds its `BufferPool` (the shaders are rebuilt here, once, for
|
|
17
|
+
* all tenants). On an intentional {@link destroy} these are dropped
|
|
18
|
+
* without firing.
|
|
19
|
+
*/
|
|
20
|
+
private _onRestore;
|
|
21
|
+
constructor(canvas: WebGLCanvas, options?: {
|
|
22
|
+
precompile?: boolean;
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Return every vertex-attribute slot to its default state: disabled,
|
|
26
|
+
* with a zero instance divisor. Vertex-array state (enable flags,
|
|
27
|
+
* pointers, divisors) is global to a context's default VAO — there
|
|
28
|
+
* are no per-chart VAOs in this codebase — so when many charts share
|
|
29
|
+
* one pooled context, a slot a prior chart enabled stays enabled for
|
|
30
|
+
* the next chart, now pointing at a buffer the prior chart's
|
|
31
|
+
* teardown deleted. Its next `drawArraysInstanced` then fails GL
|
|
32
|
+
* validation: "no buffer is bound to enabled attribute", silently
|
|
33
|
+
* dropping the draw.
|
|
34
|
+
*
|
|
35
|
+
* Glyphs already (re)enable + bind + set the divisor for every slot
|
|
36
|
+
* they use on each frame, so clearing to the default here is a safe
|
|
37
|
+
* baseline — it only removes the *leftover* enables a sibling chart
|
|
38
|
+
* left behind. Called from {@link WebGLContextManager.beginFrame} in
|
|
39
|
+
* shared (pooled) mode only; the 1:1 default never shares a context
|
|
40
|
+
* and so keeps its original, reset-free path.
|
|
41
|
+
*/
|
|
42
|
+
resetVertexArrayState(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Register a tenant's post-restore rebuild hook. Returns a disposer.
|
|
45
|
+
*/
|
|
46
|
+
onRestore(cb: () => void): () => void;
|
|
47
|
+
/**
|
|
48
|
+
* True once lost — either our own {@link destroy} or a browser
|
|
49
|
+
* eviction of the oldest context past the per-agent cap.
|
|
50
|
+
*/
|
|
51
|
+
isContextLost(): boolean;
|
|
52
|
+
get destroyed(): boolean;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
}
|
|
@@ -81,10 +81,8 @@ export declare class WorkerRenderer {
|
|
|
81
81
|
resetExpandedDomain(): void;
|
|
82
82
|
/**
|
|
83
83
|
* Hit-test the cursor against the chart's facet grid (in faceted
|
|
84
|
-
* mode) or its current layout (single-plot).
|
|
85
|
-
*
|
|
86
|
-
* worker owns the facet grid and controllers, so the resolution
|
|
87
|
-
* runs here.
|
|
84
|
+
* mode) or its current layout (single-plot). The worker owns the
|
|
85
|
+
* facet grid and controllers, so the resolution runs here.
|
|
88
86
|
*/
|
|
89
87
|
private _resolveTarget;
|
|
90
88
|
onInteraction(event: InteractionEvent): void;
|
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
"./src/*": "./src/*",
|
|
14
|
-
"./dist/*": "./dist/*",
|
|
15
|
-
"./cdn/": "./dist/cdn/",
|
|
16
|
-
"./esm/": "./dist/esm/",
|
|
17
|
-
"./package.json": "./package.json"
|
|
2
|
+
"name": "@perspective-dev/viewer-charts",
|
|
3
|
+
"version": "4.5.2",
|
|
4
|
+
"description": "Perspective.js WebGL Plugin",
|
|
5
|
+
"unpkg": "./dist/cdn/perspective-viewer-charts.js",
|
|
6
|
+
"jsdelivr": "./dist/cdn/perspective-viewer-charts.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/esm/index.d.ts",
|
|
11
|
+
"default": "./dist/esm/perspective-viewer-charts.js"
|
|
18
12
|
},
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
13
|
+
"./src/*": "./src/*",
|
|
14
|
+
"./dist/*": "./dist/*",
|
|
15
|
+
"./cdn/": "./dist/cdn/",
|
|
16
|
+
"./esm/": "./dist/esm/",
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/**/*",
|
|
21
|
+
"src/**/*"
|
|
22
|
+
],
|
|
23
|
+
"types": "dist/esm/index.d.ts",
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/perspective-dev/perspective"
|
|
30
|
+
},
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "Apache-2.0",
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@perspective-dev/client": "",
|
|
35
|
+
"@perspective-dev/viewer": "",
|
|
36
|
+
"@perspective-dev/esbuild-plugin": "",
|
|
37
|
+
"@perspective-dev/test": "",
|
|
38
|
+
"@types/node": ">=22",
|
|
39
|
+
"lightningcss": "^1.29.0",
|
|
40
|
+
"typescript": ">=5 <6",
|
|
41
|
+
"webpack-glsl-minify": "1.5.0"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "node ./build.mjs",
|
|
45
|
+
"clean": "node ./clean.mjs"
|
|
46
|
+
}
|
|
47
|
+
}
|