@voila.dev/chart 4.0.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 (377) hide show
  1. package/README.md +85 -0
  2. package/dist/brush/brush-layer.d.ts +16 -0
  3. package/dist/brush/brush-layer.d.ts.map +1 -0
  4. package/dist/brush/brush-layer.js +137 -0
  5. package/dist/brush/brush-layer.js.map +7 -0
  6. package/dist/brush/index.d.ts +10 -0
  7. package/dist/brush/index.d.ts.map +1 -0
  8. package/dist/brush/index.js +8 -0
  9. package/dist/brush/index.js.map +7 -0
  10. package/dist/canvas/canvas-renderer.d.ts +11 -0
  11. package/dist/canvas/canvas-renderer.d.ts.map +1 -0
  12. package/dist/canvas/canvas-renderer.js +49 -0
  13. package/dist/canvas/canvas-renderer.js.map +7 -0
  14. package/dist/canvas/index.d.ts +2 -0
  15. package/dist/canvas/index.d.ts.map +1 -0
  16. package/dist/canvas/index.js +5 -0
  17. package/dist/canvas/index.js.map +7 -0
  18. package/dist/canvas/paint-scene.d.ts +4 -0
  19. package/dist/canvas/paint-scene.d.ts.map +1 -0
  20. package/dist/canvas/paint-scene.js +130 -0
  21. package/dist/canvas/paint-scene.js.map +7 -0
  22. package/dist/canvas/resolve-color.d.ts +18 -0
  23. package/dist/canvas/resolve-color.d.ts.map +1 -0
  24. package/dist/canvas/resolve-color.js +52 -0
  25. package/dist/canvas/resolve-color.js.map +7 -0
  26. package/dist/contour/density.d.ts +20 -0
  27. package/dist/contour/density.d.ts.map +1 -0
  28. package/dist/contour/density.js +59 -0
  29. package/dist/contour/density.js.map +7 -0
  30. package/dist/contour/index.d.ts +2 -0
  31. package/dist/contour/index.d.ts.map +1 -0
  32. package/dist/contour/index.js +5 -0
  33. package/dist/contour/index.js.map +7 -0
  34. package/dist/core/channel.d.ts +11 -0
  35. package/dist/core/channel.d.ts.map +1 -0
  36. package/dist/core/channel.js +44 -0
  37. package/dist/core/channel.js.map +7 -0
  38. package/dist/core/compile.d.ts +22 -0
  39. package/dist/core/compile.d.ts.map +1 -0
  40. package/dist/core/compile.js +295 -0
  41. package/dist/core/compile.js.map +7 -0
  42. package/dist/core/define-chart.d.ts +96 -0
  43. package/dist/core/define-chart.d.ts.map +1 -0
  44. package/dist/core/define-chart.js +7 -0
  45. package/dist/core/define-chart.js.map +7 -0
  46. package/dist/core/facet.d.ts +7 -0
  47. package/dist/core/facet.d.ts.map +1 -0
  48. package/dist/core/facet.js +134 -0
  49. package/dist/core/facet.js.map +7 -0
  50. package/dist/core/format.d.ts +37 -0
  51. package/dist/core/format.d.ts.map +1 -0
  52. package/dist/core/format.js +108 -0
  53. package/dist/core/format.js.map +7 -0
  54. package/dist/core/guides/axes.d.ts +25 -0
  55. package/dist/core/guides/axes.d.ts.map +1 -0
  56. package/dist/core/guides/axes.js +204 -0
  57. package/dist/core/guides/axes.js.map +7 -0
  58. package/dist/core/marks/area.d.ts +23 -0
  59. package/dist/core/marks/area.d.ts.map +1 -0
  60. package/dist/core/marks/area.js +187 -0
  61. package/dist/core/marks/area.js.map +7 -0
  62. package/dist/core/marks/bar.d.ts +26 -0
  63. package/dist/core/marks/bar.d.ts.map +1 -0
  64. package/dist/core/marks/bar.js +200 -0
  65. package/dist/core/marks/bar.js.map +7 -0
  66. package/dist/core/marks/cell.d.ts +16 -0
  67. package/dist/core/marks/cell.d.ts.map +1 -0
  68. package/dist/core/marks/cell.js +98 -0
  69. package/dist/core/marks/cell.js.map +7 -0
  70. package/dist/core/marks/dot.d.ts +17 -0
  71. package/dist/core/marks/dot.d.ts.map +1 -0
  72. package/dist/core/marks/dot.js +125 -0
  73. package/dist/core/marks/dot.js.map +7 -0
  74. package/dist/core/marks/funnel-layout.d.ts +37 -0
  75. package/dist/core/marks/funnel-layout.d.ts.map +1 -0
  76. package/dist/core/marks/funnel-layout.js +61 -0
  77. package/dist/core/marks/funnel-layout.js.map +7 -0
  78. package/dist/core/marks/funnel.d.ts +19 -0
  79. package/dist/core/marks/funnel.d.ts.map +1 -0
  80. package/dist/core/marks/funnel.js +143 -0
  81. package/dist/core/marks/funnel.js.map +7 -0
  82. package/dist/core/marks/line.d.ts +17 -0
  83. package/dist/core/marks/line.d.ts.map +1 -0
  84. package/dist/core/marks/line.js +150 -0
  85. package/dist/core/marks/line.js.map +7 -0
  86. package/dist/core/marks/polar.d.ts +61 -0
  87. package/dist/core/marks/polar.d.ts.map +1 -0
  88. package/dist/core/marks/polar.js +436 -0
  89. package/dist/core/marks/polar.js.map +7 -0
  90. package/dist/core/marks/rect.d.ts +22 -0
  91. package/dist/core/marks/rect.d.ts.map +1 -0
  92. package/dist/core/marks/rect.js +119 -0
  93. package/dist/core/marks/rect.js.map +7 -0
  94. package/dist/core/marks/rule.d.ts +17 -0
  95. package/dist/core/marks/rule.d.ts.map +1 -0
  96. package/dist/core/marks/rule.js +73 -0
  97. package/dist/core/marks/rule.js.map +7 -0
  98. package/dist/core/marks/shared.d.ts +41 -0
  99. package/dist/core/marks/shared.d.ts.map +1 -0
  100. package/dist/core/marks/shared.js +74 -0
  101. package/dist/core/marks/shared.js.map +7 -0
  102. package/dist/core/marks/stack.d.ts +13 -0
  103. package/dist/core/marks/stack.d.ts.map +1 -0
  104. package/dist/core/marks/stack.js +28 -0
  105. package/dist/core/marks/stack.js.map +7 -0
  106. package/dist/core/marks/stats/difference.d.ts +20 -0
  107. package/dist/core/marks/stats/difference.d.ts.map +1 -0
  108. package/dist/core/marks/stats/difference.js +168 -0
  109. package/dist/core/marks/stats/difference.js.map +7 -0
  110. package/dist/core/marks/stats/distribution.d.ts +41 -0
  111. package/dist/core/marks/stats/distribution.d.ts.map +1 -0
  112. package/dist/core/marks/stats/distribution.js +354 -0
  113. package/dist/core/marks/stats/distribution.js.map +7 -0
  114. package/dist/core/marks/stats/dodge.d.ts +16 -0
  115. package/dist/core/marks/stats/dodge.d.ts.map +1 -0
  116. package/dist/core/marks/stats/dodge.js +104 -0
  117. package/dist/core/marks/stats/dodge.js.map +7 -0
  118. package/dist/core/marks/stats/hexbin.d.ts +26 -0
  119. package/dist/core/marks/stats/hexbin.d.ts.map +1 -0
  120. package/dist/core/marks/stats/hexbin.js +113 -0
  121. package/dist/core/marks/stats/hexbin.js.map +7 -0
  122. package/dist/core/marks/stats/histogram.d.ts +27 -0
  123. package/dist/core/marks/stats/histogram.d.ts.map +1 -0
  124. package/dist/core/marks/stats/histogram.js +70 -0
  125. package/dist/core/marks/stats/histogram.js.map +7 -0
  126. package/dist/core/marks/stats/regression.d.ts +13 -0
  127. package/dist/core/marks/stats/regression.d.ts.map +1 -0
  128. package/dist/core/marks/stats/regression.js +80 -0
  129. package/dist/core/marks/stats/regression.js.map +7 -0
  130. package/dist/core/marks/stats/statistics.d.ts +34 -0
  131. package/dist/core/marks/stats/statistics.d.ts.map +1 -0
  132. package/dist/core/marks/stats/statistics.js +111 -0
  133. package/dist/core/marks/stats/statistics.js.map +7 -0
  134. package/dist/core/marks/stats/waffle.d.ts +18 -0
  135. package/dist/core/marks/stats/waffle.d.ts.map +1 -0
  136. package/dist/core/marks/stats/waffle.js +117 -0
  137. package/dist/core/marks/stats/waffle.js.map +7 -0
  138. package/dist/core/marks/text.d.ts +19 -0
  139. package/dist/core/marks/text.d.ts.map +1 -0
  140. package/dist/core/marks/text.js +60 -0
  141. package/dist/core/marks/text.js.map +7 -0
  142. package/dist/core/motion/tween.d.ts +6 -0
  143. package/dist/core/motion/tween.d.ts.map +1 -0
  144. package/dist/core/motion/tween.js +98 -0
  145. package/dist/core/motion/tween.js.map +7 -0
  146. package/dist/core/nearest.d.ts +25 -0
  147. package/dist/core/nearest.d.ts.map +1 -0
  148. package/dist/core/nearest.js +151 -0
  149. package/dist/core/nearest.js.map +7 -0
  150. package/dist/core/paths.d.ts +65 -0
  151. package/dist/core/paths.d.ts.map +1 -0
  152. package/dist/core/paths.js +192 -0
  153. package/dist/core/paths.js.map +7 -0
  154. package/dist/core/scales/color.d.ts +11 -0
  155. package/dist/core/scales/color.d.ts.map +1 -0
  156. package/dist/core/scales/color.js +35 -0
  157. package/dist/core/scales/color.js.map +7 -0
  158. package/dist/core/scales/continuous.d.ts +18 -0
  159. package/dist/core/scales/continuous.d.ts.map +1 -0
  160. package/dist/core/scales/continuous.js +82 -0
  161. package/dist/core/scales/continuous.js.map +7 -0
  162. package/dist/core/scales/discrete.d.ts +22 -0
  163. package/dist/core/scales/discrete.d.ts.map +1 -0
  164. package/dist/core/scales/discrete.js +103 -0
  165. package/dist/core/scales/discrete.js.map +7 -0
  166. package/dist/core/scales/resolve.d.ts +18 -0
  167. package/dist/core/scales/resolve.d.ts.map +1 -0
  168. package/dist/core/scales/resolve.js +112 -0
  169. package/dist/core/scales/resolve.js.map +7 -0
  170. package/dist/core/scales/time.d.ts +4 -0
  171. package/dist/core/scales/time.d.ts.map +1 -0
  172. package/dist/core/scales/time.js +140 -0
  173. package/dist/core/scales/time.js.map +7 -0
  174. package/dist/core/text.d.ts +3 -0
  175. package/dist/core/text.d.ts.map +1 -0
  176. package/dist/core/text.js +29 -0
  177. package/dist/core/text.js.map +7 -0
  178. package/dist/core/theme.d.ts +8 -0
  179. package/dist/core/theme.d.ts.map +1 -0
  180. package/dist/core/theme.js +21 -0
  181. package/dist/core/theme.js.map +7 -0
  182. package/dist/core/ticks.d.ts +27 -0
  183. package/dist/core/ticks.d.ts.map +1 -0
  184. package/dist/core/ticks.js +76 -0
  185. package/dist/core/ticks.js.map +7 -0
  186. package/dist/core/types.d.ts +305 -0
  187. package/dist/core/types.d.ts.map +1 -0
  188. package/dist/core/types.js +1 -0
  189. package/dist/core/types.js.map +7 -0
  190. package/dist/force/force.d.ts +30 -0
  191. package/dist/force/force.d.ts.map +1 -0
  192. package/dist/force/force.js +143 -0
  193. package/dist/force/force.js.map +7 -0
  194. package/dist/force/index.d.ts +2 -0
  195. package/dist/force/index.d.ts.map +1 -0
  196. package/dist/force/index.js +7 -0
  197. package/dist/force/index.js.map +7 -0
  198. package/dist/geo/geo.d.ts +59 -0
  199. package/dist/geo/geo.d.ts.map +1 -0
  200. package/dist/geo/geo.js +231 -0
  201. package/dist/geo/geo.js.map +7 -0
  202. package/dist/geo/index.d.ts +2 -0
  203. package/dist/geo/index.d.ts.map +1 -0
  204. package/dist/geo/index.js +13 -0
  205. package/dist/geo/index.js.map +7 -0
  206. package/dist/hierarchy/hierarchy.d.ts +24 -0
  207. package/dist/hierarchy/hierarchy.d.ts.map +1 -0
  208. package/dist/hierarchy/hierarchy.js +279 -0
  209. package/dist/hierarchy/hierarchy.js.map +7 -0
  210. package/dist/hierarchy/index.d.ts +2 -0
  211. package/dist/hierarchy/index.d.ts.map +1 -0
  212. package/dist/hierarchy/index.js +11 -0
  213. package/dist/hierarchy/index.js.map +7 -0
  214. package/dist/index.d.ts +29 -0
  215. package/dist/index.d.ts.map +1 -0
  216. package/dist/index.js +96 -0
  217. package/dist/index.js.map +7 -0
  218. package/dist/react/brush-contract.d.ts +23 -0
  219. package/dist/react/brush-contract.d.ts.map +1 -0
  220. package/dist/react/brush-contract.js +7 -0
  221. package/dist/react/brush-contract.js.map +7 -0
  222. package/dist/react/chart-data-table.d.ts +18 -0
  223. package/dist/react/chart-data-table.d.ts.map +1 -0
  224. package/dist/react/chart-data-table.js +55 -0
  225. package/dist/react/chart-data-table.js.map +7 -0
  226. package/dist/react/chart-legend.d.ts +17 -0
  227. package/dist/react/chart-legend.d.ts.map +1 -0
  228. package/dist/react/chart-legend.js +126 -0
  229. package/dist/react/chart-legend.js.map +7 -0
  230. package/dist/react/chart-tooltip.d.ts +18 -0
  231. package/dist/react/chart-tooltip.d.ts.map +1 -0
  232. package/dist/react/chart-tooltip.js +95 -0
  233. package/dist/react/chart-tooltip.js.map +7 -0
  234. package/dist/react/chart.d.ts +45 -0
  235. package/dist/react/chart.d.ts.map +1 -0
  236. package/dist/react/chart.js +383 -0
  237. package/dist/react/chart.js.map +7 -0
  238. package/dist/react/focus-overlay.d.ts +14 -0
  239. package/dist/react/focus-overlay.d.ts.map +1 -0
  240. package/dist/react/focus-overlay.js +147 -0
  241. package/dist/react/focus-overlay.js.map +7 -0
  242. package/dist/react/index.d.ts +7 -0
  243. package/dist/react/index.d.ts.map +1 -0
  244. package/dist/react/index.js +11 -0
  245. package/dist/react/index.js.map +7 -0
  246. package/dist/react/messages.d.ts +16 -0
  247. package/dist/react/messages.d.ts.map +1 -0
  248. package/dist/react/messages.js +33 -0
  249. package/dist/react/messages.js.map +7 -0
  250. package/dist/react/renderer.d.ts +14 -0
  251. package/dist/react/renderer.d.ts.map +1 -0
  252. package/dist/react/renderer.js +1 -0
  253. package/dist/react/renderer.js.map +7 -0
  254. package/dist/react/sr-only.d.ts +4 -0
  255. package/dist/react/sr-only.d.ts.map +1 -0
  256. package/dist/react/sr-only.js +15 -0
  257. package/dist/react/sr-only.js.map +7 -0
  258. package/dist/react/svg-renderer.d.ts +4 -0
  259. package/dist/react/svg-renderer.d.ts.map +1 -0
  260. package/dist/react/svg-renderer.js +20 -0
  261. package/dist/react/svg-renderer.js.map +7 -0
  262. package/dist/react/svg-scene.d.ts +8 -0
  263. package/dist/react/svg-scene.d.ts.map +1 -0
  264. package/dist/react/svg-scene.js +121 -0
  265. package/dist/react/svg-scene.js.map +7 -0
  266. package/dist/react/use-animated-scene.d.ts +10 -0
  267. package/dist/react/use-animated-scene.d.ts.map +1 -0
  268. package/dist/react/use-animated-scene.js +41 -0
  269. package/dist/react/use-animated-scene.js.map +7 -0
  270. package/dist/react/use-chart-focus.d.ts +29 -0
  271. package/dist/react/use-chart-focus.d.ts.map +1 -0
  272. package/dist/react/use-chart-focus.js +180 -0
  273. package/dist/react/use-chart-focus.js.map +7 -0
  274. package/dist/react/use-chart-width.d.ts +12 -0
  275. package/dist/react/use-chart-width.d.ts.map +1 -0
  276. package/dist/react/use-chart-width.js +23 -0
  277. package/dist/react/use-chart-width.js.map +7 -0
  278. package/dist/react/use-chart-zoom.d.ts +13 -0
  279. package/dist/react/use-chart-zoom.d.ts.map +1 -0
  280. package/dist/react/use-chart-zoom.js +52 -0
  281. package/dist/react/use-chart-zoom.js.map +7 -0
  282. package/dist/react/use-text-measurer.d.ts +8 -0
  283. package/dist/react/use-text-measurer.d.ts.map +1 -0
  284. package/dist/react/use-text-measurer.js +44 -0
  285. package/dist/react/use-text-measurer.js.map +7 -0
  286. package/dist/sankey/index.d.ts +2 -0
  287. package/dist/sankey/index.d.ts.map +1 -0
  288. package/dist/sankey/index.js +7 -0
  289. package/dist/sankey/index.js.map +7 -0
  290. package/dist/sankey/sankey.d.ts +29 -0
  291. package/dist/sankey/sankey.d.ts.map +1 -0
  292. package/dist/sankey/sankey.js +127 -0
  293. package/dist/sankey/sankey.js.map +7 -0
  294. package/dist/voronoi/index.d.ts +2 -0
  295. package/dist/voronoi/index.d.ts.map +1 -0
  296. package/dist/voronoi/index.js +5 -0
  297. package/dist/voronoi/index.js.map +7 -0
  298. package/dist/voronoi/voronoi.d.ts +16 -0
  299. package/dist/voronoi/voronoi.d.ts.map +1 -0
  300. package/dist/voronoi/voronoi.js +62 -0
  301. package/dist/voronoi/voronoi.js.map +7 -0
  302. package/package.json +74 -0
  303. package/src/brush/brush-layer.tsx +174 -0
  304. package/src/brush/index.ts +14 -0
  305. package/src/canvas/canvas-renderer.tsx +56 -0
  306. package/src/canvas/index.ts +1 -0
  307. package/src/canvas/paint-scene.ts +152 -0
  308. package/src/canvas/resolve-color.ts +65 -0
  309. package/src/contour/density.ts +90 -0
  310. package/src/contour/index.ts +1 -0
  311. package/src/core/channel.ts +53 -0
  312. package/src/core/compile.ts +436 -0
  313. package/src/core/define-chart.ts +128 -0
  314. package/src/core/facet.ts +189 -0
  315. package/src/core/format.ts +163 -0
  316. package/src/core/guides/axes.ts +283 -0
  317. package/src/core/marks/area.ts +238 -0
  318. package/src/core/marks/bar.ts +278 -0
  319. package/src/core/marks/cell.ts +123 -0
  320. package/src/core/marks/dot.ts +157 -0
  321. package/src/core/marks/funnel-layout.ts +113 -0
  322. package/src/core/marks/funnel.ts +172 -0
  323. package/src/core/marks/line.ts +206 -0
  324. package/src/core/marks/polar.ts +568 -0
  325. package/src/core/marks/rect.ts +156 -0
  326. package/src/core/marks/rule.ts +104 -0
  327. package/src/core/marks/shared.ts +134 -0
  328. package/src/core/marks/stack.ts +42 -0
  329. package/src/core/marks/stats/difference.ts +205 -0
  330. package/src/core/marks/stats/distribution.ts +425 -0
  331. package/src/core/marks/stats/dodge.ts +136 -0
  332. package/src/core/marks/stats/hexbin.ts +152 -0
  333. package/src/core/marks/stats/histogram.ts +108 -0
  334. package/src/core/marks/stats/regression.ts +108 -0
  335. package/src/core/marks/stats/statistics.ts +153 -0
  336. package/src/core/marks/stats/waffle.ts +141 -0
  337. package/src/core/marks/text.ts +97 -0
  338. package/src/core/motion/tween.ts +131 -0
  339. package/src/core/nearest.ts +223 -0
  340. package/src/core/paths.ts +323 -0
  341. package/src/core/scales/color.ts +51 -0
  342. package/src/core/scales/continuous.ts +111 -0
  343. package/src/core/scales/discrete.ts +156 -0
  344. package/src/core/scales/resolve.ts +158 -0
  345. package/src/core/scales/time.ts +180 -0
  346. package/src/core/text.ts +42 -0
  347. package/src/core/theme.ts +26 -0
  348. package/src/core/ticks.ts +118 -0
  349. package/src/core/types.ts +358 -0
  350. package/src/force/force.ts +200 -0
  351. package/src/force/index.ts +6 -0
  352. package/src/geo/geo.ts +346 -0
  353. package/src/geo/index.ts +10 -0
  354. package/src/hierarchy/hierarchy.ts +377 -0
  355. package/src/hierarchy/index.ts +6 -0
  356. package/src/index.ts +70 -0
  357. package/src/react/brush-contract.ts +35 -0
  358. package/src/react/chart-data-table.tsx +98 -0
  359. package/src/react/chart-legend.tsx +130 -0
  360. package/src/react/chart-tooltip.tsx +111 -0
  361. package/src/react/chart.tsx +489 -0
  362. package/src/react/focus-overlay.tsx +164 -0
  363. package/src/react/index.ts +9 -0
  364. package/src/react/messages.ts +49 -0
  365. package/src/react/renderer.ts +15 -0
  366. package/src/react/sr-only.ts +14 -0
  367. package/src/react/svg-renderer.tsx +18 -0
  368. package/src/react/svg-scene.tsx +146 -0
  369. package/src/react/use-animated-scene.ts +57 -0
  370. package/src/react/use-chart-focus.ts +245 -0
  371. package/src/react/use-chart-width.ts +27 -0
  372. package/src/react/use-chart-zoom.ts +67 -0
  373. package/src/react/use-text-measurer.ts +49 -0
  374. package/src/sankey/index.ts +6 -0
  375. package/src/sankey/sankey.ts +179 -0
  376. package/src/voronoi/index.ts +1 -0
  377. package/src/voronoi/voronoi.ts +84 -0
@@ -0,0 +1,17 @@
1
+ import type { ChartAccessor, ChartMark, ChartValue } from "../types.js";
2
+ export interface RuleOptions<TDatum> {
3
+ readonly id?: string;
4
+ /** The value of each rule. Defaults to the datum itself, so `ruleY([0])` works. */
5
+ readonly value?: ChartAccessor<TDatum, ChartValue>;
6
+ readonly stroke?: string;
7
+ readonly strokeWidth?: number;
8
+ readonly strokeDasharray?: string;
9
+ readonly opacity?: number;
10
+ /** Text written at the end of the rule: "Objectif", "Moyenne". */
11
+ readonly label?: string;
12
+ }
13
+ /** Horizontal rules at y values: a baseline, a target, an average. */
14
+ export declare function ruleY<TDatum>(data: ReadonlyArray<TDatum>, options?: RuleOptions<TDatum>): ChartMark;
15
+ /** Vertical rules at x values: a date, a threshold. */
16
+ export declare function ruleX<TDatum>(data: ReadonlyArray<TDatum>, options?: RuleOptions<TDatum>): ChartMark;
17
+ //# sourceMappingURL=rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/core/marks/rule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EACT,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAsED,sEAAsE;AACtE,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX;AAED,uDAAuD;AACvD,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX"}
@@ -0,0 +1,73 @@
1
+ import { isPlaceable, readChannel } from "../channel.js";
2
+ import { markId, paint, valueOn } from "./shared.js";
3
+ const LABEL_GAP = 4;
4
+ function ruleMark(kind, data, options) {
5
+ const horizontal = kind === "ruleY";
6
+ const values = readChannel(
7
+ data,
8
+ options.value ?? ((datum) => datum)
9
+ );
10
+ const channel = { values: values.filter(isPlaceable) };
11
+ return {
12
+ id: options.id,
13
+ coordinate: "cartesian",
14
+ channels: horizontal ? { y: channel } : { x: channel },
15
+ render(context) {
16
+ const id = markId(options.id, kind, context);
17
+ const scale = horizontal ? context.scales.y : context.scales.x;
18
+ if (scale === void 0) {
19
+ return { nodes: [] };
20
+ }
21
+ const { plot, theme } = context;
22
+ const stroke = options.stroke ?? theme.foreground;
23
+ const nodes = [];
24
+ for (const [index, raw] of values.entries()) {
25
+ const value = valueOn(scale, raw);
26
+ if (value === void 0) {
27
+ continue;
28
+ }
29
+ const at = scale.center(value);
30
+ nodes.push({
31
+ kind: "line",
32
+ key: `${id}:${index}`,
33
+ role: "rule",
34
+ ...horizontal ? { x1: plot.x, y1: at, x2: plot.x + plot.width, y2: at } : { x1: at, y1: plot.y, x2: at, y2: plot.y + plot.height },
35
+ paint: paint({
36
+ stroke,
37
+ strokeWidth: options.strokeWidth ?? 1,
38
+ strokeDasharray: options.strokeDasharray,
39
+ opacity: options.opacity
40
+ })
41
+ });
42
+ if (options.label !== void 0) {
43
+ nodes.push({
44
+ kind: "text",
45
+ key: `${id}:label:${index}`,
46
+ role: "label",
47
+ x: horizontal ? plot.x + plot.width : at + LABEL_GAP,
48
+ y: horizontal ? at - LABEL_GAP : plot.y,
49
+ text: options.label,
50
+ paint: {
51
+ fill: stroke,
52
+ fontSize: theme.fontSize,
53
+ textAnchor: horizontal ? "end" : "start",
54
+ baseline: horizontal ? "bottom" : "top"
55
+ }
56
+ });
57
+ }
58
+ }
59
+ return { nodes };
60
+ }
61
+ };
62
+ }
63
+ function ruleY(data, options = {}) {
64
+ return ruleMark("ruleY", data, options);
65
+ }
66
+ function ruleX(data, options = {}) {
67
+ return ruleMark("ruleX", data, options);
68
+ }
69
+ export {
70
+ ruleX,
71
+ ruleY
72
+ };
73
+ //# sourceMappingURL=rule.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/marks/rule.ts"],
4
+ "sourcesContent": ["import { isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport { markId, paint, valueOn } from \"#/core/marks/shared.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface RuleOptions<TDatum> {\n\treadonly id?: string;\n\t/** The value of each rule. Defaults to the datum itself, so `ruleY([0])` works. */\n\treadonly value?: ChartAccessor<TDatum, ChartValue>;\n\treadonly stroke?: string;\n\treadonly strokeWidth?: number;\n\treadonly strokeDasharray?: string;\n\treadonly opacity?: number;\n\t/** Text written at the end of the rule: \"Objectif\", \"Moyenne\". */\n\treadonly label?: string;\n}\n\nconst LABEL_GAP = 4;\n\nfunction ruleMark<TDatum>(\n\tkind: \"ruleY\" | \"ruleX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RuleOptions<TDatum>,\n): ChartMark {\n\tconst horizontal = kind === \"ruleY\";\n\tconst values = readChannel(\n\t\tdata,\n\t\toptions.value ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t);\n\tconst channel = { values: values.filter(isPlaceable) };\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tchannels: horizontal ? { y: channel } : { x: channel },\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, kind, context);\n\t\t\tconst scale = horizontal ? context.scales.y : context.scales.x;\n\t\t\tif (scale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst { plot, theme } = context;\n\t\t\tconst stroke = options.stroke ?? theme.foreground;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tfor (const [index, raw] of values.entries()) {\n\t\t\t\tconst value = valueOn(scale, raw);\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst at = scale.center(value);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"line\",\n\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\trole: \"rule\",\n\t\t\t\t\t...(horizontal\n\t\t\t\t\t\t? { x1: plot.x, y1: at, x2: plot.x + plot.width, y2: at }\n\t\t\t\t\t\t: { x1: at, y1: plot.y, x2: at, y2: plot.y + plot.height }),\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tstroke,\n\t\t\t\t\t\tstrokeWidth: options.strokeWidth ?? 1,\n\t\t\t\t\t\tstrokeDasharray: options.strokeDasharray,\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tif (options.label !== undefined) {\n\t\t\t\t\tnodes.push({\n\t\t\t\t\t\tkind: \"text\",\n\t\t\t\t\t\tkey: `${id}:label:${index}`,\n\t\t\t\t\t\trole: \"label\",\n\t\t\t\t\t\tx: horizontal ? plot.x + plot.width : at + LABEL_GAP,\n\t\t\t\t\t\ty: horizontal ? at - LABEL_GAP : plot.y,\n\t\t\t\t\t\ttext: options.label,\n\t\t\t\t\t\tpaint: {\n\t\t\t\t\t\t\tfill: stroke,\n\t\t\t\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\t\t\t\ttextAnchor: horizontal ? \"end\" : \"start\",\n\t\t\t\t\t\t\tbaseline: horizontal ? \"bottom\" : \"top\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { nodes };\n\t\t},\n\t};\n}\n\n/** Horizontal rules at y values: a baseline, a target, an average. */\nexport function ruleY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RuleOptions<TDatum> = {},\n): ChartMark {\n\treturn ruleMark(\"ruleY\", data, options);\n}\n\n/** Vertical rules at x values: a date, a threshold. */\nexport function ruleX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RuleOptions<TDatum> = {},\n): ChartMark {\n\treturn ruleMark(\"ruleX\", data, options);\n}\n"],
5
+ "mappings": "AAAA,SAAS,aAAa,mBAAmB;AACzC,SAAS,QAAQ,OAAO,eAAe;AAoBvC,MAAM,YAAY;AAElB,SAAS,SACR,MACA,MACA,SACY;AACZ,QAAM,aAAa,SAAS;AAC5B,QAAM,SAAS;AAAA,IACd;AAAA,IACA,QAAQ,UAAU,CAAC,UAAkB;AAAA,EACtC;AACA,QAAM,UAAU,EAAE,QAAQ,OAAO,OAAO,WAAW,EAAE;AACrD,SAAO;AAAA,IACN,IAAI,QAAQ;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU,aAAa,EAAE,GAAG,QAAQ,IAAI,EAAE,GAAG,QAAQ;AAAA,IACrD,OAAO,SAAS;AACf,YAAM,KAAK,OAAO,QAAQ,IAAI,MAAM,OAAO;AAC3C,YAAM,QAAQ,aAAa,QAAQ,OAAO,IAAI,QAAQ,OAAO;AAC7D,UAAI,UAAU,QAAW;AACxB,eAAO,EAAE,OAAO,CAAC,EAAE;AAAA,MACpB;AACA,YAAM,EAAE,MAAM,MAAM,IAAI;AACxB,YAAM,SAAS,QAAQ,UAAU,MAAM;AACvC,YAAM,QAAqB,CAAC;AAC5B,iBAAW,CAAC,OAAO,GAAG,KAAK,OAAO,QAAQ,GAAG;AAC5C,cAAM,QAAQ,QAAQ,OAAO,GAAG;AAChC,YAAI,UAAU,QAAW;AACxB;AAAA,QACD;AACA,cAAM,KAAK,MAAM,OAAO,KAAK;AAC7B,cAAM,KAAK;AAAA,UACV,MAAM;AAAA,UACN,KAAK,GAAG,EAAE,IAAI,KAAK;AAAA,UACnB,MAAM;AAAA,UACN,GAAI,aACD,EAAE,IAAI,KAAK,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,OAAO,IAAI,GAAG,IACtD,EAAE,IAAI,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,OAAO;AAAA,UAC1D,OAAO,MAAM;AAAA,YACZ;AAAA,YACA,aAAa,QAAQ,eAAe;AAAA,YACpC,iBAAiB,QAAQ;AAAA,YACzB,SAAS,QAAQ;AAAA,UAClB,CAAC;AAAA,QACF,CAAC;AACD,YAAI,QAAQ,UAAU,QAAW;AAChC,gBAAM,KAAK;AAAA,YACV,MAAM;AAAA,YACN,KAAK,GAAG,EAAE,UAAU,KAAK;AAAA,YACzB,MAAM;AAAA,YACN,GAAG,aAAa,KAAK,IAAI,KAAK,QAAQ,KAAK;AAAA,YAC3C,GAAG,aAAa,KAAK,YAAY,KAAK;AAAA,YACtC,MAAM,QAAQ;AAAA,YACd,OAAO;AAAA,cACN,MAAM;AAAA,cACN,UAAU,MAAM;AAAA,cAChB,YAAY,aAAa,QAAQ;AAAA,cACjC,UAAU,aAAa,WAAW;AAAA,YACnC;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AACA,aAAO,EAAE,MAAM;AAAA,IAChB;AAAA,EACD;AACD;AAGO,SAAS,MACf,MACA,UAA+B,CAAC,GACpB;AACZ,SAAO,SAAS,SAAS,MAAM,OAAO;AACvC;AAGO,SAAS,MACf,MACA,UAA+B,CAAC,GACpB;AACZ,SAAO,SAAS,SAAS,MAAM,OAAO;AACvC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,41 @@
1
+ import type { ChartAccessor, ChartChannel, ChartMarkContext, ChartPaint, ChartPositionScale, ChartValue } from "../types.js";
2
+ /** Options every mark takes. */
3
+ export interface ChartMarkOptions<TDatum> {
4
+ /** Stable identity, so focus and legend state survive a data update. */
5
+ readonly id?: string;
6
+ /** The series' name when the mark has no color channel: legend, tooltip, table. */
7
+ readonly label?: string;
8
+ /** A field or function whose distinct values split the mark into coloured series. */
9
+ readonly color?: ChartAccessor<TDatum, ChartValue>;
10
+ /** `false` keeps the mark out of focus, tooltips and the data table. */
11
+ readonly tip?: boolean;
12
+ readonly opacity?: number;
13
+ }
14
+ export declare function markId(id: string | undefined, kind: string, context: ChartMarkContext): string;
15
+ /** A datum's series: its color value when there is a color channel, the mark otherwise. */
16
+ export interface SeriesInfo {
17
+ readonly key: string;
18
+ readonly label: string | undefined;
19
+ readonly color: string;
20
+ }
21
+ export declare function seriesResolver<TDatum>(colors: ReadonlyArray<ChartValue | undefined>, options: ChartMarkOptions<TDatum> & {
22
+ readonly fixedColor?: string;
23
+ }, id: string, context: ChartMarkContext): (index: number) => SeriesInfo;
24
+ export declare function colorChannel<TDatum>(data: ReadonlyArray<TDatum>, options: ChartMarkOptions<TDatum>): {
25
+ readonly values: ReadonlyArray<ChartValue | undefined>;
26
+ readonly channel: ChartChannel | undefined;
27
+ };
28
+ /** Keeps only the defined paint keys, so a scene snapshot shows what was asked for. */
29
+ export declare function paint<TPaint extends ChartPaint>(values: TPaint): TPaint;
30
+ /** Indices of `data` grouped by series, each group in data order. */
31
+ export declare function groupBySeries(count: number, seriesOf: (index: number) => SeriesInfo): ReadonlyMap<string, {
32
+ readonly series: SeriesInfo;
33
+ readonly indices: number[];
34
+ }>;
35
+ /**
36
+ * A raw channel value as the scale can place it, or `undefined` for a gap. A
37
+ * continuous scale reads numeric strings as numbers; a discrete one takes any
38
+ * category as is.
39
+ */
40
+ export declare function valueOn(scale: ChartPositionScale, raw: unknown): ChartValue | undefined;
41
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/core/marks/shared.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,MAAM,iBAAiB,CAAC;AAEzB,gCAAgC;AAChC,MAAM,WAAW,gBAAgB,CAAC,MAAM;IACvC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnD,wEAAwE;IACxE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,MAAM,CACrB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,GACvB,MAAM,CAER;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,cAAc,CAAC,MAAM,EACpC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,SAAS,CAAC,EAC7C,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAAG;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EACpE,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,gBAAgB,GACvB,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,CAkB/B;AAED,wBAAgB,YAAY,CAAC,MAAM,EAClC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B;IACF,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,CAAC;CAC3C,CAYA;AAED,uFAAuF;AACvF,wBAAgB,KAAK,CAAC,MAAM,SAAS,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,GACrC,WAAW,CACb,MAAM,EACN;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAC3D,CAYA;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACtB,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,OAAO,GACV,UAAU,GAAG,SAAS,CAQxB"}
@@ -0,0 +1,74 @@
1
+ import {
2
+ channelLabel,
3
+ isPlaceable,
4
+ numericValue,
5
+ readChannel
6
+ } from "../channel.js";
7
+ import { categoryKey } from "../scales/discrete.js";
8
+ function markId(id, kind, context) {
9
+ return id ?? `${kind}-${context.markIndex}`;
10
+ }
11
+ function seriesResolver(colors, options, id, context) {
12
+ const fallback = options.fixedColor ?? context.paletteColor(context.markIndex);
13
+ const single = { key: id, label: options.label, color: fallback };
14
+ if (options.color === void 0) {
15
+ return () => single;
16
+ }
17
+ return (index) => {
18
+ const value = colors[index];
19
+ if (value === void 0) {
20
+ return single;
21
+ }
22
+ return {
23
+ key: categoryKey(value),
24
+ label: context.seriesLabel(value),
25
+ color: options.fixedColor ?? context.colorOf(value)
26
+ };
27
+ };
28
+ }
29
+ function colorChannel(data, options) {
30
+ const values = readChannel(data, options.color);
31
+ return {
32
+ values,
33
+ channel: options.color === void 0 ? void 0 : {
34
+ values: values.filter(isPlaceable),
35
+ label: channelLabel(options.color)
36
+ }
37
+ };
38
+ }
39
+ function paint(values) {
40
+ return Object.fromEntries(
41
+ Object.entries(values).filter(([, value]) => value !== void 0)
42
+ );
43
+ }
44
+ function groupBySeries(count, seriesOf) {
45
+ const groups = /* @__PURE__ */ new Map();
46
+ for (let index = 0; index < count; index += 1) {
47
+ const series = seriesOf(index);
48
+ const group = groups.get(series.key);
49
+ if (group === void 0) {
50
+ groups.set(series.key, { series, indices: [index] });
51
+ } else {
52
+ group.indices.push(index);
53
+ }
54
+ }
55
+ return groups;
56
+ }
57
+ function valueOn(scale, raw) {
58
+ if (scale.kind === "band" || scale.kind === "point") {
59
+ return isPlaceable(raw) ? raw : void 0;
60
+ }
61
+ if (raw instanceof Date) {
62
+ return Number.isNaN(raw.getTime()) ? void 0 : raw;
63
+ }
64
+ return numericValue(raw);
65
+ }
66
+ export {
67
+ colorChannel,
68
+ groupBySeries,
69
+ markId,
70
+ paint,
71
+ seriesResolver,
72
+ valueOn
73
+ };
74
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/marks/shared.ts"],
4
+ "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartChannel,\n\tChartMarkContext,\n\tChartPaint,\n\tChartPositionScale,\n\tChartValue,\n} from \"#/core/types.ts\";\n\n/** Options every mark takes. */\nexport interface ChartMarkOptions<TDatum> {\n\t/** Stable identity, so focus and legend state survive a data update. */\n\treadonly id?: string;\n\t/** The series' name when the mark has no color channel: legend, tooltip, table. */\n\treadonly label?: string;\n\t/** A field or function whose distinct values split the mark into coloured series. */\n\treadonly color?: ChartAccessor<TDatum, ChartValue>;\n\t/** `false` keeps the mark out of focus, tooltips and the data table. */\n\treadonly tip?: boolean;\n\treadonly opacity?: number;\n}\n\nexport function markId(\n\tid: string | undefined,\n\tkind: string,\n\tcontext: ChartMarkContext,\n): string {\n\treturn id ?? `${kind}-${context.markIndex}`;\n}\n\n/** A datum's series: its color value when there is a color channel, the mark otherwise. */\nexport interface SeriesInfo {\n\treadonly key: string;\n\treadonly label: string | undefined;\n\treadonly color: string;\n}\n\nexport function seriesResolver<TDatum>(\n\tcolors: ReadonlyArray<ChartValue | undefined>,\n\toptions: ChartMarkOptions<TDatum> & { readonly fixedColor?: string },\n\tid: string,\n\tcontext: ChartMarkContext,\n): (index: number) => SeriesInfo {\n\tconst fallback =\n\t\toptions.fixedColor ?? context.paletteColor(context.markIndex);\n\tconst single: SeriesInfo = { key: id, label: options.label, color: fallback };\n\tif (options.color === undefined) {\n\t\treturn () => single;\n\t}\n\treturn (index) => {\n\t\tconst value = colors[index];\n\t\tif (value === undefined) {\n\t\t\treturn single;\n\t\t}\n\t\treturn {\n\t\t\tkey: categoryKey(value),\n\t\t\tlabel: context.seriesLabel(value),\n\t\t\tcolor: options.fixedColor ?? context.colorOf(value),\n\t\t};\n\t};\n}\n\nexport function colorChannel<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: ChartMarkOptions<TDatum>,\n): {\n\treadonly values: ReadonlyArray<ChartValue | undefined>;\n\treadonly channel: ChartChannel | undefined;\n} {\n\tconst values = readChannel(data, options.color);\n\treturn {\n\t\tvalues,\n\t\tchannel:\n\t\t\toptions.color === undefined\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tvalues: values.filter(isPlaceable),\n\t\t\t\t\t\tlabel: channelLabel(options.color),\n\t\t\t\t\t},\n\t};\n}\n\n/** Keeps only the defined paint keys, so a scene snapshot shows what was asked for. */\nexport function paint<TPaint extends ChartPaint>(values: TPaint): TPaint {\n\treturn Object.fromEntries(\n\t\tObject.entries(values).filter(([, value]) => value !== undefined),\n\t) as TPaint;\n}\n\n/** Indices of `data` grouped by series, each group in data order. */\nexport function groupBySeries(\n\tcount: number,\n\tseriesOf: (index: number) => SeriesInfo,\n): ReadonlyMap<\n\tstring,\n\t{ readonly series: SeriesInfo; readonly indices: number[] }\n> {\n\tconst groups = new Map<string, { series: SeriesInfo; indices: number[] }>();\n\tfor (let index = 0; index < count; index += 1) {\n\t\tconst series = seriesOf(index);\n\t\tconst group = groups.get(series.key);\n\t\tif (group === undefined) {\n\t\t\tgroups.set(series.key, { series, indices: [index] });\n\t\t} else {\n\t\t\tgroup.indices.push(index);\n\t\t}\n\t}\n\treturn groups;\n}\n\n/**\n * A raw channel value as the scale can place it, or `undefined` for a gap. A\n * continuous scale reads numeric strings as numbers; a discrete one takes any\n * category as is.\n */\nexport function valueOn(\n\tscale: ChartPositionScale,\n\traw: unknown,\n): ChartValue | undefined {\n\tif (scale.kind === \"band\" || scale.kind === \"point\") {\n\t\treturn isPlaceable(raw) ? raw : undefined;\n\t}\n\tif (raw instanceof Date) {\n\t\treturn Number.isNaN(raw.getTime()) ? undefined : raw;\n\t}\n\treturn numericValue(raw);\n}\n"],
5
+ "mappings": "AAAA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,mBAAmB;AAuBrB,SAAS,OACf,IACA,MACA,SACS;AACT,SAAO,MAAM,GAAG,IAAI,IAAI,QAAQ,SAAS;AAC1C;AASO,SAAS,eACf,QACA,SACA,IACA,SACgC;AAChC,QAAM,WACL,QAAQ,cAAc,QAAQ,aAAa,QAAQ,SAAS;AAC7D,QAAM,SAAqB,EAAE,KAAK,IAAI,OAAO,QAAQ,OAAO,OAAO,SAAS;AAC5E,MAAI,QAAQ,UAAU,QAAW;AAChC,WAAO,MAAM;AAAA,EACd;AACA,SAAO,CAAC,UAAU;AACjB,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,UAAU,QAAW;AACxB,aAAO;AAAA,IACR;AACA,WAAO;AAAA,MACN,KAAK,YAAY,KAAK;AAAA,MACtB,OAAO,QAAQ,YAAY,KAAK;AAAA,MAChC,OAAO,QAAQ,cAAc,QAAQ,QAAQ,KAAK;AAAA,IACnD;AAAA,EACD;AACD;AAEO,SAAS,aACf,MACA,SAIC;AACD,QAAM,SAAS,YAAY,MAAM,QAAQ,KAAK;AAC9C,SAAO;AAAA,IACN;AAAA,IACA,SACC,QAAQ,UAAU,SACf,SACA;AAAA,MACA,QAAQ,OAAO,OAAO,WAAW;AAAA,MACjC,OAAO,aAAa,QAAQ,KAAK;AAAA,IAClC;AAAA,EACJ;AACD;AAGO,SAAS,MAAiC,QAAwB;AACxE,SAAO,OAAO;AAAA,IACb,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AAAA,EACjE;AACD;AAGO,SAAS,cACf,OACA,UAIC;AACD,QAAM,SAAS,oBAAI,IAAuD;AAC1E,WAAS,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;AAC9C,UAAM,SAAS,SAAS,KAAK;AAC7B,UAAM,QAAQ,OAAO,IAAI,OAAO,GAAG;AACnC,QAAI,UAAU,QAAW;AACxB,aAAO,IAAI,OAAO,KAAK,EAAE,QAAQ,SAAS,CAAC,KAAK,EAAE,CAAC;AAAA,IACpD,OAAO;AACN,YAAM,QAAQ,KAAK,KAAK;AAAA,IACzB;AAAA,EACD;AACA,SAAO;AACR;AAOO,SAAS,QACf,OACA,KACyB;AACzB,MAAI,MAAM,SAAS,UAAU,MAAM,SAAS,SAAS;AACpD,WAAO,YAAY,GAAG,IAAI,MAAM;AAAA,EACjC;AACA,MAAI,eAAe,MAAM;AACxB,WAAO,OAAO,MAAM,IAAI,QAAQ,CAAC,IAAI,SAAY;AAAA,EAClD;AACA,SAAO,aAAa,GAAG;AACxB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Stacking: each value sits on the running total of the values before it at
3
+ * the same position. Positives grow away from zero upwards and negatives
4
+ * downwards, separately, so a stack of mixed signs never overlaps itself.
5
+ */
6
+ export interface StackSegment {
7
+ readonly low: number;
8
+ readonly high: number;
9
+ /** The outermost segment of its side of the stack: the one whose far end gets rounded. */
10
+ readonly outer: boolean;
11
+ }
12
+ export declare function stackSegments(positions: ReadonlyArray<string | undefined>, values: ReadonlyArray<number | undefined>): ReadonlyArray<StackSegment | undefined>;
13
+ //# sourceMappingURL=stack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../../src/core/marks/stack.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,aAAa,CAC5B,SAAS,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,EAC5C,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,GACvC,aAAa,CAAC,YAAY,GAAG,SAAS,CAAC,CAyBzC"}
@@ -0,0 +1,28 @@
1
+ function stackSegments(positions, values) {
2
+ const above = /* @__PURE__ */ new Map();
3
+ const below = /* @__PURE__ */ new Map();
4
+ const lastAbove = /* @__PURE__ */ new Map();
5
+ const lastBelow = /* @__PURE__ */ new Map();
6
+ const segments = positions.map((position, index) => {
7
+ const value = values[index];
8
+ if (position === void 0 || value === void 0) {
9
+ return void 0;
10
+ }
11
+ const totals = value >= 0 ? above : below;
12
+ const base = totals.get(position) ?? 0;
13
+ totals.set(position, base + value);
14
+ (value >= 0 ? lastAbove : lastBelow).set(position, index);
15
+ return { low: base, high: base + value, outer: false };
16
+ });
17
+ for (const index of [...lastAbove.values(), ...lastBelow.values()]) {
18
+ const segment = segments[index];
19
+ if (segment !== void 0) {
20
+ segment.outer = true;
21
+ }
22
+ }
23
+ return segments;
24
+ }
25
+ export {
26
+ stackSegments
27
+ };
28
+ //# sourceMappingURL=stack.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/marks/stack.ts"],
4
+ "sourcesContent": ["/**\n * Stacking: each value sits on the running total of the values before it at\n * the same position. Positives grow away from zero upwards and negatives\n * downwards, separately, so a stack of mixed signs never overlaps itself.\n */\n\nexport interface StackSegment {\n\treadonly low: number;\n\treadonly high: number;\n\t/** The outermost segment of its side of the stack: the one whose far end gets rounded. */\n\treadonly outer: boolean;\n}\n\nexport function stackSegments(\n\tpositions: ReadonlyArray<string | undefined>,\n\tvalues: ReadonlyArray<number | undefined>,\n): ReadonlyArray<StackSegment | undefined> {\n\tconst above = new Map<string, number>();\n\tconst below = new Map<string, number>();\n\tconst lastAbove = new Map<string, number>();\n\tconst lastBelow = new Map<string, number>();\n\tconst segments: Array<\n\t\t{ low: number; high: number; outer: boolean } | undefined\n\t> = positions.map((position, index) => {\n\t\tconst value = values[index];\n\t\tif (position === undefined || value === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst totals = value >= 0 ? above : below;\n\t\tconst base = totals.get(position) ?? 0;\n\t\ttotals.set(position, base + value);\n\t\t(value >= 0 ? lastAbove : lastBelow).set(position, index);\n\t\treturn { low: base, high: base + value, outer: false };\n\t});\n\tfor (const index of [...lastAbove.values(), ...lastBelow.values()]) {\n\t\tconst segment = segments[index];\n\t\tif (segment !== undefined) {\n\t\t\tsegment.outer = true;\n\t\t}\n\t}\n\treturn segments;\n}\n"],
5
+ "mappings": "AAaO,SAAS,cACf,WACA,QAC0C;AAC1C,QAAM,QAAQ,oBAAI,IAAoB;AACtC,QAAM,QAAQ,oBAAI,IAAoB;AACtC,QAAM,YAAY,oBAAI,IAAoB;AAC1C,QAAM,YAAY,oBAAI,IAAoB;AAC1C,QAAM,WAEF,UAAU,IAAI,CAAC,UAAU,UAAU;AACtC,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,aAAa,UAAa,UAAU,QAAW;AAClD,aAAO;AAAA,IACR;AACA,UAAM,SAAS,SAAS,IAAI,QAAQ;AACpC,UAAM,OAAO,OAAO,IAAI,QAAQ,KAAK;AACrC,WAAO,IAAI,UAAU,OAAO,KAAK;AACjC,KAAC,SAAS,IAAI,YAAY,WAAW,IAAI,UAAU,KAAK;AACxD,WAAO,EAAE,KAAK,MAAM,MAAM,OAAO,OAAO,OAAO,MAAM;AAAA,EACtD,CAAC;AACD,aAAW,SAAS,CAAC,GAAG,UAAU,OAAO,GAAG,GAAG,UAAU,OAAO,CAAC,GAAG;AACnE,UAAM,UAAU,SAAS,KAAK;AAC9B,QAAI,YAAY,QAAW;AAC1B,cAAQ,QAAQ;AAAA,IACjB;AAAA,EACD;AACA,SAAO;AACR;",
6
+ "names": []
7
+ }
@@ -0,0 +1,20 @@
1
+ import type { ChartAccessor, ChartMark, ChartValue } from "../../types.js";
2
+ export interface DifferenceOptions<TDatum> {
3
+ readonly id?: string;
4
+ readonly x: ChartAccessor<TDatum, ChartValue>;
5
+ /** The series read against the other: the fill says when it is above. */
6
+ readonly y1: ChartAccessor<TDatum, ChartValue>;
7
+ readonly y2: ChartAccessor<TDatum, ChartValue>;
8
+ /** Names of the two series, for the tooltip, the table and the legend. */
9
+ readonly labels?: readonly [string, string];
10
+ /** Fill where `y1` is above `y2`, and below. */
11
+ readonly positiveFill?: string;
12
+ readonly negativeFill?: string;
13
+ readonly fillOpacity?: number;
14
+ }
15
+ /**
16
+ * Two series and the band between them, filled by which one is ahead:
17
+ * revenue against costs, this year against last.
18
+ */
19
+ export declare function differenceY<TDatum>(data: ReadonlyArray<TDatum>, options: DifferenceOptions<TDatum>): ChartMark;
20
+ //# sourceMappingURL=difference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"difference.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/difference.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,iBAAiB,CAAC,MAAM;IACxC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,yEAAyE;IACzE,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,gDAAgD;IAChD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAsCD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAChC,SAAS,CAmIX"}
@@ -0,0 +1,168 @@
1
+ import {
2
+ channelLabel,
3
+ isPlaceable,
4
+ numericValue,
5
+ readChannel
6
+ } from "../../channel.js";
7
+ import { markId, paint, valueOn } from "../shared.js";
8
+ import { areaPath, linePath } from "../../paths.js";
9
+ function signRuns(samples) {
10
+ const runs = [];
11
+ for (const [index, sample] of samples.entries()) {
12
+ const positive = sample.top <= sample.bottom;
13
+ const current = runs[runs.length - 1];
14
+ if (current === void 0) {
15
+ runs.push({ positive, samples: [sample] });
16
+ continue;
17
+ }
18
+ if (current.positive === positive) {
19
+ current.samples.push(sample);
20
+ continue;
21
+ }
22
+ const previous = samples[index - 1];
23
+ const before = previous.top - previous.bottom;
24
+ const after = sample.top - sample.bottom;
25
+ const share = before / (before - after);
26
+ const crossX = previous.x + (sample.x - previous.x) * share;
27
+ const crossY = previous.top + (sample.top - previous.top) * share;
28
+ const cross = { x: crossX, top: crossY, bottom: crossY };
29
+ current.samples.push(cross);
30
+ runs.push({ positive, samples: [cross, sample] });
31
+ }
32
+ return runs;
33
+ }
34
+ function differenceY(data, options) {
35
+ const xs = readChannel(data, options.x);
36
+ const first = readChannel(data, options.y1).map(numericValue);
37
+ const second = readChannel(data, options.y2).map(numericValue);
38
+ const [firstLabel, secondLabel] = options.labels ?? [
39
+ channelLabel(options.y1) ?? "y1",
40
+ channelLabel(options.y2) ?? "y2"
41
+ ];
42
+ return {
43
+ id: options.id,
44
+ coordinate: "cartesian",
45
+ focusOrder: "x",
46
+ channels: {
47
+ x: { values: xs.filter(isPlaceable), label: channelLabel(options.x) },
48
+ y: {
49
+ values: [...first, ...second].filter(
50
+ (value) => value !== void 0
51
+ )
52
+ }
53
+ },
54
+ render(context) {
55
+ const id = markId(options.id, "differenceY", context);
56
+ const { x: xScale, y: yScale } = context.scales;
57
+ if (xScale === void 0 || yScale === void 0) {
58
+ return { nodes: [] };
59
+ }
60
+ const positive = options.positiveFill ?? context.paletteColor(1);
61
+ const negative = options.negativeFill ?? context.paletteColor(0);
62
+ const samples = [];
63
+ const points = [];
64
+ for (const [index, raw] of xs.entries()) {
65
+ const x = valueOn(xScale, raw);
66
+ const a = first[index];
67
+ const b = second[index];
68
+ if (x === void 0 || a === void 0 || b === void 0) continue;
69
+ const sample = {
70
+ x: xScale.center(x),
71
+ top: yScale.map(a),
72
+ bottom: yScale.map(b)
73
+ };
74
+ samples.push(sample);
75
+ for (const [series, value, pixel, label] of [
76
+ ["y1", a, sample.top, firstLabel],
77
+ ["y2", b, sample.bottom, secondLabel]
78
+ ]) {
79
+ points.push({
80
+ key: `${id}:${series}:${index}`,
81
+ markId: id,
82
+ index,
83
+ datum: data[index],
84
+ x: sample.x,
85
+ y: pixel,
86
+ xValue: x,
87
+ yValue: value,
88
+ series: `${id}:${series}`,
89
+ seriesLabel: label,
90
+ color: series === "y1" ? context.theme.foreground : context.theme.muted,
91
+ title: context.formatX(x),
92
+ value: context.formatY(value)
93
+ });
94
+ }
95
+ }
96
+ const nodes = signRuns(samples).map((run, index) => ({
97
+ kind: "path",
98
+ key: `${id}:band:${index}`,
99
+ role: "mark",
100
+ d: areaPath(
101
+ run.samples.map(
102
+ (sample) => ({ x: sample.x, y: sample.top })
103
+ ),
104
+ run.samples.map(
105
+ (sample) => ({ x: sample.x, y: sample.bottom })
106
+ )
107
+ ),
108
+ paint: paint({
109
+ fill: run.positive ? positive : negative,
110
+ fillOpacity: options.fillOpacity ?? 0.35
111
+ })
112
+ }));
113
+ nodes.push(
114
+ {
115
+ kind: "path",
116
+ key: `${id}:line:y1`,
117
+ series: `${id}:y1`,
118
+ role: "mark",
119
+ d: linePath(
120
+ samples.map((sample) => ({ x: sample.x, y: sample.top }))
121
+ ),
122
+ paint: {
123
+ fill: "none",
124
+ stroke: context.theme.foreground,
125
+ strokeWidth: 1.5
126
+ }
127
+ },
128
+ {
129
+ kind: "path",
130
+ key: `${id}:line:y2`,
131
+ series: `${id}:y2`,
132
+ role: "mark",
133
+ d: linePath(
134
+ samples.map((sample) => ({ x: sample.x, y: sample.bottom }))
135
+ ),
136
+ paint: {
137
+ fill: "none",
138
+ stroke: context.theme.muted,
139
+ strokeWidth: 1.5,
140
+ strokeDasharray: "4 3"
141
+ }
142
+ }
143
+ );
144
+ return {
145
+ nodes,
146
+ points,
147
+ legend: [
148
+ {
149
+ key: `${id}:y1`,
150
+ label: firstLabel,
151
+ color: context.theme.foreground,
152
+ shape: "line"
153
+ },
154
+ {
155
+ key: `${id}:y2`,
156
+ label: secondLabel,
157
+ color: context.theme.muted,
158
+ shape: "dashed"
159
+ }
160
+ ]
161
+ };
162
+ }
163
+ };
164
+ }
165
+ export {
166
+ differenceY
167
+ };
168
+ //# sourceMappingURL=difference.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/core/marks/stats/difference.ts"],
4
+ "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { markId, paint, valueOn } from \"#/core/marks/shared.ts\";\nimport { areaPath, type ChartXY, linePath } from \"#/core/paths.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface DifferenceOptions<TDatum> {\n\treadonly id?: string;\n\treadonly x: ChartAccessor<TDatum, ChartValue>;\n\t/** The series read against the other: the fill says when it is above. */\n\treadonly y1: ChartAccessor<TDatum, ChartValue>;\n\treadonly y2: ChartAccessor<TDatum, ChartValue>;\n\t/** Names of the two series, for the tooltip, the table and the legend. */\n\treadonly labels?: readonly [string, string];\n\t/** Fill where `y1` is above `y2`, and below. */\n\treadonly positiveFill?: string;\n\treadonly negativeFill?: string;\n\treadonly fillOpacity?: number;\n}\n\ninterface Sample {\n\treadonly x: number;\n\treadonly top: number;\n\treadonly bottom: number;\n}\n\n/** Splits the band between two lines into runs of one sign, cut where they cross. */\nfunction signRuns(\n\tsamples: ReadonlyArray<Sample>,\n): Array<{ positive: boolean; samples: Sample[] }> {\n\tconst runs: Array<{ positive: boolean; samples: Sample[] }> = [];\n\tfor (const [index, sample] of samples.entries()) {\n\t\t// Pixels: a smaller y is higher, so y1 above y2 means top < bottom.\n\t\tconst positive = sample.top <= sample.bottom;\n\t\tconst current = runs[runs.length - 1];\n\t\tif (current === undefined) {\n\t\t\truns.push({ positive, samples: [sample] });\n\t\t\tcontinue;\n\t\t}\n\t\tif (current.positive === positive) {\n\t\t\tcurrent.samples.push(sample);\n\t\t\tcontinue;\n\t\t}\n\t\tconst previous = samples[index - 1];\n\t\tconst before = previous.top - previous.bottom;\n\t\tconst after = sample.top - sample.bottom;\n\t\tconst share = before / (before - after);\n\t\tconst crossX = previous.x + (sample.x - previous.x) * share;\n\t\tconst crossY = previous.top + (sample.top - previous.top) * share;\n\t\tconst cross = { x: crossX, top: crossY, bottom: crossY };\n\t\tcurrent.samples.push(cross);\n\t\truns.push({ positive, samples: [cross, sample] });\n\t}\n\treturn runs;\n}\n\n/**\n * Two series and the band between them, filled by which one is ahead:\n * revenue against costs, this year against last.\n */\nexport function differenceY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: DifferenceOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x);\n\tconst first = readChannel(data, options.y1).map(numericValue);\n\tconst second = readChannel(data, options.y2).map(numericValue);\n\tconst [firstLabel, secondLabel] = options.labels ?? [\n\t\tchannelLabel(options.y1) ?? \"y1\",\n\t\tchannelLabel(options.y2) ?? \"y2\",\n\t];\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: \"x\",\n\t\tchannels: {\n\t\t\tx: { values: xs.filter(isPlaceable), label: channelLabel(options.x) },\n\t\t\ty: {\n\t\t\t\tvalues: [...first, ...second].filter(\n\t\t\t\t\t(value): value is number => value !== undefined,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"differenceY\", context);\n\t\t\tconst { x: xScale, y: yScale } = context.scales;\n\t\t\tif (xScale === undefined || yScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst positive = options.positiveFill ?? context.paletteColor(1);\n\t\t\tconst negative = options.negativeFill ?? context.paletteColor(0);\n\t\t\tconst samples: Sample[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, raw] of xs.entries()) {\n\t\t\t\tconst x = valueOn(xScale, raw);\n\t\t\t\tconst a = first[index];\n\t\t\t\tconst b = second[index];\n\t\t\t\tif (x === undefined || a === undefined || b === undefined) continue;\n\t\t\t\tconst sample = {\n\t\t\t\t\tx: xScale.center(x),\n\t\t\t\t\ttop: yScale.map(a),\n\t\t\t\t\tbottom: yScale.map(b),\n\t\t\t\t};\n\t\t\t\tsamples.push(sample);\n\t\t\t\tfor (const [series, value, pixel, label] of [\n\t\t\t\t\t[\"y1\", a, sample.top, firstLabel],\n\t\t\t\t\t[\"y2\", b, sample.bottom, secondLabel],\n\t\t\t\t] as const) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${series}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum: data[index],\n\t\t\t\t\t\tx: sample.x,\n\t\t\t\t\t\ty: pixel,\n\t\t\t\t\t\txValue: x,\n\t\t\t\t\t\tyValue: value,\n\t\t\t\t\t\tseries: `${id}:${series}`,\n\t\t\t\t\t\tseriesLabel: label,\n\t\t\t\t\t\tcolor:\n\t\t\t\t\t\t\tseries === \"y1\" ? context.theme.foreground : context.theme.muted,\n\t\t\t\t\t\ttitle: context.formatX(x),\n\t\t\t\t\t\tvalue: context.formatY(value),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst nodes: SceneNode[] = signRuns(samples).map((run, index) => ({\n\t\t\t\tkind: \"path\",\n\t\t\t\tkey: `${id}:band:${index}`,\n\t\t\t\trole: \"mark\",\n\t\t\t\td: areaPath(\n\t\t\t\t\trun.samples.map(\n\t\t\t\t\t\t(sample): ChartXY => ({ x: sample.x, y: sample.top }),\n\t\t\t\t\t),\n\t\t\t\t\trun.samples.map(\n\t\t\t\t\t\t(sample): ChartXY => ({ x: sample.x, y: sample.bottom }),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tpaint: paint({\n\t\t\t\t\tfill: run.positive ? positive : negative,\n\t\t\t\t\tfillOpacity: options.fillOpacity ?? 0.35,\n\t\t\t\t}),\n\t\t\t}));\n\t\t\tnodes.push(\n\t\t\t\t{\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:line:y1`,\n\t\t\t\t\tseries: `${id}:y1`,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: linePath(\n\t\t\t\t\t\tsamples.map((sample) => ({ x: sample.x, y: sample.top })),\n\t\t\t\t\t),\n\t\t\t\t\tpaint: {\n\t\t\t\t\t\tfill: \"none\",\n\t\t\t\t\t\tstroke: context.theme.foreground,\n\t\t\t\t\t\tstrokeWidth: 1.5,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:line:y2`,\n\t\t\t\t\tseries: `${id}:y2`,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: linePath(\n\t\t\t\t\t\tsamples.map((sample) => ({ x: sample.x, y: sample.bottom })),\n\t\t\t\t\t),\n\t\t\t\t\tpaint: {\n\t\t\t\t\t\tfill: \"none\",\n\t\t\t\t\t\tstroke: context.theme.muted,\n\t\t\t\t\t\tstrokeWidth: 1.5,\n\t\t\t\t\t\tstrokeDasharray: \"4 3\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tnodes,\n\t\t\t\tpoints,\n\t\t\t\tlegend: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: `${id}:y1`,\n\t\t\t\t\t\tlabel: firstLabel,\n\t\t\t\t\t\tcolor: context.theme.foreground,\n\t\t\t\t\t\tshape: \"line\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: `${id}:y2`,\n\t\t\t\t\t\tlabel: secondLabel,\n\t\t\t\t\t\tcolor: context.theme.muted,\n\t\t\t\t\t\tshape: \"dashed\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t};\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,41 @@
1
+ import type { ChartAccessor, ChartMark, ChartValue } from "../../types.js";
2
+ /**
3
+ * Distributions per category: the box plot, the violin and the ridgeline.
4
+ * Each groups the values by category first; a category's point (what the
5
+ * keyboard visits) sits on its median.
6
+ */
7
+ interface DistributionOptions<TDatum> {
8
+ readonly id?: string;
9
+ readonly label?: string;
10
+ readonly fill?: string;
11
+ readonly opacity?: number;
12
+ readonly tip?: boolean;
13
+ readonly category: ChartAccessor<TDatum, ChartValue>;
14
+ readonly value: ChartAccessor<TDatum, ChartValue>;
15
+ }
16
+ export interface BoxOptions<TDatum> extends DistributionOptions<TDatum> {
17
+ /** Share of the band the box takes. */
18
+ readonly width?: number;
19
+ }
20
+ /**
21
+ * Box and whiskers per category: the box from the first to the third
22
+ * quartile, the median across it, whiskers to the furthest values within
23
+ * 1.5 IQR, and the outliers past them as dots.
24
+ */
25
+ export declare function boxY<TDatum>(data: ReadonlyArray<TDatum>, options: BoxOptions<TDatum>): ChartMark;
26
+ /**
27
+ * The density of each category's values, mirrored around its centre: the
28
+ * shape a box plot hides (two peaks, a long tail).
29
+ */
30
+ export declare function violinY<TDatum>(data: ReadonlyArray<TDatum>, options: DistributionOptions<TDatum>): ChartMark;
31
+ export interface RidgelineOptions<TDatum> extends DistributionOptions<TDatum> {
32
+ /** How far each ridge may rise into the row above: 1 stays in its row. */
33
+ readonly overlap?: number;
34
+ }
35
+ /**
36
+ * One density per row, stacked down the chart and allowed to overlap the row
37
+ * above: many distributions compared along one shared x axis.
38
+ */
39
+ export declare function ridgeline<TDatum>(data: ReadonlyArray<TDatum>, options: RidgelineOptions<TDatum>): ChartMark;
40
+ export {};
41
+ //# sourceMappingURL=distribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distribution.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/distribution.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB;;;;GAIG;AAEH,UAAU,mBAAmB,CAAC,MAAM;IACnC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAClD;AAmCD,MAAM,WAAW,UAAU,CAAC,MAAM,CAAE,SAAQ,mBAAmB,CAAC,MAAM,CAAC;IACtE,uCAAuC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAID;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,GACzB,SAAS,CAsHX;AAID;;;GAGG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAC7B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,mBAAmB,CAAC,MAAM,CAAC,GAClC,SAAS,CAyGX;AAID,MAAM,WAAW,gBAAgB,CAAC,MAAM,CAAE,SAAQ,mBAAmB,CAAC,MAAM,CAAC;IAC5E,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAC/B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B,SAAS,CAuFX"}