@fundar/data-chart-telling 1.18.0 → 1.20.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 (252) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +2 -1
  3. package/dist/configuration/config.svelte.js +1 -1
  4. package/dist/index.d.ts +4 -2
  5. package/dist/index.js +2 -1
  6. package/dist/layout/coordinates/CoordinatesLayout.svelte +3 -1
  7. package/dist/layout/facet/FacetLayout.svelte +54 -41
  8. package/dist/layout/geometry/GeometryLayout.svelte +57 -22
  9. package/dist/layout/geometry/ScaleFreeContext.d.ts +31 -0
  10. package/dist/layout/geometry/ScaleFreeContext.js +65 -0
  11. package/dist/layout/geometry/ScaleFreeMarks.svelte +14 -0
  12. package/dist/layout/geometry/ScaleFreeMarks.svelte.d.ts +7 -0
  13. package/dist/layout/geometry/ScaleGate.svelte.d.ts +8 -0
  14. package/dist/layout/geometry/ScaleGate.svelte.js +95 -0
  15. package/dist/layout/geometry/ScaleGateMarks.svelte +15 -0
  16. package/dist/layout/geometry/ScaleGateMarks.svelte.d.ts +7 -0
  17. package/dist/layout/hover/HoverShapes.d.ts +20 -8
  18. package/dist/layout/hover/HoverShapes.js +119 -59
  19. package/dist/layout/legend/ContinuousSection.svelte +10 -0
  20. package/dist/layout/legend/LegendState.svelte.d.ts +13 -1
  21. package/dist/layout/legend/LegendState.svelte.js +32 -0
  22. package/dist/layout/margins/Box.d.ts +4 -0
  23. package/dist/layout/margins/Box.js +14 -0
  24. package/dist/layout/margins/PlotMargins.svelte.js +26 -1
  25. package/dist/layout/plot/{Plot.svelte → AbstractPlot.svelte} +83 -6
  26. package/dist/layout/plot/{Plot.svelte.d.ts → AbstractPlot.svelte.d.ts} +4 -4
  27. package/dist/layout/plot/PublicPlotContext.d.ts +5 -0
  28. package/dist/layout/plot/PublicPlotContext.js +7 -0
  29. package/dist/layout/styles/ValueLabels.d.ts +109 -58
  30. package/dist/layout/styles/ValueLabels.js +299 -141
  31. package/dist/markers/MarkerKinds.d.ts +79 -1
  32. package/dist/markers/MarkerKinds.js +149 -23
  33. package/dist/markers/area/AreaMarker.svelte +1 -1
  34. package/dist/markers/band/BandMarker.svelte +2 -1
  35. package/dist/markers/bar/BarMarker.svelte +8 -6
  36. package/dist/markers/bollinger/BollingerMarker.svelte +1 -1
  37. package/dist/markers/box/BoxMarker.svelte +1 -1
  38. package/dist/markers/dot/DotRadius.d.ts +11 -0
  39. package/dist/markers/dot/DotRadius.js +21 -0
  40. package/dist/markers/geo/GeoHoverMarker.svelte +14 -11
  41. package/dist/markers/labels/CurveLabel.svelte +56 -0
  42. package/dist/markers/labels/CurveLabel.svelte.d.ts +9 -0
  43. package/dist/markers/labels/LabelMerge.d.ts +11 -0
  44. package/dist/markers/labels/LabelMerge.js +87 -0
  45. package/dist/markers/labels/MarkerLabel.svelte +36 -0
  46. package/dist/markers/labels/MarkerLabel.svelte.d.ts +10 -0
  47. package/dist/markers/labels/MarkerLabels.d.ts +52 -0
  48. package/dist/markers/labels/MarkerLabels.js +97 -0
  49. package/dist/markers/labels/geometry/BoxGeometry.d.ts +8 -0
  50. package/dist/markers/labels/geometry/BoxGeometry.js +101 -0
  51. package/dist/markers/labels/geometry/CurveGeometry.d.ts +34 -0
  52. package/dist/markers/labels/geometry/CurveGeometry.js +193 -0
  53. package/dist/markers/labels/geometry/PointGeometry.d.ts +9 -0
  54. package/dist/markers/labels/geometry/PointGeometry.js +22 -0
  55. package/dist/markers/labels/layouts/BoxLayout.d.ts +10 -0
  56. package/dist/markers/labels/layouts/BoxLayout.js +49 -0
  57. package/dist/markers/labels/layouts/PathLayout.d.ts +11 -0
  58. package/dist/markers/labels/layouts/PathLayout.js +91 -0
  59. package/dist/markers/labels/layouts/PointLayout.d.ts +19 -0
  60. package/dist/markers/labels/layouts/PointLayout.js +94 -0
  61. package/dist/markers/regression/RegressionMarker.svelte +1 -1
  62. package/dist/markers/text/Covering.d.ts +13 -0
  63. package/dist/markers/text/Covering.js +29 -0
  64. package/dist/markers/text/Declutter.d.ts +24 -3
  65. package/dist/markers/text/Declutter.js +46 -3
  66. package/dist/markers/text/TextMarker.svelte +90 -17
  67. package/dist/markers/text/TextMarker.svelte.d.ts +1 -1
  68. package/dist/markers/tick/TickMarker.svelte +1 -1
  69. package/dist/markers/utils/MarkerChannels.d.ts +1 -1
  70. package/dist/markers/utils/MarkerChannels.js +3 -2
  71. package/dist/markers/violin/ViolinMarker.svelte +1 -1
  72. package/dist/markers/waffle/WaffleMarker.svelte +1 -1
  73. package/dist/phases/context/RowContext.d.ts +2 -0
  74. package/dist/phases/context/RowContext.js +4 -2
  75. package/dist/phases/context/rowContextKey.d.ts +2 -0
  76. package/dist/phases/context/rowContextKey.js +2 -0
  77. package/dist/phases/markers/MarkerStyles.js +14 -11
  78. package/dist/phases/markers/MarkersPhase.d.ts +2 -3
  79. package/dist/phases/markers/MarkersPhase.js +17 -11
  80. package/dist/phases/sharedScales/SharedStepScales.d.ts +10 -0
  81. package/dist/phases/sharedScales/SharedStepScales.js +43 -0
  82. package/dist/phases/statistics/MarkerGrouping.js +5 -32
  83. package/dist/phases/statistics/MarkerInheritance.d.ts +11 -0
  84. package/dist/phases/statistics/MarkerInheritance.js +25 -0
  85. package/dist/phases/statistics/MarkerOrientation.d.ts +26 -0
  86. package/dist/phases/statistics/MarkerOrientation.js +29 -0
  87. package/dist/phases/statistics/StatisticsPhase.js +15 -15
  88. package/dist/phases/transforms/TransformsPhase.js +5 -3
  89. package/dist/plots/correlation/heatmap/Plot.svelte +2 -2
  90. package/dist/plots/correlation/heatmap/Plot.svelte.d.ts +0 -1
  91. package/dist/plots/correlation/heatmap/defaults.js +14 -1
  92. package/dist/plots/correlation/heatmap/markers.d.ts +0 -6
  93. package/dist/plots/correlation/heatmap/markers.js +5 -9
  94. package/dist/plots/correlation/scatter/Plot.svelte +2 -2
  95. package/dist/plots/correlation/scatter/Plot.svelte.d.ts +0 -1
  96. package/dist/plots/correlation/scatter/defaults.js +9 -3
  97. package/dist/plots/correlation/scatter/markers.d.ts +0 -9
  98. package/dist/plots/correlation/scatter/markers.js +21 -28
  99. package/dist/plots/distribution/box/BoxSummaries.d.ts +5 -0
  100. package/dist/plots/distribution/box/BoxSummaries.js +9 -0
  101. package/dist/plots/distribution/box/Plot.svelte +2 -2
  102. package/dist/plots/distribution/box/Plot.svelte.d.ts +0 -1
  103. package/dist/plots/distribution/box/defaults.js +11 -0
  104. package/dist/plots/distribution/box/markers.js +10 -1
  105. package/dist/plots/distribution/density/Plot.svelte +2 -2
  106. package/dist/plots/distribution/density/Plot.svelte.d.ts +0 -1
  107. package/dist/plots/distribution/density/defaults.js +16 -0
  108. package/dist/plots/distribution/density/markers.js +5 -1
  109. package/dist/plots/distribution/histogram/Plot.svelte +2 -2
  110. package/dist/plots/distribution/histogram/Plot.svelte.d.ts +0 -1
  111. package/dist/plots/distribution/histogram/defaults.js +16 -11
  112. package/dist/plots/distribution/histogram/markers.js +3 -3
  113. package/dist/plots/distribution/pyramid/Plot.svelte +2 -2
  114. package/dist/plots/distribution/pyramid/Plot.svelte.d.ts +0 -1
  115. package/dist/plots/distribution/pyramid/defaults.js +9 -2
  116. package/dist/plots/distribution/pyramid/markers.d.ts +0 -8
  117. package/dist/plots/distribution/pyramid/markers.js +6 -16
  118. package/dist/plots/distribution/violin/Plot.svelte +2 -2
  119. package/dist/plots/distribution/violin/Plot.svelte.d.ts +0 -1
  120. package/dist/plots/distribution/violin/defaults.js +11 -0
  121. package/dist/plots/distribution/violin/markers.js +27 -3
  122. package/dist/plots/evolution/area/Plot.svelte +2 -2
  123. package/dist/plots/evolution/area/Plot.svelte.d.ts +0 -1
  124. package/dist/plots/evolution/area/defaults.js +4 -7
  125. package/dist/plots/evolution/area/markers.js +3 -1
  126. package/dist/plots/evolution/line/Plot.svelte +2 -2
  127. package/dist/plots/evolution/line/Plot.svelte.d.ts +0 -1
  128. package/dist/plots/evolution/line/defaults.js +4 -6
  129. package/dist/plots/evolution/line/markers.js +3 -1
  130. package/dist/plots/evolution/slope/Plot.svelte +2 -2
  131. package/dist/plots/evolution/slope/Plot.svelte.d.ts +0 -1
  132. package/dist/plots/evolution/slope/defaults.js +4 -3
  133. package/dist/plots/evolution/slope/markers.d.ts +4 -3
  134. package/dist/plots/evolution/slope/markers.js +16 -9
  135. package/dist/plots/evolution/sparkline/Plot.svelte +2 -2
  136. package/dist/plots/evolution/sparkline/Plot.svelte.d.ts +0 -1
  137. package/dist/plots/evolution/sparkline/defaults.js +1 -1
  138. package/dist/plots/evolution/sparkline/markers.js +3 -1
  139. package/dist/plots/generic/Plot.svelte +42 -0
  140. package/dist/plots/generic/Plot.svelte.d.ts +25 -0
  141. package/dist/plots/generic/defaults.d.ts +4 -0
  142. package/dist/plots/generic/defaults.js +7 -0
  143. package/dist/plots/map/geo/Core.svelte +29 -6
  144. package/dist/plots/map/geo/Plot.svelte +40 -12
  145. package/dist/plots/map/geo/Plot.svelte.d.ts +0 -1
  146. package/dist/plots/map/geo/phases/data.d.ts +2 -1
  147. package/dist/plots/map/geo/phases/data.js +8 -2
  148. package/dist/plots/map/geo/phases/scales.js +6 -2
  149. package/dist/plots/map/geo/slices.d.ts +27 -3
  150. package/dist/plots/map/geo/slices.js +58 -5
  151. package/dist/plots/part-of-a-whole/treemap/Plot.svelte +2 -2
  152. package/dist/plots/part-of-a-whole/treemap/Plot.svelte.d.ts +0 -1
  153. package/dist/plots/part-of-a-whole/treemap/defaults.js +2 -2
  154. package/dist/plots/ranking/bar/Plot.svelte +2 -2
  155. package/dist/plots/ranking/bar/Plot.svelte.d.ts +0 -1
  156. package/dist/plots/ranking/bar/defaults.js +13 -3
  157. package/dist/plots/ranking/bar/markers.js +12 -29
  158. package/dist/plots/ranking/bullet/Plot.svelte +2 -2
  159. package/dist/plots/ranking/bullet/Plot.svelte.d.ts +0 -1
  160. package/dist/plots/ranking/bullet/defaults.js +20 -0
  161. package/dist/plots/ranking/bullet/markers.js +7 -1
  162. package/dist/plots/ranking/cleveland/ClevelandMarkers.d.ts +2 -9
  163. package/dist/plots/ranking/cleveland/ClevelandMarkers.js +65 -47
  164. package/dist/plots/ranking/cleveland/Plot.svelte +2 -2
  165. package/dist/plots/ranking/cleveland/Plot.svelte.d.ts +0 -1
  166. package/dist/plots/ranking/cleveland/defaults.js +33 -2
  167. package/dist/plots/ranking/dumbbell/Plot.svelte +2 -2
  168. package/dist/plots/ranking/dumbbell/Plot.svelte.d.ts +0 -1
  169. package/dist/plots/ranking/forest/Plot.svelte +2 -2
  170. package/dist/plots/ranking/forest/Plot.svelte.d.ts +0 -1
  171. package/dist/plots/ranking/lollipop/Plot.svelte +2 -2
  172. package/dist/plots/ranking/lollipop/Plot.svelte.d.ts +0 -1
  173. package/dist/types/layout/context.d.ts +2 -0
  174. package/dist/types/layout/plot.d.ts +2 -0
  175. package/dist/types/layout/styles/bullet.d.ts +4 -1
  176. package/dist/types/layout/styles/geo.d.ts +3 -3
  177. package/dist/types/layout/styles/values.d.ts +51 -11
  178. package/dist/types/markers/axis/area.d.ts +5 -1
  179. package/dist/types/markers/axis/bar.d.ts +5 -2
  180. package/dist/types/markers/axis/bollinger.d.ts +2 -1
  181. package/dist/types/markers/axis/box.d.ts +2 -1
  182. package/dist/types/markers/axis/cell.d.ts +4 -1
  183. package/dist/types/markers/axis/line.d.ts +4 -1
  184. package/dist/types/markers/axis/rect.d.ts +4 -1
  185. package/dist/types/markers/axis/regression.d.ts +2 -1
  186. package/dist/types/markers/axis/tick.d.ts +2 -1
  187. package/dist/types/markers/axis/trail.d.ts +4 -1
  188. package/dist/types/markers/axis/violin.d.ts +2 -1
  189. package/dist/types/markers/axis/waffle.d.ts +5 -1
  190. package/dist/types/markers/basic/dot.d.ts +4 -1
  191. package/dist/types/markers/basic/text.d.ts +25 -21
  192. package/dist/types/markers/channels/commonMarkerConfigWithLabel.d.ts +5 -9
  193. package/dist/types/markers/channels/commonMarkerConfigWithOrientation.d.ts +5 -0
  194. package/dist/types/markers/channels/commonMarkerConfigWithOrientation.js +1 -0
  195. package/dist/types/markers/labels/box.d.ts +57 -0
  196. package/dist/types/markers/labels/box.js +1 -0
  197. package/dist/types/markers/labels/common.d.ts +15 -0
  198. package/dist/types/markers/labels/common.js +1 -0
  199. package/dist/types/markers/labels/path.d.ts +52 -0
  200. package/dist/types/markers/labels/path.js +1 -0
  201. package/dist/types/markers/labels/point.d.ts +40 -0
  202. package/dist/types/markers/labels/point.js +1 -0
  203. package/dist/types/markers/traits.d.ts +10 -0
  204. package/dist/types/phases/markers/phase.d.ts +1 -8
  205. package/dist/types/phases/statistics/phase.d.ts +8 -3
  206. package/dist/types/phases/styles/phase.d.ts +15 -3
  207. package/dist/types/phases/transforms/phase.d.ts +2 -0
  208. package/dist/types/plots/constants.d.ts +0 -12
  209. package/dist/types/plots/correlation/heatmap/props.d.ts +3 -2
  210. package/dist/types/plots/correlation/scatter/props.d.ts +3 -2
  211. package/dist/types/plots/data/geo.d.ts +19 -5
  212. package/dist/types/plots/distribution/box/props.d.ts +6 -2
  213. package/dist/types/plots/distribution/density/props.d.ts +2 -1
  214. package/dist/types/plots/distribution/histogram/props.d.ts +3 -2
  215. package/dist/types/plots/distribution/pyramid/props.d.ts +3 -2
  216. package/dist/types/plots/distribution/violin/props.d.ts +4 -1
  217. package/dist/types/plots/evolution/area/props.d.ts +3 -2
  218. package/dist/types/plots/evolution/line/props.d.ts +3 -2
  219. package/dist/types/plots/generic/props.d.ts +16 -0
  220. package/dist/types/plots/generic/props.js +1 -0
  221. package/dist/types/plots/generic/state.d.ts +4 -0
  222. package/dist/types/plots/generic/state.js +1 -0
  223. package/dist/types/plots/map/geo/props.d.ts +9 -3
  224. package/dist/types/plots/map/geo/state.d.ts +3 -1
  225. package/dist/types/plots/part-of-a-whole/treemap/props.d.ts +4 -2
  226. package/dist/types/plots/ranking/bar/props.d.ts +3 -2
  227. package/dist/types/plots/ranking/cleveland/props.d.ts +3 -2
  228. package/dist/types/plots/ranking/dumbbell/props.d.ts +3 -2
  229. package/dist/types/plots/ranking/forest/props.d.ts +5 -2
  230. package/dist/types/plots/ranking/lollipop/props.d.ts +3 -2
  231. package/dist/utils/ConfigEquality.d.ts +11 -0
  232. package/dist/utils/ConfigEquality.js +37 -0
  233. package/docs/architecture.md +9 -9
  234. package/docs/facets.md +12 -0
  235. package/docs/geo.md +35 -7
  236. package/docs/legend.md +6 -0
  237. package/docs/markers.md +2 -4
  238. package/docs/plots/ranking/bar.md +1 -1
  239. package/docs/plots/ranking/cleveland.md +1 -1
  240. package/docs/state.md +1 -1
  241. package/docs/styles-and-segments.md +1 -14
  242. package/docs/timeline.md +1 -1
  243. package/docs/transforms-and-statistics.md +1 -1
  244. package/docs/value-labels.md +159 -0
  245. package/examples/BarValues.svelte +1 -1
  246. package/llms-full.txt +5 -5
  247. package/llms.txt +1 -0
  248. package/package.json +3 -1
  249. package/dist/markers/utils/BoxLabel.d.ts +0 -58
  250. package/dist/markers/utils/BoxLabel.js +0 -175
  251. package/dist/markers/utils/MarkerLabel.svelte +0 -33
  252. package/dist/markers/utils/MarkerLabel.svelte.d.ts +0 -10
@@ -22,15 +22,13 @@ export function buildLineDefaults() {
22
22
  transforms: { labels: { select: 'last', skip: ValueLabels.skipGaps } },
23
23
  styles: {
24
24
  values: {
25
- anchor: 'start',
25
+ layout: 'point',
26
+ layouts: { point: { side: 'after' }, path: { side: 'above', offset: 'end' } },
26
27
  format: (v, number, context) => `${context.series} - ${number(v)}`,
27
- reach: (labels, state) => labels.reachAtSeriesEnds(state)
28
+ reach: (labels, state) => (labels.layout === 'point' ? labels.reachAtSeriesEnds(state) : [])
28
29
  }
29
30
  },
30
- markers: {
31
- marks: buildMarks,
32
- valueLabels: (labels, state) => labels.atSeriesEnds(state)
33
- },
31
+ markers: { marks: buildMarks },
34
32
  timeline: { filterMode: 'upTo', interpolation: { value: 'y', key: ['grouping'] } }
35
33
  };
36
34
  }
@@ -1,3 +1,4 @@
1
+ import { ValueLabels } from '../../../layout/styles/ValueLabels';
1
2
  import { getConfiguration } from '../../../configuration/config.svelte';
2
3
  import { resolveGapRuns, resolveGapsForSeries } from '../../utils/gaps';
3
4
  /**
@@ -197,5 +198,6 @@ export function buildMarks(state, env) {
197
198
  disabledStrokeFor,
198
199
  disabledDotsFor
199
200
  });
200
- return [...lineMarkers, ...gapMarkers];
201
+ const labels = state.valueLabels?.show ? state.valueLabels.forSeries(state, env) : undefined;
202
+ return [...ValueLabels.onMarkers(lineMarkers, 'line', labels), ...gapMarkers];
201
203
  }
@@ -1,5 +1,5 @@
1
1
  <script lang="ts" generics="TData extends Record<string, unknown>">
2
- import Plot from '../../../layout/plot/Plot.svelte';
2
+ import AbstractPlot from '../../../layout/plot/AbstractPlot.svelte';
3
3
  import { buildSlopeDefaults } from './defaults';
4
4
  import type { SlopePlotProps, SlopePlotCoreProps } from '../../../types/plots/evolution/slope/props';
5
5
 
@@ -25,7 +25,7 @@
25
25
  }: SlopePlotProps<TData> = $props();
26
26
  </script>
27
27
 
28
- <Plot
28
+ <AbstractPlot
29
29
  core={core as SlopePlotCoreProps<TData>}
30
30
  defaults={buildSlopeDefaults}
31
31
  bind:margins
@@ -1,4 +1,3 @@
1
- import Plot from '../../../layout/plot/Plot.svelte';
2
1
  import type { SlopePlotProps } from '../../../types/plots/evolution/slope/props';
3
2
  declare function $$render<TData extends Record<string, unknown>>(): {
4
3
  props: SlopePlotProps<TData>;
@@ -1,4 +1,4 @@
1
- import { buildMarks, buildValueLabels } from './markers';
1
+ import { buildMarks } from './markers';
2
2
  import { PlotAxes } from '../../../phases/data/PlotAxes';
3
3
  import { HoverDefaults } from '../../../layout/hover/HoverDefaults';
4
4
  import { ValueLabels } from '../../../layout/styles/ValueLabels';
@@ -24,11 +24,12 @@ export function buildSlopeDefaults() {
24
24
  },
25
25
  styles: {
26
26
  values: {
27
- anchor: 'start',
27
+ layout: 'point',
28
+ layouts: { point: { side: 'after' }, path: { side: 'above', offset: 'middle' } },
28
29
  format: (v, number, context) => `${context.series} - ${number(v)}`
29
30
  }
30
31
  },
31
- markers: { marks: buildMarks, valueLabels: buildValueLabels },
32
+ markers: { marks: buildMarks },
32
33
  // Only two positions: a rule along the value axis at the hovered point says more than one across them.
33
34
  hover: { ...line.hover, marker: (state) => HoverDefaults.valueRule(PlotAxes.valueOf(state)) }
34
35
  };
@@ -1,6 +1,7 @@
1
- import type { ValueLabels } from '../../../layout/styles/ValueLabels';
1
+ import { ValueLabels } from '../../../layout/styles/ValueLabels';
2
2
  import type { EdgeBox } from '../../../types/layout/box';
3
- import type { AxisBasedMarkersConfig, TextMarkerConfig } from '../../../types/markers/common';
3
+ import type { AxisBasedMarkersConfig } from '../../../types/markers/common';
4
+ import type { MarkerLabelConfig } from '../../../types/markers/labels/common';
4
5
  import type { SlopePlotState, SlopePlotEnv } from '../../../types/plots/evolution/slope/state';
5
6
  /**
6
7
  * SlopePlot's "markers" phase: each series' line, with a dot on every point
@@ -11,6 +12,6 @@ export declare function buildMarks<TData extends Record<string, unknown>>(state:
11
12
  * SlopePlot's value labels: the series' first points labelled before them and
12
13
  * its last ones after, each end spread apart where its labels would overlap.
13
14
  */
14
- export declare function buildValueLabels<TData extends Record<string, unknown>>(labels: ValueLabels, state: SlopePlotState<TData>): TextMarkerConfig[];
15
+ export declare function buildValueLabels<TData extends Record<string, unknown>>(labels: ValueLabels, state: SlopePlotState<TData>, env: SlopePlotEnv): MarkerLabelConfig[];
15
16
  /** Where SlopePlot's labels are expected to sit: past the points at both ends. */
16
17
  export declare function buildReach<TData extends Record<string, unknown>>(labels: ValueLabels, state: SlopePlotState<TData>): EdgeBox[];
@@ -1,9 +1,10 @@
1
1
  import { getConfiguration } from '../../../configuration/config.svelte';
2
2
  import { buildLineMarkers } from '../line/markers';
3
3
  import { ProcessedPositions } from '../../../phases/transforms/ProcessedPositions';
4
- /** The anchor of the labels at the plot's start: the mirror of the end's, so `'start'` always reads outward. */
5
- function startAnchor(anchor) {
6
- return anchor === 'start' ? 'end' : anchor === 'end' ? 'start' : anchor;
4
+ import { ValueLabels } from '../../../layout/styles/ValueLabels';
5
+ /** The side of the labels at the plot's start: the mirror of the end's, so `'after'` always reads outward. */
6
+ function startSide(side) {
7
+ return side === 'after' ? 'before' : side === 'before' ? 'after' : side;
7
8
  }
8
9
  /** The value a position is told apart by: a date by its time. */
9
10
  const keyOf = (value) => (value instanceof Date ? value.getTime() : value);
@@ -24,13 +25,17 @@ export function buildMarks(state, env) {
24
25
  }
25
26
  }))
26
27
  }));
27
- return buildLineMarkers({
28
+ const lines = buildLineMarkers({
28
29
  groupedSeries: groups,
29
30
  colorFor: state.colorForSeries,
30
31
  disabledStrokeFor: (name) => env.interaction?.strokeFor(name),
31
32
  disabledDotsFor: (name) => env.interaction?.dotsFor(name),
32
33
  curve: state.styles?.curve
33
34
  });
35
+ const labels = state.valueLabels?.show
36
+ ? buildValueLabels(state.valueLabels, state, env)
37
+ : undefined;
38
+ return ValueLabels.onMarkers(lines, 'line', labels);
34
39
  }
35
40
  /** The rows labelled at the plot's first position and at its last, each series' own. */
36
41
  function labelledEnds(state) {
@@ -52,25 +57,27 @@ function labelledEnds(state) {
52
57
  * SlopePlot's value labels: the series' first points labelled before them and
53
58
  * its last ones after, each end spread apart where its labels would overlap.
54
59
  */
55
- export function buildValueLabels(labels, state) {
60
+ export function buildValueLabels(labels, state, env) {
56
61
  if (!state.processedData)
57
62
  return [];
63
+ if (labels.layout === 'path')
64
+ return labels.alongSeries(state, env);
58
65
  const { start, end } = labelledEnds(state);
59
66
  return [
60
- ...labels.atSeriesEnds(state, {
67
+ ...labels.atSeriesEnds(state, env, {
61
68
  rows: start,
62
- anchor: startAnchor(labels.anchor),
69
+ side: startSide(labels.side),
63
70
  lane: true,
64
71
  flip: false
65
72
  }),
66
- ...labels.atSeriesEnds(state, { rows: end, lane: true })
73
+ ...labels.atSeriesEnds(state, env, { rows: end, lane: true })
67
74
  ];
68
75
  }
69
76
  /** Where SlopePlot's labels are expected to sit: past the points at both ends. */
70
77
  export function buildReach(labels, state) {
71
78
  // Labels before the first position reach the left edge, those after the last one the right.
72
79
  const before = labels
73
- .reachAtSeriesEnds(state, startAnchor(labels.anchor))
80
+ .reachAtSeriesEnds(state, startSide(labels.side))
74
81
  .map(({ box, edges }) => ({ box, edges: edges.filter((edge) => edge !== 'right') }));
75
82
  const after = labels
76
83
  .reachAtSeriesEnds(state)
@@ -1,5 +1,5 @@
1
1
  <script lang="ts" generics="TData extends Record<string, unknown>">
2
- import Plot from '../../../layout/plot/Plot.svelte';
2
+ import AbstractPlot from '../../../layout/plot/AbstractPlot.svelte';
3
3
  import { buildSparklineDefaults } from './defaults';
4
4
  import type {
5
5
  SparklinePlotProps,
@@ -28,7 +28,7 @@
28
28
  }: SparklinePlotProps<TData> = $props();
29
29
  </script>
30
30
 
31
- <Plot
31
+ <AbstractPlot
32
32
  core={core as SparklinePlotCoreProps<TData>}
33
33
  defaults={buildSparklineDefaults}
34
34
  bind:margins
@@ -1,4 +1,3 @@
1
- import Plot from '../../../layout/plot/Plot.svelte';
2
1
  import type { SparklinePlotProps } from '../../../types/plots/evolution/sparkline/props';
3
2
  declare function $$render<TData extends Record<string, unknown>>(): {
4
3
  props: SparklinePlotProps<TData>;
@@ -19,7 +19,7 @@ export function buildSparklineDefaults() {
19
19
  format: (value, number) => number(value)
20
20
  }
21
21
  },
22
- markers: { marks: buildMarks, valueLabels: line.markers.valueLabels },
22
+ markers: { marks: buildMarks },
23
23
  // Small and bare: a dot on the hovered point, and nothing else.
24
24
  hover: { ...line.hover, marker: () => ({ back: [], front: [HoverDefaults.dot()] }) }
25
25
  };
@@ -1,3 +1,4 @@
1
+ import { ValueLabels } from '../../../layout/styles/ValueLabels';
1
2
  import { getConfiguration } from '../../../configuration/config.svelte';
2
3
  import { buildLineMarkers } from '../line/markers';
3
4
  import { resolveAccessor } from '../../../utils/accessors';
@@ -52,5 +53,6 @@ export function buildMarks(state, env) {
52
53
  }
53
54
  ];
54
55
  });
55
- return [...lines, ...dots];
56
+ const labels = state.valueLabels?.show ? state.valueLabels.forSeries(state, env) : undefined;
57
+ return [...ValueLabels.onMarkers(lines, 'line', labels), ...dots];
56
58
  }
@@ -0,0 +1,42 @@
1
+ <script lang="ts" generics="TData extends Record<string, unknown>">
2
+ import AbstractPlot from '../../layout/plot/AbstractPlot.svelte';
3
+ import { buildGenericDefaults } from './defaults';
4
+ import type { GenericPlotProps, GenericPlotCoreProps } from '../../types/plots/generic/props';
5
+
6
+ /**
7
+ * A plot of no kind: no shapes or defaults of its own, only its `markers`. `data` and the channels
8
+ * are optional; markers without their own take them, and its `segments`, `transforms`, `styles`,
9
+ * chrome, `timeline` and `facet` work as on any plot.
10
+ * `margins` is bindable: it reports the margin the plot settled on.
11
+ */
12
+ let {
13
+ title,
14
+ subtitle,
15
+ caption,
16
+ header,
17
+ footer,
18
+ legend,
19
+ order,
20
+ timeline,
21
+ facet,
22
+ tooltip,
23
+ margins = $bindable(),
24
+ ...core
25
+ }: GenericPlotProps<TData> = $props();
26
+ </script>
27
+
28
+ <AbstractPlot
29
+ core={core as GenericPlotCoreProps<TData>}
30
+ defaults={buildGenericDefaults}
31
+ bind:margins
32
+ {title}
33
+ {subtitle}
34
+ {caption}
35
+ {header}
36
+ {footer}
37
+ {legend}
38
+ {order}
39
+ {timeline}
40
+ {facet}
41
+ {tooltip}
42
+ />
@@ -0,0 +1,25 @@
1
+ import type { GenericPlotProps } from '../../types/plots/generic/props';
2
+ declare function $$render<TData extends Record<string, unknown>>(): {
3
+ props: GenericPlotProps<TData>;
4
+ exports: {};
5
+ bindings: "margins";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<TData extends Record<string, unknown>> {
10
+ props(): ReturnType<typeof $$render<TData>>['props'];
11
+ events(): ReturnType<typeof $$render<TData>>['events'];
12
+ slots(): ReturnType<typeof $$render<TData>>['slots'];
13
+ bindings(): "margins";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <TData extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<TData>['exports']>;
20
+ <TData extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const Plot: $$IsomorphicComponent;
24
+ type Plot<TData extends Record<string, unknown>> = InstanceType<typeof Plot<TData>>;
25
+ export default Plot;
@@ -0,0 +1,4 @@
1
+ import type { AxisPlotDefaults } from '../../types/phases';
2
+ import type { GenericPlotState, GenericPlotEnv } from '../../types/plots/generic/state';
3
+ /** The plot with no kind: it draws only its `markers`. */
4
+ export declare function buildGenericDefaults<TData extends Record<string, unknown>>(): AxisPlotDefaults<GenericPlotState<TData>, GenericPlotEnv>;
@@ -0,0 +1,7 @@
1
+ /** The plot with no kind: it draws only its `markers`. */
2
+ export function buildGenericDefaults() {
3
+ return {
4
+ data: { segments: { color: (style) => style?.fill } },
5
+ markers: { marks: () => [] }
6
+ };
7
+ }
@@ -7,6 +7,7 @@
7
7
  import BasePlotLayout from '../../../layout/base/BasePlotLayout.svelte';
8
8
  import type { GeoPlotCoreProps } from '../../../types/plots/map/geo/props';
9
9
  import type { CoordinatesConfig } from '../../../types/layout/coordinates';
10
+ import type { GeoFeature } from '../../../types/plots/data/geo';
10
11
  import type { GeoPlotState, GeoPlotEnv } from '../../../types/plots/map/geo/state';
11
12
 
12
13
  /**
@@ -19,10 +20,10 @@
19
20
  let {
20
21
  data,
21
22
  object,
22
- featureId,
23
- color,
24
- grouping,
25
- opacity,
23
+ featureId: featureIdProp,
24
+ color: colorProp,
25
+ grouping: groupingProp,
26
+ opacity: opacityProp,
26
27
  excludeParts,
27
28
  width,
28
29
  height,
@@ -33,11 +34,26 @@
33
34
  coordinates = {},
34
35
  margins = $bindable(),
35
36
  tooltip = undefined,
37
+ sliceContext = {},
36
38
  pipeline
37
39
  }: Props = $props();
38
40
 
39
41
  const cfg = $derived(getConfiguration());
40
42
 
43
+ // The callbacks read a feature in the slice this core draws; the pipeline's phases call them with the feature alone.
44
+ const color = $derived(colorProp && ((f: GeoFeature<TProps>) => colorProp(f, sliceContext)));
45
+ const grouping = $derived(
46
+ groupingProp && ((f: GeoFeature<TProps>) => groupingProp(f, sliceContext))
47
+ );
48
+ const opacity = $derived(
49
+ opacityProp && ((f: GeoFeature<TProps>) => opacityProp(f, sliceContext))
50
+ );
51
+ const featureId = $derived(
52
+ typeof featureIdProp === 'function'
53
+ ? (f: GeoFeature<TProps>) => featureIdProp(f, sliceContext)
54
+ : featureIdProp
55
+ );
56
+
41
57
  // ── Resolve data: GeoJSON is synchronous, TopoJSON is converted async ────
42
58
  const resolved = new GeoFeatures<TProps>(
43
59
  () => data,
@@ -83,7 +99,7 @@
83
99
  fillOpacity: styles.fillOpacity,
84
100
  stroke: styles.stroke,
85
101
  strokeWidth: styles.strokeWidth,
86
- onFeatureClick: styles.onFeatureClick
102
+ onFeatureClick: styles.onFeatureClick && ((d, e) => styles.onFeatureClick!(d, e, sliceContext))
87
103
  });
88
104
  // The kind's pipeline, built once by its plot, over the state this core seeds.
89
105
  const plotState = $derived(
@@ -98,6 +114,7 @@
98
114
  segments,
99
115
  scales,
100
116
  authoredMarkers: markers,
117
+ slice: sliceContext,
101
118
  tooltip,
102
119
  width,
103
120
  height,
@@ -130,7 +147,13 @@
130
147
  markers: markersOut,
131
148
  scales: layoutScales,
132
149
  channels: {
133
- color: { source: ChannelName.of(color, 'color') },
150
+ // Its own ramps draw every colored feature: the plot's has nothing to show.
151
+ color: {
152
+ source:
153
+ plotState.colorRamps && !plotState.colorDomain
154
+ ? undefined
155
+ : ChannelName.of(color, 'color')
156
+ },
134
157
  opacity: { source: ChannelName.of(opacity, 'opacity') }
135
158
  },
136
159
  colorDomain: plotState.colorDomain,
@@ -1,9 +1,10 @@
1
1
  <script lang="ts" generics="TProps extends Record<string, unknown>">
2
2
  import Core from './Core.svelte';
3
- import Plot from '../../../layout/plot/Plot.svelte';
3
+ import AbstractPlot from '../../../layout/plot/AbstractPlot.svelte';
4
4
  import { merge } from '../../../utils/merge';
5
5
  import { buildGeoDefaults } from './defaults';
6
- import { buildGeoSlicing } from './slices';
6
+ import { buildGeoSlicing, GeoSlices } from './slices';
7
+ import { Slice } from '../../../layout/plot/Slice';
7
8
  import { GeoFeatures } from './GeoFeatures.svelte';
8
9
  import type { GeoPlotProps, GeoPlotCoreProps } from '../../../types/plots/map/geo/props';
9
10
  import type { GeoFeature } from '../../../types/plots/data/geo';
@@ -19,9 +20,11 @@
19
20
  * Optional chrome (`title`, `subtitle`, `caption`, `header`, `footer`,
20
21
  * `legend`) frames it. `timeline` and `facet` slice its features and its
21
22
  * markers' own rows by a field (a feature's from its `properties`); what
22
- * lacks the field draws in every slice, and the color ramp spans every
23
- * slice. With `coordinates.projection.domain: 'data'`, each facet zooms to
24
- * its own features.
23
+ * lacks the field draws in every slice, the color ramp spans every
24
+ * slice, and the panels may come from `facet.values` alone (or `rowValues`, `colValues`,
25
+ * `timeline.values`), one layer of features serving them all. The callbacks that read a
26
+ * feature get the slice as their last argument (`GeoSliceContext`). With
27
+ * `coordinates.projection.domain: 'data'`, each facet zooms to its own features.
25
28
  */
26
29
  let {
27
30
  title,
@@ -54,13 +57,29 @@
54
57
  buildGeoSlicing({ rows: [...features, ...markerRows], timeline, facet })
55
58
  );
56
59
 
57
- /** The color ramp's domain over every feature, so each slice colors on the same scale. */
60
+ /**
61
+ * The color ramp's domain over every feature as each slice reads it - a facet panel, a timeline step, each
62
+ * with its own context - so every slice colors on the same scale. Not under `scales: 'free'` (the
63
+ * facet's, or the timeline's when there is no facet): each slice then fits its own.
64
+ */
58
65
  const sharedColor = $derived.by((): GeoScalesConfig | undefined => {
59
66
  const value = core.color;
60
67
  if (!value) return undefined;
61
- const values = (resolved.features as GeoFeature<TProps>[])
62
- .map((f) => value(f))
63
- .filter((v): v is number => typeof v === 'number' && Number.isFinite(v));
68
+ if ((facet ? facet.scales : timeline?.scales) === 'free') return undefined;
69
+ const all = resolved.features as GeoFeature<TProps>[];
70
+ const whole = new Slice({
71
+ rows: features,
72
+ timeline: slicing.timeline,
73
+ facet: slicing.facet,
74
+ filterMode: undefined
75
+ });
76
+ const reads = slicing.slices.length
77
+ ? slicing.slices.flatMap(({ place, context }) => {
78
+ const keep = whole.keep(place) as unknown as (f: GeoFeature<TProps>) => boolean;
79
+ return all.filter(keep).map((f) => value(f, context));
80
+ })
81
+ : all.map((f) => value(f, {}));
82
+ const values = reads.filter((v): v is number => typeof v === 'number' && Number.isFinite(v));
64
83
  return values.length
65
84
  ? { color: { domain: [Math.min(...values), Math.max(...values)] } }
66
85
  : undefined;
@@ -69,8 +88,16 @@
69
88
  /** The core's props for one slice: the features and marker rows it keeps. */
70
89
  function sliceProps(slice: PlotCellContext<Row>): GeoPlotCoreProps<TProps> {
71
90
  const tip = slice.tooltip as TooltipConfig<GeoFeature<TProps>> | undefined;
91
+ const sliceContext = GeoSlices.contextOf(slice);
72
92
  if (!sliced)
73
- return { ...core, width: slice.width, height: slice.height, margins, tooltip: tip };
93
+ return {
94
+ ...core,
95
+ width: slice.width,
96
+ height: slice.height,
97
+ margins,
98
+ tooltip: tip,
99
+ sliceContext
100
+ };
74
101
  return {
75
102
  ...core,
76
103
  data: features.filter(slice.keep) as unknown as GeoFeature<TProps>[],
@@ -82,12 +109,13 @@
82
109
  height: slice.height,
83
110
  margins: slice.margins ?? margins,
84
111
  scales: merge(sharedColor, core.scales),
85
- tooltip: tip
112
+ tooltip: tip,
113
+ sliceContext
86
114
  } as GeoPlotCoreProps<TProps>;
87
115
  }
88
116
  </script>
89
117
 
90
- <Plot
118
+ <AbstractPlot
91
119
  {Core}
92
120
  core={core as GeoPlotCoreProps<TProps>}
93
121
  defaults={buildGeoDefaults}
@@ -1,4 +1,3 @@
1
- import Plot from '../../../layout/plot/Plot.svelte';
2
1
  import type { GeoPlotProps } from '../../../types/plots/map/geo/props';
3
2
  declare function $$render<TProps extends Record<string, unknown>>(): {
4
3
  props: GeoPlotProps<TProps>;
@@ -1,6 +1,7 @@
1
1
  import type { GeoPlotState } from '../../../../types/plots/map/geo/state';
2
2
  /**
3
3
  * GeoPlot's "data" phase: every feature tagged with its resolved id/centroid,
4
- * then reduced by `excludeParts`. Reads no env.
4
+ * then reduced by `excludeParts`. Each carries the slice it is drawn in as its
5
+ * row context. Reads no env.
5
6
  */
6
7
  export declare function buildData<TProps extends Record<string, unknown>>(state: GeoPlotState<TProps>): GeoPlotState<TProps>;
@@ -1,12 +1,14 @@
1
1
  import { resolveAccessor } from '../../../../utils/accessors';
2
2
  import { GeoGeometry } from '../GeoGeometry';
3
3
  import { GeoFeatures } from '../GeoFeatures.svelte';
4
+ import { ROW_CONTEXT_KEY } from '../../../../phases/context/rowContextKey';
4
5
  /**
5
6
  * GeoPlot's "data" phase: every feature tagged with its resolved id/centroid,
6
- * then reduced by `excludeParts`. Reads no env.
7
+ * then reduced by `excludeParts`. Each carries the slice it is drawn in as its
8
+ * row context. Reads no env.
7
9
  */
8
10
  export function buildData(state) {
9
- const { rawFeatures, featureId, excludeParts } = state;
11
+ const { rawFeatures, featureId, excludeParts, slice = {} } = state;
10
12
  const getFeatureId = featureId
11
13
  ? resolveAccessor(featureId)
12
14
  : GeoFeatures.defaultId;
@@ -23,5 +25,9 @@ export function buildData(state) {
23
25
  const [cx, cy] = GeoGeometry.centroid(geometry);
24
26
  return [{ ...f, geometry, __cx: cx, __cy: cy }];
25
27
  });
28
+ // Kept as the row's context, which a copy of the feature carries along: a tooltip's `format` reads it back.
29
+ for (const f of new Set([...allFeatures, ...features])) {
30
+ f[ROW_CONTEXT_KEY] = slice;
31
+ }
26
32
  return { ...state, allFeatures, features };
27
33
  }
@@ -61,7 +61,9 @@ export function buildScales(state, env) {
61
61
  return colorScale ? colorScale(v) : undefined;
62
62
  }
63
63
  : undefined;
64
- // Every segment ramp is built up front, so the legend can draw each one.
64
+ // Every segment ramp is built up front, so the legend can draw each one. The plot's own ramp is left out of
65
+ // the legend when every colored feature has one of its own: nothing is drawn with it.
66
+ let usesPlotRamp = false;
65
67
  if (colorScale) {
66
68
  for (const f of features) {
67
69
  const featureId = f.__id ?? '';
@@ -69,6 +71,8 @@ export function buildScales(state, env) {
69
71
  const segScales = GeoSegments.scales(segments, featureId, groupingValue);
70
72
  if (segScales?.color)
71
73
  segmentColorScaleFor(groupingValue ?? featureId, segScales);
74
+ else if (color?.(f) != null)
75
+ usesPlotRamp = true;
72
76
  }
73
77
  }
74
78
  // Plot-level only - no segment-scoped opacity ramp (unlike `resolveColor`
@@ -90,7 +94,7 @@ export function buildScales(state, env) {
90
94
  : undefined;
91
95
  return {
92
96
  ...state,
93
- colorDomain: valueDomain ?? undefined,
97
+ colorDomain: (usesPlotRamp || !colorRamps.length ? valueDomain : undefined) ?? undefined,
94
98
  colorRamps: colorRamps.length ? colorRamps : undefined,
95
99
  opacityDomain: opacityDomain && typeof opacityDomain[0] === 'number'
96
100
  ? opacityDomain
@@ -1,10 +1,22 @@
1
1
  import type { FacetConfig } from '../../../types/layout/facet';
2
- import type { TimelineConfig } from '../../../types/layout/timeline';
2
+ import type { TimelineConfig, TimeValue } from '../../../types/layout/timeline';
3
+ import type { SlicePlace } from '../../../types/layout/plot';
4
+ import type { GeoSliceContext } from '../../../types/plots/data/geo';
3
5
  type Row = Record<string, unknown>;
6
+ /** One slice of a sliced map: where it sits, and the context its features are read in. */
7
+ export type GeoSlice = {
8
+ place: SlicePlace;
9
+ context: GeoSliceContext;
10
+ };
4
11
  /**
5
12
  * What a GeoPlot hands `Plot` to slice by: one stand-in row per value
6
- * combination found in the features and markers' rows, and timeline/facet
7
- * accessors that read a stand-in or a real row.
13
+ * combination, and timeline/facet accessors that read a stand-in or a real
14
+ * row. A dimension's values are the ones the timeline or facet names
15
+ * (`timeline.values`, `facet.values`, `rowValues`, `colValues`), in
16
+ * their order, then any more found in the features and markers' rows - so
17
+ * the slices exist even when no feature carries the field. Each combination
18
+ * is also returned as a `slices` entry: its place and the context its
19
+ * features are read in.
8
20
  */
9
21
  export declare function buildGeoSlicing(args: {
10
22
  rows: Row[];
@@ -12,7 +24,19 @@ export declare function buildGeoSlicing(args: {
12
24
  facet?: FacetConfig<Row>;
13
25
  }): {
14
26
  rows: Row[];
27
+ slices: GeoSlice[];
15
28
  timeline?: TimelineConfig<Row>;
16
29
  facet?: FacetConfig<Row>;
17
30
  };
31
+ export declare const GeoSlices: {
32
+ /** The context a callback reads a feature in, for the slice at `place`: empty when there is none. */
33
+ contextOf(place: {
34
+ time?: TimeValue;
35
+ facet?: {
36
+ facetValue: string;
37
+ row?: string;
38
+ col?: string;
39
+ };
40
+ }): GeoSliceContext;
41
+ };
18
42
  export {};