@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,95 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: block;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
font-family: inherit;
|
|
8
|
+
|
|
9
|
+
/* font-family: var(--psp-interface-monospace--font-family, inherit); */
|
|
10
|
+
/* --psp-charts--font-family: var(font-family, inherit); */
|
|
11
|
+
|
|
12
|
+
--psp-charts--tooltip--color: var(--psp--color);
|
|
13
|
+
--psp-charts--tooltip--background: var(--psp--background-color);
|
|
14
|
+
--psp-charts--tooltip--border-color: var(--psp-inactive--border-color);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.webgl-container {
|
|
18
|
+
position: absolute;
|
|
19
|
+
top: 6px;
|
|
20
|
+
left: 6px;
|
|
21
|
+
right: 6px;
|
|
22
|
+
bottom: 6px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.webgl-canvas {
|
|
26
|
+
position: absolute;
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 100%;
|
|
29
|
+
top: 0;
|
|
30
|
+
left: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.webgl-gridlines {
|
|
34
|
+
position: absolute;
|
|
35
|
+
width: 100%;
|
|
36
|
+
height: 100%;
|
|
37
|
+
top: 0;
|
|
38
|
+
left: 0;
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.webgl-chrome {
|
|
43
|
+
position: absolute;
|
|
44
|
+
width: 100%;
|
|
45
|
+
height: 100%;
|
|
46
|
+
top: 0;
|
|
47
|
+
left: 0;
|
|
48
|
+
pointer-events: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.zoom-controls {
|
|
52
|
+
position: absolute;
|
|
53
|
+
top: 8px;
|
|
54
|
+
left: 50%;
|
|
55
|
+
transform: translateX(-50%);
|
|
56
|
+
display: none;
|
|
57
|
+
z-index: 2;
|
|
58
|
+
pointer-events: auto;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.zoom-controls.visible {
|
|
62
|
+
display: flex;
|
|
63
|
+
gap: 6px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.zoom-reset {
|
|
67
|
+
background: var(--psp-charts--tooltip--background);
|
|
68
|
+
color: var(--psp-charts--tooltip--color);
|
|
69
|
+
border: 1px solid var(--psp-charts--tooltip--border-color);
|
|
70
|
+
border-radius: 4px;
|
|
71
|
+
padding: 4px 12px;
|
|
72
|
+
font: 11px var(--psp-charts--font-family);
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
opacity: 0.7;
|
|
75
|
+
transition: opacity 0.15s;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.zoom-reset:hover {
|
|
79
|
+
opacity: 1;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.webgl-tooltip {
|
|
83
|
+
position: absolute;
|
|
84
|
+
pointer-events: auto;
|
|
85
|
+
font: 11px var(--psp-charts--font-family);
|
|
86
|
+
background: var(--psp-charts--tooltip--background);
|
|
87
|
+
color: var(--psp-charts--tooltip--color);
|
|
88
|
+
border: 1px solid var(--psp-charts--tooltip--border-color);
|
|
89
|
+
border-radius: 3px;
|
|
90
|
+
padding: 3px;
|
|
91
|
+
overflow-y: auto;
|
|
92
|
+
white-space: pre;
|
|
93
|
+
z-index: 10;
|
|
94
|
+
line-height: 16px;
|
|
95
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
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 { Context2D } from "../charts/canvas-types";
|
|
14
|
+
import type { PlotRect } from "../layout/plot-layout";
|
|
15
|
+
|
|
16
|
+
export const TICK_SIZE = 5;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* One horizontal row of numeric axis ticks + labels at CSS-pixel `axisY`.
|
|
20
|
+
* `side` selects tick direction (down into the bottom margin or up into
|
|
21
|
+
* the top margin) and the corresponding label baseline. Caller owns
|
|
22
|
+
* `strokeStyle`, `fillStyle`, `font`, and `lineWidth`.
|
|
23
|
+
*/
|
|
24
|
+
export function drawXTickRow(
|
|
25
|
+
ctx: Context2D,
|
|
26
|
+
plot: PlotRect,
|
|
27
|
+
ticks: number[],
|
|
28
|
+
axisY: number,
|
|
29
|
+
side: "top" | "bottom",
|
|
30
|
+
xToPixel: (v: number) => number,
|
|
31
|
+
format: (v: number) => string,
|
|
32
|
+
): void {
|
|
33
|
+
const dir = side === "bottom" ? 1 : -1;
|
|
34
|
+
ctx.textAlign = "center";
|
|
35
|
+
ctx.textBaseline = side === "bottom" ? "top" : "bottom";
|
|
36
|
+
const labelOffset = dir * (TICK_SIZE + 3);
|
|
37
|
+
for (const tick of ticks) {
|
|
38
|
+
const px = xToPixel(tick);
|
|
39
|
+
if (px < plot.x - 1 || px > plot.x + plot.width + 1) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
ctx.beginPath();
|
|
44
|
+
ctx.moveTo(px, axisY);
|
|
45
|
+
ctx.lineTo(px, axisY + dir * TICK_SIZE);
|
|
46
|
+
ctx.stroke();
|
|
47
|
+
ctx.fillText(format(tick), px, axisY + labelOffset);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* One vertical column of numeric axis ticks + labels at CSS-pixel `axisX`.
|
|
53
|
+
* `side` selects tick direction (out toward the left or right margin) and
|
|
54
|
+
* the corresponding label alignment. Caller owns styling state.
|
|
55
|
+
*/
|
|
56
|
+
export function drawYTickColumn(
|
|
57
|
+
ctx: Context2D,
|
|
58
|
+
plot: PlotRect,
|
|
59
|
+
ticks: number[],
|
|
60
|
+
axisX: number,
|
|
61
|
+
side: "left" | "right",
|
|
62
|
+
yToPixel: (v: number) => number,
|
|
63
|
+
format: (v: number) => string,
|
|
64
|
+
): void {
|
|
65
|
+
const dir = side === "left" ? -1 : 1;
|
|
66
|
+
ctx.textAlign = side === "left" ? "right" : "left";
|
|
67
|
+
ctx.textBaseline = "middle";
|
|
68
|
+
const labelOffset = dir * (TICK_SIZE + 3);
|
|
69
|
+
for (const tick of ticks) {
|
|
70
|
+
const py = yToPixel(tick);
|
|
71
|
+
if (py < plot.y - 1 || py > plot.y + plot.height + 1) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
ctx.beginPath();
|
|
76
|
+
ctx.moveTo(axisX, py);
|
|
77
|
+
ctx.lineTo(axisX + dir * TICK_SIZE, py);
|
|
78
|
+
ctx.stroke();
|
|
79
|
+
ctx.fillText(format(tick), axisX + labelOffset, py);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Vertical gridlines at numeric X ticks, clipped to `plot`.
|
|
85
|
+
*/
|
|
86
|
+
export function drawGridlinesX(
|
|
87
|
+
ctx: Context2D,
|
|
88
|
+
plot: PlotRect,
|
|
89
|
+
ticks: number[],
|
|
90
|
+
xToPixel: (v: number) => number,
|
|
91
|
+
): void {
|
|
92
|
+
for (const tick of ticks) {
|
|
93
|
+
const px = Math.round(xToPixel(tick)) + 0.5;
|
|
94
|
+
if (px < plot.x || px > plot.x + plot.width) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
ctx.beginPath();
|
|
99
|
+
ctx.moveTo(px, plot.y);
|
|
100
|
+
ctx.lineTo(px, plot.y + plot.height);
|
|
101
|
+
ctx.stroke();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Horizontal gridlines at numeric Y ticks, clipped to `plot`.
|
|
107
|
+
*/
|
|
108
|
+
export function drawGridlinesY(
|
|
109
|
+
ctx: Context2D,
|
|
110
|
+
plot: PlotRect,
|
|
111
|
+
ticks: number[],
|
|
112
|
+
yToPixel: (v: number) => number,
|
|
113
|
+
): void {
|
|
114
|
+
for (const tick of ticks) {
|
|
115
|
+
const py = Math.round(yToPixel(tick)) + 0.5;
|
|
116
|
+
if (py < plot.y || py > plot.y + plot.height) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
ctx.beginPath();
|
|
121
|
+
ctx.moveTo(plot.x, py);
|
|
122
|
+
ctx.lineTo(plot.x + plot.width, py);
|
|
123
|
+
ctx.stroke();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,345 @@
|
|
|
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 { Canvas2D, Context2D } from "../charts/canvas-types";
|
|
14
|
+
import { PlotLayout } from "../layout/plot-layout";
|
|
15
|
+
import { formatTickValue, formatDateTickValue } from "../layout/ticks";
|
|
16
|
+
import { initCanvas } from "./canvas";
|
|
17
|
+
import {
|
|
18
|
+
renderCategoricalXTicks,
|
|
19
|
+
renderCategoricalYTicks,
|
|
20
|
+
type CategoricalDomain,
|
|
21
|
+
} from "./categorical-axis";
|
|
22
|
+
import {
|
|
23
|
+
drawGridlinesX,
|
|
24
|
+
drawGridlinesY,
|
|
25
|
+
drawXTickRow,
|
|
26
|
+
drawYTickColumn,
|
|
27
|
+
} from "./axis-primitives";
|
|
28
|
+
import type { AxisDomain } from "./numeric-axis";
|
|
29
|
+
import type { Theme } from "../theme/theme";
|
|
30
|
+
|
|
31
|
+
function tickFormatter(
|
|
32
|
+
domain: AxisDomain,
|
|
33
|
+
ticks: number[],
|
|
34
|
+
override?: (v: number) => string,
|
|
35
|
+
): (v: number) => string {
|
|
36
|
+
if (override) {
|
|
37
|
+
return override;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!domain.isDate) {
|
|
41
|
+
return formatTickValue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const step = ticks.length > 1 ? ticks[1] - ticks[0] : 0;
|
|
45
|
+
return (v: number) => formatDateTickValue(v, step);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Render a numeric axis along the bottom or top of the plot area.
|
|
50
|
+
*/
|
|
51
|
+
function drawNumericXAxis(
|
|
52
|
+
ctx: Context2D,
|
|
53
|
+
layout: PlotLayout,
|
|
54
|
+
domain: AxisDomain,
|
|
55
|
+
ticks: number[],
|
|
56
|
+
side: "top" | "bottom",
|
|
57
|
+
theme: Theme,
|
|
58
|
+
formatter?: (v: number) => string,
|
|
59
|
+
): void {
|
|
60
|
+
const { labelColor, fontFamily } = theme;
|
|
61
|
+
const { plotRect: plot } = layout;
|
|
62
|
+
const axisY = side === "bottom" ? plot.y + plot.height : plot.y;
|
|
63
|
+
|
|
64
|
+
ctx.fillStyle = labelColor;
|
|
65
|
+
ctx.font = `11px ${fontFamily}`;
|
|
66
|
+
ctx.lineWidth = 1;
|
|
67
|
+
drawXTickRow(
|
|
68
|
+
ctx,
|
|
69
|
+
plot,
|
|
70
|
+
ticks,
|
|
71
|
+
axisY,
|
|
72
|
+
side,
|
|
73
|
+
(v) => layout.dataToPixel(v, 0).px,
|
|
74
|
+
tickFormatter(domain, ticks, formatter),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
ctx.font = `13px ${fontFamily}`;
|
|
78
|
+
ctx.textAlign = "center";
|
|
79
|
+
ctx.textBaseline = "bottom";
|
|
80
|
+
ctx.fillText(
|
|
81
|
+
domain.label,
|
|
82
|
+
plot.x + plot.width / 2,
|
|
83
|
+
side === "bottom" ? layout.cssHeight - 2 : 10,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Render a numeric Y axis along either the left or right side of the plot
|
|
89
|
+
* area. The caller must have already `initCanvas`'d the target canvas.
|
|
90
|
+
* Used by bar charts with a categorical X and optional split Y axes.
|
|
91
|
+
*/
|
|
92
|
+
function drawYAxis(
|
|
93
|
+
ctx: Context2D,
|
|
94
|
+
layout: PlotLayout,
|
|
95
|
+
domain: AxisDomain,
|
|
96
|
+
ticks: number[],
|
|
97
|
+
side: "left" | "right",
|
|
98
|
+
theme: Theme,
|
|
99
|
+
formatter?: (v: number) => string,
|
|
100
|
+
): void {
|
|
101
|
+
const { labelColor, fontFamily } = theme;
|
|
102
|
+
const { plotRect: plot } = layout;
|
|
103
|
+
const axisX = side === "left" ? plot.x : plot.x + plot.width;
|
|
104
|
+
|
|
105
|
+
ctx.fillStyle = labelColor;
|
|
106
|
+
ctx.font = `11px ${fontFamily}`;
|
|
107
|
+
ctx.lineWidth = 1;
|
|
108
|
+
drawYTickColumn(
|
|
109
|
+
ctx,
|
|
110
|
+
plot,
|
|
111
|
+
ticks,
|
|
112
|
+
axisX,
|
|
113
|
+
side,
|
|
114
|
+
(v) => layout.dataToPixel(0, v).py,
|
|
115
|
+
tickFormatter(domain, ticks, formatter),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
ctx.font = `13px ${fontFamily}`;
|
|
119
|
+
ctx.save();
|
|
120
|
+
if (side === "left") {
|
|
121
|
+
ctx.translate(14, plot.y + plot.height / 2);
|
|
122
|
+
ctx.rotate(-Math.PI / 2);
|
|
123
|
+
} else {
|
|
124
|
+
ctx.translate(layout.cssWidth - 10, plot.y + plot.height / 2);
|
|
125
|
+
ctx.rotate(Math.PI / 2);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
ctx.textAlign = "center";
|
|
129
|
+
ctx.textBaseline = "bottom";
|
|
130
|
+
ctx.fillText(domain.label, 0, 0);
|
|
131
|
+
ctx.restore();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The category-axis side of a bar chart can render as either a
|
|
136
|
+
* stringified hierarchical category axis or a true numeric axis (when
|
|
137
|
+
* the single group_by level is date / datetime / integer / float).
|
|
138
|
+
* Both shapes flow through `renderBarAxesChrome`; the discriminator is
|
|
139
|
+
* the `mode` field.
|
|
140
|
+
*/
|
|
141
|
+
export type BarCategoryAxis =
|
|
142
|
+
| { mode: "category"; domain: CategoricalDomain }
|
|
143
|
+
| { mode: "numeric"; domain: AxisDomain; ticks: number[] };
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Render a numeric date-aware axis along the bottom of the plot. Aliases
|
|
147
|
+
* the bar-axis bottom variant so heatmap can share the implementation.
|
|
148
|
+
*/
|
|
149
|
+
export function drawNumericCategoryX(
|
|
150
|
+
ctx: Context2D,
|
|
151
|
+
layout: PlotLayout,
|
|
152
|
+
domain: AxisDomain,
|
|
153
|
+
ticks: number[],
|
|
154
|
+
theme: Theme,
|
|
155
|
+
formatter?: (v: number) => string,
|
|
156
|
+
): void {
|
|
157
|
+
drawNumericXAxis(ctx, layout, domain, ticks, "bottom", theme, formatter);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function drawNumericCategoryY(
|
|
161
|
+
ctx: Context2D,
|
|
162
|
+
layout: PlotLayout,
|
|
163
|
+
domain: AxisDomain,
|
|
164
|
+
ticks: number[],
|
|
165
|
+
theme: Theme,
|
|
166
|
+
formatter?: (v: number) => string,
|
|
167
|
+
): void {
|
|
168
|
+
drawYAxis(ctx, layout, domain, ticks, "left", theme, formatter);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Render bar-chart chrome: L-shaped axis lines, a categorical axis
|
|
173
|
+
* (bottom for Y Bar, left for X Bar), and one or two numeric axes on
|
|
174
|
+
* the opposite sides.
|
|
175
|
+
*
|
|
176
|
+
* `isHorizontal=true` flips orientation for X Bar: categorical axis on
|
|
177
|
+
* the left, numeric axes on the bottom (and top for dual-axis). The
|
|
178
|
+
* `altDomain`/`altTicks` arguments always describe the *secondary*
|
|
179
|
+
* numeric axis regardless of orientation.
|
|
180
|
+
*/
|
|
181
|
+
export interface BarAxesFormatters {
|
|
182
|
+
/** Formatter for the value (Y in vertical, X in horizontal) axis. */
|
|
183
|
+
value?: (v: number) => string;
|
|
184
|
+
/** Formatter for the secondary alt value axis. */
|
|
185
|
+
alt?: (v: number) => string;
|
|
186
|
+
/** Formatter for the numeric category axis (when `catAxis.mode === "numeric"`). */
|
|
187
|
+
category?: (v: number) => string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function renderBarAxesChrome(
|
|
191
|
+
canvas: Canvas2D,
|
|
192
|
+
catAxis: BarCategoryAxis,
|
|
193
|
+
valueDomain: AxisDomain,
|
|
194
|
+
valueTicks: number[],
|
|
195
|
+
layout: PlotLayout,
|
|
196
|
+
theme: Theme,
|
|
197
|
+
dpr: number,
|
|
198
|
+
altDomain?: AxisDomain,
|
|
199
|
+
altTicks?: number[],
|
|
200
|
+
isHorizontal = false,
|
|
201
|
+
formatters: BarAxesFormatters = {},
|
|
202
|
+
): void {
|
|
203
|
+
const ctx = initCanvas(canvas, layout, dpr);
|
|
204
|
+
if (!ctx) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const { plotRect: plot } = layout;
|
|
209
|
+
ctx.strokeStyle = theme.axisLineColor;
|
|
210
|
+
ctx.lineWidth = 1;
|
|
211
|
+
ctx.beginPath();
|
|
212
|
+
ctx.moveTo(plot.x, plot.y);
|
|
213
|
+
ctx.lineTo(plot.x, plot.y + plot.height);
|
|
214
|
+
ctx.lineTo(plot.x + plot.width, plot.y + plot.height);
|
|
215
|
+
if (altDomain) {
|
|
216
|
+
if (isHorizontal) {
|
|
217
|
+
ctx.moveTo(plot.x, plot.y);
|
|
218
|
+
ctx.lineTo(plot.x + plot.width, plot.y);
|
|
219
|
+
} else {
|
|
220
|
+
ctx.moveTo(plot.x + plot.width, plot.y);
|
|
221
|
+
ctx.lineTo(plot.x + plot.width, plot.y + plot.height);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
ctx.stroke();
|
|
226
|
+
|
|
227
|
+
if (isHorizontal) {
|
|
228
|
+
if (catAxis.mode === "category") {
|
|
229
|
+
renderCategoricalYTicks(ctx, layout, catAxis.domain, theme);
|
|
230
|
+
} else {
|
|
231
|
+
drawNumericCategoryY(
|
|
232
|
+
ctx,
|
|
233
|
+
layout,
|
|
234
|
+
catAxis.domain,
|
|
235
|
+
catAxis.ticks,
|
|
236
|
+
theme,
|
|
237
|
+
formatters.category,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
drawNumericXAxis(
|
|
242
|
+
ctx,
|
|
243
|
+
layout,
|
|
244
|
+
valueDomain,
|
|
245
|
+
valueTicks,
|
|
246
|
+
"bottom",
|
|
247
|
+
theme,
|
|
248
|
+
formatters.value,
|
|
249
|
+
);
|
|
250
|
+
if (altDomain && altTicks) {
|
|
251
|
+
const origMin = layout.paddedXMin;
|
|
252
|
+
const origMax = layout.paddedXMax;
|
|
253
|
+
layout.paddedXMin = altDomain.min;
|
|
254
|
+
layout.paddedXMax = altDomain.max;
|
|
255
|
+
drawNumericXAxis(
|
|
256
|
+
ctx,
|
|
257
|
+
layout,
|
|
258
|
+
altDomain,
|
|
259
|
+
altTicks,
|
|
260
|
+
"top",
|
|
261
|
+
theme,
|
|
262
|
+
formatters.alt,
|
|
263
|
+
);
|
|
264
|
+
layout.paddedXMin = origMin;
|
|
265
|
+
layout.paddedXMax = origMax;
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
if (catAxis.mode === "category") {
|
|
269
|
+
renderCategoricalXTicks(ctx, layout, catAxis.domain, theme);
|
|
270
|
+
} else {
|
|
271
|
+
drawNumericCategoryX(
|
|
272
|
+
ctx,
|
|
273
|
+
layout,
|
|
274
|
+
catAxis.domain,
|
|
275
|
+
catAxis.ticks,
|
|
276
|
+
theme,
|
|
277
|
+
formatters.category,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
drawYAxis(
|
|
282
|
+
ctx,
|
|
283
|
+
layout,
|
|
284
|
+
valueDomain,
|
|
285
|
+
valueTicks,
|
|
286
|
+
"left",
|
|
287
|
+
theme,
|
|
288
|
+
formatters.value,
|
|
289
|
+
);
|
|
290
|
+
if (altDomain && altTicks) {
|
|
291
|
+
const origMin = layout.paddedYMin;
|
|
292
|
+
const origMax = layout.paddedYMax;
|
|
293
|
+
layout.paddedYMin = altDomain.min;
|
|
294
|
+
layout.paddedYMax = altDomain.max;
|
|
295
|
+
drawYAxis(
|
|
296
|
+
ctx,
|
|
297
|
+
layout,
|
|
298
|
+
altDomain,
|
|
299
|
+
altTicks,
|
|
300
|
+
"right",
|
|
301
|
+
theme,
|
|
302
|
+
formatters.alt,
|
|
303
|
+
);
|
|
304
|
+
layout.paddedYMin = origMin;
|
|
305
|
+
layout.paddedYMax = origMax;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Render gridlines at the numeric axis ticks. In vertical bar charts
|
|
312
|
+
* the gridlines run horizontally at numeric Y ticks; in horizontal bar
|
|
313
|
+
* charts they run vertically at numeric X ticks.
|
|
314
|
+
*/
|
|
315
|
+
export function renderBarGridlines(
|
|
316
|
+
canvas: Canvas2D,
|
|
317
|
+
layout: PlotLayout,
|
|
318
|
+
valueTicks: number[],
|
|
319
|
+
theme: Theme,
|
|
320
|
+
dpr: number,
|
|
321
|
+
isHorizontal = false,
|
|
322
|
+
): void {
|
|
323
|
+
const ctx = initCanvas(canvas, layout, dpr);
|
|
324
|
+
if (!ctx) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
ctx.strokeStyle = theme.gridlineColor;
|
|
329
|
+
ctx.lineWidth = 1;
|
|
330
|
+
if (isHorizontal) {
|
|
331
|
+
drawGridlinesX(
|
|
332
|
+
ctx,
|
|
333
|
+
layout.plotRect,
|
|
334
|
+
valueTicks,
|
|
335
|
+
(v) => layout.dataToPixel(v, 0).px,
|
|
336
|
+
);
|
|
337
|
+
} else {
|
|
338
|
+
drawGridlinesY(
|
|
339
|
+
ctx,
|
|
340
|
+
layout.plotRect,
|
|
341
|
+
valueTicks,
|
|
342
|
+
(v) => layout.dataToPixel(0, v).py,
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
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 { Canvas2D, Context2D } from "../charts/canvas-types";
|
|
14
|
+
import type { PlotLayout } from "../layout/plot-layout";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Destructive per-frame canvas setup: resize to CSS pixels × DPR,
|
|
18
|
+
* clear, and return a DPR-scaled 2D context. Call this exactly once
|
|
19
|
+
* per canvas per frame — setting `canvas.width` / `canvas.height`
|
|
20
|
+
* always wipes the bitmap and resets the transform, so calling it in
|
|
21
|
+
* a per-facet loop wipes every previously-drawn facet.
|
|
22
|
+
*
|
|
23
|
+
* Faceted renderers call this once per frame and then
|
|
24
|
+
* {@link getScaledContext} per facet to obtain the same context
|
|
25
|
+
* without re-wiping.
|
|
26
|
+
*/
|
|
27
|
+
export function initCanvas(
|
|
28
|
+
canvas: Canvas2D,
|
|
29
|
+
layout: PlotLayout,
|
|
30
|
+
dpr: number,
|
|
31
|
+
): Context2D | null {
|
|
32
|
+
canvas.width = Math.round(layout.cssWidth * dpr);
|
|
33
|
+
canvas.height = Math.round(layout.cssHeight * dpr);
|
|
34
|
+
const ctx = canvas.getContext("2d") as Context2D;
|
|
35
|
+
if (!ctx) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ctx.scale(dpr, dpr);
|
|
40
|
+
ctx.clearRect(0, 0, layout.cssWidth, layout.cssHeight);
|
|
41
|
+
return ctx;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Non-destructive variant: returns the 2D context with its transform
|
|
46
|
+
* forced to `scale(dpr, dpr)` via `setTransform` (idempotent — no
|
|
47
|
+
* stacking). Assumes `initCanvas` was already called on this canvas
|
|
48
|
+
* this frame; does NOT resize or clear.
|
|
49
|
+
*
|
|
50
|
+
* Intended for per-facet render helpers that must not wipe the shared
|
|
51
|
+
* canvas bitmap mid-frame.
|
|
52
|
+
*/
|
|
53
|
+
export function getScaledContext(
|
|
54
|
+
canvas: Canvas2D,
|
|
55
|
+
dpr: number,
|
|
56
|
+
): Context2D | null {
|
|
57
|
+
const ctx = canvas.getContext("2d") as Context2D;
|
|
58
|
+
if (!ctx) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
63
|
+
return ctx;
|
|
64
|
+
}
|