@fundar/data-chart-telling 0.0.38 → 0.0.40

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.
@@ -1,271 +1,297 @@
1
- <script
2
- lang="ts"
3
- generics="TData extends Record<string, unknown>"
4
- >
5
- import { paletteColor } from '../../utils/color';
6
- import { buildSeries } from '../../utils/grouping';
7
- import { getLegendInteraction } from '../../layout/legend/interaction.svelte';
8
- import { disabledFillOverride } from '../utils/legendDisabled';
9
- import { resolveAccessor } from '../utils/accessors';
10
- import { getConfiguration } from '../../configuration/config.svelte';
11
- import { buildGroupedSeries, validateSegments, buildScopedMarkerGroups } from '../utils/segments';
12
- import { createBarLayout } from './layout.svelte';
13
- import { createLabelMarginTracker } from '../utils/labelOverflow.svelte';
14
- import { buildHoverPoints } from './hoverPoints';
15
- import { buildBarMarkers } from './buildBarMarkers';
16
- import { resolveGapsForSeries, resolveDiscreteGapFills } from '../utils/gaps';
17
- import ValueLabels from './ValueLabels.svelte';
18
- import BasePlotLayout from '../../layout/plot/BasePlotLayout.svelte';
19
- import { hasHoverMarker, resolveHoverStrategy, resolveHoverSync } from '../../layout/tooltip/utils';
20
- import type { AxisBasedMarkersConfig } from '../../types/markers/common';
21
- import type { BasePlotProps } from '../../types/plots/props';
22
- import type { AxisScale, AxisBasedScalesConfig } from '../../types/layout/scales';
23
- import type { Series, SeriesProps, DataProps } from '../../types/plots/data/common';
24
- import type { GapsAwarePlotStylesConfig } from '../../types/layout/styles';
25
- import type { ValueAnchor } from '../../types/plots/constants';
26
- import type { BarSegmentStyle } from '../../types/plots/segments/common';
27
- import type { LegendDisabledStyle } from '../../types/layout/legend';
1
+ <script lang="ts" generics="TData extends Record<string, unknown>">
2
+ import { paletteColor } from '../../utils/color';
3
+ import { buildSeries } from '../../utils/grouping';
4
+ import { getLegendInteraction } from '../../layout/legend/interaction.svelte';
5
+ import { disabledFillOverride } from '../utils/legendDisabled';
6
+ import { resolveAccessor } from '../utils/accessors';
7
+ import { getConfiguration } from '../../configuration/config.svelte';
8
+ import {
9
+ buildGroupedSeries,
10
+ validateSegments,
11
+ buildScopedMarkerGroups
12
+ } from '../utils/segments';
13
+ import { createBarLayout } from './layout.svelte';
14
+ import { createLabelMarginTracker } from '../utils/labelOverflow.svelte';
15
+ import { buildHoverPoints } from './hoverPoints';
16
+ import { buildBarMarkers } from './buildBarMarkers';
17
+ import { resolveGapsForSeries, resolveDiscreteGapFills } from '../utils/gaps';
18
+ import ValueLabels from './ValueLabels.svelte';
19
+ import BasePlotLayout from '../../layout/plot/BasePlotLayout.svelte';
20
+ import {
21
+ hasHoverMarker,
22
+ resolveHoverStrategy,
23
+ resolveHoverSync
24
+ } from '../../layout/tooltip/utils';
25
+ import type { AxisBasedMarkersConfig } from '../../types/markers/common';
26
+ import type { BasePlotProps } from '../../types/plots/props';
27
+ import type { AxisScale, AxisBasedScalesConfig } from '../../types/layout/scales';
28
+ import type { Series, SeriesProps, DataProps } from '../../types/plots/data/common';
29
+ import type { GapsAwarePlotStylesConfig } from '../../types/layout/styles';
30
+ import type { ValueAnchor } from '../../types/plots/constants';
31
+ import type { BarSegmentStyle } from '../../types/plots/segments/common';
32
+ import type { LegendDisabledStyle } from '../../types/layout/legend';
28
33
 
29
- /**
30
- * A bar chart, vertical by default. Accepts either a pre-built `series`
31
- * array or flat `data/x/y/z` props — mirrors the line/heatmap plot contract
32
- * so the chart-level container/timeline/facet/legend wrap it unchanged.
33
- */
34
- type Props = BasePlotProps<
35
- SeriesProps<TData> | DataProps<TData>,
36
- TData,
37
- GapsAwarePlotStylesConfig<BarSegmentStyle>,
38
- BarSegmentStyle,
39
- AxisBasedMarkersConfig,
40
- AxisBasedScalesConfig<TData>
41
- >;
34
+ /**
35
+ * A bar chart, vertical by default. Accepts either a pre-built `series`
36
+ * array or flat `data/x/y/z` props — mirrors the line/heatmap plot contract
37
+ * so the chart-level container/timeline/facet/legend wrap it unchanged.
38
+ */
39
+ type Props = BasePlotProps<
40
+ SeriesProps<TData> | DataProps<TData>,
41
+ TData,
42
+ GapsAwarePlotStylesConfig<BarSegmentStyle>,
43
+ BarSegmentStyle,
44
+ AxisBasedMarkersConfig,
45
+ AxisBasedScalesConfig<TData>
46
+ >;
42
47
 
43
- let {
44
- width,
45
- height,
46
- series,
47
- data,
48
- x,
49
- y,
50
- z,
51
- styles = {},
52
- segments = {},
53
- markers = [],
54
- scales = {},
55
- margins,
56
- tooltip = undefined,
57
- }: Props = $props();
48
+ let {
49
+ width,
50
+ height,
51
+ series,
52
+ data,
53
+ x,
54
+ y,
55
+ z,
56
+ styles = {},
57
+ segments = {},
58
+ markers = [],
59
+ scales = {},
60
+ margins,
61
+ tooltip = undefined
62
+ }: Props = $props();
58
63
 
59
- $effect(() => { validateSegments(segments); });
64
+ $effect(() => {
65
+ validateSegments(segments);
66
+ });
60
67
 
61
- const cfg = $derived(getConfiguration());
62
- const resolvedSeries = $derived(series ?? buildSeries(data!, x!, y!, z));
63
- const groupedSeries = $derived(
64
- // connect: false — bars are discrete; there's no visual gap between
65
- // adjacent categories to bridge (see buildGroupedSeries's own doc).
66
- buildGroupedSeries<Series<TData>, BarSegmentStyle>(resolvedSeries, segments, false),
67
- );
68
- const showVals = $derived(styles.values?.show ?? false);
69
- const formatValue = $derived(styles.values?.format ?? ((v: number) => `${v}`));
70
- const valAnchor = $derived<ValueAnchor>(styles.values?.anchor ?? 'outside');
68
+ const cfg = $derived(getConfiguration());
69
+ const resolvedSeries = $derived(series ?? buildSeries(data!, x!, y!, z));
70
+ const groupedSeries = $derived(
71
+ // connect: false — bars are discrete; there's no visual gap between
72
+ // adjacent categories to bridge (see buildGroupedSeries's own doc).
73
+ buildGroupedSeries<Series<TData>, BarSegmentStyle>(resolvedSeries, segments, false)
74
+ );
75
+ const showVals = $derived(styles.values?.show ?? false);
76
+ const formatValue = $derived(styles.values?.format ?? ((v: number) => `${v}`));
77
+ const valAnchor = $derived<ValueAnchor>(styles.values?.anchor ?? 'outside');
71
78
 
72
- // Fills leading/internal/trailing missing-data holes with an
73
- // interpolated, distinctly-styled bar, resolved per series like
74
- // `segments` — see `GapsAwarePlotStylesConfig` (`types/layout/styles.ts`).
75
- const gaps = $derived(styles.gaps ?? {});
76
- const gapFillMaps = $derived(
77
- new Map(resolvedSeries.map((s) => [s.name, resolveDiscreteGapFills(s, resolveGapsForSeries(gaps, s.name))])),
78
- );
79
+ // Fills leading/internal/trailing missing-data holes with an
80
+ // interpolated, distinctly-styled bar, resolved per series like
81
+ // `segments` — see `GapsAwarePlotStylesConfig` (`types/layout/styles.ts`).
82
+ const gaps = $derived(styles.gaps ?? {});
83
+ const gapFillMaps = $derived(
84
+ new Map(
85
+ resolvedSeries.map((s) => [
86
+ s.name,
87
+ resolveDiscreteGapFills(s, resolveGapsForSeries(gaps, s.name))
88
+ ])
89
+ )
90
+ );
79
91
 
80
- // `xAcc`/`yAcc` are always data-semantic (category/value) — independent of
81
- // which *visual* axis ends up drawing them, decided by `categoricalAxis`.
82
- const xAcc = $derived(resolveAccessor(resolvedSeries[0]?.x ?? ((d: TData) => d)));
83
- const yAcc = $derived(resolveAccessor(resolvedSeries[0]?.y ?? ((d: TData) => d)));
84
- const flat = $derived(resolvedSeries.flatMap((s) => s.data));
92
+ // `xAcc`/`yAcc` are always data-semantic (category/value) — independent of
93
+ // which *visual* axis ends up drawing them, decided by `categoricalAxis`.
94
+ const xAcc = $derived(resolveAccessor(resolvedSeries[0]?.x ?? ((d: TData) => d)));
95
+ const yAcc = $derived(resolveAccessor(resolvedSeries[0]?.y ?? ((d: TData) => d)));
96
+ const flat = $derived(resolvedSeries.flatMap((s) => s.data));
85
97
 
86
- const scopedGroups = $derived(
87
- buildScopedMarkerGroups<TData, Series<TData>, BarSegmentStyle>({
88
- groupedSeries,
89
- segments,
90
- colorFor: (_series, seriesIndex) => paletteColor(seriesIndex, cfg.palette),
91
- segmentColorFor: (style, defaultColor) => style?.fill ?? defaultColor,
92
- }),
93
- );
98
+ const scopedGroups = $derived(
99
+ buildScopedMarkerGroups<TData, Series<TData>, BarSegmentStyle>({
100
+ groupedSeries,
101
+ segments,
102
+ colorFor: (_series, seriesIndex) => paletteColor(seriesIndex, cfg.palette),
103
+ segmentColorFor: (style, defaultColor) => style?.fill ?? defaultColor
104
+ })
105
+ );
94
106
 
95
- /**
96
- * Which visual axis draws the category, and therefore whether this renders
97
- * as vertical bars (`BarY`, category on X) or horizontal bars (`BarX`,
98
- * category on Y). Mirrors how pyramid/heatmap default an `AxisScale.type`
99
- * themselves: `scales.x`/`scales.y` always describe *that visual axis*
100
- * regardless of which data field lands there, so marking `scales.y.type:
101
- * 'categorical'` simply says "the category is drawn on Y this time" — x
102
- * defaults to categorical when neither is marked.
103
- */
104
- const categoricalAxis = $derived.by((): 'x' | 'y' => {
105
- const xCategorical = scales.x?.type === 'categorical';
106
- const yCategorical = scales.y?.type === 'categorical';
107
- if (xCategorical && yCategorical) {
108
- console.warn(
109
- "BarPlot: scales.x.type and scales.y.type can't both be 'categorical' — " +
110
- 'mark only one axis as the category axis. Defaulting to x.',
111
- );
112
- return 'x';
113
- }
114
- return yCategorical ? 'y' : 'x';
115
- });
116
- const isHorizontal = $derived(categoricalAxis === 'y');
107
+ /**
108
+ * Which visual axis draws the category, and therefore whether this renders
109
+ * as vertical bars (`BarY`, category on X) or horizontal bars (`BarX`,
110
+ * category on Y). Mirrors how pyramid/heatmap default an `AxisScale.type`
111
+ * themselves: `scales.x`/`scales.y` always describe *that visual axis*
112
+ * regardless of which data field lands there, so marking `scales.y.type:
113
+ * 'categorical'` simply says "the category is drawn on Y this time" — x
114
+ * defaults to categorical when neither is marked.
115
+ */
116
+ const categoricalAxis = $derived.by((): 'x' | 'y' => {
117
+ const xCategorical = scales.x?.type === 'categorical';
118
+ const yCategorical = scales.y?.type === 'categorical';
119
+ if (xCategorical && yCategorical) {
120
+ console.warn(
121
+ "BarPlot: scales.x.type and scales.y.type can't both be 'categorical' — " +
122
+ 'mark only one axis as the category axis. Defaulting to x.'
123
+ );
124
+ return 'x';
125
+ }
126
+ return yCategorical ? 'y' : 'x';
127
+ });
128
+ const isHorizontal = $derived(categoricalAxis === 'y');
117
129
 
118
- /**
119
- * `'categorical'` is our own sentinel (BarPlot-only), not a real svelteplot
120
- * scale type — svelteplot's x/y scales don't recognise it (it's valid only
121
- * for `color`/`symbol`). Strip it before the scale reaches svelteplot so it
122
- * auto-infers the real type (typically `point`/`band`) the same way it
123
- * already does when `type` is left unset entirely.
124
- */
125
- function stripCategoricalType(scale?: AxisScale<TData>): AxisScale<TData> | undefined {
126
- if (scale?.type !== 'categorical') return scale;
127
- const rest = { ...scale };
128
- delete rest.type;
129
- return rest;
130
- }
131
- // The single, fully-resolved scales object BasePlotLayout reads for
132
- // everything (ticks, grid, sort, and the real svelteplot scale) — avoids
133
- // keeping a second, separately-patched copy of `scales.x`/`scales.y` in
134
- // sync with the one actually forwarded.
135
- const resolvedScales = $derived({
136
- ...scales,
137
- x: stripCategoricalType(scales.x),
138
- y: stripCategoricalType(scales.y),
139
- });
130
+ /**
131
+ * `'categorical'` is our own sentinel (BarPlot-only), not a real svelteplot
132
+ * scale type — svelteplot's x/y scales don't recognise it (it's valid only
133
+ * for `color`/`symbol`). Strip it before the scale reaches svelteplot so it
134
+ * auto-infers the real type (typically `point`/`band`) the same way it
135
+ * already does when `type` is left unset entirely.
136
+ */
137
+ function stripCategoricalType(scale?: AxisScale<TData>): AxisScale<TData> | undefined {
138
+ if (scale?.type !== 'categorical') return scale;
139
+ const rest = { ...scale };
140
+ delete rest.type;
141
+ return rest;
142
+ }
143
+ // The single, fully-resolved scales object BasePlotLayout reads for
144
+ // everything (ticks, grid, sort, and the real svelteplot scale) — avoids
145
+ // keeping a second, separately-patched copy of `scales.x`/`scales.y` in
146
+ // sync with the one actually forwarded.
147
+ const resolvedScales = $derived({
148
+ ...scales,
149
+ x: stripCategoricalType(scales.x),
150
+ y: stripCategoricalType(scales.y)
151
+ });
140
152
 
141
- // The accessor feeding each *visual* channel — swapped from the
142
- // data-semantic xAcc/yAcc when the category is drawn on Y.
143
- const plotGetX = $derived(isHorizontal ? (d: TData) => Number(yAcc(d)) : xAcc);
144
- const plotGetY = $derived(isHorizontal ? xAcc : (d: TData) => Number(yAcc(d)));
153
+ // The accessor feeding each *visual* channel — swapped from the
154
+ // data-semantic xAcc/yAcc when the category is drawn on Y.
155
+ const plotGetX = $derived(isHorizontal ? (d: TData) => Number(yAcc(d)) : xAcc);
156
+ const plotGetY = $derived(isHorizontal ? xAcc : (d: TData) => Number(yAcc(d)));
145
157
 
146
- /**
147
- * Series-layout geometry (grouped/stacked offsets, band-width estimate,
148
- * value baseline) — the single source of truth shared by bar-segment
149
- * rendering, value labels, and hover markers below. See `layout.svelte.ts`.
150
- */
151
- const barLayout = createBarLayout<TData>({
152
- scales: () => scales,
153
- isHorizontal: () => isHorizontal,
154
- width: () => width,
155
- height: () => height,
156
- margins: () => margins,
157
- flat: () => flat,
158
- xAcc: () => xAcc,
159
- groupedSeries: () => groupedSeries,
160
- gapFillMaps: () => gapFillMaps,
161
- });
158
+ /**
159
+ * Series-layout geometry (grouped/stacked offsets, band-width estimate,
160
+ * value baseline) — the single source of truth shared by bar-segment
161
+ * rendering, value labels, and hover markers below. See `layout.svelte.ts`.
162
+ */
163
+ const barLayout = createBarLayout<TData>({
164
+ scales: () => scales,
165
+ isHorizontal: () => isHorizontal,
166
+ width: () => width,
167
+ height: () => height,
168
+ margins: () => margins,
169
+ flat: () => flat,
170
+ xAcc: () => xAcc,
171
+ groupedSeries: () => groupedSeries,
172
+ gapFillMaps: () => gapFillMaps
173
+ });
162
174
 
163
- // `x`/`y` here are visual (matched against BasePlotLayout's own getX/getY,
164
- // which drive tick/domain computation and the Pointer's hit-testing) —
165
- // `row` (see BasePlotLayout/HoverPoint) is what lets the template recover the
166
- // semantic category regardless of which axis it landed on.
167
- const legendInteraction = $derived(getLegendInteraction());
168
- const hoverIsolate = $derived(styles.values?.hoverIsolate ?? false);
175
+ // `x`/`y` here are visual (matched against BasePlotLayout's own getX/getY,
176
+ // which drive tick/domain computation and the Pointer's hit-testing) —
177
+ // `row` (see BasePlotLayout/HoverPoint) is what lets the template recover the
178
+ // semantic category regardless of which axis it landed on.
179
+ const legendInteraction = $derived(getLegendInteraction());
180
+ const hoverIsolate = $derived(styles.values?.hoverIsolate ?? false);
169
181
 
170
- // A value label hovered while `styles.values.hoverIsolate` is on dims
171
- // every other series exactly like a legend toggle would — local to this
172
- // one `<Plot>` instance (not the shared HoverStore) so the gesture can't
173
- // leak into unrelated tooltip/crosshair behavior.
174
- let hoverIsolatedSeries = $state<string | null>(null);
182
+ // A value label hovered while `styles.values.hoverIsolate` is on dims
183
+ // every other series exactly like a legend toggle would — local to this
184
+ // one `<Plot>` instance (not the shared HoverStore) so the gesture can't
185
+ // leak into unrelated tooltip/crosshair behavior.
186
+ let hoverIsolatedSeries = $state<string | null>(null);
175
187
 
176
- function effectiveDisabledFor(name: string): LegendDisabledStyle | undefined {
177
- return (
178
- legendInteraction?.disabledSeries.get(name) ??
179
- (hoverIsolate && hoverIsolatedSeries && hoverIsolatedSeries !== name
180
- ? { opacity: cfg.legend.disabledOpacity }
181
- : undefined)
182
- );
183
- }
188
+ function effectiveDisabledFor(name: string): LegendDisabledStyle | undefined {
189
+ return (
190
+ legendInteraction?.disabledSeries.get(name) ??
191
+ (hoverIsolate && hoverIsolatedSeries && hoverIsolatedSeries !== name
192
+ ? { opacity: cfg.legend.disabledOpacity }
193
+ : undefined)
194
+ );
195
+ }
184
196
 
185
- // A legend-disabled series is dimmed on the bar itself, but never surfaces
186
- // in hover/tooltip — its points are simply absent from the candidate list.
187
- const hoverPoints = $derived(
188
- buildHoverPoints(resolvedSeries, isHorizontal, barLayout, cfg.palette).filter(
189
- (p) => !legendInteraction?.disabledSeries.has(p.series!),
190
- ),
191
- );
197
+ // A legend-disabled series is dimmed on the bar itself, but never surfaces
198
+ // in hover/tooltip — its points are simply absent from the candidate list.
199
+ const hoverPoints = $derived(
200
+ buildHoverPoints(resolvedSeries, isHorizontal, barLayout, cfg.palette).filter(
201
+ (p) => !legendInteraction?.disabledSeries.has(p.series!)
202
+ )
203
+ );
192
204
 
193
- const hover = $derived({
194
- active: tooltip != null || hasHoverMarker(markers),
195
- points: hoverPoints,
196
- label: (r: TData) => String(yAcc(r)),
197
- strategy: resolveHoverStrategy(tooltip?.strategy, markers, categoricalAxis),
198
- sync: resolveHoverSync(tooltip?.sync, markers),
199
- tooltip,
200
- // The category axis is a band scale — `<Pointer>`'s nearest-point-by-
201
- // distance match (svelteplot's own projection of each candidate's band
202
- // centre) can disagree by a couple of pixels with where `<BarX>`/`<BarY>`
203
- // (via svelteplot's `RectPath`) actually render that band, which is
204
- // enough to mismatch the neighbouring category once bands get thin
205
- // (many categories). The `role: 'hitArea'` bar markers `buildBarMarkers`
206
- // emits hit-test the category bands directly instead — see its own doc
207
- // comment.
208
- pointMatching: 'contains' as const,
209
- });
205
+ const hover = $derived({
206
+ active: tooltip != null || hasHoverMarker(markers),
207
+ points: hoverPoints,
208
+ label: (r: TData) => String(yAcc(r)),
209
+ strategy: resolveHoverStrategy(tooltip?.strategy, markers, categoricalAxis),
210
+ sync: resolveHoverSync(tooltip?.sync, markers),
211
+ tooltip,
212
+ // The category axis is a band scale — `<Pointer>`'s nearest-point-by-
213
+ // distance match (svelteplot's own projection of each candidate's band
214
+ // centre) can disagree by a couple of pixels with where `<BarX>`/`<BarY>`
215
+ // (via svelteplot's `RectPath`) actually render that band, which is
216
+ // enough to mismatch the neighbouring category once bands get thin
217
+ // (many categories). The `role: 'hitArea'` bar markers `buildBarMarkers`
218
+ // emits hit-test the category bands directly instead — see its own doc
219
+ // comment.
220
+ pointMatching: 'contains' as const
221
+ });
210
222
 
211
- // A bar's value label can grow past the plot's own content box (e.g. a
212
- // tall bar's `anchor: 'outside'` label pushing past the top margin) —
213
- // reserving real space there is what each label's own overflow
214
- // measurement feeds into here, via a tracker local to this one `<Plot>`
215
- // instance. See `labelOverflow.svelte.ts`.
216
- const labelMargin = createLabelMarginTracker(() => margins);
223
+ // A bar's value label can grow past the plot's own content box (e.g. a
224
+ // tall bar's `anchor: 'outside'` label pushing past the top margin) —
225
+ // reserving real space there is what each label's own overflow
226
+ // measurement feeds into here, via a tracker local to this one `<Plot>`
227
+ // instance. See `labelOverflow.svelte.ts`. Resets on `resolvedSeries` so
228
+ // overflow from an earlier, differently-shaped frame (e.g. a timeline
229
+ // scrubber revealing a different slice of rows) doesn't linger once
230
+ // that frame is gone.
231
+ const labelMargin = createLabelMarginTracker(
232
+ () => margins,
233
+ () => resolvedSeries
234
+ );
217
235
  </script>
218
236
 
219
237
  <BasePlotLayout
220
- {width}
221
- {height}
222
- {styles}
223
- data={flat}
224
- getX={plotGetX}
225
- getY={plotGetY}
226
- {hover}
227
- scales={resolvedScales}
228
- {...labelMargin.plotProps}
229
- xTickRotate={resolvedScales?.x?.tickRotate}
230
- markers={({ setHoverMatch, clearHoverMatch }) => [
231
- ...buildBarMarkers({
232
- groupedSeries,
233
- barLayout,
234
- isHorizontal,
235
- hoverPoints,
236
- palette: cfg.palette,
237
- disabledFillFor: (name) => disabledFillOverride(effectiveDisabledFor(name)),
238
- active: hover.active,
239
- setHoverMatch,
240
- clearHoverMatch,
241
- gapFillMaps,
242
- }),
243
- ...markers,
244
- ]}
245
- seriesData={resolvedSeries}
246
- {scopedGroups}
238
+ {width}
239
+ {height}
240
+ {styles}
241
+ data={flat}
242
+ getX={plotGetX}
243
+ getY={plotGetY}
244
+ {hover}
245
+ scales={resolvedScales}
246
+ {...labelMargin.plotProps}
247
+ xTickRotate={resolvedScales?.x?.tickRotate}
248
+ markers={({ setHoverMatch, clearHoverMatch }) => [
249
+ ...buildBarMarkers({
250
+ groupedSeries,
251
+ barLayout,
252
+ isHorizontal,
253
+ hoverPoints,
254
+ palette: cfg.palette,
255
+ disabledFillFor: (name) => disabledFillOverride(effectiveDisabledFor(name)),
256
+ active: hover.active,
257
+ setHoverMatch,
258
+ clearHoverMatch,
259
+ gapFillMaps
260
+ }),
261
+ ...markers
262
+ ]}
263
+ seriesData={resolvedSeries}
264
+ {scopedGroups}
247
265
  >
248
- {#snippet children({ numericMargins })}
249
- {#if showVals}
250
- {#each groupedSeries as group, seriesIndex (group.series.name)}
251
- <ValueLabels
252
- {group}
253
- {seriesIndex}
254
- {barLayout}
255
- {isHorizontal}
256
- {valAnchor}
257
- {formatValue}
258
- values={styles.values}
259
- axisColor={cfg.axis.color}
260
- disabled={effectiveDisabledFor(group.series.name)}
261
- {width}
262
- {height}
263
- {numericMargins}
264
- onHoverSeries={hoverIsolate ? () => { hoverIsolatedSeries = group.series.name; } : undefined}
265
- onHoverEnd={hoverIsolate ? () => { hoverIsolatedSeries = null; } : undefined}
266
- onOverflow={labelMargin.report}
267
- />
268
- {/each}
269
- {/if}
270
- {/snippet}
266
+ {#snippet children({ numericMargins })}
267
+ {#if showVals}
268
+ {#each groupedSeries as group, seriesIndex (group.series.name)}
269
+ <ValueLabels
270
+ {group}
271
+ {seriesIndex}
272
+ {barLayout}
273
+ {isHorizontal}
274
+ {valAnchor}
275
+ {formatValue}
276
+ values={styles.values}
277
+ axisColor={cfg.axis.color}
278
+ disabled={effectiveDisabledFor(group.series.name)}
279
+ {width}
280
+ {height}
281
+ {numericMargins}
282
+ onHoverSeries={hoverIsolate
283
+ ? () => {
284
+ hoverIsolatedSeries = group.series.name;
285
+ }
286
+ : undefined}
287
+ onHoverEnd={hoverIsolate
288
+ ? () => {
289
+ hoverIsolatedSeries = null;
290
+ }
291
+ : undefined}
292
+ onOverflow={labelMargin.report}
293
+ />
294
+ {/each}
295
+ {/if}
296
+ {/snippet}
271
297
  </BasePlotLayout>