@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
@@ -1,15 +1,17 @@
1
1
  import { Box } from '../margins/Box';
2
2
  import { PlotAxes } from '../../phases/data/PlotAxes';
3
+ import type { PlotRowContext } from '../../types/layout/context';
3
4
  import type { PlotStylesConfig } from '../../types/configuration/styling';
4
5
  import type { ValuesStyle } from '../../types/layout/styles';
5
6
  import type { ValueLabelsOptions } from '../../types/phases/styles/phase';
6
7
  import type { Series } from '../../types/plots/data/common';
7
8
  import type { FontStyle, StrokeStyle } from '../../types/plots/styling';
8
- import type { TextAnchor, ValueAnchor } from '../../types/plots/constants';
9
+ import type { LabelAnchor, TextAnchor, ValueAnchor } from '../../types/plots/constants';
9
10
  import type { BoxAnchors, EdgeBox } from '../../types/layout/box';
10
11
  import type { MarginSide } from '../../types/plots/props';
11
- import type { AxisPlotCtx, AxisPlotState, ProcessedData, ProcessedRow } from '../../types/phases';
12
+ import type { AxisPlotEnv, AxisPlotState, ProcessedData, ProcessedRow } from '../../types/phases';
12
13
  import type { TextMarkerConfig } from '../../types/markers/common';
14
+ import type { TextLabelConfig } from '../../types/markers/basic/text';
13
15
  /**
14
16
  * A plot's value labels: the author's `styles.values` over the plot kind's
15
17
  * own defaults, how their text measures, where they are expected to sit
@@ -20,7 +22,12 @@ export declare class ValueLabels {
20
22
  #private;
21
23
  readonly show: boolean;
22
24
  readonly anchor: ValueAnchor;
23
- readonly format: (value: number, seriesName: string, row?: Record<string, unknown>) => string;
25
+ /**
26
+ * A label's text for `value`: the author's `format`, else the kind's, else the value as the display fields ask.
27
+ * `row` is the row it labels, whose context the format reads; `series` names its series where there is no row
28
+ * (a label measured ahead of the rows).
29
+ */
30
+ readonly format: (value: number, row?: object, series?: string) => string;
24
31
  readonly hoverIsolate: boolean;
25
32
  readonly font: FontStyle | undefined;
26
33
  readonly fontSize: number;
@@ -33,6 +40,8 @@ export declare class ValueLabels {
33
40
  /** Where the labels are expected to sit: boxes around their points, on the edges those can reach. */
34
41
  readonly reach: EdgeBox[];
35
42
  constructor(values: ValuesStyle | undefined, cfg: PlotStylesConfig, options?: Omit<ValueLabelsOptions<never>, 'reach'>, reach?: (labels: ValueLabels) => EdgeBox[]);
43
+ /** The context a label's `format` reads: its row's, with `series` when the row gives none. */
44
+ static contextOf(row: object | undefined, series?: string): PlotRowContext;
36
45
  /** A plot's value labels: `values` over `options`, the kind's own defaults, their reach read off `state`. */
37
46
  static build<TState>(values: ValuesStyle | undefined, cfg: PlotStylesConfig, options: ValueLabelsOptions<TState>, state: TState): ValueLabels;
38
47
  /** The configuration the labels were built under, for a plot kind's own label defaults. */
@@ -78,7 +87,37 @@ export declare class ValueLabels {
78
87
  * dims with its row's series, and with `hoverIsolate`, hovering it
79
88
  * isolates that series. A row without a series gets the margins only.
80
89
  */
81
- hooks(ctx: AxisPlotCtx): Pick<TextMarkerConfig, 'fillOpacity' | 'fitMargins' | 'onPointerEnter' | 'onPointerLeave'>;
90
+ hooks(env: AxisPlotEnv): Pick<TextMarkerConfig, 'fitMargins' | 'onpointerenter' | 'onpointerleave' | 'styles'>;
91
+ /**
92
+ * Where in a bar a label goes, from the `anchor` of `styles.values`: its `label` anchor, and whether it is beyond
93
+ * the bar. `negative` tells a bar that runs to the left (or down) from its base from one that runs right (or up),
94
+ * which `'tip'`, `'base'` and `'outside'` follow; the others are the edges of the page. A `stacked` bar's label is
95
+ * always in the middle. An anchor the shapes do not read (`'start'`, `'end'`) is taken for `'outside'`, the default.
96
+ */
97
+ static boxAnchor(anchor: ValueAnchor, shape: {
98
+ isHorizontal: boolean;
99
+ negative?: boolean;
100
+ stacked?: boolean;
101
+ }): {
102
+ anchor: LabelAnchor;
103
+ outside?: boolean;
104
+ };
105
+ /** Whether a label at `anchor` goes to one side or the other of a bar with the sign of its value. */
106
+ static followsSign(anchor: ValueAnchor): boolean;
107
+ /**
108
+ * The `label` the shapes of a plot kind write their value in: this plot's `styles.values` over the `defaults` the kind
109
+ * sets, with what every label shares ({@link hooks}) - its dimming and isolating of a series. A label inside its shape
110
+ * never reaches out of the plot, so only one `outside` has the margins grow to hold it; and it takes the default
111
+ * `fill` only `outside`, for inside it is written in the color that contrasts with its shape.
112
+ */
113
+ shapeLabel(env: AxisPlotEnv, text: (row: ProcessedRow) => string, defaults?: {
114
+ fill?: string;
115
+ fontSize?: number;
116
+ fontWeight?: FontStyle['fontWeight'];
117
+ anchor?: LabelAnchor;
118
+ outside?: boolean;
119
+ gap?: number;
120
+ }): TextLabelConfig;
82
121
  /**
83
122
  * A processed row's own value, read through its series' own value channel
84
123
  * (`y`, or `x` on a horizontal plot) - what a label shows, even where a
@@ -6,6 +6,7 @@ import { seriesIdOf } from '../../utils/grouping';
6
6
  import { isGapValue } from '../../plots/utils/gaps';
7
7
  import { PlotAxes } from '../../phases/data/PlotAxes';
8
8
  import { NumberFormat } from '../../utils/NumberFormat';
9
+ import { RowContext } from '../../phases/context/RowContext';
9
10
  /**
10
11
  * A plot's value labels: the author's `styles.values` over the plot kind's
11
12
  * own defaults, how their text measures, where they are expected to sit
@@ -15,6 +16,11 @@ import { NumberFormat } from '../../utils/NumberFormat';
15
16
  export class ValueLabels {
16
17
  show;
17
18
  anchor;
19
+ /**
20
+ * A label's text for `value`: the author's `format`, else the kind's, else the value as the display fields ask.
21
+ * `row` is the row it labels, whose context the format reads; `series` names its series where there is no row
22
+ * (a label measured ahead of the rows).
23
+ */
18
24
  format;
19
25
  hoverIsolate;
20
26
  font;
@@ -33,12 +39,10 @@ export class ValueLabels {
33
39
  this.anchor = values?.anchor ?? options.anchor ?? 'outside';
34
40
  // The value as the display fields ask (else as it is), which a plot kind's own text builds on.
35
41
  const number = NumberFormat.maybe(NumberFormat.displayOf(values), cfg) ?? ((v) => `${v}`);
36
- const kindFormat = options.format;
37
- this.format = values?.format
38
- ? (v, name, row) => values.format(v, name, row, number)
39
- : kindFormat
40
- ? (v, name) => kindFormat(v, name, number)
41
- : (v) => number(v);
42
+ const own = values?.format ?? options.format;
43
+ this.format = own
44
+ ? (v, row, series) => own(v, number, ValueLabels.contextOf(row, series))
45
+ : (v) => number(v);
42
46
  this.hoverIsolate = values?.hoverIsolate ?? false;
43
47
  this.font = values?.fontStyle;
44
48
  this.fontSize = typeof this.font?.fontSize === 'number' ? this.font.fontSize : 12;
@@ -48,6 +52,11 @@ export class ValueLabels {
48
52
  this.#cfg = cfg;
49
53
  this.reach = (this.show && reach?.(this)) || [];
50
54
  }
55
+ /** The context a label's `format` reads: its row's, with `series` when the row gives none. */
56
+ static contextOf(row, series) {
57
+ const context = RowContext.of(row);
58
+ return context.series === undefined && series !== undefined ? { ...context, series } : context;
59
+ }
51
60
  /** A plot's value labels: `values` over `options`, the kind's own defaults, their reach read off `state`. */
52
61
  static build(values, cfg, options, state) {
53
62
  const { reach } = options;
@@ -134,20 +143,80 @@ export class ValueLabels {
134
143
  * dims with its row's series, and with `hoverIsolate`, hovering it
135
144
  * isolates that series. A row without a series gets the margins only.
136
145
  */
137
- hooks(ctx) {
138
- const interaction = ctx.interaction;
146
+ hooks(env) {
147
+ const interaction = env.interaction;
139
148
  const seriesOf = (d) => d?.[SERIES_KEY] === undefined ? undefined : String(d[SERIES_KEY]);
140
149
  const isolate = this.hoverIsolate && interaction;
141
150
  return {
142
151
  fitMargins: true,
143
- fillOpacity: (d) => {
144
- const series = seriesOf(d);
145
- return series === undefined ? undefined : interaction?.fillFor(series)?.fillOpacity;
152
+ styles: {
153
+ fillOpacity: (d) => {
154
+ const series = seriesOf(d);
155
+ return series === undefined ? 1 : (interaction?.fillFor(series)?.fillOpacity ?? 1);
156
+ }
146
157
  },
147
- onPointerEnter: isolate
148
- ? (d) => interaction.isolate(seriesOf(d) ?? null)
158
+ onpointerenter: isolate
159
+ ? (_event, d) => interaction.isolate(seriesOf(d) ?? null)
149
160
  : undefined,
150
- onPointerLeave: isolate ? () => interaction.isolate(null) : undefined
161
+ onpointerleave: isolate ? () => interaction.isolate(null) : undefined
162
+ };
163
+ }
164
+ /**
165
+ * Where in a bar a label goes, from the `anchor` of `styles.values`: its `label` anchor, and whether it is beyond
166
+ * the bar. `negative` tells a bar that runs to the left (or down) from its base from one that runs right (or up),
167
+ * which `'tip'`, `'base'` and `'outside'` follow; the others are the edges of the page. A `stacked` bar's label is
168
+ * always in the middle. An anchor the shapes do not read (`'start'`, `'end'`) is taken for `'outside'`, the default.
169
+ */
170
+ static boxAnchor(anchor, shape) {
171
+ if (shape.stacked || anchor === 'middle')
172
+ return { anchor: 'middle' };
173
+ // A place in the shape as it is drawn on the page, which no sign moves.
174
+ if (anchor !== 'outside' &&
175
+ anchor !== 'start' &&
176
+ anchor !== 'end' &&
177
+ anchor !== 'tip' &&
178
+ anchor !== 'base') {
179
+ return { anchor };
180
+ }
181
+ const [tip, base] = shape.isHorizontal
182
+ ? shape.negative
183
+ ? ['left', 'right']
184
+ : ['right', 'left']
185
+ : shape.negative
186
+ ? ['bottom', 'top']
187
+ : ['top', 'bottom'];
188
+ if (anchor === 'base')
189
+ return { anchor: base };
190
+ return anchor === 'tip' ? { anchor: tip } : { anchor: tip, outside: true };
191
+ }
192
+ /** Whether a label at `anchor` goes to one side or the other of a bar with the sign of its value. */
193
+ static followsSign(anchor) {
194
+ return anchor === 'outside' || anchor === 'tip' || anchor === 'base';
195
+ }
196
+ /**
197
+ * The `label` the shapes of a plot kind write their value in: this plot's `styles.values` over the `defaults` the kind
198
+ * sets, with what every label shares ({@link hooks}) - its dimming and isolating of a series. A label inside its shape
199
+ * never reaches out of the plot, so only one `outside` has the margins grow to hold it; and it takes the default
200
+ * `fill` only `outside`, for inside it is written in the color that contrasts with its shape.
201
+ */
202
+ shapeLabel(env, text, defaults = {}) {
203
+ const { fitMargins, styles: shared, ...events } = this.hooks(env);
204
+ const { font } = this;
205
+ return {
206
+ ...events,
207
+ text,
208
+ anchor: defaults.anchor,
209
+ outside: defaults.outside,
210
+ gap: defaults.gap,
211
+ fitMargins: defaults.outside ? fitMargins : undefined,
212
+ styles: {
213
+ ...shared,
214
+ ...font,
215
+ // Inside its shape, a label unset is written in the color that reads best on it.
216
+ fill: font?.fill ?? (defaults.outside ? defaults.fill : undefined),
217
+ fontSize: font?.fontSize ?? defaults.fontSize ?? 12,
218
+ fontWeight: font?.fontWeight ?? defaults.fontWeight
219
+ }
151
220
  };
152
221
  }
153
222
  /**
@@ -229,17 +298,16 @@ export class ValueLabels {
229
298
  x: (processed.channels.x ?? position.x),
230
299
  y: (processed.channels.y2 ?? processed.channels.y ?? topOf),
231
300
  grouping: SERIES_ID_KEY,
232
- text: (d) => format(Number(valueOf(d)), nameOf(d), d),
301
+ text: (d) => format(Number(valueOf(d)), d, nameOf(d)),
233
302
  styles: {
234
303
  ...font,
235
- ...(this.fill ? { fill: this.fill } : {}),
304
+ fill: this.fill ?? ((d) => colorOf(d) ?? 'currentColor'),
236
305
  fontSize: font?.fontSize ?? 12,
237
306
  dx: font?.dx ?? (anchor === 'start' ? 6 : anchor === 'end' ? -6 : 0),
238
307
  dy: font?.dy ?? (anchor === 'outside' ? -8 : 0),
239
308
  textAnchor: this.textAnchor ?? (anchor === 'start' || anchor === 'end' ? anchor : 'middle'),
240
309
  lineAnchor: font?.lineAnchor ?? (anchor === 'outside' ? 'bottom' : 'middle')
241
310
  },
242
- fill: this.fill ? undefined : colorOf,
243
311
  declutter: {
244
312
  connector: this.strokeStyle,
245
313
  aligned: !!end.lane && (anchor === 'start' || anchor === 'end'),
@@ -297,7 +365,7 @@ export class ValueLabels {
297
365
  const lo = Number(domain[0]);
298
366
  const hi = Number(domain[domain.length - 1]);
299
367
  for (const s of series)
300
- texts.push(format(lo, s.name), format(hi, s.name));
368
+ texts.push(format(lo, undefined, s.name), format(hi, undefined, s.name));
301
369
  }
302
370
  else {
303
371
  for (const s of series) {
@@ -307,7 +375,7 @@ export class ValueLabels {
307
375
  for (const d of s.data) {
308
376
  const v = Number(y(d));
309
377
  if (!Number.isNaN(v))
310
- texts.push(format(v, s.name));
378
+ texts.push(format(v, undefined, s.name));
311
379
  }
312
380
  }
313
381
  }
@@ -2,6 +2,7 @@
2
2
  import { Plot, RuleX, RuleY, Text } from 'svelteplot';
3
3
  import { TimelineSteps } from './TimelineSteps';
4
4
  import { getConfiguration } from '../../configuration/config.svelte';
5
+ import ConfigVars from '../../configuration/ConfigVars.svelte';
5
6
  import type { Orientation, TimeValue } from '../../types/layout/timeline';
6
7
 
7
8
  /**
@@ -54,6 +55,9 @@
54
55
  );
55
56
  </script>
56
57
 
58
+ <!-- Its colors are the configuration's, with or without a figure around it. -->
59
+ <ConfigVars />
60
+
57
61
  <!-- Drawn with the configuration's font even outside a figure's chrome, which would hand it down. -->
58
62
  <div style="display: contents" style:font-family={config.font}>
59
63
  <Plot
@@ -89,7 +93,7 @@
89
93
  {...textOffset}
90
94
  fontSize={rule.activeFontSize}
91
95
  fontWeight={rule.activeFontWeight}
92
- fill={getConfiguration().timeline.activeColor}
96
+ fill="var(--dct-timeline-active, currentColor)"
93
97
  />
94
98
  </Plot>
95
99
  </div>
@@ -1,8 +1,8 @@
1
1
  import { Box } from '../margins/Box';
2
- import type { PlotAxes } from '../../phases/data/PlotAxes';
2
+ import { PlotAxes } from '../../phases/data/PlotAxes';
3
3
  import type { ProcessedData, ProcessedRow } from '../../types/phases';
4
- import type { TooltipAnchorX, TooltipAnchorY } from '../../types/layout/tooltip';
5
4
  import type { Series } from '../../types/plots/data/common';
5
+ import type { TooltipAnchorX, TooltipAnchorY } from '../../types/layout/tooltip';
6
6
  /** What a tooltip is shown from, each read reactively. */
7
7
  export type TooltipInputs = {
8
8
  /** The point it sits beside. */
@@ -46,16 +46,15 @@ export declare class TooltipState {
46
46
  /** A value as plain text: a date as a locale date, a number as `number` writes it (when given), anything else as itself. */
47
47
  static value(value: unknown, number?: (value: number) => string): string;
48
48
  /**
49
- * How a hovered row reads by default, on every plot: its series, when the
50
- * plot groups its rows; then where it sits - `category: value` when one
51
- * axis is a band of categories (the row's own value, as its series reads
52
- * it), else `x: y` as the transforms left them; then the value its color
53
- * shows, when that is a number (a heatmap's cells). With `number`, the values - the one on the value axis
54
- * (the plot's `y` when neither axis holds categories) and the color's - read as it writes them.
49
+ * How a hovered row reads by default, on every plot, from its context (see {@link RowContext}): its series,
50
+ * when the plot groups its rows; then where it sits - `category: value` when one axis is a band of categories,
51
+ * else `x: y` (an axis the transforms spread into a span, a bin's, as `from-to`); then the value its color
52
+ * shows, when that is a number (a heatmap's cells). With `number`, the values - the one on the value axis and
53
+ * the color's - read as it writes them.
55
54
  */
56
55
  static default(state: {
57
56
  processedData?: ProcessedData;
58
- resolvedSeries?: Series<Record<string, unknown>>[];
57
+ resolvedSeries?: Series<any>[];
59
58
  channels?: {
60
59
  grouping?: unknown;
61
60
  color?: {
@@ -2,7 +2,8 @@ import { Box } from '../margins/Box';
2
2
  import { PlotMargins } from '../margins/PlotMargins.svelte';
3
3
  import { resolveAccessor } from '../../utils/accessors';
4
4
  import { SERIES_KEY } from '../../phases/transforms/TransformsPhase';
5
- import { ValueLabels } from '../styles/ValueLabels';
5
+ import { RowContext } from '../../phases/context/RowContext';
6
+ import { PlotAxes } from '../../phases/data/PlotAxes';
6
7
  /** A tooltip anchor as the side of the point the tooltip sits on. */
7
8
  const SIDES = {
8
9
  left: 'before',
@@ -69,29 +70,33 @@ export class TooltipState {
69
70
  return number && typeof value === 'number' ? number(value) : String(value);
70
71
  }
71
72
  /**
72
- * How a hovered row reads by default, on every plot: its series, when the
73
- * plot groups its rows; then where it sits - `category: value` when one
74
- * axis is a band of categories (the row's own value, as its series reads
75
- * it), else `x: y` as the transforms left them; then the value its color
76
- * shows, when that is a number (a heatmap's cells). With `number`, the values - the one on the value axis
77
- * (the plot's `y` when neither axis holds categories) and the color's - read as it writes them.
73
+ * How a hovered row reads by default, on every plot, from its context (see {@link RowContext}): its series,
74
+ * when the plot groups its rows; then where it sits - `category: value` when one axis is a band of categories,
75
+ * else `x: y` (an axis the transforms spread into a span, a bin's, as `from-to`); then the value its color
76
+ * shows, when that is a number (a heatmap's cells). With `number`, the values - the one on the value axis and
77
+ * the color's - read as it writes them.
78
78
  */
79
79
  static default(state, number) {
80
80
  const processed = state.processedData;
81
81
  if (!processed)
82
82
  return () => '';
83
- const x = TooltipState.#axisText(processed, 'x');
84
- const y = TooltipState.#axisText(processed, 'y');
85
- // With no band axis, the value is the y.
86
- const valueY = TooltipState.#axisText(processed, 'y', number);
83
+ const valueAxis = PlotAxes.valueOf(state);
84
+ const contextOf = RowContext.reader(state);
87
85
  const bandX = state.axes?.bands.includes('x') ?? false;
88
86
  const bandY = state.axes?.bands.includes('y') ?? false;
89
- const valueOf = ValueLabels.valueOf(state);
87
+ const along = (axis) => {
88
+ const span = TooltipState.#spanText(processed, axis, number);
89
+ const measured = axis === valueAxis && !state.axes?.bands.includes(axis);
90
+ return (row) => span ? span(row) : TooltipState.value(contextOf(row)[axis], measured ? number : undefined);
91
+ };
92
+ const x = along('x');
93
+ const y = along('y');
94
+ const valueOf = (row) => TooltipState.value(contextOf(row).value, number);
90
95
  const position = bandX && !bandY
91
- ? (row) => `${x(row)}: ${TooltipState.value(valueOf(row), number)}`
96
+ ? (row) => `${x(row)}: ${valueOf(row)}`
92
97
  : bandY && !bandX
93
- ? (row) => `${y(row)}: ${TooltipState.value(valueOf(row), number)}`
94
- : (row) => `${x(row)}: ${valueY(row)}`;
98
+ ? (row) => `${y(row)}: ${valueOf(row)}`
99
+ : (row) => `${x(row)}: ${y(row)}`;
95
100
  const grouped = state.channels?.grouping !== undefined;
96
101
  const color = state.channels?.color;
97
102
  const colorName = typeof color?.source === 'string' ? color.source : 'color';
@@ -106,26 +111,20 @@ export class TooltipState {
106
111
  };
107
112
  }
108
113
  /**
109
- * How one axis reads on a processed row: its own channel, else the range
110
- * the transforms gave it - a stack's own share (`2 - 1`), any other span as `1-2`.
114
+ * How an axis the transforms spread into a span reads on a processed row - a bin's edges as `from-to` - or
115
+ * `undefined` when the axis has a value of its own or is a stack's (whose own value the context gives).
111
116
  */
112
- static #axisText(processed, axis, number) {
117
+ static #spanText(processed, axis, number) {
113
118
  const { channels, transforms } = processed;
114
- const read = (channel) => resolveAccessor(channel);
115
- const point = channels[axis];
116
- if (point !== undefined) {
117
- const value = read(point);
118
- return (row) => TooltipState.value(value(row), number);
119
- }
120
119
  const low = channels[`${axis}1`];
121
120
  const high = channels[`${axis}2`];
122
- if (low === undefined || high === undefined)
123
- return () => '';
121
+ if (channels[axis] !== undefined || low === undefined || high === undefined)
122
+ return undefined;
123
+ if (transforms.some((t) => t.type === STACKS[axis]))
124
+ return undefined;
125
+ const read = (channel) => resolveAccessor(channel);
124
126
  const from = read(low);
125
127
  const to = read(high);
126
- if (transforms.some((t) => t.type === STACKS[axis])) {
127
- return (row) => TooltipState.value(Number(to(row)) - Number(from(row)), number);
128
- }
129
128
  return (row) => `${TooltipState.value(from(row), number)}-${TooltipState.value(to(row), number)}`;
130
129
  }
131
130
  }
@@ -14,6 +14,11 @@ export declare class MarkerKinds {
14
14
  clip: false;
15
15
  drawsRows: true;
16
16
  };
17
+ band: {
18
+ clip: true;
19
+ drawsRows: false;
20
+ legendSymbol: "rect";
21
+ };
17
22
  bar: {
18
23
  clip: true;
19
24
  drawsRows: true;
@@ -6,6 +6,7 @@ export class MarkerKinds {
6
6
  static traits = {
7
7
  area: { clip: true, drawsRows: true, legendSymbol: 'area' },
8
8
  arrow: { clip: false, drawsRows: true },
9
+ band: { clip: true, drawsRows: false, legendSymbol: 'rect' },
9
10
  bar: { clip: true, drawsRows: true, legendSymbol: 'bar' },
10
11
  bollinger: { clip: true, drawsRows: true, legendSymbol: 'line' },
11
12
  brush: { clip: false, drawsRows: false },
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { MarkerEvents } from '../utils/MarkerEvents';
2
3
  import { AreaX, AreaY } from 'svelteplot';
3
4
  import { usePlot } from '../../layout/plot/usePlot';
4
5
  import { MarkerChannels } from '../utils/MarkerChannels';
@@ -12,6 +13,7 @@
12
13
  * a band, the area runs from zero up to its own value.
13
14
  */
14
15
  let { marker }: { marker: AreaMarkerConfig } = $props();
16
+ const events = MarkerEvents.use(() => marker);
15
17
 
16
18
  const plot = usePlot();
17
19
  const isHorizontal = $derived(plot.axes?.isHorizontal ?? false);
@@ -36,6 +38,7 @@
36
38
 
37
39
  {#snippet area(rows: typeof data, fillOpacity: number | undefined)}
38
40
  <AreaMark
41
+ {...events.props}
39
42
  data={rows}
40
43
  x={marker.x}
41
44
  y={marker.y}
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { RowStyle } from '../utils/RowStyle';
3
+ import { MarkerEvents } from '../utils/MarkerEvents';
2
4
  import { Arrow } from 'svelteplot';
3
5
  import { usePlot } from '../../layout/plot/usePlot';
4
6
  import { RowStroke } from '../utils/RowStroke';
@@ -12,11 +14,12 @@
12
14
  * last, so such an arrow is placed in pixels instead.
13
15
  */
14
16
  let { marker }: { marker: ArrowMarkerConfig } = $props();
17
+ const events = MarkerEvents.use(() => marker);
15
18
 
16
19
  const plot = usePlot().svelteplot;
17
20
  const data = $derived(marker.data ?? []);
18
- /** Each row's own stroke, over the marker's `styles`. */
19
- const row = $derived(RowStroke.of(marker, marker.styles, { stroke: 'currentColor' }));
21
+ /** Each row's stroke: the marker's `styles`, which can be functions of the row. */
22
+ const row = $derived(RowStroke.of(marker.styles, data, { stroke: 'currentColor' }));
20
23
 
21
24
  type Row = Record<string, unknown>;
22
25
  type Channel = string | number | ((d: never) => unknown) | undefined;
@@ -51,6 +54,7 @@
51
54
  </script>
52
55
 
53
56
  <Arrow
57
+ {...events.props}
54
58
  data={placed}
55
59
  x1={onBand ? own('__x1') : marker.x1}
56
60
  y1={onBand ? own('__y1') : marker.y1}
@@ -59,9 +63,9 @@
59
63
  bend={marker.bend}
60
64
  headAngle={marker.headAngle ?? 60}
61
65
  headLength={marker.headLength ?? 8}
62
- inset={marker.inset ?? 0}
63
- insetStart={marker.insetStart}
64
- insetEnd={marker.insetEnd}
66
+ inset={RowStyle.field(marker.styles?.inset) ?? 0}
67
+ insetStart={RowStyle.field(marker.styles?.insetStart)}
68
+ insetEnd={RowStyle.field(marker.styles?.insetEnd)}
65
69
  sweep={marker.sweep}
66
70
  stroke={row.stroke}
67
71
  strokeWidth={row.strokeWidth}
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ import { usePlot } from '../../layout/plot/usePlot';
3
+ import { getConfiguration } from '../../configuration/config.svelte';
4
+ import { MarkerEvents } from '../utils/MarkerEvents';
5
+ import { RowStyle } from '../utils/RowStyle';
6
+ import { Bands, type Band } from './Bands';
7
+ import type { BandMarkerConfig } from '../../types/markers/common';
8
+
9
+ /**
10
+ * Renders one `'band'` marker: a rectangle over the band of each category it names, across the whole of the
11
+ * other axis. Nothing on an axis that is not a band scale. It takes the pointer only with a handler of its own,
12
+ * so a band behind the plot's shapes does not take their hover.
13
+ */
14
+ const { marker }: { marker: BandMarkerConfig } = $props();
15
+ const cfg = $derived(getConfiguration());
16
+ const events = MarkerEvents.use(() => marker);
17
+ const plot = usePlot().svelteplot;
18
+
19
+ const bands = $derived(Bands.of(marker));
20
+ const rows = $derived(marker.data ?? []);
21
+ const styles = $derived({ ...cfg.band, ...marker.styles });
22
+ const scale = $derived(plot.scales[marker.axis]);
23
+ const across = $derived(plot.scales[marker.axis === 'x' ? 'y' : 'x']);
24
+
25
+ /** The pixels the other axis spans, lowest first. */
26
+ const extent = $derived.by((): [number, number] => {
27
+ const range = across?.fn?.range?.() as number[] | undefined;
28
+ if (!range || range.length < 2) return [0, 0];
29
+ const [a, b] = [Number(range[0]), Number(range[range.length - 1])];
30
+ return [Math.min(a, b), Math.max(a, b)];
31
+ });
32
+
33
+ /** Where a band is drawn: its slice of the band along the axis, the other axis' whole span across it. */
34
+ function boxOf(band: Band) {
35
+ const bandwidth = scale.fn.bandwidth?.() ?? 0;
36
+ const start = Number(scale.fn(band.category as never));
37
+ const from = start + band.slice.start * bandwidth;
38
+ const size = Math.max(0, bandwidth * (1 - band.slice.start - band.slice.end));
39
+ const [low, high] = extent;
40
+ return marker.axis === 'x'
41
+ ? { x: from, y: low, width: size, height: high - low }
42
+ : { x: low, y: from, width: high - low, height: size };
43
+ }
44
+
45
+ /** A color of `styles` for the row: a value, the field of the rows it names, or a function of the row. */
46
+ const colorOf = (style: unknown, row: unknown) => RowStyle.colorOf(style, rows)?.(row);
47
+ /** A number of `styles` for the row: a value, the field of the rows it names, or a function of the row. */
48
+ const numberOf = (style: unknown, row: unknown): number | undefined => {
49
+ const read = RowStyle.field(style as never) as unknown;
50
+ const value = typeof read === 'function' ? (read as (row: unknown) => unknown)(row) : read;
51
+ return value == null ? undefined : Number(value);
52
+ };
53
+ </script>
54
+
55
+ {#if scale?.type === 'band'}
56
+ <g class="band" pointer-events={events.any ? undefined : 'none'}>
57
+ {#each bands as band (band.category instanceof Date ? +band.category : band.category)}
58
+ {@const box = boxOf(band)}
59
+ {@const radius = numberOf(styles.borderRadius, band.row)}
60
+ <rect
61
+ {...box}
62
+ rx={radius}
63
+ ry={radius}
64
+ fill={colorOf(styles.fill, band.row)}
65
+ fill-opacity={numberOf(styles.fillOpacity, band.row)}
66
+ stroke={colorOf(styles.stroke, band.row)}
67
+ stroke-width={numberOf(styles.strokeWidth, band.row)}
68
+ stroke-opacity={numberOf(styles.strokeOpacity, band.row)}
69
+ stroke-dasharray={colorOf(styles.strokeDasharray, band.row)}
70
+ {...events.forRow(band.row, band.index)}
71
+ />
72
+ {/each}
73
+ </g>
74
+ {/if}
@@ -0,0 +1,7 @@
1
+ import type { BandMarkerConfig } from '../../types/markers/common';
2
+ type $$ComponentProps = {
3
+ marker: BandMarkerConfig;
4
+ };
5
+ declare const BandMarker: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type BandMarker = ReturnType<typeof BandMarker>;
7
+ export default BandMarker;
@@ -0,0 +1,16 @@
1
+ import type { AxisValue } from '../../types/layout/mapping';
2
+ import type { BandSlice } from '../../types/layout/hover';
3
+ import type { BandMarkerConfig } from '../../types/markers/common';
4
+ /** One band to draw: its category, the part of it filled, and the first row that names it. */
5
+ export type Band = {
6
+ category: AxisValue;
7
+ slice: BandSlice;
8
+ row: unknown;
9
+ index: number;
10
+ };
11
+ /** The bands a `band` marker draws, one per category its rows (or its `value`) name, in the order they first come. */
12
+ export declare class Bands {
13
+ #private;
14
+ /** The marker's bands. Rows that share a category share one band, which fills what all of their slices do. */
15
+ static of(marker: Pick<BandMarkerConfig, 'value' | 'slice' | 'data'>): Band[];
16
+ }
@@ -0,0 +1,48 @@
1
+ import { resolveAccessor } from '../../utils/accessors';
2
+ /** The bands a `band` marker draws, one per category its rows (or its `value`) name, in the order they first come. */
3
+ export class Bands {
4
+ static #WHOLE = { start: 0, end: 0 };
5
+ /** The marker's bands. Rows that share a category share one band, which fills what all of their slices do. */
6
+ static of(marker) {
7
+ const { rows, categoryOf } = Bands.#rowsOf(marker);
8
+ const sliceOf = Bands.#sliceOf(marker.slice);
9
+ const bands = new Map();
10
+ rows.forEach((row, index) => {
11
+ const category = categoryOf(row);
12
+ if (category == null)
13
+ return;
14
+ const key = category instanceof Date ? +category : category;
15
+ const slice = sliceOf(row);
16
+ const band = bands.get(key);
17
+ if (!band) {
18
+ bands.set(key, { category, slice, row, index });
19
+ return;
20
+ }
21
+ // What either one fills: the least left out at each end.
22
+ band.slice = {
23
+ start: Math.min(band.slice.start, slice.start),
24
+ end: Math.min(band.slice.end, slice.end)
25
+ };
26
+ });
27
+ return [...bands.values()];
28
+ }
29
+ /** The rows a marker draws from, and the category of each: its `data` and `value`, or its `value`'s own. */
30
+ static #rowsOf(marker) {
31
+ const { value, data } = marker;
32
+ if (data) {
33
+ const read = resolveAccessor(value);
34
+ return { rows: data, categoryOf: read };
35
+ }
36
+ const values = (Array.isArray(value) ? value : [value]);
37
+ return { rows: values, categoryOf: (row) => row };
38
+ }
39
+ /** Each row's slice: the marker's own, or a function of the row's; the whole band when it gives none. */
40
+ static #sliceOf(slice) {
41
+ const whole = Bands.#WHOLE;
42
+ const read = typeof slice === 'function' ? slice : () => slice;
43
+ return (row) => {
44
+ const own = read(row);
45
+ return own ? { start: own.start ?? 0, end: own.end ?? 0 } : whole;
46
+ };
47
+ }
48
+ }