@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.
Files changed (258) hide show
  1. package/LICENSE.md +193 -0
  2. package/dist/cdn/perspective-viewer-charts.js +3 -0
  3. package/dist/cdn/perspective-viewer-charts.js.map +7 -0
  4. package/dist/esm/axis/axis-primitives.d.ts +24 -0
  5. package/dist/esm/axis/bar-axis.d.ts +51 -0
  6. package/dist/esm/axis/canvas.d.ts +24 -0
  7. package/dist/esm/axis/categorical-axis-core.d.ts +42 -0
  8. package/dist/esm/axis/categorical-axis.d.ts +27 -0
  9. package/dist/esm/axis/facet-chrome.d.ts +13 -0
  10. package/dist/esm/axis/label-geometry.d.ts +41 -0
  11. package/dist/esm/axis/legend.d.ts +44 -0
  12. package/dist/esm/axis/numeric-axis.d.ts +20 -0
  13. package/dist/esm/charts/candlestick/candlestick-build.d.ts +129 -0
  14. package/dist/esm/charts/candlestick/candlestick-interact.d.ts +10 -0
  15. package/dist/esm/charts/candlestick/candlestick-render.d.ts +24 -0
  16. package/dist/esm/charts/candlestick/candlestick.d.ts +144 -0
  17. package/dist/esm/charts/candlestick/glyphs/draw-candlesticks.d.ts +36 -0
  18. package/dist/esm/charts/candlestick/glyphs/draw-ohlc.d.ts +33 -0
  19. package/dist/esm/charts/canvas-types.d.ts +15 -0
  20. package/dist/esm/charts/cartesian/cartesian-build.d.ts +14 -0
  21. package/dist/esm/charts/cartesian/cartesian-interact.d.ts +20 -0
  22. package/dist/esm/charts/cartesian/cartesian-render.d.ts +26 -0
  23. package/dist/esm/charts/cartesian/cartesian.d.ts +239 -0
  24. package/dist/esm/charts/cartesian/glyph.d.ts +53 -0
  25. package/dist/esm/charts/cartesian/glyphs/density.d.ts +142 -0
  26. package/dist/esm/charts/cartesian/glyphs/lines.d.ts +23 -0
  27. package/dist/esm/charts/cartesian/glyphs/points.d.ts +24 -0
  28. package/dist/esm/charts/cartesian/label-interner.d.ts +21 -0
  29. package/dist/esm/charts/cartesian/tooltip-lines.d.ts +11 -0
  30. package/dist/esm/charts/chart-base.d.ts +402 -0
  31. package/dist/esm/charts/chart.d.ts +338 -0
  32. package/dist/esm/charts/common/band-layout.d.ts +32 -0
  33. package/dist/esm/charts/common/categorical-y-chart.d.ts +53 -0
  34. package/dist/esm/charts/common/category-axis-resolver.d.ts +90 -0
  35. package/dist/esm/charts/common/chrome-cache.d.ts +18 -0
  36. package/dist/esm/charts/common/draw-tooltip-box.d.ts +9 -0
  37. package/dist/esm/charts/common/leaf-color.d.ts +33 -0
  38. package/dist/esm/charts/common/node-store.d.ts +81 -0
  39. package/dist/esm/charts/common/tree-chart.d.ts +48 -0
  40. package/dist/esm/charts/common/tree-chrome.d.ts +31 -0
  41. package/dist/esm/charts/common/tree-data.d.ts +54 -0
  42. package/dist/esm/charts/common/visible-extent.d.ts +51 -0
  43. package/dist/esm/charts/heatmap/heatmap-build.d.ts +86 -0
  44. package/dist/esm/charts/heatmap/heatmap-interact.d.ts +19 -0
  45. package/dist/esm/charts/heatmap/heatmap-render.d.ts +19 -0
  46. package/dist/esm/charts/heatmap/heatmap-y-axis.d.ts +46 -0
  47. package/dist/esm/charts/heatmap/heatmap.d.ts +117 -0
  48. package/dist/esm/charts/map/map.d.ts +67 -0
  49. package/dist/esm/charts/registry.d.ts +14 -0
  50. package/dist/esm/charts/series/glyphs/draw-areas.d.ts +30 -0
  51. package/dist/esm/charts/series/glyphs/draw-bars.d.ts +15 -0
  52. package/dist/esm/charts/series/glyphs/draw-lines.d.ts +34 -0
  53. package/dist/esm/charts/series/glyphs/draw-scatter.d.ts +33 -0
  54. package/dist/esm/charts/series/series-build.d.ts +228 -0
  55. package/dist/esm/charts/series/series-interact.d.ts +35 -0
  56. package/dist/esm/charts/series/series-render.d.ts +41 -0
  57. package/dist/esm/charts/series/series-type.d.ts +49 -0
  58. package/dist/esm/charts/series/series.d.ts +317 -0
  59. package/dist/esm/charts/sunburst/sunburst-interact.d.ts +7 -0
  60. package/dist/esm/charts/sunburst/sunburst-layout.d.ts +33 -0
  61. package/dist/esm/charts/sunburst/sunburst-render.d.ts +22 -0
  62. package/dist/esm/charts/sunburst/sunburst.d.ts +85 -0
  63. package/dist/esm/charts/treemap/treemap-interact.d.ts +12 -0
  64. package/dist/esm/charts/treemap/treemap-layout.d.ts +28 -0
  65. package/dist/esm/charts/treemap/treemap-render.d.ts +18 -0
  66. package/dist/esm/charts/treemap/treemap.d.ts +74 -0
  67. package/dist/esm/config.d.ts +27 -0
  68. package/dist/esm/data/lazy-row.d.ts +32 -0
  69. package/dist/esm/data/split-groups.d.ts +20 -0
  70. package/dist/esm/data/view-reader.d.ts +35 -0
  71. package/dist/esm/event-detail.d.ts +28 -0
  72. package/dist/esm/index.d.ts +3 -0
  73. package/dist/esm/interaction/hit-test.d.ts +30 -0
  74. package/dist/esm/interaction/host-sink-dom.d.ts +19 -0
  75. package/dist/esm/interaction/host-sink-message.d.ts +46 -0
  76. package/dist/esm/interaction/lazy-tooltip.d.ts +61 -0
  77. package/dist/esm/interaction/raw-event-forwarder.d.ts +27 -0
  78. package/dist/esm/interaction/spatial-grid.d.ts +15 -0
  79. package/dist/esm/interaction/tooltip-controller.d.ts +193 -0
  80. package/dist/esm/interaction/zoom-controller.d.ts +106 -0
  81. package/dist/esm/interaction/zoom-router.d.ts +48 -0
  82. package/dist/esm/layout/facet-grid.d.ts +126 -0
  83. package/dist/esm/layout/plot-layout.d.ts +104 -0
  84. package/dist/esm/layout/ticks.d.ts +17 -0
  85. package/dist/esm/map/mercator.d.ts +102 -0
  86. package/dist/esm/map/tile-cache.d.ts +38 -0
  87. package/dist/esm/map/tile-layer.d.ts +66 -0
  88. package/dist/esm/map/tile-loader.d.ts +52 -0
  89. package/dist/esm/map/tile-source.d.ts +66 -0
  90. package/dist/esm/perspective-viewer-charts.js +3 -0
  91. package/dist/esm/perspective-viewer-charts.js.map +7 -0
  92. package/dist/esm/plugin/charts.d.ts +40 -0
  93. package/dist/esm/plugin/plugin.d.ts +95 -0
  94. package/dist/esm/render/scheduler.d.ts +41 -0
  95. package/dist/esm/theme/gradient.d.ts +48 -0
  96. package/dist/esm/theme/palette.d.ts +13 -0
  97. package/dist/esm/theme/theme-snapshot.d.ts +7 -0
  98. package/dist/esm/theme/theme.d.ts +53 -0
  99. package/dist/esm/transport/protocol.d.ts +430 -0
  100. package/dist/esm/transport/renderer-transport.d.ts +201 -0
  101. package/dist/esm/utils/css.d.ts +1 -0
  102. package/dist/esm/utils/font-snapshot.d.ts +50 -0
  103. package/dist/esm/webgl/buffer-pool.d.ts +62 -0
  104. package/dist/esm/webgl/context-manager.d.ts +184 -0
  105. package/dist/esm/webgl/gradient-texture.d.ts +17 -0
  106. package/dist/esm/webgl/instanced-attrs.d.ts +44 -0
  107. package/dist/esm/webgl/plot-frame.d.ts +39 -0
  108. package/dist/esm/webgl/program-cache.d.ts +13 -0
  109. package/dist/esm/webgl/shader-manifest.d.ts +53 -0
  110. package/dist/esm/webgl/shader-registry.d.ts +22 -0
  111. package/dist/esm/worker/boot.d.ts +0 -0
  112. package/dist/esm/worker/dispatch.d.ts +9 -0
  113. package/dist/esm/worker/font-loader.d.ts +2 -0
  114. package/dist/esm/worker/renderer.worker.d.ts +115 -0
  115. package/dist/esm/worker/session-host.d.ts +26 -0
  116. package/package.json +47 -0
  117. package/src/css/perspective-viewer-charts.css +95 -0
  118. package/src/ts/axis/axis-primitives.ts +125 -0
  119. package/src/ts/axis/bar-axis.ts +345 -0
  120. package/src/ts/axis/canvas.ts +64 -0
  121. package/src/ts/axis/categorical-axis-core.ts +125 -0
  122. package/src/ts/axis/categorical-axis.ts +716 -0
  123. package/src/ts/axis/facet-chrome.ts +42 -0
  124. package/src/ts/axis/label-geometry.ts +188 -0
  125. package/src/ts/axis/legend.ts +218 -0
  126. package/src/ts/axis/numeric-axis.ts +353 -0
  127. package/src/ts/charts/candlestick/candlestick-build.ts +516 -0
  128. package/src/ts/charts/candlestick/candlestick-interact.ts +256 -0
  129. package/src/ts/charts/candlestick/candlestick-render.ts +387 -0
  130. package/src/ts/charts/candlestick/candlestick.ts +367 -0
  131. package/src/ts/charts/candlestick/glyphs/draw-candlesticks.ts +432 -0
  132. package/src/ts/charts/candlestick/glyphs/draw-ohlc.ts +317 -0
  133. package/src/ts/charts/canvas-types.ts +30 -0
  134. package/src/ts/charts/cartesian/cartesian-build.ts +616 -0
  135. package/src/ts/charts/cartesian/cartesian-interact.ts +355 -0
  136. package/src/ts/charts/cartesian/cartesian-render.ts +948 -0
  137. package/src/ts/charts/cartesian/cartesian.ts +469 -0
  138. package/src/ts/charts/cartesian/glyph.ts +81 -0
  139. package/src/ts/charts/cartesian/glyphs/density.ts +1263 -0
  140. package/src/ts/charts/cartesian/glyphs/lines.ts +320 -0
  141. package/src/ts/charts/cartesian/glyphs/points.ts +239 -0
  142. package/src/ts/charts/cartesian/label-interner.ts +56 -0
  143. package/src/ts/charts/cartesian/tooltip-lines.ts +80 -0
  144. package/src/ts/charts/chart-base.ts +840 -0
  145. package/src/ts/charts/chart.ts +427 -0
  146. package/src/ts/charts/common/band-layout.ts +63 -0
  147. package/src/ts/charts/common/categorical-y-chart.ts +81 -0
  148. package/src/ts/charts/common/category-axis-resolver.ts +314 -0
  149. package/src/ts/charts/common/chrome-cache.ts +79 -0
  150. package/src/ts/charts/common/draw-tooltip-box.ts +84 -0
  151. package/src/ts/charts/common/leaf-color.ts +92 -0
  152. package/src/ts/charts/common/node-store.ts +235 -0
  153. package/src/ts/charts/common/tree-chart.ts +76 -0
  154. package/src/ts/charts/common/tree-chrome.ts +123 -0
  155. package/src/ts/charts/common/tree-data.ts +623 -0
  156. package/src/ts/charts/common/visible-extent.ts +112 -0
  157. package/src/ts/charts/heatmap/heatmap-build.ts +426 -0
  158. package/src/ts/charts/heatmap/heatmap-interact.ts +274 -0
  159. package/src/ts/charts/heatmap/heatmap-render.ts +815 -0
  160. package/src/ts/charts/heatmap/heatmap-y-axis.ts +351 -0
  161. package/src/ts/charts/heatmap/heatmap.ts +368 -0
  162. package/src/ts/charts/map/map.ts +201 -0
  163. package/src/ts/charts/registry.ts +65 -0
  164. package/src/ts/charts/series/glyphs/draw-areas.ts +331 -0
  165. package/src/ts/charts/series/glyphs/draw-bars.ts +113 -0
  166. package/src/ts/charts/series/glyphs/draw-lines.ts +320 -0
  167. package/src/ts/charts/series/glyphs/draw-scatter.ts +328 -0
  168. package/src/ts/charts/series/series-build.ts +848 -0
  169. package/src/ts/charts/series/series-interact.ts +604 -0
  170. package/src/ts/charts/series/series-render.ts +1109 -0
  171. package/src/ts/charts/series/series-type.ts +99 -0
  172. package/src/ts/charts/series/series.ts +794 -0
  173. package/src/ts/charts/sunburst/sunburst-interact.ts +460 -0
  174. package/src/ts/charts/sunburst/sunburst-layout.ts +238 -0
  175. package/src/ts/charts/sunburst/sunburst-render.ts +887 -0
  176. package/src/ts/charts/sunburst/sunburst.ts +248 -0
  177. package/src/ts/charts/treemap/treemap-interact.ts +445 -0
  178. package/src/ts/charts/treemap/treemap-layout.ts +328 -0
  179. package/src/ts/charts/treemap/treemap-render.ts +886 -0
  180. package/src/ts/charts/treemap/treemap.ts +247 -0
  181. package/src/ts/config.ts +41 -0
  182. package/src/ts/data/lazy-row.ts +140 -0
  183. package/src/ts/data/split-groups.ts +97 -0
  184. package/src/ts/data/view-reader.ts +107 -0
  185. package/src/ts/event-detail.ts +44 -0
  186. package/src/ts/index.ts +53 -0
  187. package/src/ts/interaction/hit-test.ts +106 -0
  188. package/src/ts/interaction/host-sink-dom.ts +85 -0
  189. package/src/ts/interaction/host-sink-message.ts +75 -0
  190. package/src/ts/interaction/lazy-tooltip.ts +102 -0
  191. package/src/ts/interaction/raw-event-forwarder.ts +175 -0
  192. package/src/ts/interaction/spatial-grid.ts +100 -0
  193. package/src/ts/interaction/tooltip-controller.ts +407 -0
  194. package/src/ts/interaction/zoom-controller.ts +468 -0
  195. package/src/ts/interaction/zoom-router.ts +230 -0
  196. package/src/ts/layout/facet-grid.ts +346 -0
  197. package/src/ts/layout/plot-layout.ts +277 -0
  198. package/src/ts/layout/ticks.ts +168 -0
  199. package/src/ts/map/mercator.ts +204 -0
  200. package/src/ts/map/tile-cache.ts +96 -0
  201. package/src/ts/map/tile-layer.ts +382 -0
  202. package/src/ts/map/tile-loader.ts +143 -0
  203. package/src/ts/map/tile-source.ts +156 -0
  204. package/src/ts/plugin/charts.ts +286 -0
  205. package/src/ts/plugin/plugin.ts +668 -0
  206. package/src/ts/render/scheduler.ts +339 -0
  207. package/src/ts/shaders/area.frag.glsl +20 -0
  208. package/src/ts/shaders/area.vert.glsl +19 -0
  209. package/src/ts/shaders/bar.frag.glsl +25 -0
  210. package/src/ts/shaders/bar.vert.glsl +60 -0
  211. package/src/ts/shaders/candlestick-body.frag.glsl +19 -0
  212. package/src/ts/shaders/candlestick-body.vert.glsl +34 -0
  213. package/src/ts/shaders/density-extreme.frag.glsl +30 -0
  214. package/src/ts/shaders/density-mrt.frag.glsl +44 -0
  215. package/src/ts/shaders/density-mrt.vert.glsl +48 -0
  216. package/src/ts/shaders/density-resolve.frag.glsl +89 -0
  217. package/src/ts/shaders/density-resolve.vert.glsl +23 -0
  218. package/src/ts/shaders/density-splat.frag.glsl +34 -0
  219. package/src/ts/shaders/density-splat.vert.glsl +52 -0
  220. package/src/ts/shaders/gridline.frag.glsl +18 -0
  221. package/src/ts/shaders/gridline.vert.glsl +18 -0
  222. package/src/ts/shaders/heatmap.frag.glsl +23 -0
  223. package/src/ts/shaders/heatmap.vert.glsl +42 -0
  224. package/src/ts/shaders/line-uniform.frag.glsl +26 -0
  225. package/src/ts/shaders/line-uniform.vert.glsl +54 -0
  226. package/src/ts/shaders/line.frag.glsl +28 -0
  227. package/src/ts/shaders/line.vert.glsl +87 -0
  228. package/src/ts/shaders/scatter.frag.glsl +39 -0
  229. package/src/ts/shaders/scatter.vert.glsl +67 -0
  230. package/src/ts/shaders/sunburst-arc.frag.glsl +19 -0
  231. package/src/ts/shaders/sunburst-arc.vert.glsl +79 -0
  232. package/src/ts/shaders/tile.frag.glsl +27 -0
  233. package/src/ts/shaders/tile.vert.glsl +35 -0
  234. package/src/ts/shaders/treemap.frag.glsl +19 -0
  235. package/src/ts/shaders/treemap.vert.glsl +25 -0
  236. package/src/ts/shaders/y-scatter.frag.glsl +30 -0
  237. package/src/ts/shaders/y-scatter.vert.glsl +31 -0
  238. package/src/ts/theme/gradient.ts +312 -0
  239. package/src/ts/theme/palette.ts +64 -0
  240. package/src/ts/theme/theme-snapshot.ts +66 -0
  241. package/src/ts/theme/theme.ts +166 -0
  242. package/src/ts/transport/protocol.ts +497 -0
  243. package/src/ts/transport/renderer-transport.ts +788 -0
  244. package/src/ts/utils/css.ts +36 -0
  245. package/src/ts/utils/font-snapshot.ts +159 -0
  246. package/src/ts/webgl/buffer-pool.ts +163 -0
  247. package/src/ts/webgl/context-manager.ts +414 -0
  248. package/src/ts/webgl/gradient-texture.ts +84 -0
  249. package/src/ts/webgl/instanced-attrs.ts +139 -0
  250. package/src/ts/webgl/plot-frame.ts +91 -0
  251. package/src/ts/webgl/program-cache.ts +46 -0
  252. package/src/ts/webgl/shader-manifest.ts +148 -0
  253. package/src/ts/webgl/shader-registry.ts +97 -0
  254. package/src/ts/worker/boot.ts +22 -0
  255. package/src/ts/worker/dispatch.ts +99 -0
  256. package/src/ts/worker/font-loader.ts +89 -0
  257. package/src/ts/worker/renderer.worker.ts +734 -0
  258. 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
+ }