@perspective-dev/viewer-charts 4.3.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/LICENSE.md +193 -0
- package/dist/cdn/perspective-viewer-charts.js +3 -0
- package/dist/cdn/perspective-viewer-charts.js.map +7 -0
- package/dist/esm/axis/axis-primitives.d.ts +24 -0
- package/dist/esm/axis/bar-axis.d.ts +51 -0
- package/dist/esm/axis/canvas.d.ts +24 -0
- package/dist/esm/axis/categorical-axis-core.d.ts +42 -0
- package/dist/esm/axis/categorical-axis.d.ts +27 -0
- package/dist/esm/axis/facet-chrome.d.ts +13 -0
- package/dist/esm/axis/label-geometry.d.ts +41 -0
- package/dist/esm/axis/legend.d.ts +44 -0
- package/dist/esm/axis/numeric-axis.d.ts +20 -0
- package/dist/esm/charts/candlestick/candlestick-build.d.ts +129 -0
- package/dist/esm/charts/candlestick/candlestick-interact.d.ts +10 -0
- package/dist/esm/charts/candlestick/candlestick-render.d.ts +24 -0
- package/dist/esm/charts/candlestick/candlestick.d.ts +144 -0
- package/dist/esm/charts/candlestick/glyphs/draw-candlesticks.d.ts +36 -0
- package/dist/esm/charts/candlestick/glyphs/draw-ohlc.d.ts +33 -0
- package/dist/esm/charts/canvas-types.d.ts +15 -0
- package/dist/esm/charts/cartesian/cartesian-build.d.ts +14 -0
- package/dist/esm/charts/cartesian/cartesian-interact.d.ts +20 -0
- package/dist/esm/charts/cartesian/cartesian-render.d.ts +26 -0
- package/dist/esm/charts/cartesian/cartesian.d.ts +239 -0
- package/dist/esm/charts/cartesian/glyph.d.ts +53 -0
- package/dist/esm/charts/cartesian/glyphs/density.d.ts +142 -0
- package/dist/esm/charts/cartesian/glyphs/lines.d.ts +23 -0
- package/dist/esm/charts/cartesian/glyphs/points.d.ts +24 -0
- package/dist/esm/charts/cartesian/label-interner.d.ts +21 -0
- package/dist/esm/charts/cartesian/tooltip-lines.d.ts +11 -0
- package/dist/esm/charts/chart-base.d.ts +402 -0
- package/dist/esm/charts/chart.d.ts +338 -0
- package/dist/esm/charts/common/band-layout.d.ts +32 -0
- package/dist/esm/charts/common/categorical-y-chart.d.ts +53 -0
- package/dist/esm/charts/common/category-axis-resolver.d.ts +90 -0
- package/dist/esm/charts/common/chrome-cache.d.ts +18 -0
- package/dist/esm/charts/common/draw-tooltip-box.d.ts +9 -0
- package/dist/esm/charts/common/leaf-color.d.ts +33 -0
- package/dist/esm/charts/common/node-store.d.ts +81 -0
- package/dist/esm/charts/common/tree-chart.d.ts +48 -0
- package/dist/esm/charts/common/tree-chrome.d.ts +31 -0
- package/dist/esm/charts/common/tree-data.d.ts +54 -0
- package/dist/esm/charts/common/visible-extent.d.ts +51 -0
- package/dist/esm/charts/heatmap/heatmap-build.d.ts +86 -0
- package/dist/esm/charts/heatmap/heatmap-interact.d.ts +19 -0
- package/dist/esm/charts/heatmap/heatmap-render.d.ts +19 -0
- package/dist/esm/charts/heatmap/heatmap-y-axis.d.ts +46 -0
- package/dist/esm/charts/heatmap/heatmap.d.ts +117 -0
- package/dist/esm/charts/map/map.d.ts +67 -0
- package/dist/esm/charts/registry.d.ts +14 -0
- package/dist/esm/charts/series/glyphs/draw-areas.d.ts +30 -0
- package/dist/esm/charts/series/glyphs/draw-bars.d.ts +15 -0
- package/dist/esm/charts/series/glyphs/draw-lines.d.ts +34 -0
- package/dist/esm/charts/series/glyphs/draw-scatter.d.ts +33 -0
- package/dist/esm/charts/series/series-build.d.ts +228 -0
- package/dist/esm/charts/series/series-interact.d.ts +35 -0
- package/dist/esm/charts/series/series-render.d.ts +41 -0
- package/dist/esm/charts/series/series-type.d.ts +49 -0
- package/dist/esm/charts/series/series.d.ts +317 -0
- package/dist/esm/charts/sunburst/sunburst-interact.d.ts +7 -0
- package/dist/esm/charts/sunburst/sunburst-layout.d.ts +33 -0
- package/dist/esm/charts/sunburst/sunburst-render.d.ts +22 -0
- package/dist/esm/charts/sunburst/sunburst.d.ts +85 -0
- package/dist/esm/charts/treemap/treemap-interact.d.ts +12 -0
- package/dist/esm/charts/treemap/treemap-layout.d.ts +28 -0
- package/dist/esm/charts/treemap/treemap-render.d.ts +18 -0
- package/dist/esm/charts/treemap/treemap.d.ts +74 -0
- package/dist/esm/config.d.ts +27 -0
- package/dist/esm/data/lazy-row.d.ts +32 -0
- package/dist/esm/data/split-groups.d.ts +20 -0
- package/dist/esm/data/view-reader.d.ts +35 -0
- package/dist/esm/event-detail.d.ts +28 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/interaction/hit-test.d.ts +30 -0
- package/dist/esm/interaction/host-sink-dom.d.ts +19 -0
- package/dist/esm/interaction/host-sink-message.d.ts +46 -0
- package/dist/esm/interaction/lazy-tooltip.d.ts +61 -0
- package/dist/esm/interaction/raw-event-forwarder.d.ts +27 -0
- package/dist/esm/interaction/spatial-grid.d.ts +15 -0
- package/dist/esm/interaction/tooltip-controller.d.ts +193 -0
- package/dist/esm/interaction/zoom-controller.d.ts +106 -0
- package/dist/esm/interaction/zoom-router.d.ts +48 -0
- package/dist/esm/layout/facet-grid.d.ts +126 -0
- package/dist/esm/layout/plot-layout.d.ts +104 -0
- package/dist/esm/layout/ticks.d.ts +17 -0
- package/dist/esm/map/mercator.d.ts +102 -0
- package/dist/esm/map/tile-cache.d.ts +38 -0
- package/dist/esm/map/tile-layer.d.ts +66 -0
- package/dist/esm/map/tile-loader.d.ts +52 -0
- package/dist/esm/map/tile-source.d.ts +66 -0
- package/dist/esm/perspective-viewer-charts.js +3 -0
- package/dist/esm/perspective-viewer-charts.js.map +7 -0
- package/dist/esm/plugin/charts.d.ts +40 -0
- package/dist/esm/plugin/plugin.d.ts +95 -0
- package/dist/esm/render/scheduler.d.ts +41 -0
- package/dist/esm/theme/gradient.d.ts +48 -0
- package/dist/esm/theme/palette.d.ts +13 -0
- package/dist/esm/theme/theme-snapshot.d.ts +7 -0
- package/dist/esm/theme/theme.d.ts +53 -0
- package/dist/esm/transport/protocol.d.ts +430 -0
- package/dist/esm/transport/renderer-transport.d.ts +201 -0
- package/dist/esm/utils/css.d.ts +1 -0
- package/dist/esm/utils/font-snapshot.d.ts +50 -0
- package/dist/esm/webgl/buffer-pool.d.ts +62 -0
- package/dist/esm/webgl/context-manager.d.ts +184 -0
- package/dist/esm/webgl/gradient-texture.d.ts +17 -0
- package/dist/esm/webgl/instanced-attrs.d.ts +44 -0
- package/dist/esm/webgl/plot-frame.d.ts +39 -0
- package/dist/esm/webgl/program-cache.d.ts +13 -0
- package/dist/esm/webgl/shader-manifest.d.ts +53 -0
- package/dist/esm/webgl/shader-registry.d.ts +22 -0
- package/dist/esm/worker/boot.d.ts +0 -0
- package/dist/esm/worker/dispatch.d.ts +9 -0
- package/dist/esm/worker/font-loader.d.ts +2 -0
- package/dist/esm/worker/renderer.worker.d.ts +115 -0
- package/dist/esm/worker/session-host.d.ts +26 -0
- package/package.json +47 -0
- package/src/css/perspective-viewer-charts.css +95 -0
- package/src/ts/axis/axis-primitives.ts +125 -0
- package/src/ts/axis/bar-axis.ts +345 -0
- package/src/ts/axis/canvas.ts +64 -0
- package/src/ts/axis/categorical-axis-core.ts +125 -0
- package/src/ts/axis/categorical-axis.ts +716 -0
- package/src/ts/axis/facet-chrome.ts +42 -0
- package/src/ts/axis/label-geometry.ts +188 -0
- package/src/ts/axis/legend.ts +218 -0
- package/src/ts/axis/numeric-axis.ts +353 -0
- package/src/ts/charts/candlestick/candlestick-build.ts +516 -0
- package/src/ts/charts/candlestick/candlestick-interact.ts +256 -0
- package/src/ts/charts/candlestick/candlestick-render.ts +387 -0
- package/src/ts/charts/candlestick/candlestick.ts +367 -0
- package/src/ts/charts/candlestick/glyphs/draw-candlesticks.ts +432 -0
- package/src/ts/charts/candlestick/glyphs/draw-ohlc.ts +317 -0
- package/src/ts/charts/canvas-types.ts +30 -0
- package/src/ts/charts/cartesian/cartesian-build.ts +616 -0
- package/src/ts/charts/cartesian/cartesian-interact.ts +355 -0
- package/src/ts/charts/cartesian/cartesian-render.ts +948 -0
- package/src/ts/charts/cartesian/cartesian.ts +469 -0
- package/src/ts/charts/cartesian/glyph.ts +81 -0
- package/src/ts/charts/cartesian/glyphs/density.ts +1263 -0
- package/src/ts/charts/cartesian/glyphs/lines.ts +320 -0
- package/src/ts/charts/cartesian/glyphs/points.ts +239 -0
- package/src/ts/charts/cartesian/label-interner.ts +56 -0
- package/src/ts/charts/cartesian/tooltip-lines.ts +80 -0
- package/src/ts/charts/chart-base.ts +840 -0
- package/src/ts/charts/chart.ts +427 -0
- package/src/ts/charts/common/band-layout.ts +63 -0
- package/src/ts/charts/common/categorical-y-chart.ts +81 -0
- package/src/ts/charts/common/category-axis-resolver.ts +314 -0
- package/src/ts/charts/common/chrome-cache.ts +79 -0
- package/src/ts/charts/common/draw-tooltip-box.ts +84 -0
- package/src/ts/charts/common/leaf-color.ts +92 -0
- package/src/ts/charts/common/node-store.ts +235 -0
- package/src/ts/charts/common/tree-chart.ts +76 -0
- package/src/ts/charts/common/tree-chrome.ts +123 -0
- package/src/ts/charts/common/tree-data.ts +623 -0
- package/src/ts/charts/common/visible-extent.ts +112 -0
- package/src/ts/charts/heatmap/heatmap-build.ts +426 -0
- package/src/ts/charts/heatmap/heatmap-interact.ts +274 -0
- package/src/ts/charts/heatmap/heatmap-render.ts +815 -0
- package/src/ts/charts/heatmap/heatmap-y-axis.ts +351 -0
- package/src/ts/charts/heatmap/heatmap.ts +368 -0
- package/src/ts/charts/map/map.ts +201 -0
- package/src/ts/charts/registry.ts +65 -0
- package/src/ts/charts/series/glyphs/draw-areas.ts +331 -0
- package/src/ts/charts/series/glyphs/draw-bars.ts +113 -0
- package/src/ts/charts/series/glyphs/draw-lines.ts +320 -0
- package/src/ts/charts/series/glyphs/draw-scatter.ts +328 -0
- package/src/ts/charts/series/series-build.ts +848 -0
- package/src/ts/charts/series/series-interact.ts +604 -0
- package/src/ts/charts/series/series-render.ts +1109 -0
- package/src/ts/charts/series/series-type.ts +99 -0
- package/src/ts/charts/series/series.ts +794 -0
- package/src/ts/charts/sunburst/sunburst-interact.ts +460 -0
- package/src/ts/charts/sunburst/sunburst-layout.ts +238 -0
- package/src/ts/charts/sunburst/sunburst-render.ts +887 -0
- package/src/ts/charts/sunburst/sunburst.ts +248 -0
- package/src/ts/charts/treemap/treemap-interact.ts +445 -0
- package/src/ts/charts/treemap/treemap-layout.ts +328 -0
- package/src/ts/charts/treemap/treemap-render.ts +886 -0
- package/src/ts/charts/treemap/treemap.ts +247 -0
- package/src/ts/config.ts +41 -0
- package/src/ts/data/lazy-row.ts +140 -0
- package/src/ts/data/split-groups.ts +97 -0
- package/src/ts/data/view-reader.ts +107 -0
- package/src/ts/event-detail.ts +44 -0
- package/src/ts/index.ts +53 -0
- package/src/ts/interaction/hit-test.ts +106 -0
- package/src/ts/interaction/host-sink-dom.ts +85 -0
- package/src/ts/interaction/host-sink-message.ts +75 -0
- package/src/ts/interaction/lazy-tooltip.ts +102 -0
- package/src/ts/interaction/raw-event-forwarder.ts +175 -0
- package/src/ts/interaction/spatial-grid.ts +100 -0
- package/src/ts/interaction/tooltip-controller.ts +407 -0
- package/src/ts/interaction/zoom-controller.ts +468 -0
- package/src/ts/interaction/zoom-router.ts +230 -0
- package/src/ts/layout/facet-grid.ts +346 -0
- package/src/ts/layout/plot-layout.ts +277 -0
- package/src/ts/layout/ticks.ts +168 -0
- package/src/ts/map/mercator.ts +204 -0
- package/src/ts/map/tile-cache.ts +96 -0
- package/src/ts/map/tile-layer.ts +382 -0
- package/src/ts/map/tile-loader.ts +143 -0
- package/src/ts/map/tile-source.ts +156 -0
- package/src/ts/plugin/charts.ts +286 -0
- package/src/ts/plugin/plugin.ts +668 -0
- package/src/ts/render/scheduler.ts +339 -0
- package/src/ts/shaders/area.frag.glsl +20 -0
- package/src/ts/shaders/area.vert.glsl +19 -0
- package/src/ts/shaders/bar.frag.glsl +25 -0
- package/src/ts/shaders/bar.vert.glsl +60 -0
- package/src/ts/shaders/candlestick-body.frag.glsl +19 -0
- package/src/ts/shaders/candlestick-body.vert.glsl +34 -0
- package/src/ts/shaders/density-extreme.frag.glsl +30 -0
- package/src/ts/shaders/density-mrt.frag.glsl +44 -0
- package/src/ts/shaders/density-mrt.vert.glsl +48 -0
- package/src/ts/shaders/density-resolve.frag.glsl +89 -0
- package/src/ts/shaders/density-resolve.vert.glsl +23 -0
- package/src/ts/shaders/density-splat.frag.glsl +34 -0
- package/src/ts/shaders/density-splat.vert.glsl +52 -0
- package/src/ts/shaders/gridline.frag.glsl +18 -0
- package/src/ts/shaders/gridline.vert.glsl +18 -0
- package/src/ts/shaders/heatmap.frag.glsl +23 -0
- package/src/ts/shaders/heatmap.vert.glsl +42 -0
- package/src/ts/shaders/line-uniform.frag.glsl +26 -0
- package/src/ts/shaders/line-uniform.vert.glsl +54 -0
- package/src/ts/shaders/line.frag.glsl +28 -0
- package/src/ts/shaders/line.vert.glsl +87 -0
- package/src/ts/shaders/scatter.frag.glsl +39 -0
- package/src/ts/shaders/scatter.vert.glsl +67 -0
- package/src/ts/shaders/sunburst-arc.frag.glsl +19 -0
- package/src/ts/shaders/sunburst-arc.vert.glsl +79 -0
- package/src/ts/shaders/tile.frag.glsl +27 -0
- package/src/ts/shaders/tile.vert.glsl +35 -0
- package/src/ts/shaders/treemap.frag.glsl +19 -0
- package/src/ts/shaders/treemap.vert.glsl +25 -0
- package/src/ts/shaders/y-scatter.frag.glsl +30 -0
- package/src/ts/shaders/y-scatter.vert.glsl +31 -0
- package/src/ts/theme/gradient.ts +312 -0
- package/src/ts/theme/palette.ts +64 -0
- package/src/ts/theme/theme-snapshot.ts +66 -0
- package/src/ts/theme/theme.ts +166 -0
- package/src/ts/transport/protocol.ts +497 -0
- package/src/ts/transport/renderer-transport.ts +788 -0
- package/src/ts/utils/css.ts +36 -0
- package/src/ts/utils/font-snapshot.ts +159 -0
- package/src/ts/webgl/buffer-pool.ts +163 -0
- package/src/ts/webgl/context-manager.ts +414 -0
- package/src/ts/webgl/gradient-texture.ts +84 -0
- package/src/ts/webgl/instanced-attrs.ts +139 -0
- package/src/ts/webgl/plot-frame.ts +91 -0
- package/src/ts/webgl/program-cache.ts +46 -0
- package/src/ts/webgl/shader-manifest.ts +148 -0
- package/src/ts/webgl/shader-registry.ts +97 -0
- package/src/ts/worker/boot.ts +22 -0
- package/src/ts/worker/dispatch.ts +99 -0
- package/src/ts/worker/font-loader.ts +89 -0
- package/src/ts/worker/renderer.worker.ts +734 -0
- package/src/ts/worker/session-host.ts +118 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import type { WebGLContextManager } from "../webgl/context-manager";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Module-level render scheduler. The single entry point for driving a
|
|
17
|
+
* chart frame. Every render-triggering caller — upload chunks, zoom /
|
|
18
|
+
* pan, resize, theme invalidation, host-driven redraws — calls
|
|
19
|
+
* `requestRender(glManager, fullRender)` and awaits the returned
|
|
20
|
+
* promise.
|
|
21
|
+
*
|
|
22
|
+
* ## Guarantees
|
|
23
|
+
*
|
|
24
|
+
* 1. **At most one RAF queued globally.** The first request kicks
|
|
25
|
+
* off `requestAnimationFrame(drain)`; subsequent requests during
|
|
26
|
+
* that window enqueue without scheduling another callback.
|
|
27
|
+
*
|
|
28
|
+
* 2. **Coalesced per `glManager`.** The pending map is keyed by
|
|
29
|
+
* `WebGLContextManager`, so concurrent requests for the same
|
|
30
|
+
* chart share an entry — there is exactly one `_fullRender` call
|
|
31
|
+
* per glManager per RAF, regardless of how many requests landed.
|
|
32
|
+
*
|
|
33
|
+
* 3. **Promise resolves after the entry's own present.** Each
|
|
34
|
+
* waiter resolves when its entry's `_fullRender` +
|
|
35
|
+
* `awaitGpuFence` + `endFrame` chain completes. Independent
|
|
36
|
+
* glManagers run their fence waits in parallel (Phase 2 below),
|
|
37
|
+
* so a fast chart's waiters do not block on a slow chart in the
|
|
38
|
+
* same frame.
|
|
39
|
+
*
|
|
40
|
+
* 4. **At most one `_fullRender` per glManager per RAF.** GL
|
|
41
|
+
* contexts are not re-entered. `transferToImageBitmap` is called
|
|
42
|
+
* exactly once per glManager per frame, so the host blitter
|
|
43
|
+
* receives one bitmap per frame per chart and never an empty
|
|
44
|
+
* one.
|
|
45
|
+
*
|
|
46
|
+
* ## Drain ordering
|
|
47
|
+
*
|
|
48
|
+
* - **Phase 1 (synchronous):** iterate the pending snapshot and call
|
|
49
|
+
* each entry's `fullRender()` in one un-yielded loop. This pushes
|
|
50
|
+
* all GL command buffers to all contexts before any fence wait
|
|
51
|
+
* begins, letting per-context GPU work overlap.
|
|
52
|
+
*
|
|
53
|
+
* - **Phase 2 (parallel):** `Promise.all(snapshot.map(present))`
|
|
54
|
+
* where `present` does `await awaitGpuFence(); endFrame();
|
|
55
|
+
* resolve waiters`. Each entry's waiters resolve as soon as its
|
|
56
|
+
* own present completes — independent of other entries.
|
|
57
|
+
*
|
|
58
|
+
* ## Failure modes
|
|
59
|
+
*
|
|
60
|
+
* - A throw from `fullRender()` rejects that entry's waiters and
|
|
61
|
+
* drops the entry; other entries continue to drain normally.
|
|
62
|
+
*
|
|
63
|
+
* - A rejection from `awaitGpuFence` calls `endFrame` anyway (so
|
|
64
|
+
* canvas state stays consistent — `transferToImageBitmap` clears
|
|
65
|
+
* the offscreen even on the error path) and rejects that entry's
|
|
66
|
+
* waiters.
|
|
67
|
+
*
|
|
68
|
+
* ## Snapshot bypass
|
|
69
|
+
*
|
|
70
|
+
* The scheduler always pairs `_fullRender` with `endFrame()`, which
|
|
71
|
+
* calls `transferToImageBitmap` and clears the offscreen. PNG
|
|
72
|
+
* export needs `gl.readPixels` against an intact backbuffer, so
|
|
73
|
+
* `snapshotPng` deliberately calls `_fullRender` directly and skips
|
|
74
|
+
* `endFrame`. That is the only sanctioned bypass; everything else
|
|
75
|
+
* goes through `requestRender`.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
interface Entry {
|
|
79
|
+
glManager: WebGLContextManager;
|
|
80
|
+
fullRender: () => void;
|
|
81
|
+
waiters: PromiseWithResolvers<void>[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const pending = new Map<WebGLContextManager, Entry>();
|
|
85
|
+
let rafId = 0;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Set of `glManager`s currently in `present()` (Phase 2 — between
|
|
89
|
+
* Phase 1 paint and `endFrame`). Mutations to these canvases must be
|
|
90
|
+
* deferred until Phase 2 completes, otherwise they corrupt the bitmap
|
|
91
|
+
* that `transferToImageBitmap` ships:
|
|
92
|
+
*
|
|
93
|
+
* - `glManager.resize` sets `canvas.width = N`, which the spec
|
|
94
|
+
* mandates clears the drawing buffer immediately (out-of-band
|
|
95
|
+
* from the GL command queue).
|
|
96
|
+
* - `glManager.clear` queues `gl.clear` after Phase 1's draw
|
|
97
|
+
* commands but before the fence; if it executes before
|
|
98
|
+
* `transferToImageBitmap`, the canvas is wiped.
|
|
99
|
+
*
|
|
100
|
+
* Either path produces a blank frame on the host. `deferIfDraining`
|
|
101
|
+
* is the gate; sibling message handlers (resize, clear) wrap their
|
|
102
|
+
* canvas-mutating bodies in it.
|
|
103
|
+
*/
|
|
104
|
+
const inFlight = new Set<WebGLContextManager>();
|
|
105
|
+
const deferred = new Map<WebGLContextManager, (() => void)[]>();
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Request a coalesced render of `glManager` whose body is
|
|
109
|
+
* `fullRender`. Returns a promise that resolves when this entry's
|
|
110
|
+
* Phase 2 (`awaitGpuFence` + `endFrame`) completes.
|
|
111
|
+
*
|
|
112
|
+
* If a request is already pending for the same glManager, the new
|
|
113
|
+
* call's `fullRender` closure replaces the prior one (latest call
|
|
114
|
+
* wins; closures read chart state lazily so this is functionally a
|
|
115
|
+
* no-op, but keeps the closure fresh) and the returned promise
|
|
116
|
+
* resolves alongside the existing waiters.
|
|
117
|
+
*/
|
|
118
|
+
export function requestRender(
|
|
119
|
+
glManager: WebGLContextManager,
|
|
120
|
+
fullRender: () => void,
|
|
121
|
+
): Promise<void> {
|
|
122
|
+
let entry = pending.get(glManager);
|
|
123
|
+
if (entry) {
|
|
124
|
+
entry.fullRender = fullRender;
|
|
125
|
+
} else {
|
|
126
|
+
entry = { glManager, fullRender, waiters: [] };
|
|
127
|
+
pending.set(glManager, entry);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const waiter = Promise.withResolvers<void>();
|
|
131
|
+
entry.waiters.push(waiter);
|
|
132
|
+
|
|
133
|
+
if (!rafId) {
|
|
134
|
+
rafId = scheduleFrame(drain);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return waiter.promise;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Run `op` synchronously if no drain `present()` is currently active
|
|
142
|
+
* for `glManager`. Otherwise queue `op` to run as soon as that
|
|
143
|
+
* glManager's in-flight `present()` completes (after `endFrame`,
|
|
144
|
+
* after the resolved/rejected waiters).
|
|
145
|
+
*
|
|
146
|
+
* Used by canvas-mutating callers — `WorkerRenderer.resize`,
|
|
147
|
+
* `WorkerRenderer.clear` — to avoid wiping the offscreen between
|
|
148
|
+
* Phase 1 paint and Phase 2 `endFrame`. `glManager.resize` setting
|
|
149
|
+
* `canvas.width = N` clears the drawing buffer immediately
|
|
150
|
+
* (per the WebGL spec, out-of-band from the GL command queue), and
|
|
151
|
+
* a clear that lands in Phase 2's fence-wait yield window corrupts
|
|
152
|
+
* the bitmap that `transferToImageBitmap` ships, producing a blank
|
|
153
|
+
* frame on the host.
|
|
154
|
+
*
|
|
155
|
+
* Deferred ops execute in `present()`'s `finally` clause, so they
|
|
156
|
+
* land *after* the in-flight drain's bitmap has been shipped and
|
|
157
|
+
* before the next drain starts. If a deferred op itself triggers a
|
|
158
|
+
* `requestRender`, the resulting entry queues into `pending` and
|
|
159
|
+
* the drain's tail check (`pending.size > 0 → scheduleFrame(drain)`)
|
|
160
|
+
* picks it up for the next RAF.
|
|
161
|
+
*/
|
|
162
|
+
export function deferIfDraining(
|
|
163
|
+
glManager: WebGLContextManager,
|
|
164
|
+
op: () => void,
|
|
165
|
+
): void {
|
|
166
|
+
if (!inFlight.has(glManager)) {
|
|
167
|
+
op();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let ops = deferred.get(glManager);
|
|
172
|
+
if (!ops) {
|
|
173
|
+
ops = [];
|
|
174
|
+
deferred.set(glManager, ops);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
ops.push(op);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Test-only: clear pending state. Production callers must not use
|
|
182
|
+
* this — outstanding waiters are silently dropped.
|
|
183
|
+
*/
|
|
184
|
+
export function _resetForTest(): void {
|
|
185
|
+
if (rafId) {
|
|
186
|
+
cancelFrame(rafId);
|
|
187
|
+
rafId = 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
pending.clear();
|
|
191
|
+
inFlight.clear();
|
|
192
|
+
deferred.clear();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// async function drain(): Promise<void> {
|
|
196
|
+
// rafId = 0;
|
|
197
|
+
|
|
198
|
+
// // Snapshot the pending set up front so requests that arrive during
|
|
199
|
+
// // the drain (in microtasks between Phase 2 awaits, or in tasks
|
|
200
|
+
// // unblocked by `awaitGpuFence`'s yields) queue into the next RAF
|
|
201
|
+
// // rather than mutating this drain's working set.
|
|
202
|
+
// const snapshot = Array.from(pending.values());
|
|
203
|
+
// pending.clear();
|
|
204
|
+
|
|
205
|
+
// // Phase 1: synchronously queue GL commands for every entry. One
|
|
206
|
+
// // un-yielded loop so all contexts have their commands submitted
|
|
207
|
+
// // before any fence wait begins; otherwise fence waits serialize
|
|
208
|
+
// // behind each subsequent `_fullRender`'s draw submissions.
|
|
209
|
+
// const ready: Entry[] = [];
|
|
210
|
+
// for (const entry of snapshot) {
|
|
211
|
+
// try {
|
|
212
|
+
// entry.fullRender();
|
|
213
|
+
// ready.push(entry);
|
|
214
|
+
// } catch (err) {
|
|
215
|
+
// console.error("scheduler: fullRender threw", err);
|
|
216
|
+
// for (const w of entry.waiters) {
|
|
217
|
+
// w.reject(err);
|
|
218
|
+
// }
|
|
219
|
+
// }
|
|
220
|
+
// }
|
|
221
|
+
|
|
222
|
+
// // Phase 2: run each entry's fence + endFrame + waiter-resolve as
|
|
223
|
+
// // its own async task. `Promise.all` joins for the drain wall
|
|
224
|
+
// // time, but per-entry waiters resolve as soon as their entry's
|
|
225
|
+
// // present completes — a fast chart in this frame is not held up
|
|
226
|
+
// // by a slow chart.
|
|
227
|
+
// await Promise.all(ready.map(present));
|
|
228
|
+
// }
|
|
229
|
+
|
|
230
|
+
async function drain(): Promise<void> {
|
|
231
|
+
const snapshot = Array.from(pending.values());
|
|
232
|
+
pending.clear();
|
|
233
|
+
const ready: Entry[] = [];
|
|
234
|
+
for (const entry of snapshot) {
|
|
235
|
+
try {
|
|
236
|
+
// Apply any dimension change recorded by
|
|
237
|
+
// `glManager.requestResize` *before* the paint, in the
|
|
238
|
+
// same un-yielded synchronous Phase 1 loop. This pairs
|
|
239
|
+
// the canvas-clearing `canvas.width = N` assignment
|
|
240
|
+
// with the immediately-following `_fullRender`, so the
|
|
241
|
+
// browser's compositor only ever observes the canvas
|
|
242
|
+
// post-paint. In direct/in-process modes the visible
|
|
243
|
+
// canvas IS the GL canvas, and a clear-without-matching-
|
|
244
|
+
// paint in the previous task would otherwise present an
|
|
245
|
+
// empty frame to the user.
|
|
246
|
+
entry.glManager.applyPendingResize();
|
|
247
|
+
entry.fullRender();
|
|
248
|
+
ready.push(entry);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error("scheduler: fullRender threw", err);
|
|
251
|
+
for (const w of entry.waiters) {
|
|
252
|
+
w.reject(err);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
await Promise.all(ready.map(present));
|
|
258
|
+
|
|
259
|
+
// Now (and only now) clear rafId. If new requests landed during
|
|
260
|
+
// this drain, schedule the next RAF.
|
|
261
|
+
rafId = 0;
|
|
262
|
+
if (pending.size > 0) {
|
|
263
|
+
rafId = scheduleFrame(drain);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function present(entry: Entry): Promise<void> {
|
|
268
|
+
// Mark this glManager as in-flight *synchronously*, before the
|
|
269
|
+
// first await. `Promise.all(ready.map(present))` calls each
|
|
270
|
+
// `present` synchronously to collect its returned promise, so
|
|
271
|
+
// every entry's glManager is registered in `inFlight` before
|
|
272
|
+
// any fence-wait yields and before any sibling message handler
|
|
273
|
+
// can run. Mutations posted by sibling handlers (resize, clear)
|
|
274
|
+
// route through `deferIfDraining` and queue into `deferred`
|
|
275
|
+
// until the `finally` block flushes them.
|
|
276
|
+
inFlight.add(entry.glManager);
|
|
277
|
+
try {
|
|
278
|
+
await entry.glManager.awaitGpuFence();
|
|
279
|
+
entry.glManager.endFrame();
|
|
280
|
+
for (const w of entry.waiters) {
|
|
281
|
+
w.resolve();
|
|
282
|
+
}
|
|
283
|
+
} catch (err) {
|
|
284
|
+
console.error("scheduler: present failed", err);
|
|
285
|
+
// Still call `endFrame` so the canvas state is consistent —
|
|
286
|
+
// `transferToImageBitmap` clears the offscreen, and skipping
|
|
287
|
+
// it would leave a stale image bound to a context the host
|
|
288
|
+
// already considers presented.
|
|
289
|
+
try {
|
|
290
|
+
entry.glManager.endFrame();
|
|
291
|
+
} catch {
|
|
292
|
+
// Swallow: already in a failure path.
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
for (const w of entry.waiters) {
|
|
296
|
+
w.reject(err);
|
|
297
|
+
}
|
|
298
|
+
} finally {
|
|
299
|
+
// Bitmap shipped (or error reported). Re-open the canvas to
|
|
300
|
+
// mutations and flush any deferred ops in arrival order.
|
|
301
|
+
// Deferred ops may call `requestRender`; the resulting
|
|
302
|
+
// entry queues into `pending` and the drain's tail check
|
|
303
|
+
// picks it up for the next RAF.
|
|
304
|
+
inFlight.delete(entry.glManager);
|
|
305
|
+
const ops = deferred.get(entry.glManager);
|
|
306
|
+
if (ops) {
|
|
307
|
+
deferred.delete(entry.glManager);
|
|
308
|
+
for (const op of ops) {
|
|
309
|
+
try {
|
|
310
|
+
op();
|
|
311
|
+
} catch (err) {
|
|
312
|
+
console.error("scheduler: deferred op threw", err);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* RAF in worker scope is exposed by `DedicatedWorkerGlobalScope` for
|
|
321
|
+
* `OffscreenCanvas` painting and is the same primitive as on the
|
|
322
|
+
* main thread. Fall back to `setTimeout(16)` for environments
|
|
323
|
+
* without RAF (jsdom, headless tests without a polyfill).
|
|
324
|
+
*/
|
|
325
|
+
function scheduleFrame(cb: () => void): number {
|
|
326
|
+
if (typeof requestAnimationFrame === "function") {
|
|
327
|
+
return requestAnimationFrame(cb);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return setTimeout(cb, 16) as unknown as number;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function cancelFrame(id: number): void {
|
|
334
|
+
if (typeof cancelAnimationFrame === "function") {
|
|
335
|
+
cancelAnimationFrame(id);
|
|
336
|
+
} else {
|
|
337
|
+
clearTimeout(id);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
precision highp float;
|
|
14
|
+
|
|
15
|
+
uniform vec3 u_color;
|
|
16
|
+
uniform float u_opacity;
|
|
17
|
+
|
|
18
|
+
void main() {
|
|
19
|
+
gl_FragColor = vec4(u_color, u_opacity);
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
attribute vec2 a_position;
|
|
14
|
+
|
|
15
|
+
uniform mat4 u_projection;
|
|
16
|
+
|
|
17
|
+
void main() {
|
|
18
|
+
gl_Position = u_projection * vec4(a_position, 0.0, 1.0);
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
precision highp float;
|
|
14
|
+
|
|
15
|
+
varying vec3 v_color;
|
|
16
|
+
varying float v_hover;
|
|
17
|
+
varying vec2 v_local;
|
|
18
|
+
|
|
19
|
+
void main() {
|
|
20
|
+
vec3 color = v_color;
|
|
21
|
+
if (v_hover > 0.5) {
|
|
22
|
+
color = mix(color, vec3(1.0), 0.25);
|
|
23
|
+
}
|
|
24
|
+
gl_FragColor = vec4(color, 1.0);
|
|
25
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
// Per-vertex (divisor=0): unit quad corner in [0,1]^2 order
|
|
14
|
+
// 0=(0,0) bottom-left, 1=(1,0) bottom-right, 2=(0,1) top-left, 3=(1,1) top-right
|
|
15
|
+
attribute vec2 a_corner;
|
|
16
|
+
|
|
17
|
+
// Per-instance (divisor=1) bar attributes
|
|
18
|
+
attribute float a_x_center;
|
|
19
|
+
attribute float a_half_width;
|
|
20
|
+
attribute float a_y0;
|
|
21
|
+
attribute float a_y1;
|
|
22
|
+
attribute vec3 a_color;
|
|
23
|
+
attribute float a_series_id;
|
|
24
|
+
attribute float a_axis;
|
|
25
|
+
|
|
26
|
+
uniform mat4 u_proj_left;
|
|
27
|
+
uniform mat4 u_proj_right;
|
|
28
|
+
uniform float u_hover_series;
|
|
29
|
+
// 0 = vertical bars (categorical X, numeric Y).
|
|
30
|
+
// 1 = horizontal bars (numeric X, categorical Y). Instance attributes
|
|
31
|
+
// stay in "logical" form — x_center + halfWidth on the categorical axis,
|
|
32
|
+
// y0/y1 on the value axis — and we transpose at projection time.
|
|
33
|
+
uniform float u_horizontal;
|
|
34
|
+
|
|
35
|
+
varying vec3 v_color;
|
|
36
|
+
varying float v_hover;
|
|
37
|
+
varying vec2 v_local;
|
|
38
|
+
|
|
39
|
+
void main() {
|
|
40
|
+
vec2 pos;
|
|
41
|
+
if (u_horizontal > 0.5) {
|
|
42
|
+
pos = vec2(
|
|
43
|
+
mix(a_y0, a_y1, a_corner.x),
|
|
44
|
+
a_x_center + (a_corner.y - 0.5) * 2.0 * a_half_width
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
pos = vec2(
|
|
48
|
+
a_x_center + (a_corner.x - 0.5) * 2.0 * a_half_width,
|
|
49
|
+
mix(a_y0, a_y1, a_corner.y)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Branch on per-instance axis flag. Both matrices are set each frame.
|
|
54
|
+
mat4 proj = a_axis < 0.5 ? u_proj_left : u_proj_right;
|
|
55
|
+
gl_Position = proj * vec4(pos, 0.0, 1.0);
|
|
56
|
+
|
|
57
|
+
v_color = a_color;
|
|
58
|
+
v_hover = abs(a_series_id - u_hover_series) < 0.5 ? 1.0 : 0.0;
|
|
59
|
+
v_local = a_corner;
|
|
60
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
precision highp float;
|
|
14
|
+
|
|
15
|
+
varying vec3 v_color;
|
|
16
|
+
|
|
17
|
+
void main() {
|
|
18
|
+
gl_FragColor = vec4(v_color, 1.0);
|
|
19
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
// Filled-rectangle shader for candlestick bodies. A trimmed copy of
|
|
14
|
+
// the bar shader without the hover-highlight / dual-axis plumbing that
|
|
15
|
+
// candlestick doesn't need.
|
|
16
|
+
|
|
17
|
+
attribute vec2 a_corner; // per-vertex, divisor=0: (0|1, 0|1)
|
|
18
|
+
|
|
19
|
+
attribute float a_x_center; // per-instance
|
|
20
|
+
attribute float a_half_width;
|
|
21
|
+
attribute float a_y0;
|
|
22
|
+
attribute float a_y1;
|
|
23
|
+
attribute vec3 a_color;
|
|
24
|
+
|
|
25
|
+
uniform mat4 u_projection;
|
|
26
|
+
|
|
27
|
+
varying vec3 v_color;
|
|
28
|
+
|
|
29
|
+
void main() {
|
|
30
|
+
float x = a_x_center + (a_corner.x - 0.5) * 2.0 * a_half_width;
|
|
31
|
+
float y = mix(a_y0, a_y1, a_corner.y);
|
|
32
|
+
gl_Position = u_projection * vec4(x, y, 0.0, 1.0);
|
|
33
|
+
v_color = a_color;
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
precision highp float;
|
|
14
|
+
|
|
15
|
+
varying vec2 v_uv;
|
|
16
|
+
varying float v_color_t;
|
|
17
|
+
|
|
18
|
+
void main() {
|
|
19
|
+
float r = length(v_uv);
|
|
20
|
+
if(r >= 1.0) {
|
|
21
|
+
discard;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Signed deviation from the gradient midpoint, in [-1, +1]. Split
|
|
25
|
+
// into two non-negative channels so the FBO format stays in [0, 1]
|
|
26
|
+
// and so the `MAX` blend at the call site keeps the strongest
|
|
27
|
+
// contributor of each sign separately.
|
|
28
|
+
float dev = (v_color_t - 0.5) * 2.0;
|
|
29
|
+
gl_FragColor = vec4(max(0.0, dev), max(0.0, -dev), 0.0, 0.0);
|
|
30
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#version 300 es
|
|
2
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
3
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
4
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
5
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
6
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
7
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
8
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
9
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
10
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
11
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
12
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
13
|
+
|
|
14
|
+
// MRT variant of the splat fragment used by `extreme` mode when the
|
|
15
|
+
// running context advertises `OES_draw_buffers_indexed`. One pass
|
|
16
|
+
// writes to both targets:
|
|
17
|
+
//
|
|
18
|
+
// - location 0 (heat FBO, ADD blend): same payload as
|
|
19
|
+
// density-splat.frag.glsl — `(w, w·t, 0, 0)`.
|
|
20
|
+
// - location 1 (extreme FBO, MAX blend): same payload as
|
|
21
|
+
// density-extreme.frag.glsl — split signed deviation.
|
|
22
|
+
|
|
23
|
+
precision highp float;
|
|
24
|
+
|
|
25
|
+
uniform float u_intensity;
|
|
26
|
+
|
|
27
|
+
in vec2 v_uv;
|
|
28
|
+
in float v_color_t;
|
|
29
|
+
|
|
30
|
+
layout(location = 0) out vec4 outHeat;
|
|
31
|
+
layout(location = 1) out vec4 outExtreme;
|
|
32
|
+
|
|
33
|
+
void main() {
|
|
34
|
+
float r = length(v_uv);
|
|
35
|
+
float w = max(0.0f, 1.0f - r);
|
|
36
|
+
w = w * w * u_intensity;
|
|
37
|
+
if(w <= 0.0f) {
|
|
38
|
+
discard;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
outHeat = vec4(w, w * v_color_t, 0.0f, 0.0f);
|
|
42
|
+
float dev = (v_color_t - 0.5f) * 2.0f;
|
|
43
|
+
outExtreme = vec4(max(0.0f, dev), max(0.0f, -dev), 0.0f, 0.0f);
|
|
44
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#version 300 es
|
|
2
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
3
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
4
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
5
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
6
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
7
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
8
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
9
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
10
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
11
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
12
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
13
|
+
|
|
14
|
+
// GLSL ES 3.00 variant of `density-splat.vert.glsl`, mirroring its math
|
|
15
|
+
// 1:1 in the modern dialect (`in`/`out` instead of `attribute`/
|
|
16
|
+
// `varying`). Paired with `density-mrt.frag.glsl` for the MRT fast
|
|
17
|
+
// path used by `extreme` mode on WebGL2 — the program's vertex and
|
|
18
|
+
// fragment shaders must share a GLSL version, so the WebGL1-style
|
|
19
|
+
// splat vert can't be linked against a 300 ES MRT frag.
|
|
20
|
+
|
|
21
|
+
in vec2 a_corner;
|
|
22
|
+
in vec2 a_position;
|
|
23
|
+
in float a_color_value;
|
|
24
|
+
|
|
25
|
+
uniform mat4 u_projection;
|
|
26
|
+
uniform vec2 u_radius_ndc;
|
|
27
|
+
uniform vec2 u_color_range;
|
|
28
|
+
|
|
29
|
+
out vec2 v_uv;
|
|
30
|
+
out float v_color_t;
|
|
31
|
+
|
|
32
|
+
void main() {
|
|
33
|
+
vec4 center = u_projection * vec4(a_position, 0.0, 1.0);
|
|
34
|
+
gl_Position = center + vec4(a_corner * u_radius_ndc * center.w, 0.0, 0.0);
|
|
35
|
+
|
|
36
|
+
v_uv = a_corner;
|
|
37
|
+
|
|
38
|
+
float cmin = u_color_range.x;
|
|
39
|
+
float cmax = u_color_range.y;
|
|
40
|
+
if(cmax <= cmin) {
|
|
41
|
+
v_color_t = 0.5;
|
|
42
|
+
} else if(cmin < 0.0 && cmax > 0.0) {
|
|
43
|
+
float denom = max(-cmin, cmax);
|
|
44
|
+
v_color_t = clamp(0.5 + 0.5 * (a_color_value / denom), 0.0, 1.0);
|
|
45
|
+
} else {
|
|
46
|
+
v_color_t = clamp((a_color_value - cmin) / (cmax - cmin), 0.0, 1.0);
|
|
47
|
+
}
|
|
48
|
+
}
|