@fundar/data-chart-telling 1.16.0 → 1.18.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 (330) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/configuration/ConfigVars.svelte +14 -0
  3. package/dist/configuration/ConfigVars.svelte.d.ts +3 -0
  4. package/dist/configuration/config.svelte.d.ts +5 -0
  5. package/dist/configuration/config.svelte.js +20 -6
  6. package/dist/configuration/themes/dark.js +1 -1
  7. package/dist/configuration/themes/editorial.js +1 -1
  8. package/dist/index.d.ts +12 -4
  9. package/dist/index.js +4 -1
  10. package/dist/layout/base/BasePlotLayout.svelte +1 -1
  11. package/dist/layout/figure/Figure.svelte +5 -12
  12. package/dist/layout/figure/FigureChrome.svelte +2 -10
  13. package/dist/layout/geometry/GeometryLayout.svelte +219 -44
  14. package/dist/layout/hover/HoverDefaults.d.ts +52 -0
  15. package/dist/layout/hover/HoverDefaults.js +96 -0
  16. package/dist/layout/hover/HoverLayers.d.ts +35 -0
  17. package/dist/layout/hover/HoverLayers.js +122 -0
  18. package/dist/layout/hover/HoverSettings.js +4 -1
  19. package/dist/layout/hover/HoverShapes.d.ts +44 -0
  20. package/dist/layout/hover/HoverShapes.js +103 -0
  21. package/dist/layout/hover/PlotHover.svelte.d.ts +18 -0
  22. package/dist/layout/hover/PlotHover.svelte.js +54 -1
  23. package/dist/layout/legend/DisabledStyle.d.ts +1 -1
  24. package/dist/layout/legend/DisabledStyle.js +1 -1
  25. package/dist/layout/legend/DiscreteBadgeItem.svelte +1 -1
  26. package/dist/layout/legend/DiscreteSection.svelte +1 -1
  27. package/dist/layout/legend/LegendState.svelte.d.ts +14 -2
  28. package/dist/layout/legend/LegendState.svelte.js +23 -4
  29. package/dist/layout/legend/LegendText.d.ts +4 -1
  30. package/dist/layout/legend/LegendText.js +7 -1
  31. package/dist/layout/margins/PlotMargins.svelte.d.ts +2 -2
  32. package/dist/layout/margins/PlotMargins.svelte.js +2 -2
  33. package/dist/layout/plot/Core.svelte +2 -2
  34. package/dist/layout/plot/Plot.svelte +4 -2
  35. package/dist/layout/plot/Plot.svelte.d.ts +2 -1
  36. package/dist/layout/plot/PublicPlotContext.d.ts +6 -0
  37. package/dist/layout/plot/PublicPlotContext.js +8 -0
  38. package/dist/layout/scales/ScalesLayout.svelte +1 -1
  39. package/dist/layout/styles/ValueLabels.d.ts +43 -4
  40. package/dist/layout/styles/ValueLabels.js +87 -19
  41. package/dist/layout/timeline/Timeline.svelte +5 -1
  42. package/dist/layout/tooltip/TooltipState.svelte.d.ts +8 -9
  43. package/dist/layout/tooltip/TooltipState.svelte.js +28 -29
  44. package/dist/markers/MarkerKinds.d.ts +5 -0
  45. package/dist/markers/MarkerKinds.js +1 -0
  46. package/dist/markers/area/AreaMarker.svelte +3 -0
  47. package/dist/markers/arrow/ArrowMarker.svelte +9 -5
  48. package/dist/markers/band/BandMarker.svelte +74 -0
  49. package/dist/markers/band/BandMarker.svelte.d.ts +7 -0
  50. package/dist/markers/band/Bands.d.ts +16 -0
  51. package/dist/markers/band/Bands.js +48 -0
  52. package/dist/markers/bar/BarMarker.svelte +50 -96
  53. package/dist/markers/bollinger/BollingerMarker.svelte +3 -0
  54. package/dist/markers/box/BoxMarker.svelte +3 -1
  55. package/dist/markers/cell/CellMarker.svelte +11 -7
  56. package/dist/markers/contour/ContourMarker.svelte +3 -0
  57. package/dist/markers/delaunay/DelaunayLinkMarker.svelte +9 -5
  58. package/dist/markers/delaunay/DelaunayMeshMarker.svelte +3 -0
  59. package/dist/markers/density/DensityMarker.svelte +3 -0
  60. package/dist/markers/difference/DifferenceMarker.svelte +3 -0
  61. package/dist/markers/dot/DotMarker.svelte +11 -6
  62. package/dist/markers/geo/GraticuleMarker.svelte +3 -0
  63. package/dist/markers/geo/SphereMarker.svelte +3 -0
  64. package/dist/markers/hover/HoverMarker.svelte +7 -249
  65. package/dist/markers/hover/HoverMarker.svelte.d.ts +4 -27
  66. package/dist/markers/hull/HullMarker.svelte +3 -0
  67. package/dist/markers/image/ImageMarker.svelte +3 -0
  68. package/dist/markers/line/LineMarker.svelte +3 -0
  69. package/dist/markers/link/LinkMarker.svelte +3 -0
  70. package/dist/markers/raster/RasterMarker.svelte +3 -0
  71. package/dist/markers/rect/RectMarker.svelte +25 -17
  72. package/dist/markers/regression/RegressionMarker.svelte +3 -0
  73. package/dist/markers/rule/RuleMarker.svelte +15 -5
  74. package/dist/markers/text/TextFit.d.ts +44 -0
  75. package/dist/markers/text/TextFit.js +86 -0
  76. package/dist/markers/text/TextMarker.svelte +186 -90
  77. package/dist/markers/text/TextMarker.svelte.d.ts +2 -0
  78. package/dist/markers/tick/TickMarker.svelte +9 -3
  79. package/dist/markers/trail/TrailMarker.svelte +3 -0
  80. package/dist/markers/utils/BoxLabel.d.ts +58 -0
  81. package/dist/markers/utils/BoxLabel.js +175 -0
  82. package/dist/markers/utils/MarkerEvents.d.ts +23 -0
  83. package/dist/markers/utils/MarkerEvents.js +44 -0
  84. package/dist/markers/utils/MarkerLabel.svelte +33 -0
  85. package/dist/markers/utils/MarkerLabel.svelte.d.ts +10 -0
  86. package/dist/markers/utils/PointPixel.d.ts +37 -0
  87. package/dist/markers/utils/PointPixel.js +44 -0
  88. package/dist/markers/utils/RowStroke.d.ts +9 -21
  89. package/dist/markers/utils/RowStroke.js +10 -21
  90. package/dist/markers/utils/RowStyle.d.ts +26 -0
  91. package/dist/markers/utils/RowStyle.js +55 -0
  92. package/dist/markers/vector/VectorMarker.svelte +3 -0
  93. package/dist/markers/voronoi/VoronoiMarker.svelte +9 -5
  94. package/dist/markers/voronoi/VoronoiMeshMarker.svelte +3 -0
  95. package/dist/markers/waffle/WaffleMarker.svelte +9 -5
  96. package/dist/phases/Pipeline.d.ts +10 -8
  97. package/dist/phases/Pipeline.js +13 -9
  98. package/dist/phases/context/ContextPhase.d.ts +22 -0
  99. package/dist/phases/context/ContextPhase.js +23 -0
  100. package/dist/phases/context/RowContext.d.ts +35 -0
  101. package/dist/phases/context/RowContext.js +95 -0
  102. package/dist/phases/data/DataPhase.d.ts +4 -4
  103. package/dist/phases/data/DataPhase.js +53 -12
  104. package/dist/phases/hover/HoverPhase.d.ts +6 -7
  105. package/dist/phases/hover/HoverPhase.js +28 -15
  106. package/dist/phases/mapping/MappingPhase.d.ts +4 -4
  107. package/dist/phases/mapping/MappingPhase.js +4 -3
  108. package/dist/phases/markers/MarkerStyles.d.ts +26 -0
  109. package/dist/phases/markers/MarkerStyles.js +126 -0
  110. package/dist/phases/markers/MarkersPhase.d.ts +5 -5
  111. package/dist/phases/markers/MarkersPhase.js +8 -6
  112. package/dist/phases/scales/ScalesPhase.d.ts +4 -4
  113. package/dist/phases/scales/ScalesPhase.js +4 -4
  114. package/dist/phases/sharedScales/SharedScalesPhase.d.ts +2 -2
  115. package/dist/phases/sharedScales/SharedScalesPhase.js +2 -2
  116. package/dist/phases/statistics/MarkerGrouping.d.ts +0 -9
  117. package/dist/phases/statistics/MarkerGrouping.js +0 -16
  118. package/dist/phases/statistics/StatisticsPhase.js +1 -1
  119. package/dist/phases/styles/StylesPhase.d.ts +3 -3
  120. package/dist/phases/styles/StylesPhase.js +2 -2
  121. package/dist/phases/tooltip/TooltipPhase.d.ts +4 -4
  122. package/dist/phases/tooltip/TooltipPhase.js +10 -7
  123. package/dist/phases/transforms/Transforms.js +3 -1
  124. package/dist/phases/transforms/TransformsPhase.d.ts +3 -3
  125. package/dist/phases/transforms/TransformsPhase.js +60 -6
  126. package/dist/phases/transforms/methods/TreemapTransform.d.ts +28 -0
  127. package/dist/phases/transforms/methods/TreemapTransform.js +119 -0
  128. package/dist/plots/correlation/heatmap/defaults.d.ts +2 -2
  129. package/dist/plots/correlation/heatmap/defaults.js +23 -8
  130. package/dist/plots/correlation/heatmap/markers.d.ts +2 -10
  131. package/dist/plots/correlation/heatmap/markers.js +11 -37
  132. package/dist/plots/correlation/scatter/defaults.d.ts +2 -2
  133. package/dist/plots/correlation/scatter/defaults.js +9 -3
  134. package/dist/plots/correlation/scatter/markers.d.ts +3 -3
  135. package/dist/plots/correlation/scatter/markers.js +6 -5
  136. package/dist/plots/distribution/box/BoxSummaries.d.ts +17 -8
  137. package/dist/plots/distribution/box/BoxSummaries.js +90 -40
  138. package/dist/plots/distribution/box/defaults.d.ts +2 -2
  139. package/dist/plots/distribution/box/defaults.js +9 -6
  140. package/dist/plots/distribution/box/markers.d.ts +2 -2
  141. package/dist/plots/distribution/box/markers.js +3 -3
  142. package/dist/plots/distribution/density/defaults.d.ts +2 -2
  143. package/dist/plots/distribution/density/defaults.js +17 -1
  144. package/dist/plots/distribution/density/markers.d.ts +2 -2
  145. package/dist/plots/distribution/density/markers.js +4 -4
  146. package/dist/plots/distribution/histogram/defaults.d.ts +2 -2
  147. package/dist/plots/distribution/histogram/defaults.js +22 -27
  148. package/dist/plots/distribution/histogram/markers.d.ts +3 -12
  149. package/dist/plots/distribution/histogram/markers.js +21 -62
  150. package/dist/plots/distribution/pyramid/defaults.d.ts +2 -2
  151. package/dist/plots/distribution/pyramid/defaults.js +7 -4
  152. package/dist/plots/distribution/pyramid/markers.d.ts +2 -12
  153. package/dist/plots/distribution/pyramid/markers.js +16 -66
  154. package/dist/plots/distribution/violin/defaults.d.ts +2 -2
  155. package/dist/plots/distribution/violin/defaults.js +9 -7
  156. package/dist/plots/distribution/violin/markers.d.ts +2 -2
  157. package/dist/plots/distribution/violin/markers.js +4 -4
  158. package/dist/plots/evolution/area/defaults.d.ts +2 -2
  159. package/dist/plots/evolution/area/defaults.js +1 -1
  160. package/dist/plots/evolution/area/markers.d.ts +2 -2
  161. package/dist/plots/evolution/area/markers.js +4 -4
  162. package/dist/plots/evolution/line/defaults.d.ts +2 -2
  163. package/dist/plots/evolution/line/defaults.js +1 -1
  164. package/dist/plots/evolution/line/markers.d.ts +2 -2
  165. package/dist/plots/evolution/line/markers.js +3 -3
  166. package/dist/plots/evolution/slope/defaults.d.ts +2 -2
  167. package/dist/plots/evolution/slope/defaults.js +8 -4
  168. package/dist/plots/evolution/slope/markers.d.ts +2 -2
  169. package/dist/plots/evolution/slope/markers.js +3 -3
  170. package/dist/plots/evolution/sparkline/defaults.d.ts +2 -2
  171. package/dist/plots/evolution/sparkline/defaults.js +5 -2
  172. package/dist/plots/evolution/sparkline/markers.d.ts +2 -2
  173. package/dist/plots/evolution/sparkline/markers.js +3 -3
  174. package/dist/plots/map/geo/Core.svelte +3 -3
  175. package/dist/plots/map/geo/defaults.d.ts +2 -2
  176. package/dist/plots/map/geo/phases/data.d.ts +1 -1
  177. package/dist/plots/map/geo/phases/data.js +1 -1
  178. package/dist/plots/map/geo/phases/hover.d.ts +2 -2
  179. package/dist/plots/map/geo/phases/hover.js +3 -3
  180. package/dist/plots/map/geo/phases/markers.d.ts +2 -2
  181. package/dist/plots/map/geo/phases/markers.js +5 -4
  182. package/dist/plots/map/geo/phases/scales.d.ts +2 -2
  183. package/dist/plots/map/geo/phases/scales.js +2 -2
  184. package/dist/plots/part-of-a-whole/treemap/Plot.svelte +47 -0
  185. package/dist/plots/part-of-a-whole/treemap/Plot.svelte.d.ts +26 -0
  186. package/dist/plots/part-of-a-whole/treemap/defaults.d.ts +10 -0
  187. package/dist/plots/part-of-a-whole/treemap/defaults.js +183 -0
  188. package/dist/plots/ranking/bar/defaults.d.ts +2 -2
  189. package/dist/plots/ranking/bar/defaults.js +15 -9
  190. package/dist/plots/ranking/bar/markers.d.ts +4 -14
  191. package/dist/plots/ranking/bar/markers.js +45 -86
  192. package/dist/plots/ranking/bullet/defaults.d.ts +2 -2
  193. package/dist/plots/ranking/bullet/defaults.js +4 -4
  194. package/dist/plots/ranking/bullet/markers.d.ts +3 -3
  195. package/dist/plots/ranking/bullet/markers.js +11 -12
  196. package/dist/plots/ranking/cleveland/ClevelandMarkers.d.ts +3 -3
  197. package/dist/plots/ranking/cleveland/ClevelandMarkers.js +28 -23
  198. package/dist/plots/ranking/cleveland/defaults.d.ts +2 -2
  199. package/dist/plots/ranking/cleveland/defaults.js +7 -4
  200. package/dist/plots/ranking/dumbbell/defaults.d.ts +2 -2
  201. package/dist/plots/ranking/forest/defaults.d.ts +2 -2
  202. package/dist/plots/ranking/lollipop/defaults.d.ts +2 -2
  203. package/dist/types/configuration/styling.d.ts +31 -2
  204. package/dist/types/layout/context.d.ts +21 -0
  205. package/dist/types/layout/context.js +1 -0
  206. package/dist/types/layout/hover.d.ts +3 -0
  207. package/dist/types/layout/legend.d.ts +8 -1
  208. package/dist/types/layout/mapping.d.ts +12 -3
  209. package/dist/types/layout/scales.d.ts +6 -0
  210. package/dist/types/layout/styles/values.d.ts +8 -2
  211. package/dist/types/layout/tooltip.d.ts +11 -4
  212. package/dist/types/markers/axis/arrow.d.ts +2 -8
  213. package/dist/types/markers/axis/axisBasedMarkersConfig.d.ts +2 -1
  214. package/dist/types/markers/axis/band.d.ts +24 -0
  215. package/dist/types/markers/axis/band.js +1 -0
  216. package/dist/types/markers/axis/bar.d.ts +6 -10
  217. package/dist/types/markers/axis/cell.d.ts +5 -5
  218. package/dist/types/markers/axis/delaunayLink.d.ts +2 -2
  219. package/dist/types/markers/axis/hover.d.ts +60 -15
  220. package/dist/types/markers/axis/rect.d.ts +4 -8
  221. package/dist/types/markers/axis/rule.d.ts +2 -16
  222. package/dist/types/markers/axis/tick.d.ts +2 -2
  223. package/dist/types/markers/axis/voronoi.d.ts +2 -2
  224. package/dist/types/markers/axis/waffle.d.ts +4 -3
  225. package/dist/types/markers/basic/dot.d.ts +2 -2
  226. package/dist/types/markers/basic/text.d.ts +56 -14
  227. package/dist/types/markers/channels/commonMarkerConfig.d.ts +8 -1
  228. package/dist/types/markers/channels/commonMarkerConfigWithArea.d.ts +1 -2
  229. package/dist/types/markers/channels/commonMarkerConfigWithLabel.d.ts +10 -0
  230. package/dist/types/markers/channels/commonMarkerConfigWithLabel.js +1 -0
  231. package/dist/types/markers/channels/commonMarkerEvents.d.ts +17 -0
  232. package/dist/types/markers/channels/commonMarkerEvents.js +13 -0
  233. package/dist/types/markers/common.d.ts +1 -0
  234. package/dist/types/markers/common.js +1 -0
  235. package/dist/types/markers/geo/contour.d.ts +2 -1
  236. package/dist/types/markers/geo/graticule.d.ts +2 -1
  237. package/dist/types/markers/geo/link.d.ts +2 -1
  238. package/dist/types/markers/geo/sphere.d.ts +2 -1
  239. package/dist/types/markers/geo/vector.d.ts +2 -1
  240. package/dist/types/phases/context/phase.d.ts +7 -0
  241. package/dist/types/phases/context/phase.js +1 -0
  242. package/dist/types/phases/data/phase.d.ts +7 -2
  243. package/dist/types/phases/hover/phase.d.ts +10 -5
  244. package/dist/types/phases/index.d.ts +2 -1
  245. package/dist/types/phases/kind.d.ts +11 -8
  246. package/dist/types/phases/mapping/phase.d.ts +2 -2
  247. package/dist/types/phases/markers/phase.d.ts +3 -3
  248. package/dist/types/phases/scales/phase.d.ts +4 -4
  249. package/dist/types/phases/stage.d.ts +3 -3
  250. package/dist/types/phases/state.d.ts +8 -1
  251. package/dist/types/phases/statistics/phase.d.ts +2 -1
  252. package/dist/types/phases/styles/phase.d.ts +3 -2
  253. package/dist/types/phases/transforms/phase.d.ts +13 -2
  254. package/dist/types/plots/constants.d.ts +17 -19
  255. package/dist/types/plots/correlation/heatmap/props.d.ts +3 -3
  256. package/dist/types/plots/correlation/heatmap/state.d.ts +2 -2
  257. package/dist/types/plots/correlation/scatter/props.d.ts +3 -3
  258. package/dist/types/plots/correlation/scatter/state.d.ts +2 -2
  259. package/dist/types/plots/data/common.d.ts +19 -6
  260. package/dist/types/plots/data/geo.d.ts +1 -1
  261. package/dist/types/plots/distribution/box/props.d.ts +25 -3
  262. package/dist/types/plots/distribution/box/state.d.ts +6 -17
  263. package/dist/types/plots/distribution/density/props.d.ts +3 -11
  264. package/dist/types/plots/distribution/density/state.d.ts +2 -2
  265. package/dist/types/plots/distribution/histogram/props.d.ts +16 -11
  266. package/dist/types/plots/distribution/histogram/state.d.ts +2 -2
  267. package/dist/types/plots/distribution/pyramid/props.d.ts +3 -3
  268. package/dist/types/plots/distribution/pyramid/state.d.ts +2 -2
  269. package/dist/types/plots/distribution/violin/props.d.ts +4 -3
  270. package/dist/types/plots/distribution/violin/state.d.ts +2 -2
  271. package/dist/types/plots/evolution/area/props.d.ts +3 -3
  272. package/dist/types/plots/evolution/area/state.d.ts +2 -2
  273. package/dist/types/plots/evolution/line/props.d.ts +3 -3
  274. package/dist/types/plots/evolution/line/state.d.ts +2 -2
  275. package/dist/types/plots/evolution/slope/state.d.ts +2 -2
  276. package/dist/types/plots/evolution/sparkline/state.d.ts +2 -2
  277. package/dist/types/plots/map/geo/state.d.ts +1 -1
  278. package/dist/types/plots/part-of-a-whole/treemap/props.d.ts +29 -0
  279. package/dist/types/plots/part-of-a-whole/treemap/props.js +1 -0
  280. package/dist/types/plots/part-of-a-whole/treemap/state.d.ts +6 -0
  281. package/dist/types/plots/part-of-a-whole/treemap/state.js +1 -0
  282. package/dist/types/plots/props.d.ts +10 -4
  283. package/dist/types/plots/ranking/bar/props.d.ts +3 -3
  284. package/dist/types/plots/ranking/bar/state.d.ts +2 -2
  285. package/dist/types/plots/ranking/bullet/state.d.ts +2 -2
  286. package/dist/types/plots/ranking/cleveland/props.d.ts +3 -3
  287. package/dist/types/plots/ranking/cleveland/state.d.ts +2 -2
  288. package/dist/types/plots/ranking/dumbbell/props.d.ts +3 -3
  289. package/dist/types/plots/ranking/dumbbell/state.d.ts +2 -2
  290. package/dist/types/plots/ranking/forest/props.d.ts +3 -3
  291. package/dist/types/plots/ranking/forest/state.d.ts +2 -2
  292. package/dist/types/plots/ranking/lollipop/props.d.ts +3 -3
  293. package/dist/types/plots/ranking/lollipop/state.d.ts +2 -2
  294. package/dist/types/plots/styling.d.ts +24 -0
  295. package/dist/types/transforms/index.d.ts +3 -1
  296. package/dist/types/transforms/treemap.d.ts +32 -0
  297. package/dist/types/transforms/treemap.js +5 -0
  298. package/dist/utils/color/ColorTones.d.ts +19 -0
  299. package/dist/utils/color/ColorTones.js +64 -0
  300. package/dist/utils/color/CssColor.d.ts +14 -5
  301. package/dist/utils/color/CssColor.js +69 -27
  302. package/dist/utils/color/index.d.ts +4 -0
  303. package/dist/utils/color/index.js +4 -0
  304. package/dist/utils/grouping.d.ts +18 -1
  305. package/dist/utils/grouping.js +31 -0
  306. package/docs/concepts.md +3 -2
  307. package/docs/legend.md +8 -5
  308. package/docs/markers.md +110 -28
  309. package/docs/plots/evolution/line.md +1 -1
  310. package/docs/plots/evolution/slope.md +1 -1
  311. package/docs/plots/part-of-a-whole/treemap.md +103 -0
  312. package/docs/plots/ranking/bar.md +2 -1
  313. package/docs/plots/ranking/cleveland.md +1 -1
  314. package/docs/plots.md +21 -20
  315. package/docs/scales.md +3 -0
  316. package/docs/state.md +34 -1
  317. package/docs/styles-and-segments.md +20 -19
  318. package/docs/theming.md +6 -12
  319. package/docs/tooltip-and-hover.md +81 -3
  320. package/docs/transforms-and-statistics.md +17 -16
  321. package/examples/LineDates.svelte +1 -1
  322. package/examples/ResponsiveLine.svelte +3 -1
  323. package/examples/Treemap.svelte +13 -0
  324. package/examples/TreemapHover.svelte +25 -0
  325. package/examples/ValueLabels.svelte +1 -1
  326. package/examples/datasets/economic-activity.ts +40 -0
  327. package/examples/datasets/index.ts +1 -0
  328. package/llms-full.txt +11 -9
  329. package/llms.txt +4 -1
  330. package/package.json +3 -1
@@ -0,0 +1,183 @@
1
+ import { TREEMAP_ROW } from '../../../phases/transforms/methods/TreemapTransform';
2
+ import { HoverDefaults } from '../../../layout/hover/HoverDefaults';
3
+ import { RowContext } from '../../../phases/context/RowContext';
4
+ import { NumberFormat } from '../../../utils/NumberFormat';
5
+ import { Grouping } from '../../../utils/grouping';
6
+ import { getConfiguration } from '../../../configuration/config.svelte';
7
+ /** A share is written with one decimal unless the author or the configuration's `numbers.decimals` says otherwise. */
8
+ const SHARE_DECIMALS = 1;
9
+ /** The width over the height of the box the tiles are shaped for, before the plot's own is known. */
10
+ const DEFAULT_ASPECT = 1.6;
11
+ /**
12
+ * What a treemap writes for a tile's share: `suffix` is a percent sign unless the author asks for something
13
+ * else, since a tile is a part of a whole.
14
+ */
15
+ function shareDisplay(values) {
16
+ return { ...NumberFormat.displayOf(values), suffix: values?.suffix ?? '%' };
17
+ }
18
+ /**
19
+ * What a treemap knows of a tile, as the transform left it on its row: its name, path, summed value and share
20
+ * (from `0` to `100`). The tiles sit in a unit square, so they have no `x` or `y` to read.
21
+ */
22
+ function tileOf(row) {
23
+ return {
24
+ name: String(row[TREEMAP_ROW.name] ?? ''),
25
+ path: row[TREEMAP_ROW.path] ?? [],
26
+ value: Number(row[TREEMAP_ROW.value]),
27
+ share: Number(row[TREEMAP_ROW.share]) * 100,
28
+ x: undefined,
29
+ y: undefined
30
+ };
31
+ }
32
+ /** A tile's context, as the "context" phase left it on its row. */
33
+ const contextOf = (row) => RowContext.of(row);
34
+ /**
35
+ * The plot's tiles: a `treemap` of its `value`, nested by the levels of its `grouping` (its `color` when unset,
36
+ * as every plot groups by it then) and shaped for its box,
37
+ * with the options of the author's own `treemap` transforms over it (`tile`...), and their other transforms
38
+ * after it in order.
39
+ */
40
+ function buildTransforms(state) {
41
+ const own = state.transforms ?? [];
42
+ const base = {
43
+ type: 'treemap',
44
+ value: state.value,
45
+ levels: Grouping.levels(state.grouping ?? state.color, state.data),
46
+ aspect: state.width && state.height ? state.width / state.height : DEFAULT_ASPECT
47
+ };
48
+ const treemap = own
49
+ .filter((t) => t.type === 'treemap')
50
+ .reduce((merged, t) => ({ ...merged, ...t }), base);
51
+ return [treemap, ...own.filter((t) => t.type !== 'treemap')];
52
+ }
53
+ /** The edges of the tiles, as the processed rows carry them. */
54
+ function edgesOf(state) {
55
+ const { x1, x2, y1, y2 } = state.processedData.channels;
56
+ return { x1, x2, y1, y2 };
57
+ }
58
+ /**
59
+ * The keys of the segments a tile has below its series: its path down to each deeper level
60
+ * (`'Tertiary.Finance'`), outermost first, so the more specific wins. The series' own are in its style already.
61
+ */
62
+ function pathKeysOf(state, row) {
63
+ const { path } = contextOf(row);
64
+ return path
65
+ .slice(1)
66
+ .map((_, i) => path.slice(0, i + 2).join(Grouping.SEPARATOR))
67
+ .filter((key) => state.segments?.[key]);
68
+ }
69
+ /**
70
+ * The tiles as `rect` markers, each with a `label`: the name of the tile over its share, fitted to it. A series'
71
+ * tiles take its style - its color, under `styles.area` and the segments keyed by it (and `default`) - and the
72
+ * segments keyed by a tile's path restyle it, so the tiles split into one marker per style. The legend's dimming
73
+ * goes over all of them, and the hover marker's `active` and `others` over the tiles it reaches.
74
+ */
75
+ function buildMarks(state, env) {
76
+ if (!state.processedData?.data.length)
77
+ return [];
78
+ const look = env.cfg.treemap;
79
+ const edges = edgesOf(state);
80
+ const labels = state.valueLabels?.show ? state.valueLabels : undefined;
81
+ const number = NumberFormat.of(shareDisplay(state.values), env.cfg, SHARE_DECIMALS);
82
+ const shareText = (row) => {
83
+ const context = contextOf(row);
84
+ return state.values?.format
85
+ ? state.values.format(context.share, number, context)
86
+ : number(context.share);
87
+ };
88
+ /** The label of a series' tiles: the name over the share, fitted - or the share alone where the name does not fit. */
89
+ const labelOf = (labels) => {
90
+ const shape = labels.shapeLabel(env, (row) => `${contextOf(row).name}
91
+ ${shareText(row)}`, { fontSize: look.fontSize });
92
+ return {
93
+ ...shape,
94
+ styles: { lineHeight: look.lineHeight, ...shape.styles },
95
+ fit: { padding: look.padding, fallback: (row) => shareText(row) }
96
+ };
97
+ };
98
+ return (state.processedGroups ?? []).flatMap((group) => {
99
+ const series = group.series.name;
100
+ const dimmed = env.interaction?.fillFor(series);
101
+ const seriesColor = state.colorForSeries(series);
102
+ /** A tile's color: its series', or a tone of it by its path while `scales.color.depth` asks for one. */
103
+ const colorOf = (row) => state.colorForPath ? state.colorForPath(contextOf(row).path) : seriesColor;
104
+ return group.visualSegments.flatMap((segment) => {
105
+ const styled = new Map();
106
+ for (const row of segment.data) {
107
+ const keys = pathKeysOf(state, row);
108
+ const color = colorOf(row);
109
+ const id = JSON.stringify([keys, color]);
110
+ const bucket = styled.get(id) ?? styled.set(id, { keys, color, rows: [] }).get(id);
111
+ bucket.rows.push(row);
112
+ }
113
+ return [...styled.values()].map(({ keys, color, rows }) => {
114
+ const style = Object.assign({}, segment.styles, ...keys.flatMap((key) => state.segments[key].map((own) => own.styles ?? {})));
115
+ return {
116
+ type: 'rect',
117
+ data: rows,
118
+ ...edges,
119
+ styles: {
120
+ ...style,
121
+ fill: dimmed?.fill ?? style.fill ?? color,
122
+ fillOpacity: dimmed?.fillOpacity ?? style.fillOpacity,
123
+ stroke: style.stroke ?? look.stroke,
124
+ strokeWidth: style.strokeWidth ?? look.strokeWidth
125
+ },
126
+ label: labels && labelOf(labels),
127
+ hover: 'style'
128
+ };
129
+ });
130
+ });
131
+ });
132
+ }
133
+ /**
134
+ * TreemapPlot on the shared pipeline: its rows are the tiles of the `treemap` transform, laid out in a unit square
135
+ * the plot's two continuous axes span (hidden). Its series are the outermost level of its `grouping`, which colors
136
+ * the tiles and fills the legend. The tiles are `rect` markers, labelled by their own `label`. Hovering a tile is
137
+ * hovering its row: an invisible `rect` over each one drives the plot's hover, and its tooltip names the tile and
138
+ * gives its share.
139
+ */
140
+ export function buildTreemapDefaults() {
141
+ return {
142
+ data: {
143
+ discreteAxes: 0,
144
+ nested: true,
145
+ segments: { color: (style) => style?.fill, connect: false, base: { flat: 'area' } }
146
+ },
147
+ // An omitted sector keeps its tiles' room, and every other tile its share; a rescaled one does not.
148
+ transforms: { transforms: buildTransforms, keepsOmitted: true },
149
+ // A tile's name, path, value and share, for its label, its tooltip and its hover.
150
+ context: () => tileOf,
151
+ scales: {
152
+ defaults: () => ({
153
+ x: { axisDisplay: 'none', grid: false },
154
+ y: { axisDisplay: 'none', grid: false, reverse: true }
155
+ }),
156
+ fit: () => ({ x: { domain: [0, 1], fitted: true }, y: { domain: [0, 1], fitted: true } })
157
+ },
158
+ styles: { values: { show: true } },
159
+ markers: { marks: buildMarks },
160
+ hover: {
161
+ strategy: 'punctual',
162
+ // A tile is hovered through its own hit area, not through whichever point the pointer is nearest.
163
+ pointMatching: 'contains',
164
+ // A tile has no axes for a crosshair, and writes its own label: its hover only restyles the tiles.
165
+ marker: (_state, env) => HoverDefaults.shapes(env.cfg),
166
+ hitAreas: (state, hover) => hover.points.map(({ row }) => ({
167
+ type: 'rect',
168
+ data: [row],
169
+ ...edgesOf(state),
170
+ styles: { fill: 'transparent' },
171
+ hover: hover.active && 'trigger'
172
+ })),
173
+ format: (state) => {
174
+ const number = NumberFormat.of(shareDisplay(state.values), getConfiguration(), SHARE_DECIMALS);
175
+ return ((row) => {
176
+ const tile = contextOf(row);
177
+ return `${tile.name}: ${number(tile.share)}`;
178
+ });
179
+ },
180
+ label: () => ((row) => contextOf(row).name)
181
+ }
182
+ };
183
+ }
@@ -1,6 +1,6 @@
1
1
  import type { AxisPlotDefaults } from '../../../types/phases';
2
2
  import type { AxisScale } from '../../../types/layout/scales';
3
- import type { BarPlotState, BarPlotCtx } from '../../../types/plots/ranking/bar/state';
3
+ import type { BarPlotState, BarPlotEnv } from '../../../types/plots/ranking/bar/state';
4
4
  /**
5
5
  * The domain a bar plot fits to its own bars on its value axis: from zero to
6
6
  * the tallest span (and the `extra` values a plot draws beyond its bars), niced to as many ticks as fit the plot. Left out when the
@@ -13,4 +13,4 @@ export declare function fitValueDomain<TData extends Record<string, unknown>>(st
13
13
  * it off the values - its own scales (padding, bar layout) and markers.
14
14
  * Its plot defaults to: hover along the category axis, timeline tweens matched per category and group.
15
15
  */
16
- export declare function buildBarDefaults<TData extends Record<string, unknown>>(): AxisPlotDefaults<BarPlotState<TData>, BarPlotCtx>;
16
+ export declare function buildBarDefaults<TData extends Record<string, unknown>>(): AxisPlotDefaults<BarPlotState<TData>, BarPlotEnv>;
@@ -1,8 +1,9 @@
1
1
  import { ProcessedPositions } from '../../../phases/transforms/ProcessedPositions';
2
- import { buildMarks, buildValueLabels, buildHitAreas, buildBarGeometry } from './markers';
2
+ import { buildMarks, buildHitAreas, buildBarGeometry } from './markers';
3
3
  import { NiceTicks } from '../../../layout/scales/NiceTicks';
4
4
  import { SERIES_KEY } from '../../../phases/transforms/TransformsPhase';
5
5
  import { PlotAxes } from '../../../phases/data/PlotAxes';
6
+ import { HoverDefaults } from '../../../layout/hover/HoverDefaults';
6
7
  /**
7
8
  * The domain a bar plot fits to its own bars on its value axis: from zero to
8
9
  * the tallest span (and the `extra` values a plot draws beyond its bars), niced to as many ticks as fit the plot. Left out when the
@@ -53,8 +54,8 @@ export function buildBarDefaults() {
53
54
  },
54
55
  scales: {
55
56
  zero: ['value'],
56
- defaults: (_state, ctx) => ({
57
- category: { paddingInner: ctx.cfg.bar.paddingInner, paddingOuter: ctx.cfg.bar.paddingOuter }
57
+ defaults: (_state, env) => ({
58
+ category: { paddingInner: env.cfg.bar.paddingInner, paddingOuter: env.cfg.bar.paddingOuter }
58
59
  }),
59
60
  fit: (state) => fitValueDomain(state)
60
61
  },
@@ -85,23 +86,28 @@ export function buildBarDefaults() {
85
86
  return labels
86
87
  .extremes(state.resolvedSeries ?? [], PlotAxes.valueOf(state), 'both')
87
88
  .map(({ series, value }) => value < 0
88
- ? labels.edgeBox(labels.format(value, series.name), { x: 'before', y: 'middle' }, { x: -offset }, ['left'])
89
- : labels.edgeBox(labels.format(value, series.name), { x: 'after', y: 'middle' }, { x: offset }, ['right']));
89
+ ? labels.edgeBox(labels.format(value, undefined, series.name), { x: 'before', y: 'middle' }, { x: -offset }, ['left'])
90
+ : labels.edgeBox(labels.format(value, undefined, series.name), { x: 'after', y: 'middle' }, { x: offset }, ['right']));
90
91
  }
91
92
  }
92
93
  },
93
- markers: { marks: buildMarks, valueLabels: buildValueLabels },
94
+ markers: { marks: buildMarks },
94
95
  hover: {
95
96
  // Each bar matched by its own band (see `buildHitAreas`); a grouped bar's dot is
96
97
  // drawn in its series' slice of the band.
97
98
  pointMatching: 'contains',
98
- decorate: (state, ctx) => {
99
- const { sliceOf } = buildBarGeometry(state, ctx.cfg.bar.seriesPadding);
99
+ decorate: (state, env) => {
100
+ const { sliceOf } = buildBarGeometry(state, env.cfg.bar.seriesPadding);
100
101
  return (row) => ({
101
102
  areaInset: sliceOf(String(row[SERIES_KEY]))
102
103
  });
103
104
  },
104
- hitAreas: buildHitAreas
105
+ hitAreas: buildHitAreas,
106
+ // The hovered category's band behind its bars - its series' slice of it, when that bar alone is hovered.
107
+ marker: (state) => ({
108
+ back: [HoverDefaults.band(state.axes?.isHorizontal ? 'y' : 'x')],
109
+ front: []
110
+ })
105
111
  },
106
112
  timeline: { interpolation: { value: 'value', key: ['category', 'grouping'] } }
107
113
  };
@@ -1,10 +1,9 @@
1
- import type { BarMarkerConfig, TextMarkerConfig } from '../../../types/markers/common';
2
- import type { BarPlotState, BarPlotCtx } from '../../../types/plots/ranking/bar/state';
1
+ import type { BarMarkerConfig } from '../../../types/markers/common';
2
+ import type { BarPlotState, BarPlotEnv } from '../../../types/plots/ranking/bar/state';
3
3
  import type { ProcessedRow } from '../../../types/phases';
4
4
  import type { AxisValue } from '../../../types/layout/mapping';
5
5
  import type { BandSlice } from '../../../types/layout/hover';
6
6
  import type { HoverConfig } from '../../../types/plots/props';
7
- import { ValueLabels } from '../../../layout/styles/ValueLabels';
8
7
  import type { AxisBasedMarkersConfig } from '../../../types/markers/common';
9
8
  /**
10
9
  * Where a bar plot's bars sit, read off the state its phases leave: each
@@ -26,20 +25,11 @@ export declare function buildBarGeometry<TData extends Record<string, unknown>>(
26
25
  * slice of it. The pointer needn't be over the visible bar. They drive the
27
26
  * plot's hover when it is active.
28
27
  */
29
- export declare function buildHitAreas<TData extends Record<string, unknown>>(state: BarPlotState<TData>, hover: HoverConfig<any>, ctx: BarPlotCtx): BarMarkerConfig[];
30
- /**
31
- * BarPlot's `styles.values` as one `'text'` marker per series, over the same
32
- * processed rows its bars draw (gap rows never get a label). `anchor` places
33
- * each label along its bar: past its top (`'outside'`), just inside it
34
- * (`'start'`), at its base (`'end'`), or centred (`'middle'`); a stacked bar's
35
- * label always sits at the middle of its own span. A grouped bar's label
36
- * shifts with its series' slice of the band.
37
- */
38
- export declare function buildValueLabels<TData extends Record<string, unknown>>(labels: ValueLabels, state: BarPlotState<TData>, ctx: BarPlotCtx): TextMarkerConfig[];
28
+ export declare function buildHitAreas<TData extends Record<string, unknown>>(state: BarPlotState<TData>, hover: HoverConfig<any>, env: BarPlotEnv): BarMarkerConfig[];
39
29
  /**
40
30
  * BarPlot's "markers" phase: visible `role: 'segment'` bars - real data plus
41
31
  * gap fills - drawing the rows the "transforms" phase left, prepended onto
42
32
  * whatever the "statistics" phase already put in `state.markers`, and its
43
33
  * value labels on top of everything.
44
34
  */
45
- export declare function buildMarks<TData extends Record<string, unknown>>(state: BarPlotState<TData>, ctx: BarPlotCtx): AxisBasedMarkersConfig[];
35
+ export declare function buildMarks<TData extends Record<string, unknown>>(state: BarPlotState<TData>, env: BarPlotEnv): AxisBasedMarkersConfig[];
@@ -46,8 +46,8 @@ export function buildBarGeometry(state, seriesPadding) {
46
46
  */
47
47
  export function buildHitAreas(state,
48
48
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
- hover, ctx) {
50
- const { categoryOf, sliceOf } = buildBarGeometry(state, ctx.cfg.bar.seriesPadding);
49
+ hover, env) {
50
+ const { categoryOf, sliceOf } = buildBarGeometry(state, env.cfg.bar.seriesPadding);
51
51
  const isHorizontal = state.axes?.isHorizontal ?? false;
52
52
  return hover.points.map(({ row, series }) => {
53
53
  const slice = series === undefined ? undefined : sliceOf(series);
@@ -57,7 +57,7 @@ hover, ctx) {
57
57
  isHorizontal,
58
58
  data: [row],
59
59
  category: categoryOf(row),
60
- hover: hover.active,
60
+ hover: hover.active && 'trigger',
61
61
  ...(slice
62
62
  ? isHorizontal
63
63
  ? { insetTop: slice.start, insetBottom: slice.end }
@@ -66,88 +66,17 @@ hover, ctx) {
66
66
  };
67
67
  });
68
68
  }
69
- /**
70
- * BarPlot's `styles.values` as one `'text'` marker per series, over the same
71
- * processed rows its bars draw (gap rows never get a label). `anchor` places
72
- * each label along its bar: past its top (`'outside'`), just inside it
73
- * (`'start'`), at its base (`'end'`), or centred (`'middle'`); a stacked bar's
74
- * label always sits at the middle of its own span. A grouped bar's label
75
- * shifts with its series' slice of the band.
76
- */
77
- export function buildValueLabels(labels, state, ctx) {
78
- const { processedData } = state;
79
- const isHorizontal = state.axes?.isHorizontal ?? false;
80
- if (!processedData)
81
- return [];
82
- const geometry = buildBarGeometry(state, ctx.cfg.bar.seriesPadding);
83
- const { font, anchor, format } = labels;
84
- const valueOf = ValueLabels.valueOf(state);
85
- const spanOf = (d) => geometry.spanOf(d) ?? [0, 0];
86
- const lowOf = (d) => Math.min(...spanOf(d));
87
- const highOf = (d) => Math.max(...spanOf(d));
88
- const below = (d) => Number(valueOf(d)) < 0;
89
- const place = (negative) => {
90
- const mid = (d) => (lowOf(d) + highOf(d)) / 2;
91
- if (geometry.stacked)
92
- return { at: mid, side: 0 };
93
- if (anchor === 'middle')
94
- return { at: mid, side: 0 };
95
- if (anchor === 'outside')
96
- return isHorizontal
97
- ? { at: negative ? lowOf : highOf, side: negative ? -1 : 1 }
98
- : { at: negative ? lowOf : highOf, side: negative ? 1 : -1 };
99
- if (anchor === 'start')
100
- return isHorizontal ? { at: lowOf, side: 1 } : { at: highOf, side: 1 };
101
- return isHorizontal ? { at: highOf, side: -1 } : { at: lowOf, side: -1 };
102
- };
103
- const gap = anchor === 'outside' ? 6 : 4;
104
- const labelled = processedData.data.filter((d) => d[GAP_VALUE] === undefined && geometry.spanOf(d) !== undefined);
105
- return (state.resolvedSeries ?? []).flatMap((s) => {
106
- const own = labelled.filter((d) => d[SERIES_ID_KEY] === seriesIdOf(s));
107
- // Only a label beyond the tip turns with the sign of its value.
108
- const turns = !geometry.stacked && anchor === 'outside';
109
- return (turns ? [false, true] : [false]).flatMap((negative) => {
110
- const data = turns ? own.filter((d) => below(d) === negative) : own;
111
- if (data.length === 0)
112
- return [];
113
- const { at, side } = place(negative);
114
- // A horizontal label reads away from its point to `side`; a vertical one sits on the far side of it.
115
- const textAnchor = labels.textAnchor ??
116
- (isHorizontal ? (side === 1 ? 'start' : side === -1 ? 'end' : 'middle') : 'middle');
117
- const lineAnchor = font?.lineAnchor ??
118
- (isHorizontal ? 'middle' : side === 1 ? 'top' : side === -1 ? 'bottom' : 'middle');
119
- return [
120
- {
121
- type: 'text',
122
- data,
123
- ...(isHorizontal ? { x: at, y: geometry.categoryOf } : { x: geometry.categoryOf, y: at }),
124
- bandSlice: geometry.sliceOf(s.name),
125
- text: (d) => format(Number(valueOf(d)), s.name, d),
126
- styles: {
127
- ...font,
128
- fill: font?.fill ?? ctx.cfg.axis.color,
129
- fontSize: font?.fontSize ?? 12,
130
- dx: font?.dx ?? (isHorizontal ? side * gap : 0),
131
- dy: font?.dy ?? (isHorizontal ? 0 : side * gap),
132
- textAnchor,
133
- lineAnchor
134
- }
135
- }
136
- ];
137
- });
138
- });
139
- }
140
69
  /**
141
70
  * BarPlot's "markers" phase: visible `role: 'segment'` bars - real data plus
142
71
  * gap fills - drawing the rows the "transforms" phase left, prepended onto
143
72
  * whatever the "statistics" phase already put in `state.markers`, and its
144
73
  * value labels on top of everything.
145
74
  */
146
- export function buildMarks(state, ctx) {
75
+ export function buildMarks(state, env) {
147
76
  const { gapFillMaps, colorForSeries, processedData } = state;
148
77
  const isHorizontal = state.axes?.isHorizontal ?? false;
149
78
  const [categoryAxis, valueAxis] = isHorizontal ? ['y', 'x'] : ['x', 'y'];
150
- const geometry = buildBarGeometry(state, ctx.cfg.bar.seriesPadding);
79
+ const geometry = buildBarGeometry(state, env.cfg.bar.seriesPadding);
151
80
  const { channels } = processedData;
152
81
  const gapDefaults = getConfiguration().bar.gap;
153
82
  // Forwarded raw when the transforms left a plain channel (a field key keeps
@@ -160,7 +89,25 @@ export function buildMarks(state, ctx) {
160
89
  // which stays a field key whenever the plot has no transforms.
161
90
  const valueOf = (channel) => (geometry.stacked || channel === undefined ? top : channel);
162
91
  const gapValue = valueOf(channels[valueAxis]);
163
- function makeMarker(data, slice, value, styles) {
92
+ // What each bar writes in itself: its value, anchored along the bar by `anchor` - past its tip
93
+ // (`'outside'`), just inside it (`'start'`), at its base (`'end'`) or in the middle. A stacked bar's
94
+ // label is always in the middle of its segment.
95
+ const labels = state.valueLabels?.show ? state.valueLabels : undefined;
96
+ const valueRead = ValueLabels.valueOf(state);
97
+ const turns = !!labels && !geometry.stacked && ValueLabels.followsSign(labels.anchor);
98
+ const labelAnchor = (negative) => ValueLabels.boxAnchor(labels?.anchor ?? 'outside', {
99
+ isHorizontal,
100
+ negative,
101
+ stacked: geometry.stacked
102
+ });
103
+ const labelFor = (name, slice, negative) => labels && {
104
+ ...labels.shapeLabel(env, (d) => labels.format(Number(valueRead(d)), d, name), {
105
+ fill: 'currentColor',
106
+ ...labelAnchor(negative)
107
+ }),
108
+ bandSlice: slice
109
+ };
110
+ function makeMarker(data, slice, value, styles, label) {
164
111
  if (data.length === 0)
165
112
  return null;
166
113
  const from = (geometry.stacked ? bottom : geometry.baseline);
@@ -170,18 +117,18 @@ export function buildMarks(state, ctx) {
170
117
  isHorizontal,
171
118
  data,
172
119
  styles,
120
+ hover: 'style',
121
+ ...(label ? { label } : {}),
173
122
  ...(isHorizontal
174
123
  ? { y: category, x1: from, x2: value }
175
124
  : { x: category, y1: from, y2: value })
176
125
  };
177
126
  if (slice) {
178
127
  if (isHorizontal) {
179
- marker.insetTop = slice.start;
180
- marker.insetBottom = slice.end;
128
+ marker.styles = { ...marker.styles, insetTop: slice.start, insetBottom: slice.end };
181
129
  }
182
130
  else {
183
- marker.insetLeft = slice.start;
184
- marker.insetRight = slice.end;
131
+ marker.styles = { ...marker.styles, insetLeft: slice.start, insetRight: slice.end };
185
132
  }
186
133
  }
187
134
  return marker;
@@ -192,10 +139,10 @@ export function buildMarks(state, ctx) {
192
139
  const name = group.series.name;
193
140
  const slice = geometry.sliceOf(name);
194
141
  const defaultColor = colorForSeries(name);
195
- const disabledFill = ctx.interaction?.fillFor(name);
142
+ const disabledFill = env.interaction?.fillFor(name);
196
143
  for (const seg of group.visualSegments) {
197
144
  const fill = disabledFill?.fill ?? seg.styles.fill ?? defaultColor;
198
- const marker = makeMarker(seg.data.filter(isReal), slice, valueOf(group.series[valueAxis]), {
145
+ const styles = {
199
146
  // An outline asked for without a color is the fill's.
200
147
  ...(seg.styles.strokeWidth !== undefined ? { stroke: fill } : {}),
201
148
  ...seg.styles,
@@ -205,9 +152,21 @@ export function buildMarks(state, ctx) {
205
152
  ...(disabledFill?.fillOpacity !== undefined
206
153
  ? { strokeOpacity: disabledFill.fillOpacity }
207
154
  : {})
208
- });
209
- if (marker)
210
- segmentMarkers.push(marker);
155
+ };
156
+ const real = seg.data.filter(isReal);
157
+ const value = valueOf(group.series[valueAxis]);
158
+ // A label past the tip turns with the sign of its value, so the bars below zero are a marker of their own.
159
+ const parts = turns
160
+ ? [false, true].map((negative) => ({
161
+ negative,
162
+ rows: real.filter((row) => Number(valueRead(row)) < 0 === negative)
163
+ }))
164
+ : [{ negative: false, rows: real }];
165
+ for (const { negative, rows } of parts) {
166
+ const marker = makeMarker(rows, slice, value, styles, labelFor(name, slice, negative));
167
+ if (marker)
168
+ segmentMarkers.push(marker);
169
+ }
211
170
  }
212
171
  const id = seriesIdOf(group.series);
213
172
  const fills = [...(gapFillMaps.get(id)?.values() ?? [])];
@@ -1,8 +1,8 @@
1
1
  import type { AxisPlotDefaults } from '../../../types/phases';
2
- import type { BulletPlotState, BulletPlotCtx } from '../../../types/plots/ranking/bullet/state';
2
+ import type { BulletPlotState, BulletPlotEnv } from '../../../types/plots/ranking/bullet/state';
3
3
  /**
4
4
  * BulletPlot on the shared pipeline: a BarPlot whose bars are drawn thinner
5
5
  * over `ranges` - bands that grade the value - with a tick at each `target`.
6
6
  * Its value axis fits them along with the bars.
7
7
  */
8
- export declare function buildBulletDefaults<TData extends Record<string, unknown>>(): AxisPlotDefaults<BulletPlotState<TData>, BulletPlotCtx>;
8
+ export declare function buildBulletDefaults<TData extends Record<string, unknown>>(): AxisPlotDefaults<BulletPlotState<TData>, BulletPlotEnv>;
@@ -11,13 +11,13 @@ export function buildBulletDefaults() {
11
11
  ...bar,
12
12
  scales: {
13
13
  ...bar.scales,
14
- defaults: (_state, ctx) => ({
14
+ defaults: (_state, env) => ({
15
15
  category: {
16
- paddingInner: ctx.cfg.bullet.paddingInner,
17
- paddingOuter: ctx.cfg.bullet.paddingOuter
16
+ paddingInner: env.cfg.bullet.paddingInner,
17
+ paddingOuter: env.cfg.bullet.paddingOuter
18
18
  }
19
19
  }),
20
- fit: (state, ctx) => fitValueDomain(state, buildReach(state, ctx))
20
+ fit: (state, env) => fitValueDomain(state, buildReach(state, env))
21
21
  },
22
22
  markers: { ...bar.markers, marks: buildMarks }
23
23
  };
@@ -1,10 +1,10 @@
1
1
  import type { AxisBasedMarkersConfig } from '../../../types/markers/common';
2
- import type { BulletPlotState, BulletPlotCtx } from '../../../types/plots/ranking/bullet/state';
2
+ import type { BulletPlotState, BulletPlotEnv } from '../../../types/plots/ranking/bullet/state';
3
3
  /** Every value the axis has to reach beyond the bars. */
4
- export declare function buildReach<TData extends Record<string, unknown>>(state: BulletPlotState<TData>, ctx: BulletPlotCtx): number[];
4
+ export declare function buildReach<TData extends Record<string, unknown>>(state: BulletPlotState<TData>, env: BulletPlotEnv): number[];
5
5
  /**
6
6
  * BulletPlot's "markers" phase, back to front: a rule per range, the bars of a
7
7
  * bar plot - thinner, so the ranges show around them - and a tick at each
8
8
  * target.
9
9
  */
10
- export declare function buildMarks<TData extends Record<string, unknown>>(state: BulletPlotState<TData>, ctx: BulletPlotCtx): AxisBasedMarkersConfig[];
10
+ export declare function buildMarks<TData extends Record<string, unknown>>(state: BulletPlotState<TData>, env: BulletPlotEnv): AxisBasedMarkersConfig[];
@@ -2,8 +2,8 @@ import { buildMarks as buildBarMarks, buildBarGeometry } from '../bar/markers';
2
2
  import { GAP_VALUE } from '../../../phases/transforms/TransformsPhase';
3
3
  import { RowNumbers } from '../../utils/RowNumbers';
4
4
  /** Each category's target and range bounds, read off the rows the bars draw. */
5
- function buildMeasures(state, ctx) {
6
- const geometry = buildBarGeometry(state, ctx.cfg.bar.seriesPadding);
5
+ function buildMeasures(state, env) {
6
+ const geometry = buildBarGeometry(state, env.cfg.bar.seriesPadding);
7
7
  return (state.processedData?.data ?? [])
8
8
  .filter((row) => row[GAP_VALUE] === undefined && geometry.spanOf(row) !== undefined)
9
9
  .map((row) => ({
@@ -16,8 +16,8 @@ function buildMeasures(state, ctx) {
16
16
  }));
17
17
  }
18
18
  /** Every value the axis has to reach beyond the bars. */
19
- export function buildReach(state, ctx) {
20
- return buildMeasures(state, ctx).flatMap(({ target, bounds }) => [
19
+ export function buildReach(state, env) {
20
+ return buildMeasures(state, env).flatMap(({ target, bounds }) => [
21
21
  ...(target === undefined ? [] : [target]),
22
22
  ...bounds
23
23
  ]);
@@ -27,19 +27,19 @@ export function buildReach(state, ctx) {
27
27
  * bar plot - thinner, so the ranges show around them - and a tick at each
28
28
  * target.
29
29
  */
30
- export function buildMarks(state, ctx) {
31
- const configured = ctx.cfg.bullet;
30
+ export function buildMarks(state, env) {
31
+ const configured = env.cfg.bullet;
32
32
  const own = (state.styles ?? {});
33
33
  const rangeColors = own.ranges?.colors ?? configured.rangeColors;
34
34
  const rangeWidth = own.ranges?.width ?? configured.rangeWidth;
35
35
  const target = {
36
- color: own.target?.color ?? configured.targetColor ?? ctx.cfg.axis.color,
36
+ color: own.target?.color ?? configured.targetColor ?? 'currentColor',
37
37
  width: own.target?.width ?? configured.targetWidth,
38
38
  length: own.target?.length ?? configured.targetLength
39
39
  };
40
40
  const isHorizontal = state.axes?.isHorizontal ?? false;
41
- const baseline = buildBarGeometry(state, ctx.cfg.bar.seriesPadding).baseline;
42
- const measures = buildMeasures(state, ctx);
41
+ const baseline = buildBarGeometry(state, env.cfg.bar.seriesPadding).baseline;
42
+ const measures = buildMeasures(state, env);
43
43
  // Each bound is a band from the baseline, drawn widest first so the narrower ones lie over it.
44
44
  const rows = measures.flatMap(({ category, bounds }) => bounds
45
45
  .map((bound, rank) => ({
@@ -59,12 +59,11 @@ export function buildMarks(state, ctx) {
59
59
  data: rows,
60
60
  value: 'category',
61
61
  ...(isHorizontal ? { x1: 'from', x2: 'to' } : { y1: 'from', y2: 'to' }),
62
- stroke: 'stroke',
63
- styles: { strokeWidth: rangeWidth }
62
+ styles: { stroke: 'stroke', strokeWidth: rangeWidth }
64
63
  }
65
64
  ];
66
65
  // The bars narrowed to a thickness of their own, centered in their band.
67
- const bars = buildBarMarks(state, ctx).map((marker) => marker.type === 'bar' && marker.role === 'segment'
66
+ const bars = buildBarMarks(state, env).map((marker) => marker.type === 'bar' && marker.role === 'segment'
68
67
  ? {
69
68
  ...marker,
70
69
  thickness: own.bar?.thickness ?? configured.barThickness
@@ -1,5 +1,5 @@
1
1
  import { ValueLabels } from '../../../layout/styles/ValueLabels';
2
- import type { ClevelandPlotState, ClevelandPlotCtx, ClevelandOptions } from '../../../types/plots/ranking/cleveland/state';
2
+ import type { ClevelandPlotState, ClevelandPlotEnv, ClevelandOptions } from '../../../types/plots/ranking/cleveland/state';
3
3
  import type { AxisBasedMarkersConfig, TextMarkerConfig } from '../../../types/markers/common';
4
4
  import type { EdgeBox } from '../../../types/layout/box';
5
5
  /**
@@ -16,14 +16,14 @@ export declare class ClevelandMarkers {
16
16
  /** Forgets what was warned about; for tests. */
17
17
  static resetWarnings(): void;
18
18
  /** The plot's connectors, then its dots, which draw on top of them. */
19
- marks: <TData extends Record<string, unknown>>(state: ClevelandPlotState<TData>, ctx: ClevelandPlotCtx) => AxisBasedMarkersConfig[];
19
+ marks: <TData extends Record<string, unknown>>(state: ClevelandPlotState<TData>, env: ClevelandPlotEnv) => AxisBasedMarkersConfig[];
20
20
  /**
21
21
  * The value labels of the dots `styles.values.of` picks, one `'text'` marker
22
22
  * per place a dot can hold in its range - past the top end (above, or right
23
23
  * of it), past the bottom end (below, or left of it) and, for the dots
24
24
  * between, beside it - and per series, when they take their series' color.
25
25
  */
26
- valueLabels: <TData extends Record<string, unknown>>(labels: ValueLabels, state: ClevelandPlotState<TData>, ctx: ClevelandPlotCtx) => TextMarkerConfig[];
26
+ valueLabels: <TData extends Record<string, unknown>>(labels: ValueLabels, state: ClevelandPlotState<TData>, env: ClevelandPlotEnv) => TextMarkerConfig[];
27
27
  /**
28
28
  * Room for the labels past the dots at the end of the value axis, so the
29
29
  * farthest one fits inside the figure instead of crossing its edge. Only the