@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,36 @@
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
+ export function parseCSSColorToVec3(
14
+ colorStr: string,
15
+ ): [number, number, number] {
16
+ const s = colorStr.trim();
17
+ if (s.startsWith("#")) {
18
+ let hex = s.slice(1);
19
+ if (hex.length === 3) {
20
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
21
+ }
22
+
23
+ return [
24
+ parseInt(hex.slice(0, 2), 16) / 255,
25
+ parseInt(hex.slice(2, 4), 16) / 255,
26
+ parseInt(hex.slice(4, 6), 16) / 255,
27
+ ];
28
+ }
29
+
30
+ const m = s.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
31
+ if (m) {
32
+ return [+m[1] / 255, +m[2] / 255, +m[3] / 255];
33
+ }
34
+
35
+ return [0.5, 0.5, 0.5];
36
+ }
@@ -0,0 +1,159 @@
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 { FontFaceDescriptor } from "../transport/protocol";
14
+
15
+ /**
16
+ * Walk every accessible `@font-face` rule in the document and collect a
17
+ * descriptor list ready for forwarding to a Web Worker, where each
18
+ * entry is reconstituted via `new FontFace(family, src, descriptors)`
19
+ * and registered in the worker's own `self.fonts` set.
20
+ *
21
+ * Background: a `Worker` has its own `FontFaceSet` distinct from the
22
+ * document's. Fonts loaded into `document.fonts` (by `<link>`,
23
+ * `@font-face`, or programmatic `FontFace`) are *not* visible to the
24
+ * worker — Canvas2D `ctx.font` lookups inside the worker fall back to
25
+ * the platform default if the family isn't in `self.fonts`. This
26
+ * helper bridges that gap for the in-CSS case.
27
+ *
28
+ * # CORS / security caveats
29
+ *
30
+ * 1. **Cross-origin stylesheets without permissive CORS** throw
31
+ * `SecurityError` on `cssRules` access, and we silently skip them.
32
+ * Their `@font-face` rules are unreachable to JS regardless of
33
+ * where the worker would re-load them, so this is the same
34
+ * fundamental limitation the document itself has.
35
+ *
36
+ * 2. **Font URLs are absolutized against the parent stylesheet's
37
+ * `href`** before forwarding. The worker's own script URL is a
38
+ * Blob URL produced by `WorkerPlugin`, so relative URLs in the raw
39
+ * `src:` declaration would resolve against the Blob origin (i.e.
40
+ * fail). Callers should treat the absolute URLs as the canonical
41
+ * source.
42
+ *
43
+ * 3. **The actual font fetch issued by `face.load()` in the worker
44
+ * is a fresh cross-origin request from the worker scope.** The
45
+ * font server must respond with `Access-Control-Allow-Origin`
46
+ * (e.g. `*` or the page origin) and an appropriate
47
+ * `Access-Control-Allow-Headers` policy if any non-simple headers
48
+ * are involved. A "no-cors" / opaque response is *not* usable
49
+ * here: `FontFace.load()` rejects on opaque responses, and even
50
+ * if it didn't, painted glyphs would taint the canvas and break
51
+ * `getImageData`. Same-origin fonts (including `data:` URIs)
52
+ * sidestep this entirely.
53
+ *
54
+ * 4. **Programmatic fonts** (e.g. `document.fonts.add(new
55
+ * FontFace(name, source))`) are *not* captured by this walker —
56
+ * they don't appear in any stylesheet's `cssRules`. Iterating
57
+ * `document.fonts` directly would catch them, but `FontFace`
58
+ * instances don't expose their source URL or buffer post-
59
+ * construction, so there's no public path to forward them. If a
60
+ * test or app needs that, it must register the same fonts in the
61
+ * worker explicitly.
62
+ */
63
+ export function snapshotFontFaces(): FontFaceDescriptor[] {
64
+ const out: FontFaceDescriptor[] = [];
65
+ for (const sheet of Array.from(document.styleSheets)) {
66
+ let rules: CSSRuleList;
67
+ try {
68
+ rules = sheet.cssRules;
69
+ } catch {
70
+ // Cross-origin stylesheet without permissive CORS — its
71
+ // `@font-face` rules are unreachable to JS. See caveat (1).
72
+ continue;
73
+ }
74
+
75
+ const base = sheet.href ?? document.baseURI;
76
+ for (const rule of Array.from(rules)) {
77
+ if (!(rule instanceof CSSFontFaceRule)) {
78
+ continue;
79
+ }
80
+
81
+ const style = rule.style;
82
+ const rawFamily = style.getPropertyValue("font-family").trim();
83
+ const rawSrc = style.getPropertyValue("src").trim();
84
+ if (!rawFamily || !rawSrc) {
85
+ continue;
86
+ }
87
+
88
+ out.push({
89
+ // CSSOM serializes multi-word family names with their
90
+ // CSS quotes preserved (e.g. `"Roboto Mono"`). The
91
+ // `FontFace` constructor *doesn't* unquote on parse —
92
+ // Chromium stores the literal input and re-quotes /
93
+ // escapes on `face.family` getter access, yielding
94
+ // `"\"Roboto Mono\""` and a name that no `ctx.font`
95
+ // lookup can match. Strip one layer of matching outer
96
+ // quotes here so the worker's font set keys align
97
+ // with how Canvas2D resolves family names.
98
+ family: stripOuterQuotes(rawFamily),
99
+ src: resolveSrcUrls(rawSrc, base),
100
+ style: optional(style, "font-style"),
101
+ weight: optional(style, "font-weight"),
102
+ stretch: optional(style, "font-stretch"),
103
+ unicodeRange: optional(style, "unicode-range"),
104
+ variant: optional(style, "font-variant"),
105
+ featureSettings: optional(style, "font-feature-settings"),
106
+ display: optional(style, "font-display"),
107
+ });
108
+ }
109
+ }
110
+
111
+ return out;
112
+ }
113
+
114
+ function optional(
115
+ style: CSSStyleDeclaration,
116
+ prop: string,
117
+ ): string | undefined {
118
+ const v = style.getPropertyValue(prop).trim();
119
+ return v || undefined;
120
+ }
121
+
122
+ /**
123
+ * Remove a single matching pair of outer `"…"` or `'…'` quotes from a
124
+ * family name. CSSOM serializes multi-word `font-family` descriptor
125
+ * values with their quotes preserved; `FontFace` then re-quotes on
126
+ * serialization, producing the literal `"\"Foo\""` double-quoting
127
+ * observed in `face.family`. Stripping one layer here aligns the
128
+ * stored family with what Canvas2D resolves at render time.
129
+ */
130
+ function stripOuterQuotes(s: string): string {
131
+ if (s.length >= 2) {
132
+ const first = s.charCodeAt(0);
133
+ const last = s.charCodeAt(s.length - 1);
134
+ if (first === last && (first === 0x22 || first === 0x27)) {
135
+ return s.slice(1, -1);
136
+ }
137
+ }
138
+
139
+ return s;
140
+ }
141
+
142
+ /**
143
+ * Rewrite every `url(...)` token inside a CSS `src:` value to its
144
+ * absolute form. Multi-source declarations (`url(...) format(...),
145
+ * url(...) format(...)`) are handled by replacing each `url(...)`
146
+ * chunk independently. See caveat (2).
147
+ */
148
+ function resolveSrcUrls(src: string, base: string): string {
149
+ return src.replace(
150
+ /url\(\s*(['"]?)([^'")]+)\1\s*\)/g,
151
+ (match, _quote, url) => {
152
+ try {
153
+ return `url(${new URL(url, base).href})`;
154
+ } catch {
155
+ return match;
156
+ }
157
+ },
158
+ );
159
+ }
@@ -0,0 +1,163 @@
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 { BUFFER_POOL_STRICT } from "../config";
14
+
15
+ type GL = WebGL2RenderingContext | WebGLRenderingContext;
16
+
17
+ export interface ManagedBuffer {
18
+ buffer: WebGLBuffer;
19
+ byteCapacity: number;
20
+ }
21
+
22
+ export class BufferPool {
23
+ private _gl: GL;
24
+ private _buffers: Map<string, ManagedBuffer> = new Map();
25
+ private _totalCapacity = 0;
26
+ private _maxCapacity = 0;
27
+
28
+ constructor(gl: GL) {
29
+ this._gl = gl;
30
+ }
31
+
32
+ get totalCapacity(): number {
33
+ return this._totalCapacity;
34
+ }
35
+
36
+ get maxCapacity() {
37
+ return this._maxCapacity;
38
+ }
39
+
40
+ set maxCapacity(cap: number) {
41
+ this._maxCapacity = cap;
42
+ }
43
+
44
+ ensureCapacity(totalRows: number): void {
45
+ this._totalCapacity =
46
+ this._maxCapacity > 0
47
+ ? Math.min(totalRows, this._maxCapacity)
48
+ : totalRows;
49
+ }
50
+
51
+ /**
52
+ * Read-only lookup by name. Returns the existing managed buffer, or
53
+ * `undefined` if no buffer has been allocated under that name yet.
54
+ *
55
+ * Render-path callers that bind buffers for `drawArrays` /
56
+ * `drawArraysInstanced` MUST use this rather than `getOrCreate`:
57
+ * the latter recreates (zero-initialized) when `_totalCapacity` has
58
+ * grown past the current `byteCapacity`. That recreate is desired
59
+ * during `upload` (where `bufferSubData` immediately writes the
60
+ * actual data) but catastrophic during render — it wipes the
61
+ * previous draw's vertex data, leaving `drawArrays` to issue
62
+ * against zeros and produce no visible glyphs (a one-frame blank
63
+ * plot area while gridlines/chrome remain correct).
64
+ *
65
+ * Specifically, `ensureBufferCapacity(totalRows)` from a pending
66
+ * draw updates `_totalCapacity` *before* its matching `uploadChunk`
67
+ * has run; a pan/zoom-induced render landing in that window would
68
+ * otherwise see `requiredBytes > byteCapacity` and recreate.
69
+ */
70
+ peek(name: string): ManagedBuffer | undefined {
71
+ return this._buffers.get(name);
72
+ }
73
+
74
+ getOrCreate(
75
+ name: string,
76
+ componentsPerVertex: number,
77
+ bytesPerElement: number,
78
+ ): ManagedBuffer {
79
+ const requiredBytes =
80
+ this._totalCapacity * componentsPerVertex * bytesPerElement;
81
+ let managed = this._buffers.get(name);
82
+ if (managed && managed.byteCapacity >= requiredBytes) {
83
+ return managed;
84
+ }
85
+
86
+ const gl = this._gl;
87
+ if (managed) {
88
+ gl.deleteBuffer(managed.buffer);
89
+ }
90
+
91
+ const buffer = gl.createBuffer()!;
92
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
93
+ gl.bufferData(gl.ARRAY_BUFFER, requiredBytes, gl.DYNAMIC_DRAW);
94
+
95
+ managed = { buffer, byteCapacity: requiredBytes };
96
+ this._buffers.set(name, managed);
97
+ return managed;
98
+ }
99
+
100
+ /**
101
+ * Upload `data` into the named GPU buffer at `byteOffset`. The
102
+ * buffer is sized lazily by `getOrCreate` to
103
+ * `_totalCapacity × componentsPerVertex × data.BYTES_PER_ELEMENT`.
104
+ * Callers MUST keep `byteOffset + data.byteLength` within that
105
+ * capacity — `bufferSubData` raises `INVALID_VALUE` on overflow
106
+ * and the upload is silently dropped at the GL layer.
107
+ *
108
+ * Common pitfall: passing a module-level scratch typed array whose
109
+ * `length` exceeds the current frame's valid-data count. Scratch
110
+ * buffers in chart impls grow monotonically across frames; the
111
+ * GPU buffer is sized to the *current* `_totalCapacity`. After a
112
+ * renderer-session reset (e.g. plugin disconnect/reconnect) the
113
+ * GPU buffer is fresh while the scratch retains its historical-
114
+ * peak length, and the upload writes past the buffer end. Always
115
+ * pass `data.subarray(0, n × componentsPerVertex)` when uploading
116
+ * from a scratch.
117
+ *
118
+ * Set `BUFFER_POOL_STRICT = true` in `config.ts` to convert
119
+ * overflows from opaque GL errors into descriptive throws at the
120
+ * offending stack frame.
121
+ */
122
+ upload(
123
+ name: string,
124
+ data: Float32Array | Int32Array,
125
+ byteOffset: number,
126
+ componentsPerVertex: number = 1,
127
+ ): WebGLBuffer {
128
+ const gl = this._gl;
129
+ const managed = this.getOrCreate(
130
+ name,
131
+ componentsPerVertex,
132
+ data.BYTES_PER_ELEMENT,
133
+ );
134
+
135
+ if (BUFFER_POOL_STRICT) {
136
+ const writeEnd = byteOffset + data.byteLength;
137
+ if (writeEnd > managed.byteCapacity) {
138
+ throw new Error(
139
+ `BufferPool.upload("${name}"): write ${byteOffset}..${writeEnd} ` +
140
+ `exceeds capacity ${managed.byteCapacity} ` +
141
+ `(_totalCapacity=${this._totalCapacity}, ` +
142
+ `components=${componentsPerVertex}, ` +
143
+ `bytes=${data.BYTES_PER_ELEMENT}). ` +
144
+ `Did you pass the full scratch buffer instead of a subarray(0, n)?`,
145
+ );
146
+ }
147
+ }
148
+
149
+ gl.bindBuffer(gl.ARRAY_BUFFER, managed.buffer);
150
+ gl.bufferSubData(gl.ARRAY_BUFFER, byteOffset, data);
151
+
152
+ return managed.buffer;
153
+ }
154
+
155
+ releaseAll(): void {
156
+ for (const managed of this._buffers.values()) {
157
+ this._gl.deleteBuffer(managed.buffer);
158
+ }
159
+
160
+ this._buffers.clear();
161
+ this._totalCapacity = 0;
162
+ }
163
+ }