@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,200 @@
1
+ import {
2
+ channelLabel,
3
+ isPlaceable,
4
+ numericValue,
5
+ readChannel
6
+ } from "../channel.js";
7
+ import {
8
+ colorChannel,
9
+ markId,
10
+ paint,
11
+ seriesResolver
12
+ } from "./shared.js";
13
+ import { stackSegments } from "./stack.js";
14
+ import { categoryKey } from "../scales/discrete.js";
15
+ const DEFAULT_RADIUS = 4;
16
+ function barMark(kind, data, options) {
17
+ const vertical = kind === "barY";
18
+ const positionKey = vertical ? options.x : options.y;
19
+ const valueKey = vertical ? options.y : options.x;
20
+ const positions = readChannel(
21
+ data,
22
+ positionKey ?? ((_datum, index) => index)
23
+ );
24
+ const values = readChannel(
25
+ data,
26
+ valueKey ?? ((datum) => datum)
27
+ ).map(numericValue);
28
+ const colors = colorChannel(data, options);
29
+ const explicit = options.from !== void 0 && options.to !== void 0;
30
+ const froms = readChannel(data, options.from).map(numericValue);
31
+ const tos = readChannel(data, options.to).map(numericValue);
32
+ const stacked = !explicit && !options.group && (options.stack ?? options.color !== void 0);
33
+ const segments = stacked ? stackSegments(
34
+ positions.map(
35
+ (position) => isPlaceable(position) ? categoryKey(position) : void 0
36
+ ),
37
+ values
38
+ ) : [];
39
+ const bars = [];
40
+ for (const [index, position] of positions.entries()) {
41
+ if (!isPlaceable(position)) {
42
+ continue;
43
+ }
44
+ if (explicit) {
45
+ const low = froms[index];
46
+ const high = tos[index];
47
+ if (low !== void 0 && high !== void 0) {
48
+ bars.push({
49
+ index,
50
+ position,
51
+ low,
52
+ high,
53
+ value: high - low,
54
+ outer: true
55
+ });
56
+ }
57
+ continue;
58
+ }
59
+ const value = values[index];
60
+ if (value === void 0) {
61
+ continue;
62
+ }
63
+ const segment = segments[index];
64
+ bars.push(
65
+ segment === void 0 ? { index, position, low: 0, high: value, value, outer: true } : { index, position, ...segment, value }
66
+ );
67
+ }
68
+ const positionChannel = {
69
+ values: bars.map((bar) => bar.position),
70
+ discrete: "band",
71
+ label: channelLabel(positionKey)
72
+ };
73
+ const valueChannel = {
74
+ values: bars.flatMap((bar) => [bar.low, bar.high]),
75
+ includeZero: !explicit,
76
+ label: channelLabel(valueKey) ?? options.label
77
+ };
78
+ return {
79
+ id: options.id,
80
+ coordinate: "cartesian",
81
+ focusOrder: vertical ? "x" : "y",
82
+ channels: {
83
+ x: vertical ? positionChannel : valueChannel,
84
+ y: vertical ? valueChannel : positionChannel,
85
+ color: colors.channel
86
+ },
87
+ render(context) {
88
+ const id = markId(options.id, kind, context);
89
+ const positionScale = vertical ? context.scales.x : context.scales.y;
90
+ const valueScale = vertical ? context.scales.y : context.scales.x;
91
+ if (positionScale === void 0 || valueScale === void 0) {
92
+ return { nodes: [] };
93
+ }
94
+ const seriesOf = seriesResolver(
95
+ colors.values,
96
+ { ...options, fixedColor: options.fill },
97
+ id,
98
+ context
99
+ );
100
+ const seriesOrder = [
101
+ ...new Set(bars.map((bar) => seriesOf(bar.index).key))
102
+ ];
103
+ const lanes = options.group ? Math.max(1, seriesOrder.length) : 1;
104
+ const laneWidth = positionScale.bandwidth / lanes;
105
+ const inset = options.inset ?? 0;
106
+ const radius = options.radius ?? DEFAULT_RADIUS;
107
+ const nodes = [];
108
+ const points = [];
109
+ for (const bar of bars) {
110
+ const series = seriesOf(bar.index);
111
+ const lane = options.group ? seriesOrder.indexOf(series.key) : 0;
112
+ const alongStart = positionScale.map(bar.position) + lane * laneWidth + inset;
113
+ const alongSize = Math.max(0, laneWidth - inset * 2);
114
+ const lowPixel = valueScale.map(bar.low);
115
+ const highPixel = valueScale.map(bar.high);
116
+ const acrossStart = Math.min(lowPixel, highPixel);
117
+ const acrossSize = Math.abs(highPixel - lowPixel);
118
+ const rect = vertical ? {
119
+ x: alongStart,
120
+ y: acrossStart,
121
+ width: alongSize,
122
+ height: acrossSize
123
+ } : {
124
+ x: acrossStart,
125
+ y: alongStart,
126
+ width: acrossSize,
127
+ height: alongSize
128
+ };
129
+ nodes.push({
130
+ kind: "rect",
131
+ key: `${id}:${bar.index}`,
132
+ series: series.key,
133
+ role: "mark",
134
+ ...rect,
135
+ corners: corners(vertical, bar, radius, explicit),
136
+ paint: paint({
137
+ fill: series.color,
138
+ fillOpacity: options.fillOpacity,
139
+ stroke: options.stroke,
140
+ strokeDasharray: options.strokeDasharray,
141
+ opacity: options.opacity
142
+ })
143
+ });
144
+ if (options.tip === false) {
145
+ continue;
146
+ }
147
+ const along = alongStart + alongSize / 2;
148
+ points.push({
149
+ key: `${id}:${bar.index}`,
150
+ markId: id,
151
+ index: bar.index,
152
+ datum: data[bar.index],
153
+ x: vertical ? along : highPixel,
154
+ y: vertical ? highPixel : along,
155
+ xValue: vertical ? bar.position : bar.value,
156
+ yValue: vertical ? bar.value : bar.position,
157
+ series: series.key,
158
+ seriesLabel: series.label,
159
+ color: series.color,
160
+ title: vertical ? context.formatX(bar.position) : context.formatY(bar.position),
161
+ value: vertical ? context.formatY(bar.value) : context.formatX(bar.value),
162
+ hit: { kind: "rect", rect }
163
+ });
164
+ }
165
+ const legend = options.color === void 0 && options.label !== void 0 ? [
166
+ {
167
+ key: id,
168
+ label: options.label,
169
+ color: options.fill ?? context.paletteColor(context.markIndex),
170
+ shape: "square"
171
+ }
172
+ ] : [];
173
+ return { nodes, points, legend };
174
+ }
175
+ };
176
+ }
177
+ function corners(vertical, bar, radius, explicit) {
178
+ if (radius === 0 || !bar.outer) {
179
+ return void 0;
180
+ }
181
+ if (explicit) {
182
+ return [radius, radius, radius, radius];
183
+ }
184
+ const positive = bar.high >= bar.low;
185
+ if (vertical) {
186
+ return positive ? [radius, radius, 0, 0] : [0, 0, radius, radius];
187
+ }
188
+ return positive ? [0, radius, radius, 0] : [radius, 0, 0, radius];
189
+ }
190
+ function barY(data, options = {}) {
191
+ return barMark("barY", data, options);
192
+ }
193
+ function barX(data, options = {}) {
194
+ return barMark("barX", data, options);
195
+ }
196
+ export {
197
+ barX,
198
+ barY
199
+ };
200
+ //# sourceMappingURL=bar.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/marks/bar.ts"],
4
+ "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n} from \"#/core/marks/shared.ts\";\nimport { stackSegments } from \"#/core/marks/stack.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartCorners,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface BarOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** Explicit start and end of the bar on the value axis: floating bars, ranges, Gantt rows. */\n\treadonly from?: ChartAccessor<TDatum, ChartValue>;\n\treadonly to?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\treadonly stroke?: string;\n\treadonly strokeDasharray?: string;\n\t/** Series stack on one another. On by default when there is a color channel. */\n\treadonly stack?: boolean;\n\t/** Series stand side by side inside the band instead of stacking. */\n\treadonly group?: boolean;\n\t/** Corner radius of the bar's far end. */\n\treadonly radius?: number;\n\t/** Pixels kept clear on each side of the bar inside its band. */\n\treadonly inset?: number;\n}\n\nconst DEFAULT_RADIUS = 4;\n\ninterface BarDatum {\n\treadonly index: number;\n\treadonly position: ChartValue;\n\treadonly low: number;\n\treadonly high: number;\n\treadonly value: number;\n\t/** Round the far end: the outer segment of a stack, or any unstacked bar. */\n\treadonly outer: boolean;\n}\n\nfunction barMark<TDatum>(\n\tkind: \"barY\" | \"barX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum>,\n): ChartMark {\n\tconst vertical = kind === \"barY\";\n\tconst positionKey = vertical ? options.x : options.y;\n\tconst valueKey = vertical ? options.y : options.x;\n\tconst positions = readChannel(\n\t\tdata,\n\t\tpositionKey ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst values = readChannel(\n\t\tdata,\n\t\tvalueKey ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t).map(numericValue);\n\tconst colors = colorChannel(data, options);\n\tconst explicit = options.from !== undefined && options.to !== undefined;\n\tconst froms = readChannel(data, options.from).map(numericValue);\n\tconst tos = readChannel(data, options.to).map(numericValue);\n\tconst stacked =\n\t\t!explicit &&\n\t\t!options.group &&\n\t\t(options.stack ?? options.color !== undefined);\n\tconst segments = stacked\n\t\t? stackSegments(\n\t\t\t\tpositions.map((position) =>\n\t\t\t\t\tisPlaceable(position) ? categoryKey(position) : undefined,\n\t\t\t\t),\n\t\t\t\tvalues,\n\t\t\t)\n\t\t: [];\n\n\tconst bars: BarDatum[] = [];\n\tfor (const [index, position] of positions.entries()) {\n\t\tif (!isPlaceable(position)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (explicit) {\n\t\t\tconst low = froms[index];\n\t\t\tconst high = tos[index];\n\t\t\tif (low !== undefined && high !== undefined) {\n\t\t\t\tbars.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tposition,\n\t\t\t\t\tlow,\n\t\t\t\t\thigh,\n\t\t\t\t\tvalue: high - low,\n\t\t\t\t\touter: true,\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = values[index];\n\t\tif (value === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst segment = segments[index];\n\t\tbars.push(\n\t\t\tsegment === undefined\n\t\t\t\t? { index, position, low: 0, high: value, value, outer: true }\n\t\t\t\t: { index, position, ...segment, value },\n\t\t);\n\t}\n\n\tconst positionChannel = {\n\t\tvalues: bars.map((bar) => bar.position),\n\t\tdiscrete: \"band\" as const,\n\t\tlabel: channelLabel(positionKey),\n\t};\n\tconst valueChannel = {\n\t\tvalues: bars.flatMap((bar) => [bar.low, bar.high]),\n\t\tincludeZero: !explicit,\n\t\tlabel: channelLabel(valueKey) ?? options.label,\n\t};\n\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: vertical ? \"x\" : \"y\",\n\t\tchannels: {\n\t\t\tx: vertical ? positionChannel : valueChannel,\n\t\t\ty: vertical ? valueChannel : positionChannel,\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, kind, context);\n\t\t\tconst positionScale = vertical ? context.scales.x : context.scales.y;\n\t\t\tconst valueScale = vertical ? context.scales.y : context.scales.x;\n\t\t\tif (positionScale === undefined || valueScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst seriesOrder = [\n\t\t\t\t...new Set(bars.map((bar) => seriesOf(bar.index).key)),\n\t\t\t];\n\t\t\tconst lanes = options.group ? Math.max(1, seriesOrder.length) : 1;\n\t\t\tconst laneWidth = positionScale.bandwidth / lanes;\n\t\t\tconst inset = options.inset ?? 0;\n\t\t\tconst radius = options.radius ?? DEFAULT_RADIUS;\n\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const bar of bars) {\n\t\t\t\tconst series = seriesOf(bar.index);\n\t\t\t\tconst lane = options.group ? seriesOrder.indexOf(series.key) : 0;\n\t\t\t\tconst alongStart =\n\t\t\t\t\tpositionScale.map(bar.position) + lane * laneWidth + inset;\n\t\t\t\tconst alongSize = Math.max(0, laneWidth - inset * 2);\n\t\t\t\tconst lowPixel = valueScale.map(bar.low);\n\t\t\t\tconst highPixel = valueScale.map(bar.high);\n\t\t\t\tconst acrossStart = Math.min(lowPixel, highPixel);\n\t\t\t\tconst acrossSize = Math.abs(highPixel - lowPixel);\n\t\t\t\tconst rect = vertical\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tx: alongStart,\n\t\t\t\t\t\t\ty: acrossStart,\n\t\t\t\t\t\t\twidth: alongSize,\n\t\t\t\t\t\t\theight: acrossSize,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tx: acrossStart,\n\t\t\t\t\t\t\ty: alongStart,\n\t\t\t\t\t\t\twidth: acrossSize,\n\t\t\t\t\t\t\theight: alongSize,\n\t\t\t\t\t\t};\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\tkey: `${id}:${bar.index}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t...rect,\n\t\t\t\t\tcorners: corners(vertical, bar, radius, explicit),\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\tfillOpacity: options.fillOpacity,\n\t\t\t\t\t\tstroke: options.stroke,\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.tip === false) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst along = alongStart + alongSize / 2;\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${bar.index}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex: bar.index,\n\t\t\t\t\tdatum: data[bar.index],\n\t\t\t\t\tx: vertical ? along : highPixel,\n\t\t\t\t\ty: vertical ? highPixel : along,\n\t\t\t\t\txValue: vertical ? bar.position : bar.value,\n\t\t\t\t\tyValue: vertical ? bar.value : bar.position,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\ttitle: vertical\n\t\t\t\t\t\t? context.formatX(bar.position)\n\t\t\t\t\t\t: context.formatY(bar.position),\n\t\t\t\t\tvalue: vertical\n\t\t\t\t\t\t? context.formatY(bar.value)\n\t\t\t\t\t\t: context.formatX(bar.value),\n\t\t\t\t\thit: { kind: \"rect\", rect },\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst legend =\n\t\t\t\toptions.color === undefined && options.label !== undefined\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: id,\n\t\t\t\t\t\t\t\tlabel: options.label,\n\t\t\t\t\t\t\t\tcolor: options.fill ?? context.paletteColor(context.markIndex),\n\t\t\t\t\t\t\t\tshape: \"square\" as const,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: [];\n\t\t\treturn { nodes, points, legend };\n\t\t},\n\t};\n}\n\n/** Rounds the end of the bar away from zero, and only that end: stacked joins stay square. */\nfunction corners(\n\tvertical: boolean,\n\tbar: BarDatum,\n\tradius: number,\n\texplicit: boolean,\n): ChartCorners | undefined {\n\tif (radius === 0 || !bar.outer) {\n\t\treturn undefined;\n\t}\n\tif (explicit) {\n\t\treturn [radius, radius, radius, radius];\n\t}\n\tconst positive = bar.high >= bar.low;\n\tif (vertical) {\n\t\treturn positive ? [radius, radius, 0, 0] : [0, 0, radius, radius];\n\t}\n\treturn positive ? [0, radius, radius, 0] : [radius, 0, 0, radius];\n}\n\n/** Upright bars: categories along x, values up y. */\nexport function barY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum> = {},\n): ChartMark {\n\treturn barMark(\"barY\", data, options);\n}\n\n/** Bars on their side: categories down y, values along x. */\nexport function barX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum> = {},\n): ChartMark {\n\treturn barMark(\"barX\", data, options);\n}\n"],
5
+ "mappings": "AAAA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP;AAAA,EAEC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AA8B5B,MAAM,iBAAiB;AAYvB,SAAS,QACR,MACA,MACA,SACY;AACZ,QAAM,WAAW,SAAS;AAC1B,QAAM,cAAc,WAAW,QAAQ,IAAI,QAAQ;AACnD,QAAM,WAAW,WAAW,QAAQ,IAAI,QAAQ;AAChD,QAAM,YAAY;AAAA,IACjB;AAAA,IACA,gBAAgB,CAAC,QAAgB,UAAkB;AAAA,EACpD;AACA,QAAM,SAAS;AAAA,IACd;AAAA,IACA,aAAa,CAAC,UAAkB;AAAA,EACjC,EAAE,IAAI,YAAY;AAClB,QAAM,SAAS,aAAa,MAAM,OAAO;AACzC,QAAM,WAAW,QAAQ,SAAS,UAAa,QAAQ,OAAO;AAC9D,QAAM,QAAQ,YAAY,MAAM,QAAQ,IAAI,EAAE,IAAI,YAAY;AAC9D,QAAM,MAAM,YAAY,MAAM,QAAQ,EAAE,EAAE,IAAI,YAAY;AAC1D,QAAM,UACL,CAAC,YACD,CAAC,QAAQ,UACR,QAAQ,SAAS,QAAQ,UAAU;AACrC,QAAM,WAAW,UACd;AAAA,IACA,UAAU;AAAA,MAAI,CAAC,aACd,YAAY,QAAQ,IAAI,YAAY,QAAQ,IAAI;AAAA,IACjD;AAAA,IACA;AAAA,EACD,IACC,CAAC;AAEJ,QAAM,OAAmB,CAAC;AAC1B,aAAW,CAAC,OAAO,QAAQ,KAAK,UAAU,QAAQ,GAAG;AACpD,QAAI,CAAC,YAAY,QAAQ,GAAG;AAC3B;AAAA,IACD;AACA,QAAI,UAAU;AACb,YAAM,MAAM,MAAM,KAAK;AACvB,YAAM,OAAO,IAAI,KAAK;AACtB,UAAI,QAAQ,UAAa,SAAS,QAAW;AAC5C,aAAK,KAAK;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,OAAO;AAAA,UACd,OAAO;AAAA,QACR,CAAC;AAAA,MACF;AACA;AAAA,IACD;AACA,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,UAAU,QAAW;AACxB;AAAA,IACD;AACA,UAAM,UAAU,SAAS,KAAK;AAC9B,SAAK;AAAA,MACJ,YAAY,SACT,EAAE,OAAO,UAAU,KAAK,GAAG,MAAM,OAAO,OAAO,OAAO,KAAK,IAC3D,EAAE,OAAO,UAAU,GAAG,SAAS,MAAM;AAAA,IACzC;AAAA,EACD;AAEA,QAAM,kBAAkB;AAAA,IACvB,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,QAAQ;AAAA,IACtC,UAAU;AAAA,IACV,OAAO,aAAa,WAAW;AAAA,EAChC;AACA,QAAM,eAAe;AAAA,IACpB,QAAQ,KAAK,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC;AAAA,IACjD,aAAa,CAAC;AAAA,IACd,OAAO,aAAa,QAAQ,KAAK,QAAQ;AAAA,EAC1C;AAEA,SAAO;AAAA,IACN,IAAI,QAAQ;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,WAAW,MAAM;AAAA,IAC7B,UAAU;AAAA,MACT,GAAG,WAAW,kBAAkB;AAAA,MAChC,GAAG,WAAW,eAAe;AAAA,MAC7B,OAAO,OAAO;AAAA,IACf;AAAA,IACA,OAAO,SAAS;AACf,YAAM,KAAK,OAAO,QAAQ,IAAI,MAAM,OAAO;AAC3C,YAAM,gBAAgB,WAAW,QAAQ,OAAO,IAAI,QAAQ,OAAO;AACnE,YAAM,aAAa,WAAW,QAAQ,OAAO,IAAI,QAAQ,OAAO;AAChE,UAAI,kBAAkB,UAAa,eAAe,QAAW;AAC5D,eAAO,EAAE,OAAO,CAAC,EAAE;AAAA,MACpB;AACA,YAAM,WAAW;AAAA,QAChB,OAAO;AAAA,QACP,EAAE,GAAG,SAAS,YAAY,QAAQ,KAAK;AAAA,QACvC;AAAA,QACA;AAAA,MACD;AACA,YAAM,cAAc;AAAA,QACnB,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,SAAS,IAAI,KAAK,EAAE,GAAG,CAAC;AAAA,MACtD;AACA,YAAM,QAAQ,QAAQ,QAAQ,KAAK,IAAI,GAAG,YAAY,MAAM,IAAI;AAChE,YAAM,YAAY,cAAc,YAAY;AAC5C,YAAM,QAAQ,QAAQ,SAAS;AAC/B,YAAM,SAAS,QAAQ,UAAU;AAEjC,YAAM,QAAqB,CAAC;AAC5B,YAAM,SAAuB,CAAC;AAC9B,iBAAW,OAAO,MAAM;AACvB,cAAM,SAAS,SAAS,IAAI,KAAK;AACjC,cAAM,OAAO,QAAQ,QAAQ,YAAY,QAAQ,OAAO,GAAG,IAAI;AAC/D,cAAM,aACL,cAAc,IAAI,IAAI,QAAQ,IAAI,OAAO,YAAY;AACtD,cAAM,YAAY,KAAK,IAAI,GAAG,YAAY,QAAQ,CAAC;AACnD,cAAM,WAAW,WAAW,IAAI,IAAI,GAAG;AACvC,cAAM,YAAY,WAAW,IAAI,IAAI,IAAI;AACzC,cAAM,cAAc,KAAK,IAAI,UAAU,SAAS;AAChD,cAAM,aAAa,KAAK,IAAI,YAAY,QAAQ;AAChD,cAAM,OAAO,WACV;AAAA,UACA,GAAG;AAAA,UACH,GAAG;AAAA,UACH,OAAO;AAAA,UACP,QAAQ;AAAA,QACT,IACC;AAAA,UACA,GAAG;AAAA,UACH,GAAG;AAAA,UACH,OAAO;AAAA,UACP,QAAQ;AAAA,QACT;AACF,cAAM,KAAK;AAAA,UACV,MAAM;AAAA,UACN,KAAK,GAAG,EAAE,IAAI,IAAI,KAAK;AAAA,UACvB,QAAQ,OAAO;AAAA,UACf,MAAM;AAAA,UACN,GAAG;AAAA,UACH,SAAS,QAAQ,UAAU,KAAK,QAAQ,QAAQ;AAAA,UAChD,OAAO,MAAM;AAAA,YACZ,MAAM,OAAO;AAAA,YACb,aAAa,QAAQ;AAAA,YACrB,QAAQ,QAAQ;AAAA,YAChB,iBAAiB,QAAQ;AAAA,YACzB,SAAS,QAAQ;AAAA,UAClB,CAAC;AAAA,QACF,CAAC;AACD,YAAI,QAAQ,QAAQ,OAAO;AAC1B;AAAA,QACD;AACA,cAAM,QAAQ,aAAa,YAAY;AACvC,eAAO,KAAK;AAAA,UACX,KAAK,GAAG,EAAE,IAAI,IAAI,KAAK;AAAA,UACvB,QAAQ;AAAA,UACR,OAAO,IAAI;AAAA,UACX,OAAO,KAAK,IAAI,KAAK;AAAA,UACrB,GAAG,WAAW,QAAQ;AAAA,UACtB,GAAG,WAAW,YAAY;AAAA,UAC1B,QAAQ,WAAW,IAAI,WAAW,IAAI;AAAA,UACtC,QAAQ,WAAW,IAAI,QAAQ,IAAI;AAAA,UACnC,QAAQ,OAAO;AAAA,UACf,aAAa,OAAO;AAAA,UACpB,OAAO,OAAO;AAAA,UACd,OAAO,WACJ,QAAQ,QAAQ,IAAI,QAAQ,IAC5B,QAAQ,QAAQ,IAAI,QAAQ;AAAA,UAC/B,OAAO,WACJ,QAAQ,QAAQ,IAAI,KAAK,IACzB,QAAQ,QAAQ,IAAI,KAAK;AAAA,UAC5B,KAAK,EAAE,MAAM,QAAQ,KAAK;AAAA,QAC3B,CAAC;AAAA,MACF;AACA,YAAM,SACL,QAAQ,UAAU,UAAa,QAAQ,UAAU,SAC9C;AAAA,QACA;AAAA,UACC,KAAK;AAAA,UACL,OAAO,QAAQ;AAAA,UACf,OAAO,QAAQ,QAAQ,QAAQ,aAAa,QAAQ,SAAS;AAAA,UAC7D,OAAO;AAAA,QACR;AAAA,MACD,IACC,CAAC;AACL,aAAO,EAAE,OAAO,QAAQ,OAAO;AAAA,IAChC;AAAA,EACD;AACD;AAGA,SAAS,QACR,UACA,KACA,QACA,UAC2B;AAC3B,MAAI,WAAW,KAAK,CAAC,IAAI,OAAO;AAC/B,WAAO;AAAA,EACR;AACA,MAAI,UAAU;AACb,WAAO,CAAC,QAAQ,QAAQ,QAAQ,MAAM;AAAA,EACvC;AACA,QAAM,WAAW,IAAI,QAAQ,IAAI;AACjC,MAAI,UAAU;AACb,WAAO,WAAW,CAAC,QAAQ,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,MAAM;AAAA,EACjE;AACA,SAAO,WAAW,CAAC,GAAG,QAAQ,QAAQ,CAAC,IAAI,CAAC,QAAQ,GAAG,GAAG,MAAM;AACjE;AAGO,SAAS,KACf,MACA,UAA8B,CAAC,GACnB;AACZ,SAAO,QAAQ,QAAQ,MAAM,OAAO;AACrC;AAGO,SAAS,KACf,MACA,UAA8B,CAAC,GACnB;AACZ,SAAO,QAAQ,QAAQ,MAAM,OAAO;AACrC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import { type ChartMarkOptions } from "./shared.js";
2
+ import type { ChartAccessor, ChartMark, ChartValue } from "../types.js";
3
+ export interface CellOptions<TDatum> extends ChartMarkOptions<TDatum> {
4
+ readonly x?: ChartAccessor<TDatum, ChartValue>;
5
+ readonly y?: ChartAccessor<TDatum, ChartValue>;
6
+ readonly fill?: string;
7
+ /** Pixels kept clear around each cell. */
8
+ readonly inset?: number;
9
+ readonly radius?: number;
10
+ }
11
+ /**
12
+ * A rectangle per (x, y) pair of categories, filled by its color value: a
13
+ * heatmap, a calendar, a matrix.
14
+ */
15
+ export declare function cell<TDatum>(data: ReadonlyArray<TDatum>, options: CellOptions<TDatum>): ChartMark;
16
+ //# sourceMappingURL=cell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell.d.ts","sourceRoot":"","sources":["../../../src/core/marks/cell.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACpE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAKD;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC1B,SAAS,CAqFX"}
@@ -0,0 +1,98 @@
1
+ import { channelLabel, isPlaceable, readChannel } from "../channel.js";
2
+ import { formatValue } from "../format.js";
3
+ import {
4
+ colorChannel,
5
+ markId,
6
+ paint,
7
+ seriesResolver,
8
+ valueOn
9
+ } from "./shared.js";
10
+ const DEFAULT_INSET = 1;
11
+ const DEFAULT_RADIUS = 2;
12
+ function cell(data, options) {
13
+ const xs = readChannel(data, options.x);
14
+ const ys = readChannel(data, options.y);
15
+ const colors = colorChannel(data, options);
16
+ return {
17
+ id: options.id,
18
+ coordinate: "cartesian",
19
+ focusOrder: "point",
20
+ channels: {
21
+ x: {
22
+ values: xs.filter(isPlaceable),
23
+ discrete: "band",
24
+ padding: 0,
25
+ label: channelLabel(options.x)
26
+ },
27
+ y: {
28
+ values: ys.filter(isPlaceable),
29
+ discrete: "band",
30
+ padding: 0,
31
+ label: channelLabel(options.y)
32
+ },
33
+ color: colors.channel
34
+ },
35
+ render(context) {
36
+ const id = markId(options.id, "cell", context);
37
+ const { x: xScale, y: yScale } = context.scales;
38
+ if (xScale === void 0 || yScale === void 0) {
39
+ return { nodes: [] };
40
+ }
41
+ const seriesOf = seriesResolver(
42
+ colors.values,
43
+ { ...options, fixedColor: options.fill },
44
+ id,
45
+ context
46
+ );
47
+ const inset = options.inset ?? DEFAULT_INSET;
48
+ const radius = options.radius ?? DEFAULT_RADIUS;
49
+ const nodes = [];
50
+ const points = [];
51
+ for (const [index, datum] of data.entries()) {
52
+ const xValue = valueOn(xScale, xs[index]);
53
+ const yValue = valueOn(yScale, ys[index]);
54
+ if (xValue === void 0 || yValue === void 0) {
55
+ continue;
56
+ }
57
+ const rect = {
58
+ x: xScale.map(xValue) + inset,
59
+ y: yScale.map(yValue) + inset,
60
+ width: Math.max(0, xScale.bandwidth - inset * 2),
61
+ height: Math.max(0, yScale.bandwidth - inset * 2)
62
+ };
63
+ const series = seriesOf(index);
64
+ const colorValue = colors.values[index];
65
+ nodes.push({
66
+ kind: "rect",
67
+ key: `${id}:${index}`,
68
+ role: "mark",
69
+ ...rect,
70
+ corners: [radius, radius, radius, radius],
71
+ paint: paint({ fill: series.color, opacity: options.opacity })
72
+ });
73
+ if (options.tip !== false) {
74
+ points.push({
75
+ key: `${id}:${index}`,
76
+ markId: id,
77
+ index,
78
+ datum,
79
+ x: rect.x + rect.width / 2,
80
+ y: rect.y + rect.height / 2,
81
+ xValue,
82
+ yValue,
83
+ color: series.color,
84
+ seriesLabel: options.label,
85
+ title: `${context.formatX(xValue)} \xB7 ${context.formatY(yValue)}`,
86
+ value: colorValue === void 0 ? "" : formatValue(colorValue, context.locale),
87
+ hit: { kind: "rect", rect }
88
+ });
89
+ }
90
+ }
91
+ return { nodes, points };
92
+ }
93
+ };
94
+ }
95
+ export {
96
+ cell
97
+ };
98
+ //# sourceMappingURL=cell.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/marks/cell.ts"],
4
+ "sourcesContent": ["import { channelLabel, isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport { formatValue } from \"#/core/format.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface CellOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\t/** Pixels kept clear around each cell. */\n\treadonly inset?: number;\n\treadonly radius?: number;\n}\n\nconst DEFAULT_INSET = 1;\nconst DEFAULT_RADIUS = 2;\n\n/**\n * A rectangle per (x, y) pair of categories, filled by its color value: a\n * heatmap, a calendar, a matrix.\n */\nexport function cell<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: CellOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x);\n\tconst ys = readChannel(data, options.y);\n\tconst colors = colorChannel(data, options);\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: \"point\",\n\t\tchannels: {\n\t\t\tx: {\n\t\t\t\tvalues: xs.filter(isPlaceable),\n\t\t\t\tdiscrete: \"band\",\n\t\t\t\tpadding: 0,\n\t\t\t\tlabel: channelLabel(options.x),\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: ys.filter(isPlaceable),\n\t\t\t\tdiscrete: \"band\",\n\t\t\t\tpadding: 0,\n\t\t\t\tlabel: channelLabel(options.y),\n\t\t\t},\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"cell\", 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 seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst inset = options.inset ?? DEFAULT_INSET;\n\t\t\tconst radius = options.radius ?? DEFAULT_RADIUS;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, datum] of data.entries()) {\n\t\t\t\tconst xValue = valueOn(xScale, xs[index]);\n\t\t\t\tconst yValue = valueOn(yScale, ys[index]);\n\t\t\t\tif (xValue === undefined || yValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst rect = {\n\t\t\t\t\tx: xScale.map(xValue) + inset,\n\t\t\t\t\ty: yScale.map(yValue) + inset,\n\t\t\t\t\twidth: Math.max(0, xScale.bandwidth - inset * 2),\n\t\t\t\t\theight: Math.max(0, yScale.bandwidth - inset * 2),\n\t\t\t\t};\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst colorValue = colors.values[index];\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t...rect,\n\t\t\t\t\tcorners: [radius, radius, radius, radius],\n\t\t\t\t\tpaint: paint({ fill: series.color, opacity: options.opacity }),\n\t\t\t\t});\n\t\t\t\tif (options.tip !== false) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum,\n\t\t\t\t\t\tx: rect.x + rect.width / 2,\n\t\t\t\t\t\ty: rect.y + rect.height / 2,\n\t\t\t\t\t\txValue,\n\t\t\t\t\t\tyValue,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\tseriesLabel: options.label,\n\t\t\t\t\t\ttitle: `${context.formatX(xValue)} \u00B7 ${context.formatY(yValue)}`,\n\t\t\t\t\t\tvalue:\n\t\t\t\t\t\t\tcolorValue === undefined\n\t\t\t\t\t\t\t\t? \"\"\n\t\t\t\t\t\t\t\t: formatValue(colorValue, context.locale),\n\t\t\t\t\t\thit: { kind: \"rect\", rect },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import { type ChartMarkOptions } from "./shared.js";
2
+ import type { ChartAccessor, ChartMark, ChartValue } from "../types.js";
3
+ export interface DotOptions<TDatum> extends ChartMarkOptions<TDatum> {
4
+ readonly x?: ChartAccessor<TDatum, ChartValue>;
5
+ readonly y?: ChartAccessor<TDatum, ChartValue>;
6
+ /** A radius in pixels, or a field whose values set the area of each dot. */
7
+ readonly r?: number | ChartAccessor<TDatum, ChartValue>;
8
+ /** The largest radius a sized dot reaches. */
9
+ readonly maxRadius?: number;
10
+ readonly fill?: string;
11
+ readonly fillOpacity?: number;
12
+ readonly stroke?: string;
13
+ readonly strokeWidth?: number;
14
+ }
15
+ /** A dot per datum: a scatter plot, or a bubble chart when `r` is a field. */
16
+ export declare function dot<TDatum>(data: ReadonlyArray<TDatum>, options?: DotOptions<TDatum>): ChartMark;
17
+ //# sourceMappingURL=dot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/core/marks/dot.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,UAAU,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACnE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,4EAA4E;IAC5E,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxD,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAKD,8EAA8E;AAC9E,wBAAgB,GAAG,CAAC,MAAM,EACzB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,MAAM,CAAM,GAC9B,SAAS,CAkHX"}
@@ -0,0 +1,125 @@
1
+ import {
2
+ channelLabel,
3
+ isPlaceable,
4
+ numericValue,
5
+ readChannel
6
+ } from "../channel.js";
7
+ import {
8
+ colorChannel,
9
+ markId,
10
+ paint,
11
+ seriesResolver,
12
+ valueOn
13
+ } from "./shared.js";
14
+ const DEFAULT_RADIUS = 4;
15
+ const DEFAULT_MAX_RADIUS = 16;
16
+ function dot(data, options = {}) {
17
+ const xs = readChannel(
18
+ data,
19
+ options.x ?? ((_datum, index) => index)
20
+ );
21
+ const ys = readChannel(
22
+ data,
23
+ options.y ?? ((datum) => datum)
24
+ );
25
+ const colors = colorChannel(data, options);
26
+ const sized = options.r !== void 0 && typeof options.r !== "number";
27
+ const sizes = sized ? readChannel(data, options.r).map(
28
+ numericValue
29
+ ) : [];
30
+ const largest = Math.max(0, ...sizes.map((size) => Math.abs(size ?? 0)));
31
+ const reach = typeof options.r === "number" ? options.r : sized ? options.maxRadius ?? DEFAULT_MAX_RADIUS : DEFAULT_RADIUS;
32
+ return {
33
+ id: options.id,
34
+ coordinate: "cartesian",
35
+ focusOrder: "point",
36
+ channels: {
37
+ x: {
38
+ values: xs.filter(isPlaceable),
39
+ label: channelLabel(options.x),
40
+ inset: reach
41
+ },
42
+ y: {
43
+ values: ys.filter(isPlaceable),
44
+ label: channelLabel(options.y) ?? options.label,
45
+ inset: reach
46
+ },
47
+ color: colors.channel
48
+ },
49
+ render(context) {
50
+ const id = markId(options.id, "dot", context);
51
+ const { x: xScale, y: yScale } = context.scales;
52
+ if (xScale === void 0 || yScale === void 0) {
53
+ return { nodes: [] };
54
+ }
55
+ const seriesOf = seriesResolver(
56
+ colors.values,
57
+ { ...options, fixedColor: options.fill },
58
+ id,
59
+ context
60
+ );
61
+ const maxRadius = options.maxRadius ?? DEFAULT_MAX_RADIUS;
62
+ function radiusOf(index) {
63
+ if (typeof options.r === "number") return options.r;
64
+ if (!sized) return DEFAULT_RADIUS;
65
+ const size = Math.abs(sizes[index] ?? 0);
66
+ return largest === 0 ? 0 : Math.sqrt(size / largest) * maxRadius;
67
+ }
68
+ const nodes = [];
69
+ const points = [];
70
+ for (const [index, datum] of data.entries()) {
71
+ const xValue = valueOn(xScale, xs[index]);
72
+ const yValue = valueOn(yScale, ys[index]);
73
+ if (xValue === void 0 || yValue === void 0) {
74
+ continue;
75
+ }
76
+ const series = seriesOf(index);
77
+ const cx = xScale.center(xValue);
78
+ const cy = yScale.center(yValue);
79
+ const r = radiusOf(index);
80
+ nodes.push({
81
+ kind: "circle",
82
+ key: `${id}:${index}`,
83
+ series: series.key,
84
+ role: "mark",
85
+ cx,
86
+ cy,
87
+ r,
88
+ paint: paint({
89
+ fill: series.color,
90
+ fillOpacity: options.fillOpacity,
91
+ stroke: options.stroke,
92
+ strokeWidth: options.strokeWidth,
93
+ opacity: options.opacity
94
+ })
95
+ });
96
+ if (options.tip !== false) {
97
+ points.push({
98
+ key: `${id}:${index}`,
99
+ markId: id,
100
+ index,
101
+ datum,
102
+ x: cx,
103
+ y: cy,
104
+ xValue,
105
+ yValue,
106
+ series: series.key,
107
+ seriesLabel: series.label,
108
+ color: series.color,
109
+ title: context.formatX(xValue),
110
+ value: context.formatY(yValue),
111
+ hit: {
112
+ kind: "rect",
113
+ rect: { x: cx - r, y: cy - r, width: r * 2, height: r * 2 }
114
+ }
115
+ });
116
+ }
117
+ }
118
+ return { nodes, points };
119
+ }
120
+ };
121
+ }
122
+ export {
123
+ dot
124
+ };
125
+ //# sourceMappingURL=dot.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/marks/dot.ts"],
4
+ "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface DotOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** A radius in pixels, or a field whose values set the area of each dot. */\n\treadonly r?: number | ChartAccessor<TDatum, ChartValue>;\n\t/** The largest radius a sized dot reaches. */\n\treadonly maxRadius?: number;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\treadonly stroke?: string;\n\treadonly strokeWidth?: number;\n}\n\nconst DEFAULT_RADIUS = 4;\nconst DEFAULT_MAX_RADIUS = 16;\n\n/** A dot per datum: a scatter plot, or a bubble chart when `r` is a field. */\nexport function dot<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: DotOptions<TDatum> = {},\n): ChartMark {\n\tconst xs = readChannel(\n\t\tdata,\n\t\toptions.x ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst ys = readChannel(\n\t\tdata,\n\t\toptions.y ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t);\n\tconst colors = colorChannel(data, options);\n\tconst sized = options.r !== undefined && typeof options.r !== \"number\";\n\tconst sizes = sized\n\t\t? readChannel(data, options.r as ChartAccessor<TDatum, ChartValue>).map(\n\t\t\t\tnumericValue,\n\t\t\t)\n\t\t: [];\n\tconst largest = Math.max(0, ...sizes.map((size) => Math.abs(size ?? 0)));\n\tconst reach =\n\t\ttypeof options.r === \"number\"\n\t\t\t? options.r\n\t\t\t: sized\n\t\t\t\t? (options.maxRadius ?? DEFAULT_MAX_RADIUS)\n\t\t\t\t: DEFAULT_RADIUS;\n\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: \"point\",\n\t\tchannels: {\n\t\t\tx: {\n\t\t\t\tvalues: xs.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.x),\n\t\t\t\tinset: reach,\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: ys.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.y) ?? options.label,\n\t\t\t\tinset: reach,\n\t\t\t},\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"dot\", 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 seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst maxRadius = options.maxRadius ?? DEFAULT_MAX_RADIUS;\n\t\t\t// Area, not radius, carries the value: a dot twice the value looks twice as big.\n\t\t\tfunction radiusOf(index: number): number {\n\t\t\t\tif (typeof options.r === \"number\") return options.r;\n\t\t\t\tif (!sized) return DEFAULT_RADIUS;\n\t\t\t\tconst size = Math.abs(sizes[index] ?? 0);\n\t\t\t\treturn largest === 0 ? 0 : Math.sqrt(size / largest) * maxRadius;\n\t\t\t}\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, datum] of data.entries()) {\n\t\t\t\tconst xValue = valueOn(xScale, xs[index]);\n\t\t\t\tconst yValue = valueOn(yScale, ys[index]);\n\t\t\t\tif (xValue === undefined || yValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst cx = xScale.center(xValue);\n\t\t\t\tconst cy = yScale.center(yValue);\n\t\t\t\tconst r = radiusOf(index);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"circle\",\n\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\tr,\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\tfillOpacity: options.fillOpacity,\n\t\t\t\t\t\tstroke: options.stroke,\n\t\t\t\t\t\tstrokeWidth: options.strokeWidth,\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.tip !== false) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum,\n\t\t\t\t\t\tx: cx,\n\t\t\t\t\t\ty: cy,\n\t\t\t\t\t\txValue,\n\t\t\t\t\t\tyValue,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\ttitle: context.formatX(xValue),\n\t\t\t\t\t\tvalue: context.formatY(yValue),\n\t\t\t\t\t\thit: {\n\t\t\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\t\t\trect: { x: cx - r, y: cy - r, width: r * 2, height: r * 2 },\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, points };\n\t\t},\n\t};\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Funnel geometry, worked out away from React so it can be asserted on
3
+ * directly. One slice per step: a horizontal band whose left edge is as tall
4
+ * as the step's value and whose right edge slopes down to the next step's
5
+ * value, so the drop between two steps is visible as the flank itself.
6
+ */
7
+ export interface FunnelSlice {
8
+ /** Index of the datum, i.e. of the category slot. */
9
+ readonly index: number;
10
+ readonly value: number;
11
+ /** Left edge of the band, in plot coordinates. */
12
+ readonly x: number;
13
+ readonly width: number;
14
+ /** Height of the left flank, proportional to the step's value. */
15
+ readonly leftHeight: number;
16
+ /** Height of the right flank — the next step's value, or its own on the last step. */
17
+ readonly rightHeight: number;
18
+ /** The trapezoid, vertically centred on the band. `""` when there is nothing to draw. */
19
+ readonly path: string;
20
+ /** Conversion into the next step. `null` on the last step or when this one is empty. */
21
+ readonly ratioToNext: number | null;
22
+ }
23
+ export interface FunnelLayoutOptions {
24
+ readonly values: ReadonlyArray<number>;
25
+ readonly innerWidth: number;
26
+ readonly innerHeight: number;
27
+ /** Pixels of blank between two bands. */
28
+ readonly gap?: number;
29
+ /** Vertical centre line of the funnel. Defaults to half the inner height. */
30
+ readonly centerY?: number;
31
+ /** Height the largest value maps to. Defaults to the inner height. */
32
+ readonly maxHeight?: number;
33
+ /** Left edge of the first band. */
34
+ readonly originX?: number;
35
+ }
36
+ export declare function funnelSlices(options: FunnelLayoutOptions): ReadonlyArray<FunnelSlice>;
37
+ //# sourceMappingURL=funnel-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel-layout.d.ts","sourceRoot":"","sources":["../../../src/core/marks/funnel-layout.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,WAAW;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yCAAyC;IACzC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,mCAAmC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAkCD,wBAAgB,YAAY,CAC3B,OAAO,EAAE,mBAAmB,GAC1B,aAAa,CAAC,WAAW,CAAC,CAwC5B"}
@@ -0,0 +1,61 @@
1
+ const DEFAULT_GAP = 4;
2
+ const PATH_PRECISION = 2;
3
+ function round(value) {
4
+ const factor = 10 ** PATH_PRECISION;
5
+ return Math.round(value * factor) / factor;
6
+ }
7
+ function point(x, y) {
8
+ return `${round(x)},${round(y)}`;
9
+ }
10
+ function trapezoidPath(x, width, centerY, leftHeight, rightHeight) {
11
+ if (width <= 0 || leftHeight <= 0 && rightHeight <= 0) {
12
+ return "";
13
+ }
14
+ const right = x + width;
15
+ return [
16
+ `M${point(x, centerY - leftHeight / 2)}`,
17
+ `L${point(right, centerY - rightHeight / 2)}`,
18
+ `L${point(right, centerY + rightHeight / 2)}`,
19
+ `L${point(x, centerY + leftHeight / 2)}`,
20
+ "Z"
21
+ ].join("");
22
+ }
23
+ function funnelSlices(options) {
24
+ const {
25
+ values,
26
+ innerWidth,
27
+ innerHeight,
28
+ gap = DEFAULT_GAP,
29
+ centerY = innerHeight / 2,
30
+ maxHeight = innerHeight,
31
+ originX = 0
32
+ } = options;
33
+ const count = values.length;
34
+ if (count === 0 || innerWidth <= 0 || maxHeight <= 0) {
35
+ return [];
36
+ }
37
+ const clamped = values.map((value) => Math.max(0, value));
38
+ const peak = Math.max(...clamped);
39
+ const heightFor = (value) => peak <= 0 ? 0 : value / peak * maxHeight;
40
+ const bandWidth = Math.max(0, (innerWidth - gap * (count - 1)) / count);
41
+ return clamped.map((value, index) => {
42
+ const next = clamped[index + 1];
43
+ const leftHeight = heightFor(value);
44
+ const rightHeight = next === void 0 ? leftHeight : heightFor(next);
45
+ const x = originX + index * (bandWidth + gap);
46
+ return {
47
+ index,
48
+ value: values[index],
49
+ x,
50
+ width: bandWidth,
51
+ leftHeight,
52
+ rightHeight,
53
+ path: trapezoidPath(x, bandWidth, centerY, leftHeight, rightHeight),
54
+ ratioToNext: next === void 0 || value <= 0 ? null : next / value
55
+ };
56
+ });
57
+ }
58
+ export {
59
+ funnelSlices
60
+ };
61
+ //# sourceMappingURL=funnel-layout.js.map