@fundar/data-chart-telling 0.0.30 → 0.0.32
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.
- package/dist/charts/BaseChart.svelte +1 -0
- package/dist/plots/bar/Plot.svelte +24 -19
- package/dist/plots/bar/ValueLabels.svelte +18 -9
- package/dist/plots/bar/ValueLabels.svelte.d.ts +10 -0
- package/dist/plots/line/Plot.svelte +15 -10
- package/dist/plots/line/ValueLabels.svelte +27 -22
- package/dist/plots/line/ValueLabels.svelte.d.ts +10 -0
- package/dist/plots/pyramid/Plot.svelte +21 -16
- package/dist/plots/pyramid/ValueLabels.svelte +18 -9
- package/dist/plots/pyramid/ValueLabels.svelte.d.ts +10 -0
- package/dist/plots/scatter/Plot.svelte +20 -15
- package/dist/plots/scatter/ValueLabels.svelte +18 -7
- package/dist/plots/scatter/ValueLabels.svelte.d.ts +10 -0
- package/package.json +1 -1
|
@@ -225,7 +225,7 @@
|
|
|
225
225
|
getY={plotGetY}
|
|
226
226
|
{hover}
|
|
227
227
|
scales={resolvedScales}
|
|
228
|
-
|
|
228
|
+
{...labelMargin.plotProps}
|
|
229
229
|
xTickRotate={resolvedScales?.x?.tickRotate}
|
|
230
230
|
markers={({ setHoverMatch, clearHoverMatch }) => [
|
|
231
231
|
...buildBarMarkers({
|
|
@@ -245,22 +245,27 @@
|
|
|
245
245
|
seriesData={resolvedSeries}
|
|
246
246
|
{scopedGroups}
|
|
247
247
|
>
|
|
248
|
-
{#
|
|
249
|
-
{#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
271
|
</BasePlotLayout>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
import { Text
|
|
2
|
+
import { Text } from 'svelteplot';
|
|
3
3
|
import { resolveAccessor } from '../utils/accessors';
|
|
4
4
|
import { disabledFillOverride } from '../utils/legendDisabled';
|
|
5
5
|
import { watchLabelOverflow } from '../utils/labelOverflow.svelte';
|
|
@@ -30,6 +30,9 @@
|
|
|
30
30
|
values,
|
|
31
31
|
axisColor,
|
|
32
32
|
disabled,
|
|
33
|
+
width,
|
|
34
|
+
height,
|
|
35
|
+
numericMargins,
|
|
33
36
|
onHoverSeries,
|
|
34
37
|
onHoverEnd,
|
|
35
38
|
onOverflow,
|
|
@@ -44,6 +47,11 @@
|
|
|
44
47
|
axisColor: string;
|
|
45
48
|
/** Resolved legend/hover-isolate dimming style for this group's series, if any. */
|
|
46
49
|
disabled?: LegendDisabledStyle;
|
|
50
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below). */
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
54
|
+
numericMargins: { top: number; right: number; bottom: number; left: number };
|
|
47
55
|
/** Fired when the pointer enters this series' label — only wired when hover-isolate is enabled. */
|
|
48
56
|
onHoverSeries?: () => void;
|
|
49
57
|
onHoverEnd?: () => void;
|
|
@@ -52,25 +60,26 @@
|
|
|
52
60
|
} = $props();
|
|
53
61
|
|
|
54
62
|
const fillOverride = $derived(disabledFillOverride(disabled));
|
|
55
|
-
const plot = usePlot();
|
|
56
63
|
let groupEl: SVGGElement | undefined = $state();
|
|
57
64
|
|
|
58
65
|
watchLabelOverflow({
|
|
59
66
|
el: () => groupEl,
|
|
67
|
+
// Built from our own `width`/`height`/`numericMargins` rather than
|
|
68
|
+
// `usePlot().scales.x/y.fn.range()` — see line/ValueLabels.svelte's
|
|
69
|
+
// matching comment for why that scale's exposed range can't be trusted
|
|
70
|
+
// once a caller fixes `width`/`height` explicitly (every plot kind here
|
|
71
|
+
// does).
|
|
60
72
|
bounds: () => {
|
|
61
73
|
// getBBox() inside isn't itself tracked — depend on whatever actually
|
|
62
74
|
// changes the rendered label layout so this re-measures.
|
|
63
75
|
void group;
|
|
64
76
|
void values;
|
|
65
77
|
void valAnchor;
|
|
66
|
-
const xRange = plot.scales.x?.fn?.range?.()?.map(Number);
|
|
67
|
-
const yRange = plot.scales.y?.fn?.range?.()?.map(Number);
|
|
68
|
-
if (!xRange || !yRange) return undefined;
|
|
69
78
|
return {
|
|
70
|
-
left:
|
|
71
|
-
right:
|
|
72
|
-
top:
|
|
73
|
-
bottom:
|
|
79
|
+
left: numericMargins.left,
|
|
80
|
+
right: width - numericMargins.right,
|
|
81
|
+
top: numericMargins.top,
|
|
82
|
+
bottom: height - numericMargins.bottom,
|
|
74
83
|
};
|
|
75
84
|
},
|
|
76
85
|
onOverflow: (overflow) => onOverflow?.(overflow),
|
|
@@ -18,6 +18,16 @@ declare function $$render<TData extends Record<string, unknown>>(): {
|
|
|
18
18
|
axisColor: string;
|
|
19
19
|
/** Resolved legend/hover-isolate dimming style for this group's series, if any. */
|
|
20
20
|
disabled?: LegendDisabledStyle;
|
|
21
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below). */
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
25
|
+
numericMargins: {
|
|
26
|
+
top: number;
|
|
27
|
+
right: number;
|
|
28
|
+
bottom: number;
|
|
29
|
+
left: number;
|
|
30
|
+
};
|
|
21
31
|
/** Fired when the pointer enters this series' label — only wired when hover-isolate is enabled. */
|
|
22
32
|
onHoverSeries?: () => void;
|
|
23
33
|
onHoverEnd?: () => void;
|
|
@@ -178,14 +178,19 @@
|
|
|
178
178
|
seriesData={resolvedSeries}
|
|
179
179
|
{scopedGroups}
|
|
180
180
|
>
|
|
181
|
-
{#
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
181
|
+
{#snippet children({ numericMargins })}
|
|
182
|
+
{#if showVals}
|
|
183
|
+
<ValueLabels
|
|
184
|
+
{lastPoints}
|
|
185
|
+
values={styles.values}
|
|
186
|
+
{width}
|
|
187
|
+
{height}
|
|
188
|
+
{numericMargins}
|
|
189
|
+
onOverflow={labelMargin.report}
|
|
190
|
+
disabledFor={effectiveDisabledFor}
|
|
191
|
+
onHoverSeries={hoverIsolate ? (name) => { hoverIsolatedSeries = name; } : undefined}
|
|
192
|
+
onHoverEnd={hoverIsolate ? () => { hoverIsolatedSeries = null; } : undefined}
|
|
193
|
+
/>
|
|
194
|
+
{/if}
|
|
195
|
+
{/snippet}
|
|
191
196
|
</BasePlotLayout>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
import { untrack } from 'svelte';
|
|
3
2
|
import { SvelteMap } from 'svelte/reactivity';
|
|
4
3
|
import { Text, usePlot } from 'svelteplot';
|
|
5
4
|
import { resolveAccessor } from '../utils/accessors';
|
|
@@ -25,6 +24,9 @@
|
|
|
25
24
|
let {
|
|
26
25
|
lastPoints,
|
|
27
26
|
values,
|
|
27
|
+
width,
|
|
28
|
+
height,
|
|
29
|
+
numericMargins,
|
|
28
30
|
onOverflow,
|
|
29
31
|
disabledFor,
|
|
30
32
|
onHoverSeries,
|
|
@@ -32,6 +34,11 @@
|
|
|
32
34
|
}: {
|
|
33
35
|
lastPoints: { series: Series<TData>; lastRow: TData; seriesIndex: number }[];
|
|
34
36
|
values: ValuesStyle | undefined;
|
|
37
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below for why `usePlot()`'s own scale range can't be trusted for this). */
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
41
|
+
numericMargins: { top: number; right: number; bottom: number; left: number };
|
|
35
42
|
/** Reports how far the rendered labels overflow the plot's own content box, in pixels, on each side (0 = no overflow). */
|
|
36
43
|
onOverflow?: (overflow: MarginOverflow) => void;
|
|
37
44
|
/** Resolved legend/hover-isolate dimming style for a series, if any. */
|
|
@@ -93,33 +100,31 @@
|
|
|
93
100
|
|
|
94
101
|
watchLabelOverflow({
|
|
95
102
|
el: () => groupEl,
|
|
103
|
+
// Deliberately built from our own `width`/`height`/`numericMargins`
|
|
104
|
+
// (all already correctly sized off the `width`/`height` this `<Plot>`
|
|
105
|
+
// was actually mounted with — see `BasePlotLayout`'s own `numericMargins`
|
|
106
|
+
// doc comment), not from `usePlot().scales.x/y.fn.range()`: svelteplot's
|
|
107
|
+
// `<Plot>` accepts an explicit `width`/`height` (our `fixedWidth`) for
|
|
108
|
+
// its own real layout, but the scale object it exposes through context
|
|
109
|
+
// is computed off its *internal* auto-detected size instead — normally
|
|
110
|
+
// the same number, but never reconciled with `fixedWidth` when one is
|
|
111
|
+
// given. That left `.range()` reporting a stale/placeholder boundary
|
|
112
|
+
// (svelteplot's own internal default, unrelated to this plot's actual
|
|
113
|
+
// pixel size) wherever a caller fixes `width`/`height` explicitly — which
|
|
114
|
+
// every plot kind here does — so this watcher never saw genuine
|
|
115
|
+
// right/bottom overflow past the *real* edge and never grew the margin
|
|
116
|
+
// to fit it, leaving end-point labels to render past the plot's true
|
|
117
|
+
// right edge with no space reserved for them.
|
|
96
118
|
bounds: () => {
|
|
97
119
|
// getBBox() inside isn't itself tracked — depend on whatever actually
|
|
98
120
|
// changes the rendered label layout so this re-measures.
|
|
99
121
|
void lastPoints;
|
|
100
122
|
void values;
|
|
101
|
-
// The scale range itself is read `untrack`ed on purpose: this margin
|
|
102
|
-
// watcher's own report (see labelOverflow.svelte.ts) grows the plot's
|
|
103
|
-
// margin to fit the labels, which feeds back into svelteplot's own
|
|
104
|
-
// auto-margin sizing and nudges this same range — occasionally by a
|
|
105
|
-
// permanent, never-settling ±1px each render. Treating the range as a
|
|
106
|
-
// tracked dependency here reran the whole watcher every single time it
|
|
107
|
-
// twitched, which (when it never settles) never let the watcher's own
|
|
108
|
-
// "poll until stable" loop finish — an infinite effect-restart loop
|
|
109
|
-
// that tripped Svelte's effect_update_depth_exceeded guard. Reading it
|
|
110
|
-
// untracked still measures against the *current* range on every
|
|
111
|
-
// re-run triggered by `lastPoints`/`values` above; it just stops the
|
|
112
|
-
// range's own fluctuations from being what triggers those re-runs.
|
|
113
|
-
const { xRange, yRange } = untrack(() => ({
|
|
114
|
-
xRange: plot.scales.x?.fn?.range?.()?.map(Number),
|
|
115
|
-
yRange: plot.scales.y?.fn?.range?.()?.map(Number),
|
|
116
|
-
}));
|
|
117
|
-
if (!xRange || !yRange) return undefined;
|
|
118
123
|
return {
|
|
119
|
-
left:
|
|
120
|
-
right:
|
|
121
|
-
top:
|
|
122
|
-
bottom:
|
|
124
|
+
left: numericMargins.left,
|
|
125
|
+
right: width - numericMargins.right,
|
|
126
|
+
top: numericMargins.top,
|
|
127
|
+
bottom: height - numericMargins.bottom,
|
|
123
128
|
};
|
|
124
129
|
},
|
|
125
130
|
onOverflow: (overflow) => onOverflow?.(overflow),
|
|
@@ -10,6 +10,16 @@ declare function $$render<TData extends Record<string, unknown>>(): {
|
|
|
10
10
|
seriesIndex: number;
|
|
11
11
|
}[];
|
|
12
12
|
values: ValuesStyle | undefined;
|
|
13
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below for why `usePlot()`'s own scale range can't be trusted for this). */
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
17
|
+
numericMargins: {
|
|
18
|
+
top: number;
|
|
19
|
+
right: number;
|
|
20
|
+
bottom: number;
|
|
21
|
+
left: number;
|
|
22
|
+
};
|
|
13
23
|
/** Reports how far the rendered labels overflow the plot's own content box, in pixels, on each side (0 = no overflow). */
|
|
14
24
|
onOverflow?: (overflow: MarginOverflow) => void;
|
|
15
25
|
/** Resolved legend/hover-isolate dimming style for a series, if any. */
|
|
@@ -262,25 +262,30 @@
|
|
|
262
262
|
{getY}
|
|
263
263
|
{hover}
|
|
264
264
|
scales={resolvedScales}
|
|
265
|
-
|
|
265
|
+
{...labelMargin.plotProps}
|
|
266
266
|
xTickRotate={resolvedScales?.x?.tickRotate}
|
|
267
267
|
markers={[...pyramidMarkers, ...markers]}
|
|
268
268
|
seriesData={resolvedSeries}
|
|
269
269
|
{scopedGroups}
|
|
270
270
|
>
|
|
271
|
-
{#
|
|
272
|
-
{#
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
271
|
+
{#snippet children({ numericMargins })}
|
|
272
|
+
{#if showVals}
|
|
273
|
+
{#each groupedSeries as group (group.series.name)}
|
|
274
|
+
<ValueLabels
|
|
275
|
+
{group}
|
|
276
|
+
{valAnchor}
|
|
277
|
+
{formatValue}
|
|
278
|
+
values={styles.values}
|
|
279
|
+
axisColor={cfg.axis.color}
|
|
280
|
+
disabled={effectiveDisabledFor(group.series.name)}
|
|
281
|
+
{width}
|
|
282
|
+
{height}
|
|
283
|
+
{numericMargins}
|
|
284
|
+
onHoverSeries={hoverIsolate ? () => { hoverIsolatedSeries = group.series.name; } : undefined}
|
|
285
|
+
onHoverEnd={hoverIsolate ? () => { hoverIsolatedSeries = null; } : undefined}
|
|
286
|
+
onOverflow={labelMargin.report}
|
|
287
|
+
/>
|
|
288
|
+
{/each}
|
|
289
|
+
{/if}
|
|
290
|
+
{/snippet}
|
|
286
291
|
</BasePlotLayout>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
import { Text
|
|
2
|
+
import { Text } from 'svelteplot';
|
|
3
3
|
import { resolveAccessor } from '../utils/accessors';
|
|
4
4
|
import { disabledFillOverride } from '../utils/legendDisabled';
|
|
5
5
|
import { watchLabelOverflow } from '../utils/labelOverflow.svelte';
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
values,
|
|
26
26
|
axisColor,
|
|
27
27
|
disabled,
|
|
28
|
+
width,
|
|
29
|
+
height,
|
|
30
|
+
numericMargins,
|
|
28
31
|
onHoverSeries,
|
|
29
32
|
onHoverEnd,
|
|
30
33
|
onOverflow,
|
|
@@ -36,6 +39,11 @@
|
|
|
36
39
|
axisColor: string;
|
|
37
40
|
/** Resolved legend/hover-isolate dimming style for this group's series, if any. */
|
|
38
41
|
disabled?: LegendDisabledStyle;
|
|
42
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below). */
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
46
|
+
numericMargins: { top: number; right: number; bottom: number; left: number };
|
|
39
47
|
/** Fired when the pointer enters this series' label — only wired when hover-isolate is enabled. */
|
|
40
48
|
onHoverSeries?: () => void;
|
|
41
49
|
onHoverEnd?: () => void;
|
|
@@ -44,25 +52,26 @@
|
|
|
44
52
|
} = $props();
|
|
45
53
|
|
|
46
54
|
const fillOverride = $derived(disabledFillOverride(disabled));
|
|
47
|
-
const plot = usePlot();
|
|
48
55
|
let groupEl: SVGGElement | undefined = $state();
|
|
49
56
|
|
|
50
57
|
watchLabelOverflow({
|
|
51
58
|
el: () => groupEl,
|
|
59
|
+
// Built from our own `width`/`height`/`numericMargins` rather than
|
|
60
|
+
// `usePlot().scales.x/y.fn.range()` — see line/ValueLabels.svelte's
|
|
61
|
+
// matching comment for why that scale's exposed range can't be trusted
|
|
62
|
+
// once a caller fixes `width`/`height` explicitly (every plot kind here
|
|
63
|
+
// does).
|
|
52
64
|
bounds: () => {
|
|
53
65
|
// getBBox() inside isn't itself tracked — depend on whatever actually
|
|
54
66
|
// changes the rendered label layout so this re-measures.
|
|
55
67
|
void group;
|
|
56
68
|
void values;
|
|
57
69
|
void valAnchor;
|
|
58
|
-
const xRange = plot.scales.x?.fn?.range?.()?.map(Number);
|
|
59
|
-
const yRange = plot.scales.y?.fn?.range?.()?.map(Number);
|
|
60
|
-
if (!xRange || !yRange) return undefined;
|
|
61
70
|
return {
|
|
62
|
-
left:
|
|
63
|
-
right:
|
|
64
|
-
top:
|
|
65
|
-
bottom:
|
|
71
|
+
left: numericMargins.left,
|
|
72
|
+
right: width - numericMargins.right,
|
|
73
|
+
top: numericMargins.top,
|
|
74
|
+
bottom: height - numericMargins.bottom,
|
|
66
75
|
};
|
|
67
76
|
},
|
|
68
77
|
onOverflow: (overflow) => onOverflow?.(overflow),
|
|
@@ -16,6 +16,16 @@ declare function $$render<TData extends Record<string, unknown>>(): {
|
|
|
16
16
|
axisColor: string;
|
|
17
17
|
/** Resolved legend/hover-isolate dimming style for this group's series, if any. */
|
|
18
18
|
disabled?: LegendDisabledStyle;
|
|
19
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below). */
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
23
|
+
numericMargins: {
|
|
24
|
+
top: number;
|
|
25
|
+
right: number;
|
|
26
|
+
bottom: number;
|
|
27
|
+
left: number;
|
|
28
|
+
};
|
|
19
29
|
/** Fired when the pointer enters this series' label — only wired when hover-isolate is enabled. */
|
|
20
30
|
onHoverSeries?: () => void;
|
|
21
31
|
onHoverEnd?: () => void;
|
|
@@ -220,23 +220,28 @@
|
|
|
220
220
|
getY={(d) => Number(yAcc(d))}
|
|
221
221
|
{hover}
|
|
222
222
|
scales={resolvedScales}
|
|
223
|
-
|
|
223
|
+
{...labelMargin.plotProps}
|
|
224
224
|
markers={[...scatterMarkers, ...markers]}
|
|
225
225
|
seriesData={resolvedSeries}
|
|
226
226
|
{scopedGroups}
|
|
227
227
|
>
|
|
228
|
-
{#
|
|
229
|
-
{#
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
228
|
+
{#snippet children({ numericMargins })}
|
|
229
|
+
{#if showVals}
|
|
230
|
+
{#each groupedSeries as group (group.series.name)}
|
|
231
|
+
<ValueLabels
|
|
232
|
+
{group}
|
|
233
|
+
{formatValue}
|
|
234
|
+
values={styles.values}
|
|
235
|
+
defaultColor={cfg.axis.color}
|
|
236
|
+
disabled={effectiveDisabledFor(group.series.name)}
|
|
237
|
+
{width}
|
|
238
|
+
{height}
|
|
239
|
+
{numericMargins}
|
|
240
|
+
onHoverSeries={hoverIsolate ? () => { hoverIsolatedSeries = group.series.name; } : undefined}
|
|
241
|
+
onHoverEnd={hoverIsolate ? () => { hoverIsolatedSeries = null; } : undefined}
|
|
242
|
+
onOverflow={labelMargin.report}
|
|
243
|
+
/>
|
|
244
|
+
{/each}
|
|
245
|
+
{/if}
|
|
246
|
+
{/snippet}
|
|
242
247
|
</BasePlotLayout>
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
values,
|
|
30
30
|
defaultColor,
|
|
31
31
|
disabled,
|
|
32
|
+
width,
|
|
33
|
+
height,
|
|
34
|
+
numericMargins,
|
|
32
35
|
onHoverSeries,
|
|
33
36
|
onHoverEnd,
|
|
34
37
|
onOverflow,
|
|
@@ -39,6 +42,11 @@
|
|
|
39
42
|
defaultColor: string;
|
|
40
43
|
/** Resolved legend/hover-isolate dimming style for this group's series, if any. */
|
|
41
44
|
disabled?: LegendDisabledStyle;
|
|
45
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below). */
|
|
46
|
+
width: number;
|
|
47
|
+
height: number;
|
|
48
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
49
|
+
numericMargins: { top: number; right: number; bottom: number; left: number };
|
|
42
50
|
/** Fired when the pointer enters this series' label — only wired when hover-isolate is enabled. */
|
|
43
51
|
onHoverSeries?: () => void;
|
|
44
52
|
onHoverEnd?: () => void;
|
|
@@ -54,19 +62,22 @@
|
|
|
54
62
|
|
|
55
63
|
watchLabelOverflow({
|
|
56
64
|
el: () => groupEl,
|
|
65
|
+
// Built from our own `width`/`height`/`numericMargins` rather than
|
|
66
|
+
// `usePlot().scales.x/y.fn.range()` — see line/ValueLabels.svelte's
|
|
67
|
+
// matching comment for why that scale's exposed range can't be trusted
|
|
68
|
+
// once a caller fixes `width`/`height` explicitly (every plot kind here
|
|
69
|
+
// does). `plot.plotWidth`/`plotHeight` (used below for edge-aware
|
|
70
|
+
// placement) don't have this problem — only the scale's own `.range()`.
|
|
57
71
|
bounds: () => {
|
|
58
72
|
// getBBox() inside isn't itself tracked — depend on whatever actually
|
|
59
73
|
// changes the rendered label layout so this re-measures.
|
|
60
74
|
void data;
|
|
61
75
|
void values;
|
|
62
|
-
const xRange = plot.scales.x?.fn?.range?.()?.map(Number);
|
|
63
|
-
const yRange = plot.scales.y?.fn?.range?.()?.map(Number);
|
|
64
|
-
if (!xRange || !yRange) return undefined;
|
|
65
76
|
return {
|
|
66
|
-
left:
|
|
67
|
-
right:
|
|
68
|
-
top:
|
|
69
|
-
bottom:
|
|
77
|
+
left: numericMargins.left,
|
|
78
|
+
right: width - numericMargins.right,
|
|
79
|
+
top: numericMargins.top,
|
|
80
|
+
bottom: height - numericMargins.bottom,
|
|
70
81
|
};
|
|
71
82
|
},
|
|
72
83
|
onOverflow: (overflow) => onOverflow?.(overflow),
|
|
@@ -12,6 +12,16 @@ declare function $$render<TData extends Record<string, unknown>>(): {
|
|
|
12
12
|
defaultColor: string;
|
|
13
13
|
/** Resolved legend/hover-isolate dimming style for this group's series, if any. */
|
|
14
14
|
disabled?: LegendDisabledStyle;
|
|
15
|
+
/** The plot's own pixel size — together with `numericMargins`, the ground truth for its content box (see `bounds()` below). */
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
/** `BasePlotLayout`'s resolved margins, already numeric on every side. */
|
|
19
|
+
numericMargins: {
|
|
20
|
+
top: number;
|
|
21
|
+
right: number;
|
|
22
|
+
bottom: number;
|
|
23
|
+
left: number;
|
|
24
|
+
};
|
|
15
25
|
/** Fired when the pointer enters this series' label — only wired when hover-isolate is enabled. */
|
|
16
26
|
onHoverSeries?: () => void;
|
|
17
27
|
onHoverEnd?: () => void;
|