@fundar/data-chart-telling 0.0.14 → 0.0.16

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 (148) hide show
  1. package/README.md +121 -17
  2. package/dist/charts/{Chart.svelte → BaseChart.svelte} +2 -0
  3. package/dist/charts/{Chart.svelte.d.ts → BaseChart.svelte.d.ts} +3 -3
  4. package/dist/charts/bar/Chart.svelte +5 -5
  5. package/dist/charts/bar/Chart.svelte.d.ts +1 -2
  6. package/dist/charts/heatmap/Chart.svelte +8 -7
  7. package/dist/charts/heatmap/Chart.svelte.d.ts +2 -3
  8. package/dist/charts/line/Chart.svelte +5 -5
  9. package/dist/charts/line/Chart.svelte.d.ts +1 -2
  10. package/dist/charts/pyramid/Chart.svelte +7 -6
  11. package/dist/charts/pyramid/Chart.svelte.d.ts +2 -3
  12. package/dist/configuration/config.svelte.js +2 -1
  13. package/dist/configuration/themes/index.d.ts +60 -40
  14. package/dist/index.d.ts +27 -13
  15. package/dist/index.js +12 -7
  16. package/dist/layout/facet/FacetLayout.svelte +1 -1
  17. package/dist/layout/facet/FacetLayout.svelte.d.ts +1 -1
  18. package/dist/layout/geo/GeoLayout.svelte +47 -0
  19. package/dist/layout/geo/GeoLayout.svelte.d.ts +22 -0
  20. package/dist/layout/geo/resolveProjection.d.ts +10 -0
  21. package/dist/layout/geo/resolveProjection.js +48 -0
  22. package/dist/layout/legend/ContinuousSection.svelte +158 -17
  23. package/dist/layout/legend/DiscreteSection.svelte +56 -4
  24. package/dist/layout/legend/interaction.svelte.d.ts +7 -0
  25. package/dist/layout/legend/interaction.svelte.js +24 -0
  26. package/dist/layout/plot/AxisLayout.svelte +95 -0
  27. package/dist/layout/plot/AxisLayout.svelte.d.ts +39 -0
  28. package/dist/layout/plot/BasePlotLayout.svelte +302 -0
  29. package/dist/layout/plot/BasePlotLayout.svelte.d.ts +95 -0
  30. package/dist/layout/plot/GridLayout.svelte +30 -0
  31. package/dist/layout/plot/GridLayout.svelte.d.ts +27 -0
  32. package/dist/layout/plot/RuleLayout.svelte +111 -0
  33. package/dist/layout/plot/RuleLayout.svelte.d.ts +40 -0
  34. package/dist/layout/plot/margins.d.ts +34 -0
  35. package/dist/layout/plot/margins.js +26 -0
  36. package/dist/layout/timeline/TimelineLayout.svelte +1 -1
  37. package/dist/layout/timeline/TimelineLayout.svelte.d.ts +1 -1
  38. package/dist/layout/tooltip/Tooltip.svelte +15 -0
  39. package/dist/layout/tooltip/Tooltip.svelte.d.ts +7 -0
  40. package/dist/layout/tooltip/TooltipLayout.svelte +45 -0
  41. package/dist/layout/tooltip/TooltipLayout.svelte.d.ts +41 -0
  42. package/dist/layout/tooltip/controller.svelte.d.ts +4 -3
  43. package/dist/layout/tooltip/controller.svelte.js +5 -6
  44. package/dist/layout/tooltip/hover.svelte.d.ts +1 -1
  45. package/dist/layout/tooltip/hover.svelte.js +1 -1
  46. package/dist/layout/tooltip/utils.d.ts +2 -2
  47. package/dist/markers/ContourClipMarker.svelte +77 -0
  48. package/dist/markers/ContourClipMarker.svelte.d.ts +10 -0
  49. package/dist/{plots/markers → markers}/DeltaMarker.svelte +4 -4
  50. package/dist/{plots/markers → markers}/DeltaMarker.svelte.d.ts +3 -3
  51. package/dist/{plots/markers → markers}/DotMarker.svelte +3 -3
  52. package/dist/{plots/markers → markers}/DotMarker.svelte.d.ts +3 -3
  53. package/dist/markers/HoverMarker.svelte +136 -0
  54. package/dist/{plots/markers → markers}/HoverMarker.svelte.d.ts +4 -4
  55. package/dist/{plots/markers → markers}/PeakMarker.svelte +2 -2
  56. package/dist/{plots/markers → markers}/PeakMarker.svelte.d.ts +2 -2
  57. package/dist/{plots/markers → markers}/TextMarker.svelte +11 -4
  58. package/dist/{plots/markers → markers}/TextMarker.svelte.d.ts +3 -3
  59. package/dist/markers/inset/InsetMarker.svelte +170 -0
  60. package/dist/markers/inset/InsetMarker.svelte.d.ts +51 -0
  61. package/dist/markers/inset/insetLayout.d.ts +25 -0
  62. package/dist/markers/inset/insetLayout.js +39 -0
  63. package/dist/markers/inset/insetProjection.d.ts +8 -0
  64. package/dist/markers/inset/insetProjection.js +39 -0
  65. package/dist/plots/bar/BarSegments.svelte +69 -0
  66. package/dist/plots/bar/BarSegments.svelte.d.ts +40 -0
  67. package/dist/plots/bar/Plot.svelte +140 -74
  68. package/dist/plots/bar/Plot.svelte.d.ts +7 -3
  69. package/dist/plots/bar/ValueLabels.svelte +89 -0
  70. package/dist/plots/bar/ValueLabels.svelte.d.ts +39 -0
  71. package/dist/plots/bar/hoverPoints.d.ts +15 -0
  72. package/dist/plots/bar/hoverPoints.js +35 -0
  73. package/dist/plots/bar/layout.svelte.d.ts +37 -0
  74. package/dist/plots/bar/layout.svelte.js +132 -0
  75. package/dist/plots/geo/Plot.svelte +577 -0
  76. package/dist/plots/geo/Plot.svelte.d.ts +29 -0
  77. package/dist/plots/geo/TileLayer.svelte +77 -0
  78. package/dist/plots/geo/TileLayer.svelte.d.ts +11 -0
  79. package/dist/plots/geo/projections/argentina.d.ts +8 -0
  80. package/dist/plots/geo/projections/argentina.js +35 -0
  81. package/dist/plots/geo/projections/fit.d.ts +8 -0
  82. package/dist/plots/geo/projections/fit.js +14 -0
  83. package/dist/plots/geo/rotate.svelte.d.ts +26 -0
  84. package/dist/plots/geo/rotate.svelte.js +79 -0
  85. package/dist/plots/geo/zoom.svelte.d.ts +32 -0
  86. package/dist/plots/geo/zoom.svelte.js +50 -0
  87. package/dist/plots/heatmap/Plot.svelte +171 -58
  88. package/dist/plots/heatmap/Plot.svelte.d.ts +7 -3
  89. package/dist/plots/line/Plot.svelte +67 -30
  90. package/dist/plots/line/Plot.svelte.d.ts +7 -3
  91. package/dist/plots/pyramid/Plot.svelte +88 -35
  92. package/dist/plots/pyramid/Plot.svelte.d.ts +7 -3
  93. package/dist/plots/utils/delta.d.ts +1 -1
  94. package/dist/plots/utils/geoAccessors.d.ts +64 -0
  95. package/dist/plots/utils/geoAccessors.js +188 -0
  96. package/dist/plots/utils/geoSegments.d.ts +14 -0
  97. package/dist/plots/utils/geoSegments.js +17 -0
  98. package/dist/plots/utils/legendDisabled.d.ts +15 -0
  99. package/dist/plots/utils/legendDisabled.js +41 -0
  100. package/dist/plots/utils/segments.d.ts +14 -5
  101. package/dist/plots/utils/segments.js +25 -13
  102. package/dist/plots/utils/tiles.d.ts +89 -0
  103. package/dist/plots/utils/tiles.js +159 -0
  104. package/dist/plots/utils/topojson.d.ts +9 -0
  105. package/dist/plots/utils/topojson.js +30 -0
  106. package/dist/types/charts/common.d.ts +2 -1
  107. package/dist/types/charts/legend.d.ts +32 -1
  108. package/dist/types/charts/props.d.ts +9 -6
  109. package/dist/types/configuration/styling.d.ts +13 -5
  110. package/dist/types/layout/legend.d.ts +26 -0
  111. package/dist/types/layout/tooltip.d.ts +14 -21
  112. package/dist/types/{plots/markers.d.ts → markers/common.d.ts} +2 -18
  113. package/dist/types/markers/geo.d.ts +237 -0
  114. package/dist/types/markers/props.d.ts +11 -0
  115. package/dist/types/markers/props.js +1 -0
  116. package/dist/types/plots/axis.d.ts +55 -0
  117. package/dist/types/plots/axis.js +1 -0
  118. package/dist/types/plots/constants.d.ts +30 -0
  119. package/dist/types/plots/constants.js +1 -0
  120. package/dist/types/plots/data/common.d.ts +40 -0
  121. package/dist/types/plots/data/common.js +1 -0
  122. package/dist/types/plots/data/geo.d.ts +74 -0
  123. package/dist/types/plots/data/geo.js +1 -0
  124. package/dist/types/plots/delta.d.ts +2 -2
  125. package/dist/types/plots/props.d.ts +105 -16
  126. package/dist/types/plots/scales/geo.d.ts +44 -0
  127. package/dist/types/plots/scales/geo.js +1 -0
  128. package/dist/types/plots/segments/common.d.ts +25 -0
  129. package/dist/types/plots/segments/common.js +1 -0
  130. package/dist/types/plots/segments/config.d.ts +51 -0
  131. package/dist/types/plots/segments/config.js +1 -0
  132. package/dist/types/plots/styles/common.d.ts +37 -0
  133. package/dist/types/plots/styles/common.js +1 -0
  134. package/dist/types/plots/styles/geo.d.ts +42 -0
  135. package/dist/types/plots/styles/geo.js +1 -0
  136. package/dist/types/plots/styling.d.ts +45 -0
  137. package/dist/types/plots/styling.js +1 -0
  138. package/dist/utils/grouping.d.ts +2 -1
  139. package/dist/utils/interpolate.d.ts +2 -1
  140. package/package.json +27 -13
  141. package/dist/layout/plot/PlotLayout.svelte +0 -294
  142. package/dist/layout/plot/PlotLayout.svelte.d.ts +0 -70
  143. package/dist/plots/markers/HoverMarker.svelte +0 -98
  144. package/dist/types/plots/common.d.ts +0 -97
  145. package/dist/types/plots/styles.d.ts +0 -187
  146. /package/dist/types/{plots/common.js → layout/legend.js} +0 -0
  147. /package/dist/types/{plots/markers.js → markers/common.js} +0 -0
  148. /package/dist/types/{plots/styles.js → markers/geo.js} +0 -0
@@ -8,13 +8,32 @@
8
8
  import { getConfiguration } from '../../configuration/config.svelte';
9
9
  import { paletteColor } from '../../utils/color';
10
10
  import { buildSeries } from '../../utils/grouping';
11
- import PlotLayout from '../../layout/plot/PlotLayout.svelte';
12
- import HoverMarker from '../markers/HoverMarker.svelte';
11
+ import { getLegendInteraction } from '../../layout/legend/interaction.svelte';
12
+ import { disabledStrokeOverride, disabledDotsOverride } from '../utils/legendDisabled';
13
+ import BasePlotLayout from '../../layout/plot/BasePlotLayout.svelte';
14
+ import AxisLayout from '../../layout/plot/AxisLayout.svelte';
15
+ import GridLayout from '../../layout/plot/GridLayout.svelte';
16
+ import RuleLayout from '../../layout/plot/RuleLayout.svelte';
17
+ import HoverMarker from '../../markers/HoverMarker.svelte';
18
+ import { hasHoverMarker, resolveHoverStrategy, resolveHoverSync } from '../../layout/tooltip/utils';
13
19
  import { buildGroupedSeries, validateSegments, resolveSegmentsForSeries, matchesSegmentX, getDataForSegments } from '../utils/segments';
14
- import type { PlotProps } from '../../types/plots/props';
15
- import type { Series, AxisValue } from '../../types/plots/common';
16
- import type { LineSegmentStyle, ValueAnchor } from '../../types/plots/styles';
17
- import type { Marker } from '../../types/plots/markers';
20
+ import type { BasePlotProps } from '../../types/plots/props';
21
+ import type { AxisValue } from '../../types/plots/axis';
22
+ import type { Series, SeriesProps, DataProps } from '../../types/plots/data/common';
23
+ import type { AxisBasedScalesConfig } from '../../types/plots/props';
24
+ import type { BasePlotStyles } from '../../types/plots/styles/common';
25
+ import type { ValueAnchor } from '../../types/plots/constants';
26
+ import type { LineSegmentStyle } from '../../types/plots/segments/common';
27
+ import type { Marker } from '../../types/markers/common';
28
+
29
+ type Props = BasePlotProps<
30
+ SeriesProps<TData> | DataProps<TData>,
31
+ TData,
32
+ BasePlotStyles,
33
+ LineSegmentStyle,
34
+ Marker,
35
+ AxisBasedScalesConfig<TData>
36
+ >;
18
37
 
19
38
  let {
20
39
  width,
@@ -30,9 +49,10 @@
30
49
  scales = {},
31
50
  margins,
32
51
  tooltip = undefined,
33
- }: PlotProps<TData, LineSegmentStyle> = $props();
52
+ }: Props = $props();
34
53
 
35
54
  const resolvedSeries = $derived(series ?? buildSeries(data!, x!, y!, z));
55
+ const legendInteraction = $derived(getLegendInteraction());
36
56
 
37
57
  $effect(() => { validateSegments(segments); });
38
58
 
@@ -57,12 +77,19 @@
57
77
  styles.values?.format ?? ((v: number, name: string) => `${name} - ${v}`),
58
78
  );
59
79
  const valAnchor = $derived<ValueAnchor>(styles.values?.anchor ?? 'start');
80
+ // 'outside' is a per-point escape hatch resolved by HoverMarker; line's own
81
+ // value labels already have their own `anchor: 'outside'` concept above,
82
+ // so treat it as unset here.
83
+ const resolvedTextAnchor = $derived(styles.values?.textAnchor === 'outside' ? undefined : styles.values?.textAnchor);
60
84
 
61
85
  const xAcc = $derived(resolveAccessor(resolvedSeries[0]?.x ?? ((d: TData) => d)));
62
86
  const yAcc = $derived(resolveAccessor(resolvedSeries[0]?.y ?? ((d: TData) => d)));
63
87
  const flat = $derived(resolvedSeries.flatMap((s) => s.data));
88
+ // A legend-disabled series is dimmed on the mark itself, but never surfaces
89
+ // in hover/tooltip — its points are simply absent from the candidate list.
64
90
  const hoverPoints = $derived(
65
91
  resolvedSeries.flatMap((s, idx) => {
92
+ if (legendInteraction?.disabledSeries.has(s.name)) return [];
66
93
  const sx = resolveAccessor(s.x);
67
94
  const sy = resolveAccessor(s.y);
68
95
  return s.data.map((d) => ({
@@ -82,28 +109,37 @@
82
109
  .map((s, idx) => ({ series: s, lastRow: s.data[s.data.length - 1], seriesIndex: idx }))
83
110
  .filter(({ lastRow }) => lastRow !== undefined),
84
111
  );
112
+
113
+ const hoverActive = $derived(tooltip != null || hasHoverMarker(markers));
114
+ const hoverStrategy = $derived(resolveHoverStrategy(tooltip?.strategy, markers, 'x'));
115
+ const hoverSync = $derived(resolveHoverSync(tooltip?.sync, markers));
85
116
  </script>
86
117
 
87
- <PlotLayout
118
+ <BasePlotLayout
88
119
  {width}
89
120
  {height}
90
- x={scales.x}
91
- y={scales.y}
92
121
  data={flat}
93
122
  getX={xAcc}
94
123
  getY={(d) => Number(yAcc(d))}
95
124
  {hoverPoints}
96
125
  label={(r) => String(yAcc(r))}
97
126
  {tooltip}
98
- {markers}
99
- seriesData={resolvedSeries}
127
+ {hoverActive}
128
+ {hoverStrategy}
129
+ {hoverSync}
100
130
  {scales}
101
131
  {margins}
102
- defaultStrategy="x"
132
+ xTickRotate={scales?.x?.tickRotate}
103
133
  >
104
- {#snippet children({ matchedPoints, ruleX, ruleY, impliesRuleX, impliesRuleY })}
134
+ {#snippet children({ matchedPoints, ruleX, ruleY, impliesRuleX, impliesRuleY, numericMargins })}
135
+ <AxisLayout data={flat} getX={xAcc} getY={(d) => Number(yAcc(d))} {width} {height} {numericMargins} {scales} />
136
+ <GridLayout {scales} />
137
+ <RuleLayout {markers} seriesData={resolvedSeries} {matchedPoints} {ruleX} {ruleY} {impliesRuleX} {impliesRuleY}>
105
138
  {#each groupedSeries as group, seriesIndex (group.series.name)}
106
139
  {@const defaultColor = paletteColor(seriesIndex, cfg.palette)}
140
+ {@const disabledOverride = legendInteraction?.disabledSeries.get(group.series.name)}
141
+ {@const disabledStroke = disabledStrokeOverride(disabledOverride)}
142
+ {@const disabledDots = disabledDotsOverride(disabledOverride)}
107
143
  {#each group.visualSegments as seg, i (`${group.series.name}-${i}`)}
108
144
  {@const strokeStyle = seg.style.stroke}
109
145
  {@const lineData = seg.data as unknown as Record<string | symbol, never>[]}
@@ -111,12 +147,12 @@
111
147
  data={lineData}
112
148
  x={resolveAccessor(group.series.x)}
113
149
  y={resolveAccessor(group.series.y)}
114
- stroke={strokeStyle?.stroke ?? defaultColor}
115
- strokeWidth={strokeStyle?.strokeWidth ?? cfg.line.strokeWidth}
116
- strokeOpacity={strokeStyle?.strokeOpacity ?? 1}
117
- strokeDasharray={strokeStyle?.strokeDasharray}
118
- strokeLinejoin={strokeStyle?.strokeLinejoin}
119
- strokeLinecap={strokeStyle?.strokeLinecap}
150
+ stroke={disabledStroke?.stroke ?? strokeStyle?.stroke ?? defaultColor}
151
+ strokeWidth={disabledStroke?.strokeWidth ?? strokeStyle?.strokeWidth ?? cfg.line.strokeWidth}
152
+ strokeOpacity={disabledStroke?.strokeOpacity ?? strokeStyle?.strokeOpacity ?? 1}
153
+ strokeDasharray={disabledStroke?.strokeDasharray ?? strokeStyle?.strokeDasharray}
154
+ strokeLinejoin={disabledStroke?.strokeLinejoin ?? strokeStyle?.strokeLinejoin}
155
+ strokeLinecap={disabledStroke?.strokeLinecap ?? strokeStyle?.strokeLinecap}
120
156
  />
121
157
  {#if seg.style.dots}
122
158
  {@const dotStyle = seg.style.dots}
@@ -124,14 +160,14 @@
124
160
  data={seg.data}
125
161
  x={resolveAccessor(group.series.x)}
126
162
  y={resolveAccessor(group.series.y)}
127
- r={dotStyle.dotRadius ?? cfg.line.dotRadius}
128
- fill={dotStyle.dotFill ?? strokeStyle?.stroke ?? defaultColor}
129
- symbol={dotStyle.dotSymbol ?? 'circle'}
130
- stroke={dotStyle.dotStroke ?? strokeStyle?.stroke ?? defaultColor}
131
- strokeWidth={dotStyle.dotStrokeWidth ?? 1}
132
- fillOpacity={dotStyle.dotFillOpacity ?? strokeStyle?.strokeOpacity ?? 1}
133
- strokeOpacity={dotStyle.dotStrokeOpacity ?? strokeStyle?.strokeOpacity ?? 1}
134
- strokeDasharray={dotStyle.dotStrokeDasharray}
163
+ r={disabledDots?.dotRadius ?? dotStyle.dotRadius ?? cfg.line.dotRadius}
164
+ fill={disabledDots?.dotFill ?? dotStyle.dotFill ?? strokeStyle?.stroke ?? defaultColor}
165
+ symbol={disabledDots?.dotSymbol ?? dotStyle.dotSymbol ?? 'circle'}
166
+ stroke={disabledDots?.dotStroke ?? dotStyle.dotStroke ?? strokeStyle?.stroke ?? defaultColor}
167
+ strokeWidth={disabledDots?.dotStrokeWidth ?? dotStyle.dotStrokeWidth ?? 1}
168
+ fillOpacity={disabledDots?.dotFillOpacity ?? dotStyle.dotFillOpacity ?? strokeStyle?.strokeOpacity ?? 1}
169
+ strokeOpacity={disabledDots?.dotStrokeOpacity ?? dotStyle.dotStrokeOpacity ?? strokeStyle?.strokeOpacity ?? 1}
170
+ strokeDasharray={disabledDots?.dotStrokeDasharray ?? dotStyle.dotStrokeDasharray}
135
171
  />
136
172
  {/if}
137
173
  {/each}
@@ -221,7 +257,7 @@
221
257
  text={() => fmtVal(Number(yFn(lastRow)), s.name)}
222
258
  dx={styles.values?.dx ?? defaultDx}
223
259
  dy={styles.values?.dy ?? defaultDy}
224
- textAnchor={styles.values?.textAnchor ?? defaultTA}
260
+ textAnchor={resolvedTextAnchor ?? defaultTA}
225
261
  lineAnchor={styles.values?.lineAnchor ?? defaultLA}
226
262
  lineHeight={styles.values?.lineHeight}
227
263
  rotate={styles.values?.rotate}
@@ -232,5 +268,6 @@
232
268
  />
233
269
  {/each}
234
270
  {/if}
271
+ </RuleLayout>
235
272
  {/snippet}
236
- </PlotLayout>
273
+ </BasePlotLayout>
@@ -1,7 +1,11 @@
1
- import type { PlotProps } from '../../types/plots/props';
2
- import type { LineSegmentStyle } from '../../types/plots/styles';
1
+ import type { BasePlotProps } from '../../types/plots/props';
2
+ import type { SeriesProps, DataProps } from '../../types/plots/data/common';
3
+ import type { AxisBasedScalesConfig } from '../../types/plots/props';
4
+ import type { BasePlotStyles } from '../../types/plots/styles/common';
5
+ import type { LineSegmentStyle } from '../../types/plots/segments/common';
6
+ import type { Marker } from '../../types/markers/common';
3
7
  declare function $$render<TData extends Record<string, unknown>>(): {
4
- props: PlotProps<TData, LineSegmentStyle>;
8
+ props: BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, BasePlotStyles, LineSegmentStyle, Marker, AxisBasedScalesConfig<TData>>;
5
9
  exports: {};
6
10
  bindings: "";
7
11
  slots: {};
@@ -5,13 +5,23 @@
5
5
  import { getConfiguration } from '../../configuration/config.svelte';
6
6
  import { paletteColor } from '../../utils/color';
7
7
  import { buildSeries } from '../../utils/grouping';
8
+ import { getLegendInteraction } from '../../layout/legend/interaction.svelte';
9
+ import { disabledFillOverride } from '../utils/legendDisabled';
8
10
  import { buildGroupedSeries, validateSegments, resolveSegmentsForSeries, matchesSegmentX, getDataForSegments } from '../utils/segments';
9
- import PlotLayout from '../../layout/plot/PlotLayout.svelte';
10
- import HoverMarker from '../markers/HoverMarker.svelte';
11
- import type { PlotProps } from '../../types/plots/props';
12
- import type { Series, AxisValue } from '../../types/plots/common';
13
- import type { BarSegmentStyle, ValueAnchor } from '../../types/plots/styles';
14
- import type { Marker } from '../../types/plots/markers';
11
+ import BasePlotLayout from '../../layout/plot/BasePlotLayout.svelte';
12
+ import AxisLayout from '../../layout/plot/AxisLayout.svelte';
13
+ import GridLayout from '../../layout/plot/GridLayout.svelte';
14
+ import RuleLayout from '../../layout/plot/RuleLayout.svelte';
15
+ import HoverMarker from '../../markers/HoverMarker.svelte';
16
+ import { hasHoverMarker, resolveHoverStrategy, resolveHoverSync } from '../../layout/tooltip/utils';
17
+ import type { BasePlotProps } from '../../types/plots/props';
18
+ import type { AxisValue } from '../../types/plots/axis';
19
+ import type { Series, SeriesProps, DataProps } from '../../types/plots/data/common';
20
+ import type { AxisBasedScalesConfig } from '../../types/plots/props';
21
+ import type { BasePlotStyles } from '../../types/plots/styles/common';
22
+ import type { ValueAnchor } from '../../types/plots/constants';
23
+ import type { BarSegmentStyle } from '../../types/plots/segments/common';
24
+ import type { Marker } from '../../types/markers/common';
15
25
 
16
26
  /**
17
27
  * A population-pyramid-style diverging bar chart: each series is mirrored
@@ -29,6 +39,15 @@
29
39
  type PyramidSide = 'left' | 'right';
30
40
  type InternalSeries = Series<TData> & { side: PyramidSide };
31
41
 
42
+ type Props = BasePlotProps<
43
+ SeriesProps<TData> | DataProps<TData>,
44
+ TData,
45
+ BasePlotStyles,
46
+ BarSegmentStyle,
47
+ Marker,
48
+ AxisBasedScalesConfig<TData>
49
+ >;
50
+
32
51
  let {
33
52
  width,
34
53
  height,
@@ -43,16 +62,21 @@
43
62
  segments = {},
44
63
  markers = [],
45
64
  tooltip = undefined,
46
- }: PlotProps<TData, BarSegmentStyle> = $props();
65
+ }: Props = $props();
47
66
 
48
67
  $effect(() => { validateSegments(segments); });
49
68
 
50
69
  const cfg = $derived(getConfiguration());
70
+ const legendInteraction = $derived(getLegendInteraction());
51
71
  const leftColor = $derived(styles.colors?.left ?? paletteColor(0, cfg.palette));
52
72
  const rightColor = $derived(styles.colors?.right ?? paletteColor(1, cfg.palette));
53
73
  const showVals = $derived(styles.values?.show ?? false);
54
74
  const fmtVal = $derived(styles.values?.format ?? ((v: number) => `${v}`));
55
75
  const valAnchor = $derived<ValueAnchor>(styles.values?.anchor ?? 'outside');
76
+ // 'outside' is a per-point escape hatch resolved by HoverMarker; pyramid's
77
+ // own value labels already have their own `anchor: 'outside'` concept
78
+ // above, so treat it as unset here.
79
+ const resolvedTextAnchor = $derived(styles.values?.textAnchor === 'outside' ? undefined : styles.values?.textAnchor);
56
80
 
57
81
  // Sort series names alphabetically; even index → left, odd → right.
58
82
  // scales.z.reverse flips the assignment so the second name goes left.
@@ -68,7 +92,9 @@
68
92
  });
69
93
 
70
94
  const groupedSeries = $derived(
71
- buildGroupedSeries<InternalSeries, BarSegmentStyle>(resolvedSeries, segments),
95
+ // connect: false — bars are discrete; there's no visual gap between
96
+ // adjacent categories to bridge (see buildGroupedSeries's own doc).
97
+ buildGroupedSeries<InternalSeries, BarSegmentStyle>(resolvedSeries, segments, false),
72
98
  );
73
99
 
74
100
  function signedValue(s: InternalSeries, d: TData): number {
@@ -111,15 +137,19 @@
111
137
  const getY = (d: TaggedRow) => d.__y;
112
138
  const labelFor = (d: TaggedRow) => d.__label;
113
139
 
140
+ // A legend-disabled series is dimmed on the bar itself, but never surfaces
141
+ // in hover/tooltip — its points are simply absent from the candidate list.
114
142
  const hoverPoints = $derived(
115
- flat.map((d) => ({
116
- x: d.__x,
117
- y: d.__y,
118
- row: d,
119
- label: d.__label,
120
- series: d.__series,
121
- color: d.__side === 'left' ? leftColor : rightColor,
122
- })),
143
+ flat
144
+ .filter((d) => !legendInteraction?.disabledSeries.has(d.__series))
145
+ .map((d) => ({
146
+ x: d.__x,
147
+ y: d.__y,
148
+ row: d,
149
+ label: d.__label,
150
+ series: d.__series,
151
+ color: d.__side === 'left' ? leftColor : rightColor,
152
+ })),
123
153
  );
124
154
 
125
155
  const yDomain = $derived([
@@ -149,42 +179,59 @@
149
179
  }
150
180
  return map;
151
181
  });
182
+
183
+ // The single, fully-resolved scales object BasePlotLayout reads for
184
+ // everything (ticks, grid, sort, and the real svelteplot scale) — avoids
185
+ // keeping a second, separately-defaulted copy of `scales.x`/`scales.y`
186
+ // (our own diverging-domain + band-scale defaults) out of sync with the
187
+ // one actually forwarded.
188
+ const resolvedScales = $derived<AxisBasedScalesConfig<TData>>({
189
+ ...scales,
190
+ x: {
191
+ domain: [-maxMagnitude, maxMagnitude],
192
+ tickFormat: (v: unknown) => fmtVal(Math.abs(Number(v)), ''),
193
+ ...(scales.x ?? {}),
194
+ },
195
+ y: { type: 'band', padding: 0.2, domain: yDomain, ...(scales.y ?? {}) },
196
+ });
197
+
198
+ const hoverActive = $derived(tooltip != null || hasHoverMarker(markers));
199
+ const hoverStrategy = $derived(resolveHoverStrategy(tooltip?.strategy, markers, 'y'));
200
+ const hoverSync = $derived(resolveHoverSync(tooltip?.sync, markers));
152
201
  </script>
153
202
 
154
- <PlotLayout
203
+ <BasePlotLayout
155
204
  {width}
156
205
  {height}
157
- x={{
158
- domain: [-maxMagnitude, maxMagnitude],
159
- tickFormat: (v: unknown) => fmtVal(Math.abs(Number(v)), ''),
160
- ...(scales.x ?? {}),
161
- }}
162
- y={{ type: 'band', padding: 0.2, domain: yDomain, ...(scales.y ?? {}) }}
163
206
  data={flat}
164
207
  {getX}
165
208
  {getY}
166
- matchY={getY}
167
209
  {hoverPoints}
168
210
  label={labelFor}
169
211
  {tooltip}
170
- {markers}
171
- seriesData={resolvedSeries}
172
- {scales}
212
+ {hoverActive}
213
+ {hoverStrategy}
214
+ {hoverSync}
215
+ scales={resolvedScales}
173
216
  {margins}
174
- defaultStrategy="y"
217
+ xTickRotate={resolvedScales?.x?.tickRotate}
175
218
  >
176
- {#snippet children({ matchedPoints, ruleX, ruleY, impliesRuleX, impliesRuleY })}
219
+ {#snippet children({ matchedPoints, ruleX, ruleY, impliesRuleX, impliesRuleY, numericMargins })}
220
+ <AxisLayout data={flat} {getX} {getY} {width} {height} {numericMargins} scales={resolvedScales} />
221
+ <GridLayout scales={resolvedScales} />
222
+ <RuleLayout {markers} seriesData={resolvedSeries} {matchedPoints} {ruleX} {ruleY} {impliesRuleX} {impliesRuleY}>
177
223
  {#each groupedSeries as group (group.series.name)}
178
224
  {@const defaultColor = group.series.side === 'left' ? leftColor : rightColor}
179
225
  {@const getCategory = resolveAccessor(group.series.x)}
226
+ {@const disabledFill = disabledFillOverride(legendInteraction?.disabledSeries.get(group.series.name))}
180
227
  {#each group.visualSegments as seg, i (`${group.series.name}-${i}`)}
181
228
  <BarX
182
229
  data={seg.data}
183
230
  x1={0}
184
231
  x2={(d: TData) => signedValue(group.series, d)}
185
232
  y={getCategory}
186
- fill={seg.style.fill ?? defaultColor}
187
- fillOpacity={seg.style.fillOpacity ?? 1}
233
+ fill={disabledFill?.fill ?? seg.style.fill ?? defaultColor}
234
+ fillOpacity={disabledFill?.fillOpacity ?? seg.style.fillOpacity ?? 1}
188
235
  />
189
236
  {/each}
190
237
 
@@ -210,14 +257,19 @@
210
257
  text={(d: TData) => fmtVal(Math.abs(Number(resolveAccessor(group.series.y)(d))), group.series.name)}
211
258
  dx={styles.values?.dx ?? defaultDx}
212
259
  dy={styles.values?.dy ?? 0}
213
- textAnchor={styles.values?.textAnchor ?? defaultTextAnchor}
260
+ textAnchor={resolvedTextAnchor ?? defaultTextAnchor}
214
261
  lineAnchor={styles.values?.lineAnchor ?? 'middle'}
215
262
  lineHeight={styles.values?.lineHeight}
216
263
  rotate={styles.values?.rotate}
217
264
  class={styles.values?.class}
218
265
  textClass={styles.values?.textClass}
219
- fill={cfg.axis.color}
220
- fontSize={12}
266
+ fill={styles.values?.fill ?? cfg.axis.color}
267
+ fontSize={styles.values?.fontSize ?? 12}
268
+ fontWeight={styles.values?.fontWeight}
269
+ fontStyle={styles.values?.fontStyle}
270
+ stroke={styles.values?.stroke}
271
+ strokeWidth={styles.values?.strokeWidth}
272
+ paintOrder={styles.values?.paintOrder}
221
273
  />
222
274
  {/if}
223
275
 
@@ -282,5 +334,6 @@
282
334
  {/if}
283
335
  {/each}
284
336
  {/each}
337
+ </RuleLayout>
285
338
  {/snippet}
286
- </PlotLayout>
339
+ </BasePlotLayout>
@@ -1,7 +1,11 @@
1
- import type { PlotProps } from '../../types/plots/props';
2
- import type { BarSegmentStyle } from '../../types/plots/styles';
1
+ import type { BasePlotProps } from '../../types/plots/props';
2
+ import type { SeriesProps, DataProps } from '../../types/plots/data/common';
3
+ import type { AxisBasedScalesConfig } from '../../types/plots/props';
4
+ import type { BasePlotStyles } from '../../types/plots/styles/common';
5
+ import type { BarSegmentStyle } from '../../types/plots/segments/common';
6
+ import type { Marker } from '../../types/markers/common';
3
7
  declare function $$render<TData extends Record<string, unknown>>(): {
4
- props: PlotProps<TData, BarSegmentStyle>;
8
+ props: BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, BasePlotStyles, BarSegmentStyle, Marker, AxisBasedScalesConfig<TData>>;
5
9
  exports: {};
6
10
  bindings: "";
7
11
  slots: {};
@@ -1,4 +1,4 @@
1
- import type { Series } from '../../types/plots/common';
1
+ import type { Series } from '../../types/plots/data/common';
2
2
  import type { DeltaConfig } from '../../types/plots/delta';
3
3
  export type ResolvedDelta = {
4
4
  cfg: DeltaConfig;
@@ -0,0 +1,64 @@
1
+ import type { GeoFeature } from '../../types/plots/data/geo';
2
+ /**
3
+ * Bounding-box center of a geometry's flattened coordinates — a cheap
4
+ * approximation used for default label placement, not a true
5
+ * geographic/area centroid (no polygon-hole or geodesic-area weighting).
6
+ * For hover-matching specifically, see `geometryPartCentroids` instead —
7
+ * this single combined point can land far from every actual part of a
8
+ * multi-part geometry whose pieces are geographically spread out.
9
+ */
10
+ export declare function geometryCentroid(geometry: GeoJSON.Geometry): [number, number];
11
+ /**
12
+ * Splits a geometry into its disjoint parts: one `Polygon` per element of a
13
+ * `MultiPolygon`'s `coordinates`, one `LineString` per element of a
14
+ * `MultiLineString`'s, `GeometryCollection` recursed and flattened, and any
15
+ * other geometry type returned unchanged as its own single-element array.
16
+ * The shared building block behind `geometryPartCentroids` (one centroid per
17
+ * part) and `filterGeometryParts` (keep/drop whole parts).
18
+ */
19
+ export declare function splitGeometryParts(geometry: GeoJSON.Geometry): GeoJSON.Geometry[];
20
+ /**
21
+ * Like `geometryCentroid`, but returns one point per disjoint part instead
22
+ * of a single bounding-box center across all of them. A `MultiPolygon`
23
+ * whose parts are geographically far apart — e.g. Argentina's "Tierra del
24
+ * Fuego, Antártida e Islas del Atlántico Sur" province, whose `MultiPolygon`
25
+ * spans the mainland island, the Antarctic sector, and the South Atlantic
26
+ * islands in one feature — would otherwise get a single hover point
27
+ * stranded somewhere between all of them, matching hovers over *none* of
28
+ * the actually-rendered shapes. Multiple points attributed to the same
29
+ * feature is fine for hover-matching (nearest point wins, whichever part
30
+ * that is); it's only label placement (`geometryCentroid`) that needs a
31
+ * single point.
32
+ */
33
+ export declare function geometryPartCentroids(geometry: GeoJSON.Geometry): [number, number][];
34
+ /**
35
+ * Keeps or drops each disjoint part of a geometry (see `splitGeometryParts`)
36
+ * based on a per-part predicate, reassembling a geometry of the same type
37
+ * from whatever survives — `null` if nothing does. Used to let a single
38
+ * feature's geometry be split between the main map and an `inset` marker
39
+ * (see `GeoDataProps.excludeParts`/`GeoInsetMarker.featurePartsFilter`)
40
+ * without preprocessing the source data: e.g. a province whose `MultiPolygon`
41
+ * spans both a mainland part and a far-flung part can have the main map
42
+ * exclude the latter while an inset shows only it.
43
+ */
44
+ export declare function filterGeometryParts(geometry: GeoJSON.Geometry, keep: (part: {
45
+ centroid: [number, number];
46
+ geometry: GeoJSON.Geometry;
47
+ }) => boolean): GeoJSON.Geometry | null;
48
+ /** Default `featureId`: `feature.id`, else `properties.id`, else `properties.name`. */
49
+ export declare function defaultFeatureId<TProps extends Record<string, unknown>>(f: GeoFeature<TProps>): string;
50
+ /**
51
+ * Densifies a great-circle arc between two lon/lat points into `steps + 1`
52
+ * points via spherical linear interpolation (slerp) — used to draw a `link`
53
+ * marker's geodesic curve through the `Geo` mark (see `Plot.svelte`).
54
+ *
55
+ * Not delegated to svelteplot's own `Link` mark: its 0.14.2 projection
56
+ * integration (`Mark.svelte`'s paired-channel handling) reads a single
57
+ * `row.x`/`row.y` pair regardless of channel suffix, so a mark bound to
58
+ * `x1`/`y1`/`x2`/`y2` (never plain `x`/`y`) resolves every point as invalid
59
+ * whenever the plot has an active `projection` scale — which GeoPlot always
60
+ * does. `Geo` has no such limitation (geo marks are explicitly excluded from
61
+ * that code path), so a manually-interpolated `LineString` feature sidesteps
62
+ * the bug entirely while still producing the same geodesic visual.
63
+ */
64
+ export declare function greatCircleInterpolate(lon1: number, lat1: number, lon2: number, lat2: number, steps?: number): [number, number][];