@fundar/data-chart-telling 0.0.24 → 0.0.26
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/bar/Chart.svelte +2 -0
- package/dist/charts/heatmap/Chart.svelte +3 -1
- package/dist/charts/heatmap/Chart.svelte.d.ts +1 -2
- package/dist/charts/line/Chart.svelte +2 -0
- package/dist/charts/pyramid/Chart.svelte +3 -1
- package/dist/charts/pyramid/Chart.svelte.d.ts +1 -2
- package/dist/charts/scatter/Chart.svelte +95 -0
- package/dist/charts/scatter/Chart.svelte.d.ts +28 -0
- package/dist/configuration/config.svelte.js +13 -1
- package/dist/configuration/themes/index.d.ts +76 -0
- package/dist/index.d.ts +20 -14
- package/dist/index.js +9 -3
- package/dist/layout/coordinates/CoordinatesLayout.svelte +95 -0
- package/dist/layout/{plot/RuleLayout.svelte.d.ts → coordinates/CoordinatesLayout.svelte.d.ts} +13 -16
- package/dist/layout/coordinates/margins.d.ts +16 -0
- package/dist/layout/coordinates/margins.js +11 -0
- package/dist/{plots/geo → layout/coordinates}/projections/argentina.d.ts +1 -1
- package/dist/layout/{geo → coordinates}/resolveProjection.d.ts +1 -1
- package/dist/layout/coordinates/resolveProjection.js +24 -0
- package/dist/{plots/geo → layout/coordinates}/zoom.svelte.d.ts +1 -1
- package/dist/layout/geometry/GeometryLayout.svelte +231 -0
- package/dist/layout/geometry/GeometryLayout.svelte.d.ts +62 -0
- package/dist/layout/plot/BasePlotLayout.svelte +142 -155
- package/dist/layout/plot/BasePlotLayout.svelte.d.ts +61 -51
- package/dist/layout/plot/margins.d.ts +0 -16
- package/dist/layout/plot/margins.js +0 -11
- package/dist/layout/{plot/AxisLayout.svelte → scales/ScalesLayout.svelte} +23 -16
- package/dist/layout/{plot/AxisLayout.svelte.d.ts → scales/ScalesLayout.svelte.d.ts} +4 -5
- package/dist/layout/scales/buildScale.d.ts +8 -0
- package/dist/layout/scales/buildScale.js +43 -0
- package/dist/layout/styles/StylesLayout.svelte +75 -0
- package/dist/layout/styles/StylesLayout.svelte.d.ts +15 -0
- package/dist/{plots/geo → layout/styles}/TileLayer.svelte +2 -2
- package/dist/{plots/geo → layout/styles}/TileLayer.svelte.d.ts +1 -1
- package/dist/layout/tooltip/Tooltip.svelte +16 -20
- package/dist/layout/tooltip/Tooltip.svelte.d.ts +5 -0
- package/dist/layout/tooltip/TooltipLayout.svelte +7 -1
- package/dist/layout/tooltip/TooltipLayout.svelte.d.ts +4 -0
- package/dist/layout/tooltip/controller.svelte.d.ts +4 -5
- package/dist/layout/tooltip/controller.svelte.js +28 -16
- package/dist/layout/tooltip/resolveTooltipPlacement.d.ts +24 -0
- package/dist/layout/tooltip/resolveTooltipPlacement.js +49 -0
- package/dist/layout/tooltip/utils.d.ts +27 -19
- package/dist/layout/tooltip/utils.js +16 -15
- package/dist/markers/BarMarker.svelte +92 -0
- package/dist/markers/BarMarker.svelte.d.ts +7 -0
- package/dist/markers/CellMarker.svelte +21 -0
- package/dist/markers/CellMarker.svelte.d.ts +7 -0
- package/dist/markers/ContourMarker.svelte +28 -0
- package/dist/markers/ContourMarker.svelte.d.ts +7 -0
- package/dist/markers/DeltaMarker.svelte +32 -39
- package/dist/markers/DeltaMarker.svelte.d.ts +4 -5
- package/dist/markers/DotMarker.svelte +35 -6
- package/dist/markers/DotMarker.svelte.d.ts +11 -2
- package/dist/markers/GeoFeaturesMarker.svelte +19 -0
- package/dist/markers/GeoFeaturesMarker.svelte.d.ts +7 -0
- package/dist/markers/GeoHoverMarker.svelte +25 -0
- package/dist/markers/GeoHoverMarker.svelte.d.ts +9 -0
- package/dist/markers/GraticuleMarker.svelte +18 -0
- package/dist/markers/GraticuleMarker.svelte.d.ts +7 -0
- package/dist/markers/HoverMarker.svelte +32 -33
- package/dist/markers/HoverMarker.svelte.d.ts +15 -9
- package/dist/markers/LineMarker.svelte +19 -0
- package/dist/markers/LineMarker.svelte.d.ts +7 -0
- package/dist/markers/LinkMarker.svelte +42 -0
- package/dist/markers/LinkMarker.svelte.d.ts +7 -0
- package/dist/markers/RuleMarker.svelte +24 -0
- package/dist/markers/RuleMarker.svelte.d.ts +10 -0
- package/dist/markers/SphereMarker.svelte +15 -0
- package/dist/markers/SphereMarker.svelte.d.ts +7 -0
- package/dist/markers/TextMarker.svelte +1 -1
- package/dist/markers/TextMarker.svelte.d.ts +1 -1
- package/dist/markers/VectorMarker.svelte +20 -0
- package/dist/markers/VectorMarker.svelte.d.ts +7 -0
- package/dist/markers/inset/InsetMarker.svelte +38 -45
- package/dist/markers/inset/InsetMarker.svelte.d.ts +6 -2
- package/dist/plots/bar/Plot.svelte +54 -84
- package/dist/plots/bar/Plot.svelte.d.ts +4 -5
- package/dist/plots/bar/ValueLabels.svelte +1 -1
- package/dist/plots/bar/ValueLabels.svelte.d.ts +1 -1
- package/dist/plots/bar/buildBarMarkers.d.ts +30 -0
- package/dist/plots/bar/buildBarMarkers.js +100 -0
- package/dist/plots/bar/layout.svelte.d.ts +1 -2
- package/dist/plots/bar/layout.svelte.js +1 -1
- package/dist/plots/geo/Plot.svelte +113 -387
- package/dist/plots/geo/Plot.svelte.d.ts +5 -4
- package/dist/plots/geo/buildGeoMarkers.d.ts +33 -0
- package/dist/plots/geo/buildGeoMarkers.js +47 -0
- package/dist/plots/heatmap/Plot.svelte +24 -49
- package/dist/plots/heatmap/Plot.svelte.d.ts +4 -5
- package/dist/plots/heatmap/ValueLabels.svelte +2 -2
- package/dist/plots/heatmap/ValueLabels.svelte.d.ts +2 -2
- package/dist/plots/heatmap/buildCellMarkers.d.ts +21 -0
- package/dist/plots/heatmap/buildCellMarkers.js +25 -0
- package/dist/plots/line/Plot.svelte +68 -141
- package/dist/plots/line/Plot.svelte.d.ts +4 -4
- package/dist/plots/line/ValueLabels.svelte +94 -49
- package/dist/plots/line/ValueLabels.svelte.d.ts +6 -1
- package/dist/plots/line/buildLineMarkers.d.ts +15 -0
- package/dist/plots/line/buildLineMarkers.js +57 -0
- package/dist/plots/pyramid/Plot.svelte +41 -117
- package/dist/plots/pyramid/Plot.svelte.d.ts +4 -5
- package/dist/plots/pyramid/ValueLabels.svelte +1 -1
- package/dist/plots/pyramid/ValueLabels.svelte.d.ts +1 -1
- package/dist/plots/pyramid/buildPyramidBarMarkers.d.ts +19 -0
- package/dist/plots/pyramid/buildPyramidBarMarkers.js +32 -0
- package/dist/plots/scatter/Plot.svelte +206 -0
- package/dist/plots/{bar/BarSegments.svelte.d.ts → scatter/Plot.svelte.d.ts} +9 -20
- package/dist/plots/scatter/ValueLabels.svelte +106 -0
- package/dist/{layout/plot/GridLayout.svelte.d.ts → plots/scatter/ValueLabels.svelte.d.ts} +11 -5
- package/dist/plots/scatter/buildScatterMarkers.d.ts +11 -0
- package/dist/plots/scatter/buildScatterMarkers.js +37 -0
- package/dist/plots/scatter/resolveRadiusPaddedDomain.d.ts +10 -0
- package/dist/plots/scatter/resolveRadiusPaddedDomain.js +23 -0
- package/dist/plots/utils/declutter.d.ts +82 -33
- package/dist/plots/utils/declutter.js +182 -40
- package/dist/plots/utils/geoAccessors.d.ts +1 -1
- package/dist/plots/utils/geoAccessors.js +1 -1
- package/dist/plots/utils/segments.d.ts +17 -10
- package/dist/plots/utils/segments.js +26 -16
- package/dist/types/charts/common.d.ts +1 -1
- package/dist/types/charts/props.d.ts +5 -6
- package/dist/types/configuration/styling.d.ts +24 -2
- package/dist/types/{plots/scales/geo.d.ts → layout/coordinates.d.ts} +33 -1
- package/dist/types/layout/geometry.d.ts +17 -0
- package/dist/types/{plots/axis.d.ts → layout/scales.d.ts} +11 -0
- package/dist/types/layout/styles.d.ts +126 -0
- package/dist/types/layout/tooltip.d.ts +20 -1
- package/dist/types/markers/all.d.ts +11 -0
- package/dist/types/markers/base.d.ts +45 -0
- package/dist/types/markers/base.js +1 -0
- package/dist/types/markers/common.d.ts +64 -16
- package/dist/types/markers/geo.d.ts +75 -100
- package/dist/types/markers/line.d.ts +34 -0
- package/dist/types/markers/line.js +1 -0
- package/dist/types/markers/props.d.ts +1 -1
- package/dist/types/plots/data/common.d.ts +1 -1
- package/dist/types/plots/data/scatter.d.ts +13 -0
- package/dist/types/plots/data/scatter.js +1 -0
- package/dist/types/plots/props.d.ts +46 -74
- package/dist/types/plots/segments/common.d.ts +6 -12
- package/dist/types/plots/segments/config.d.ts +1 -1
- package/dist/types/plots/styling.d.ts +10 -0
- package/dist/{plots/utils → utils}/delta.d.ts +2 -2
- package/dist/{plots/utils → utils}/delta.js +1 -1
- package/dist/utils/edgeAwareAnchor.d.ts +37 -0
- package/dist/utils/edgeAwareAnchor.js +65 -0
- package/dist/utils/grouping.d.ts +1 -1
- package/dist/utils/interpolate.d.ts +1 -1
- package/package.json +3 -1
- package/dist/layout/geo/GeoLayout.svelte +0 -51
- package/dist/layout/geo/GeoLayout.svelte.d.ts +0 -24
- package/dist/layout/geo/resolveProjection.js +0 -48
- package/dist/layout/plot/GridLayout.svelte +0 -30
- package/dist/layout/plot/RuleLayout.svelte +0 -111
- package/dist/plots/bar/BarSegments.svelte +0 -69
- package/dist/types/plots/delta.d.ts +0 -19
- package/dist/types/plots/styles/common.d.ts +0 -52
- package/dist/types/plots/styles/geo.d.ts +0 -42
- /package/dist/{plots/geo → layout/coordinates}/projections/argentina.js +0 -0
- /package/dist/{plots/geo → layout/coordinates}/projections/fit.d.ts +0 -0
- /package/dist/{plots/geo → layout/coordinates}/projections/fit.js +0 -0
- /package/dist/{plots/geo → layout/coordinates}/rotate.svelte.d.ts +0 -0
- /package/dist/{plots/geo → layout/coordinates}/rotate.svelte.js +0 -0
- /package/dist/{plots/geo → layout/coordinates}/zoom.svelte.js +0 -0
- /package/dist/types/{plots/axis.js → layout/coordinates.js} +0 -0
- /package/dist/types/{plots/delta.js → layout/geometry.js} +0 -0
- /package/dist/types/{plots/scales/geo.js → layout/scales.js} +0 -0
- /package/dist/types/{plots/styles/common.js → layout/styles.js} +0 -0
- /package/dist/types/{plots/styles/geo.js → markers/all.js} +0 -0
|
@@ -4,31 +4,11 @@
|
|
|
4
4
|
import { resolveAccessor } from '../utils/accessors';
|
|
5
5
|
import { getConfiguration } from '../../configuration/config.svelte';
|
|
6
6
|
import { paletteColor } from '../../utils/color';
|
|
7
|
-
import { declutter1D,
|
|
7
|
+
import { declutter1D, laneAssignment } from '../utils/declutter';
|
|
8
8
|
import type { Series } from '../../types/plots/data/common';
|
|
9
|
-
import type { ValuesStyle } from '../../types/
|
|
9
|
+
import type { ValuesStyle } from '../../types/layout/styles';
|
|
10
10
|
import type { ValueAnchor } from '../../types/plots/constants';
|
|
11
11
|
|
|
12
|
-
// Elbow-routed leader line geometry (pixels) — a run's top/bottom pair
|
|
13
|
-
// share the shortest lane, its next-in pair the next lane out, and so on
|
|
14
|
-
// (see `mirrorRanks`'s doc comment for why sharing a lane is safe). Each
|
|
15
|
-
// lane is `LANE_STEP` further out than the last; `ELBOW_GAP` is the
|
|
16
|
-
// shortest lane (rank 0, right off the data point); `LABEL_GAP` is the
|
|
17
|
-
// small clearance between the outermost lane and the label text it feeds
|
|
18
|
-
// into.
|
|
19
|
-
const ELBOW_GAP = 10;
|
|
20
|
-
const LANE_STEP = 7;
|
|
21
|
-
const LABEL_GAP = 6;
|
|
22
|
-
|
|
23
|
-
// Default connector look — deliberately *not* each series' own colour or
|
|
24
|
-
// stroke weight: a leader line only needs to be traceable back to its
|
|
25
|
-
// label, and matching the data line's own styling reads as if it were
|
|
26
|
-
// more data, which is confusing right where several lines already
|
|
27
|
-
// converge. Neutral, thin, and solid keeps it legible as a leader — the
|
|
28
|
-
// colour and weight are still fully overridable via `values.strokeStyle`.
|
|
29
|
-
const DEFAULT_CONNECTOR_COLOR = '#94a3b8';
|
|
30
|
-
const DEFAULT_CONNECTOR_WIDTH = 0.5;
|
|
31
|
-
|
|
32
12
|
/**
|
|
33
13
|
* End-point value labels for `LinePlot` — one label per series at its last
|
|
34
14
|
* data point, with automatic collision resolution whenever several series
|
|
@@ -40,12 +20,33 @@
|
|
|
40
20
|
let {
|
|
41
21
|
lastPoints,
|
|
42
22
|
values,
|
|
23
|
+
onOverflow,
|
|
43
24
|
}: {
|
|
44
25
|
lastPoints: { series: Series<TData>; lastRow: TData; seriesIndex: number }[];
|
|
45
26
|
values: ValuesStyle | undefined;
|
|
27
|
+
/** Reports how far the rendered labels overflow the plot's own content box, in pixels, on each side (0 = no overflow). */
|
|
28
|
+
onOverflow?: (overflow: { left: number; right: number }) => void;
|
|
46
29
|
} = $props();
|
|
47
30
|
|
|
48
31
|
const cfg = $derived(getConfiguration());
|
|
32
|
+
|
|
33
|
+
// Elbow-routed leader line geometry (pixels), configurable project-wide
|
|
34
|
+
// via `setConfiguration({ line: { valueLabels: {...} } })` — each lane a
|
|
35
|
+
// run's members get spread across (see `laneAssignment`'s doc comment for
|
|
36
|
+
// how lanes are picked without crossing) is `laneStep` further out than
|
|
37
|
+
// the last; `elbowGap` is the shortest lane (rank 0, right off the data
|
|
38
|
+
// point); `labelGap` is the small clearance between the outermost lane and
|
|
39
|
+
// the label text it feeds into. `connectorColor`/`connectorWidth` are the
|
|
40
|
+
// leader line's own default look — deliberately *not* each series' own
|
|
41
|
+
// colour or stroke weight (matching the data line reads as more data, not
|
|
42
|
+
// as a leader, right where several lines are already converging) — both
|
|
43
|
+
// still overridable per-plot via `values.strokeStyle`.
|
|
44
|
+
const elbowGap = $derived(cfg.line.valueLabels.elbowGap);
|
|
45
|
+
const laneStep = $derived(cfg.line.valueLabels.laneStep);
|
|
46
|
+
const labelGap = $derived(cfg.line.valueLabels.labelGap);
|
|
47
|
+
const defaultConnectorColor = $derived(cfg.line.valueLabels.connectorColor);
|
|
48
|
+
const defaultConnectorWidth = $derived(cfg.line.valueLabels.connectorWidth);
|
|
49
|
+
|
|
49
50
|
const font = $derived(values?.fontStyle);
|
|
50
51
|
const connector = $derived(values?.strokeStyle);
|
|
51
52
|
const fmtVal = $derived(values?.format ?? ((v: number, name: string) => `${name} - ${v}`));
|
|
@@ -61,9 +62,45 @@
|
|
|
61
62
|
valAnchor === 'start' ? ('start' as const) : valAnchor === 'end' ? ('end' as const) : ('middle' as const),
|
|
62
63
|
);
|
|
63
64
|
const defaultLA = $derived(valAnchor === 'outside' ? ('bottom' as const) : ('middle' as const));
|
|
65
|
+
const fontSize = $derived(typeof font?.fontSize === 'number' ? font.fontSize : 12);
|
|
64
66
|
|
|
65
67
|
const plot = usePlot();
|
|
66
68
|
|
|
69
|
+
// ── Overflow measurement ─────────────────────────────────────────────────
|
|
70
|
+
// Measures how far the rendered labels extend past the plot's own content
|
|
71
|
+
// box and reports it to the caller (`Plot.svelte`), which grows its own
|
|
72
|
+
// local margin state to fit — real `getBBox()` measurement, same as the
|
|
73
|
+
// approach this used to register directly into svelteplot's *shared*
|
|
74
|
+
// margin-auto-sizing context. Reporting through a plain callback instead
|
|
75
|
+
// keeps this entirely local to one `<Plot>` instance: nothing here is
|
|
76
|
+
// shared across instances, which is what made the old approach spike
|
|
77
|
+
// CPU/memory into unresponsiveness when many instances mounted/unmounted
|
|
78
|
+
// together (e.g. a multi-story docs page → single story).
|
|
79
|
+
let groupEl: SVGGElement | undefined = $state();
|
|
80
|
+
|
|
81
|
+
$effect(() => {
|
|
82
|
+
// getBBox() below is a plain DOM read, not itself tracked — depend on
|
|
83
|
+
// whatever actually changes the rendered label layout so this re-runs.
|
|
84
|
+
void lastPoints;
|
|
85
|
+
void values;
|
|
86
|
+
const el = groupEl;
|
|
87
|
+
if (!el || !onOverflow) return;
|
|
88
|
+
const xRange = plot.scales.x?.fn?.range?.()?.map(Number);
|
|
89
|
+
if (!xRange) return;
|
|
90
|
+
const plotLeft = Math.min(xRange[0], xRange[1]);
|
|
91
|
+
const plotRight = Math.max(xRange[0], xRange[1]);
|
|
92
|
+
let box: { x: number; width: number };
|
|
93
|
+
try {
|
|
94
|
+
box = el.getBBox();
|
|
95
|
+
} catch {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
onOverflow({
|
|
99
|
+
left: Math.ceil(Math.max(0, plotLeft - box.x)),
|
|
100
|
+
right: Math.ceil(Math.max(0, box.x + box.width - plotRight)),
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
67
104
|
/**
|
|
68
105
|
* Pixel-space collision fix-up for end-point labels: resolves each label's
|
|
69
106
|
* true pixel Y through the plot's own live y-scale, then runs the shared
|
|
@@ -74,45 +111,49 @@
|
|
|
74
111
|
* which would extend the y-scale's own domain and provoke an infinite
|
|
75
112
|
* autoscale ↔ declutter feedback loop.
|
|
76
113
|
*
|
|
77
|
-
* `inGroup`/`rank`/`
|
|
78
|
-
* own `connected` record rather than re-inferred from
|
|
79
|
-
* both functions' doc comments for why that's the only
|
|
80
|
-
* position-based heuristics either miss a series that
|
|
81
|
-
* because a neighbour got pushed into it, or wrongly
|
|
82
|
-
* clusters that each happened to need decluttering
|
|
83
|
-
* elbow connector below turns `rank` into a lane index
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* its label renders with no extra offset.
|
|
114
|
+
* `inGroup`/`rank`/`lanesUsed` come from `laneAssignment`, fed by
|
|
115
|
+
* `declutter1D`'s own `connected` record rather than re-inferred from
|
|
116
|
+
* positions — see both functions' doc comments for why that's the only
|
|
117
|
+
* reliable source: position-based heuristics either miss a series that
|
|
118
|
+
* only had to move because a neighbour got pushed into it, or wrongly
|
|
119
|
+
* bridge two unrelated clusters that each happened to need decluttering
|
|
120
|
+
* on their own. The elbow connector below turns `rank` into a lane index.
|
|
121
|
+
* A series with nothing nearby is absent from the map, and its label
|
|
122
|
+
* renders with no extra offset.
|
|
87
123
|
*/
|
|
88
124
|
const declutteredOffsets = $derived.by(() => {
|
|
89
|
-
const map = new SvelteMap<string, { extraDy: number; inGroup: boolean; rank: number;
|
|
125
|
+
const map = new SvelteMap<string, { extraDy: number; inGroup: boolean; rank: number; lanesUsed: number }>();
|
|
90
126
|
if (lastPoints.length < 2) return map;
|
|
91
127
|
const yScale = plot.scales.y?.fn;
|
|
92
128
|
if (!yScale) return map;
|
|
93
|
-
const fontSize = font?.fontSize ?? 12;
|
|
94
129
|
const minGap = Math.max(16, fontSize * 1.4);
|
|
95
130
|
const items = lastPoints.map(({ series: s, lastRow }) => ({
|
|
96
131
|
name: s.name,
|
|
97
132
|
pos: Number(yScale(Number(resolveAccessor(s.y)(lastRow)))),
|
|
98
133
|
}));
|
|
99
134
|
const sorted = [...items].sort((a, b) => a.pos - b.pos);
|
|
100
|
-
const
|
|
135
|
+
const range = yScale.range?.().map(Number);
|
|
136
|
+
const bounds: [number, number] | undefined = range
|
|
137
|
+
? [Math.min(range[0], range[1]), Math.max(range[0], range[1])]
|
|
138
|
+
: undefined;
|
|
139
|
+
const { positions: spread, connected } = declutter1D(items, minGap, bounds);
|
|
101
140
|
const spreadByName = new Map(spread.map((d) => [d.name, d.pos]));
|
|
102
|
-
const
|
|
141
|
+
const originals = sorted.map((item) => item.pos);
|
|
142
|
+
const finals = sorted.map((item) => spreadByName.get(item.name) ?? item.pos);
|
|
143
|
+
const ranks = laneAssignment(originals, finals, connected);
|
|
103
144
|
sorted.forEach((item, i) => {
|
|
104
|
-
const final = spreadByName.get(item.name) ?? item.pos;
|
|
105
145
|
map.set(item.name, {
|
|
106
|
-
extraDy:
|
|
107
|
-
inGroup: ranks[i].
|
|
146
|
+
extraDy: finals[i] - originals[i],
|
|
147
|
+
inGroup: ranks[i].runSize > 1,
|
|
108
148
|
rank: ranks[i].rank,
|
|
109
|
-
|
|
149
|
+
lanesUsed: ranks[i].lanesUsed,
|
|
110
150
|
});
|
|
111
151
|
});
|
|
112
152
|
return map;
|
|
113
153
|
});
|
|
114
154
|
</script>
|
|
115
155
|
|
|
156
|
+
<g bind:this={groupEl}>
|
|
116
157
|
{#each lastPoints as { series: s, lastRow, seriesIndex } (s.name)}
|
|
117
158
|
{@const xFn = resolveAccessor(s.x)}
|
|
118
159
|
{@const yFn = resolveAccessor(s.y)}
|
|
@@ -121,20 +162,23 @@
|
|
|
121
162
|
{@const extraDy = offset?.inGroup ? offset.extraDy : 0}
|
|
122
163
|
{@const baseDx = font?.dx ?? defaultDx}
|
|
123
164
|
{@const dir = Math.sign(baseDx) || 1}
|
|
124
|
-
{@const numLanes = offset?.inGroup ?
|
|
165
|
+
{@const numLanes = offset?.inGroup ? offset.lanesUsed : 0}
|
|
125
166
|
{@const labelDx = offset?.inGroup
|
|
126
|
-
? dir * (
|
|
167
|
+
? dir * (elbowGap + (numLanes - 1) * laneStep + labelGap)
|
|
127
168
|
: baseDx}
|
|
169
|
+
{@const text = fmtVal(Number(yFn(lastRow)), s.name)}
|
|
170
|
+
{@const preferredTA = resolvedTextAnchor ?? defaultTA}
|
|
171
|
+
{@const preferredLA = font?.lineAnchor ?? defaultLA}
|
|
128
172
|
{#if offset?.inGroup && plot.scales.x?.fn && plot.scales.y?.fn}
|
|
129
173
|
{@const px = Number(plot.scales.x.fn(xFn(lastRow)))}
|
|
130
174
|
{@const py = Number(plot.scales.y.fn(Number(yFn(lastRow))))}
|
|
131
|
-
{@const laneX = px + dir * (
|
|
175
|
+
{@const laneX = px + dir * (elbowGap + offset.rank * laneStep)}
|
|
132
176
|
{@const targetY = py + extraDy}
|
|
133
177
|
<path
|
|
134
178
|
d={`M ${px} ${py} H ${laneX} V ${targetY} H ${px + labelDx}`}
|
|
135
179
|
fill="none"
|
|
136
|
-
stroke={connector?.stroke ??
|
|
137
|
-
stroke-width={connector?.strokeWidth ??
|
|
180
|
+
stroke={connector?.stroke ?? defaultConnectorColor}
|
|
181
|
+
stroke-width={connector?.strokeWidth ?? defaultConnectorWidth}
|
|
138
182
|
stroke-opacity={connector?.strokeOpacity ?? 1}
|
|
139
183
|
stroke-dasharray={connector?.strokeDasharray}
|
|
140
184
|
stroke-linecap={connector?.strokeLinecap ?? 'square'}
|
|
@@ -145,17 +189,17 @@
|
|
|
145
189
|
data={[lastRow]}
|
|
146
190
|
x={xFn}
|
|
147
191
|
y={yFn}
|
|
148
|
-
text={() =>
|
|
192
|
+
text={() => text}
|
|
149
193
|
dx={labelDx}
|
|
150
194
|
dy={(font?.dy ?? defaultDy) + extraDy}
|
|
151
|
-
textAnchor={
|
|
152
|
-
lineAnchor={
|
|
195
|
+
textAnchor={preferredTA}
|
|
196
|
+
lineAnchor={preferredLA}
|
|
153
197
|
lineHeight={font?.lineHeight}
|
|
154
198
|
rotate={font?.rotate}
|
|
155
199
|
class={font?.class}
|
|
156
200
|
textClass={font?.textClass}
|
|
157
201
|
fill={font?.fill ?? seriesColor}
|
|
158
|
-
|
|
202
|
+
{fontSize}
|
|
159
203
|
fontWeight={font?.fontWeight}
|
|
160
204
|
fontStyle={font?.fontStyle}
|
|
161
205
|
stroke={font?.stroke}
|
|
@@ -163,3 +207,4 @@
|
|
|
163
207
|
paintOrder={font?.paintOrder}
|
|
164
208
|
/>
|
|
165
209
|
{/each}
|
|
210
|
+
</g>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Series } from '../../types/plots/data/common';
|
|
2
|
-
import type { ValuesStyle } from '../../types/
|
|
2
|
+
import type { ValuesStyle } from '../../types/layout/styles';
|
|
3
3
|
declare function $$render<TData extends Record<string, unknown>>(): {
|
|
4
4
|
props: {
|
|
5
5
|
lastPoints: {
|
|
@@ -8,6 +8,11 @@ declare function $$render<TData extends Record<string, unknown>>(): {
|
|
|
8
8
|
seriesIndex: number;
|
|
9
9
|
}[];
|
|
10
10
|
values: ValuesStyle | undefined;
|
|
11
|
+
/** Reports how far the rendered labels overflow the plot's own content box, in pixels, on each side (0 = no overflow). */
|
|
12
|
+
onOverflow?: (overflow: {
|
|
13
|
+
left: number;
|
|
14
|
+
right: number;
|
|
15
|
+
}) => void;
|
|
11
16
|
};
|
|
12
17
|
exports: {};
|
|
13
18
|
bindings: "";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Series } from '../../types/plots/data/common';
|
|
2
|
+
import type { LineSegmentStyle } from '../../types/plots/segments/common';
|
|
3
|
+
import type { VisualGroup } from '../../types/plots/segments/config';
|
|
4
|
+
import type { StrokeStyle, DotStyle } from '../../types/plots/styling';
|
|
5
|
+
import type { LineMarkerConfig, DotMarkerConfig } from '../../types/markers/common';
|
|
6
|
+
/**
|
|
7
|
+
* Every `'line'` (+ `'dot'`, where a segment's style asks for them) marker
|
|
8
|
+
* for one LinePlot render: one `'line'` marker per visual segment, plus a
|
|
9
|
+
* `'dot'` marker right after it when that segment sets `style.dots`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildLineMarkers<TData extends Record<string, unknown>>(args: {
|
|
12
|
+
groupedSeries: VisualGroup<Series<TData>, LineSegmentStyle>[];
|
|
13
|
+
disabledStrokeFor: (seriesName: string) => StrokeStyle | undefined;
|
|
14
|
+
disabledDotsFor: (seriesName: string) => DotStyle | undefined;
|
|
15
|
+
}): (LineMarkerConfig | DotMarkerConfig)[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { resolveAccessor } from '../utils/accessors';
|
|
2
|
+
import { paletteColor } from '../../utils/color';
|
|
3
|
+
import { getConfiguration } from '../../configuration/config.svelte';
|
|
4
|
+
/**
|
|
5
|
+
* Every `'line'` (+ `'dot'`, where a segment's style asks for them) marker
|
|
6
|
+
* for one LinePlot render: one `'line'` marker per visual segment, plus a
|
|
7
|
+
* `'dot'` marker right after it when that segment sets `style.dots`.
|
|
8
|
+
*/
|
|
9
|
+
export function buildLineMarkers(args) {
|
|
10
|
+
const { groupedSeries, disabledStrokeFor, disabledDotsFor } = args;
|
|
11
|
+
const cfg = getConfiguration();
|
|
12
|
+
const markers = [];
|
|
13
|
+
groupedSeries.forEach((group, seriesIndex) => {
|
|
14
|
+
const defaultColor = paletteColor(seriesIndex, cfg.palette);
|
|
15
|
+
const disabledStroke = disabledStrokeFor(group.series.name);
|
|
16
|
+
const disabledDots = disabledDotsFor(group.series.name);
|
|
17
|
+
const xFn = resolveAccessor(group.series.x);
|
|
18
|
+
const yFn = resolveAccessor(group.series.y);
|
|
19
|
+
for (const seg of group.visualSegments) {
|
|
20
|
+
const strokeStyle = seg.style.stroke;
|
|
21
|
+
const dotStyle = seg.style.dots;
|
|
22
|
+
markers.push({
|
|
23
|
+
type: 'line',
|
|
24
|
+
data: seg.data,
|
|
25
|
+
x: xFn,
|
|
26
|
+
y: yFn,
|
|
27
|
+
style: {
|
|
28
|
+
stroke: disabledStroke?.stroke ?? strokeStyle?.stroke ?? defaultColor,
|
|
29
|
+
strokeWidth: disabledStroke?.strokeWidth ?? strokeStyle?.strokeWidth ?? cfg.line.strokeWidth,
|
|
30
|
+
strokeOpacity: disabledStroke?.strokeOpacity ?? strokeStyle?.strokeOpacity ?? 1,
|
|
31
|
+
strokeDasharray: disabledStroke?.strokeDasharray ?? strokeStyle?.strokeDasharray,
|
|
32
|
+
strokeLinejoin: disabledStroke?.strokeLinejoin ?? strokeStyle?.strokeLinejoin,
|
|
33
|
+
strokeLinecap: disabledStroke?.strokeLinecap ?? strokeStyle?.strokeLinecap,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
if (!dotStyle)
|
|
37
|
+
continue;
|
|
38
|
+
markers.push({
|
|
39
|
+
type: 'dot',
|
|
40
|
+
data: seg.data,
|
|
41
|
+
x: xFn,
|
|
42
|
+
y: yFn,
|
|
43
|
+
style: {
|
|
44
|
+
dotRadius: disabledDots?.dotRadius ?? dotStyle.dotRadius ?? cfg.line.dotRadius,
|
|
45
|
+
dotFill: disabledDots?.dotFill ?? dotStyle.dotFill ?? strokeStyle?.stroke ?? defaultColor,
|
|
46
|
+
dotSymbol: disabledDots?.dotSymbol ?? dotStyle.dotSymbol ?? 'circle',
|
|
47
|
+
dotStroke: disabledDots?.dotStroke ?? dotStyle.dotStroke ?? strokeStyle?.stroke ?? defaultColor,
|
|
48
|
+
dotStrokeWidth: disabledDots?.dotStrokeWidth ?? dotStyle.dotStrokeWidth ?? 1,
|
|
49
|
+
dotFillOpacity: disabledDots?.dotFillOpacity ?? dotStyle.dotFillOpacity ?? strokeStyle?.strokeOpacity ?? 1,
|
|
50
|
+
dotStrokeOpacity: disabledDots?.dotStrokeOpacity ?? dotStyle.dotStrokeOpacity ?? strokeStyle?.strokeOpacity ?? 1,
|
|
51
|
+
dotStrokeDasharray: disabledDots?.dotStrokeDasharray ?? dotStyle.dotStrokeDasharray,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return markers;
|
|
57
|
+
}
|
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
-
import { SvelteMap } from 'svelte/reactivity';
|
|
3
|
-
import { BarX } from 'svelteplot';
|
|
4
2
|
import { resolveAccessor } from '../utils/accessors';
|
|
5
3
|
import { getConfiguration } from '../../configuration/config.svelte';
|
|
6
4
|
import { paletteColor } from '../../utils/color';
|
|
7
5
|
import { buildSeries } from '../../utils/grouping';
|
|
8
6
|
import { getLegendInteraction } from '../../layout/legend/interaction.svelte';
|
|
9
7
|
import { disabledFillOverride } from '../utils/legendDisabled';
|
|
10
|
-
import {
|
|
8
|
+
import { buildPyramidBarMarkers } from './buildPyramidBarMarkers';
|
|
9
|
+
import { buildGroupedSeries, validateSegments, buildScopedMarkerGroups } from '../utils/segments';
|
|
11
10
|
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
11
|
import ValueLabels from './ValueLabels.svelte';
|
|
17
12
|
import { hasHoverMarker, resolveHoverStrategy, resolveHoverSync } from '../../layout/tooltip/utils';
|
|
18
13
|
import type { BasePlotProps } from '../../types/plots/props';
|
|
19
|
-
import type { AxisValue } from '../../types/
|
|
14
|
+
import type { AxisValue, AxisBasedScalesConfig } from '../../types/layout/scales';
|
|
20
15
|
import type { Series, SeriesProps, DataProps } from '../../types/plots/data/common';
|
|
21
|
-
import type {
|
|
22
|
-
import type { BasePlotStyles } from '../../types/plots/styles/common';
|
|
16
|
+
import type { BasePlotStylesConfig } from '../../types/layout/styles';
|
|
23
17
|
import type { ValueAnchor } from '../../types/plots/constants';
|
|
24
18
|
import type { BarSegmentStyle } from '../../types/plots/segments/common';
|
|
25
|
-
import type {
|
|
19
|
+
import type { AxisBasedMarkersConfig } from '../../types/markers/common';
|
|
26
20
|
|
|
27
21
|
/**
|
|
28
22
|
* A population-pyramid-style diverging bar chart: each series is mirrored
|
|
@@ -43,9 +37,9 @@
|
|
|
43
37
|
type Props = BasePlotProps<
|
|
44
38
|
SeriesProps<TData> | DataProps<TData>,
|
|
45
39
|
TData,
|
|
46
|
-
|
|
40
|
+
BasePlotStylesConfig,
|
|
47
41
|
BarSegmentStyle,
|
|
48
|
-
|
|
42
|
+
AxisBasedMarkersConfig,
|
|
49
43
|
AxisBasedScalesConfig<TData>
|
|
50
44
|
>;
|
|
51
45
|
|
|
@@ -166,17 +160,6 @@
|
|
|
166
160
|
return vals.length ? Math.max(...vals) : 1;
|
|
167
161
|
});
|
|
168
162
|
|
|
169
|
-
const seriesMarkers = $derived.by(() => {
|
|
170
|
-
const map = new SvelteMap<string, Marker[]>();
|
|
171
|
-
for (const marker of markers) {
|
|
172
|
-
if ((marker.type === 'component' || marker.type === 'hover') && marker.series) {
|
|
173
|
-
if (!map.has(marker.series)) map.set(marker.series, []);
|
|
174
|
-
map.get(marker.series)!.push(marker);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return map;
|
|
178
|
-
});
|
|
179
|
-
|
|
180
163
|
// The single, fully-resolved scales object BasePlotLayout reads for
|
|
181
164
|
// everything (ticks, grid, sort, and the real svelteplot scale) — avoids
|
|
182
165
|
// keeping a second, separately-defaulted copy of `scales.x`/`scales.y`
|
|
@@ -192,111 +175,52 @@
|
|
|
192
175
|
y: { type: 'band', padding: 0.2, domain: yDomain, ...(scales.y ?? {}) },
|
|
193
176
|
});
|
|
194
177
|
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
178
|
+
const hover = $derived({
|
|
179
|
+
active: tooltip != null || hasHoverMarker(markers),
|
|
180
|
+
points: hoverPoints,
|
|
181
|
+
label: labelFor,
|
|
182
|
+
strategy: resolveHoverStrategy(tooltip?.strategy, markers, 'y'),
|
|
183
|
+
sync: resolveHoverSync(tooltip?.sync, markers),
|
|
184
|
+
tooltip,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const pyramidMarkers = $derived(
|
|
188
|
+
buildPyramidBarMarkers({
|
|
189
|
+
groupedSeries,
|
|
190
|
+
valueFor: signedValue,
|
|
191
|
+
colorFor: (s) => (s.side === 'left' ? leftColor : rightColor),
|
|
192
|
+
disabledFillFor: (name) => disabledFillOverride(legendInteraction?.disabledSeries.get(name)),
|
|
193
|
+
}),
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const scopedGroups = $derived(
|
|
197
|
+
buildScopedMarkerGroups<TData, InternalSeries, BarSegmentStyle>({
|
|
198
|
+
groupedSeries,
|
|
199
|
+
segments,
|
|
200
|
+
colorFor: (series) => (series.side === 'left' ? leftColor : rightColor),
|
|
201
|
+
segmentColorFor: (style, defaultColor) => style?.fill ?? defaultColor,
|
|
202
|
+
}),
|
|
203
|
+
);
|
|
198
204
|
</script>
|
|
199
205
|
|
|
200
206
|
<BasePlotLayout
|
|
201
207
|
{width}
|
|
202
208
|
{height}
|
|
209
|
+
{styles}
|
|
203
210
|
data={flat}
|
|
204
211
|
{getX}
|
|
205
212
|
{getY}
|
|
206
|
-
{
|
|
207
|
-
label={labelFor}
|
|
208
|
-
{tooltip}
|
|
209
|
-
{hoverActive}
|
|
210
|
-
{hoverStrategy}
|
|
211
|
-
{hoverSync}
|
|
213
|
+
{hover}
|
|
212
214
|
scales={resolvedScales}
|
|
213
215
|
{margins}
|
|
214
216
|
xTickRotate={resolvedScales?.x?.tickRotate}
|
|
217
|
+
markers={[...pyramidMarkers, ...markers]}
|
|
218
|
+
seriesData={resolvedSeries}
|
|
219
|
+
{scopedGroups}
|
|
215
220
|
>
|
|
216
|
-
{#
|
|
217
|
-
<AxisLayout data={flat} {getX} {getY} {width} {height} {numericMargins} scales={resolvedScales} />
|
|
218
|
-
<GridLayout scales={resolvedScales} />
|
|
219
|
-
<RuleLayout {markers} seriesData={resolvedSeries} {matchedPoints} {ruleX} {ruleY} {impliesRuleX} {impliesRuleY}>
|
|
221
|
+
{#if showVals}
|
|
220
222
|
{#each groupedSeries as group (group.series.name)}
|
|
221
|
-
{
|
|
222
|
-
{@const getCategory = resolveAccessor(group.series.x)}
|
|
223
|
-
{@const disabledFill = disabledFillOverride(legendInteraction?.disabledSeries.get(group.series.name))}
|
|
224
|
-
{#each group.visualSegments as seg, i (`${group.series.name}-${i}`)}
|
|
225
|
-
<BarX
|
|
226
|
-
data={seg.data}
|
|
227
|
-
x1={0}
|
|
228
|
-
x2={(d: TData) => signedValue(group.series, d)}
|
|
229
|
-
y={getCategory}
|
|
230
|
-
fill={disabledFill?.fill ?? seg.style.fill ?? defaultColor}
|
|
231
|
-
fillOpacity={disabledFill?.fillOpacity ?? seg.style.fillOpacity ?? 1}
|
|
232
|
-
/>
|
|
233
|
-
{/each}
|
|
234
|
-
|
|
235
|
-
{#if showVals}
|
|
236
|
-
<ValueLabels {group} {valAnchor} {fmtVal} values={styles.values} axisColor={cfg.axis.color} />
|
|
237
|
-
{/if}
|
|
238
|
-
|
|
239
|
-
{#each seriesMarkers.get(group.series.name) ?? [] as marker, i (`series-${group.series.name}-${marker.type}-${i}`)}
|
|
240
|
-
{#if marker.type === 'component'}
|
|
241
|
-
{#if marker.scope === 'segment'}
|
|
242
|
-
{@const segs = resolveSegmentsForSeries(segments, group.series.name)}
|
|
243
|
-
{@const segmentDataArrays = getDataForSegments(group.series.data, getCategory, segs)}
|
|
244
|
-
{#each segmentDataArrays as segmentData, segIdx (`${group.series.name}-marker-segment-${segIdx}`)}
|
|
245
|
-
{#if segmentData.length > 0}
|
|
246
|
-
{@const segmentColor = segs[segIdx]?.style?.fill ?? defaultColor}
|
|
247
|
-
<marker.component
|
|
248
|
-
{...marker.props}
|
|
249
|
-
series={group.series.name}
|
|
250
|
-
data={segmentData}
|
|
251
|
-
seriesColor={segmentColor}
|
|
252
|
-
/>
|
|
253
|
-
{/if}
|
|
254
|
-
{/each}
|
|
255
|
-
{:else}
|
|
256
|
-
{@const segs = resolveSegmentsForSeries(segments, group.series.name)}
|
|
257
|
-
{@const seriesColor = segs[0]?.style?.fill ?? defaultColor}
|
|
258
|
-
<marker.component
|
|
259
|
-
{...marker.props}
|
|
260
|
-
series={group.series.name}
|
|
261
|
-
data={group.series.data}
|
|
262
|
-
seriesColor={seriesColor}
|
|
263
|
-
/>
|
|
264
|
-
{/if}
|
|
265
|
-
{:else if marker.type === 'hover'}
|
|
266
|
-
{@const seriesPoints = matchedPoints.filter((p) => p.series === group.series.name)}
|
|
267
|
-
{#if marker.scope === 'segment'}
|
|
268
|
-
{@const segs = resolveSegmentsForSeries(segments, group.series.name)}
|
|
269
|
-
{#each segs as seg, segIdx (`${group.series.name}-hover-segment-${segIdx}`)}
|
|
270
|
-
{@const segPoints = seriesPoints.filter((p) => matchesSegmentX(p.x, seg))}
|
|
271
|
-
{#if segPoints.length > 0}
|
|
272
|
-
<HoverMarker
|
|
273
|
-
data={segPoints}
|
|
274
|
-
ruleX={marker.ruleX !== false && (impliesRuleX || marker.ruleX === true) ? ruleX : null}
|
|
275
|
-
ruleY={marker.ruleY !== false && (impliesRuleY || marker.ruleY === true) ? ruleY : null}
|
|
276
|
-
showLabels={marker.showLabels}
|
|
277
|
-
ruleStyle={marker.ruleStyle}
|
|
278
|
-
dotStyle={marker.dotStyle}
|
|
279
|
-
fontStyle={marker.fontStyle}
|
|
280
|
-
seriesColor={seg.style?.fill ?? defaultColor}
|
|
281
|
-
/>
|
|
282
|
-
{/if}
|
|
283
|
-
{/each}
|
|
284
|
-
{:else}
|
|
285
|
-
{@const segs = resolveSegmentsForSeries(segments, group.series.name)}
|
|
286
|
-
<HoverMarker
|
|
287
|
-
data={seriesPoints}
|
|
288
|
-
ruleX={marker.ruleX !== false && (impliesRuleX || marker.ruleX === true) ? ruleX : null}
|
|
289
|
-
ruleY={marker.ruleY !== false && (impliesRuleY || marker.ruleY === true) ? ruleY : null}
|
|
290
|
-
showLabels={marker.showLabels}
|
|
291
|
-
ruleStyle={marker.ruleStyle}
|
|
292
|
-
dotStyle={marker.dotStyle}
|
|
293
|
-
fontStyle={marker.fontStyle}
|
|
294
|
-
seriesColor={segs[0]?.style?.fill ?? defaultColor}
|
|
295
|
-
/>
|
|
296
|
-
{/if}
|
|
297
|
-
{/if}
|
|
298
|
-
{/each}
|
|
223
|
+
<ValueLabels {group} {valAnchor} {fmtVal} values={styles.values} axisColor={cfg.axis.color} />
|
|
299
224
|
{/each}
|
|
300
|
-
|
|
301
|
-
{/snippet}
|
|
225
|
+
{/if}
|
|
302
226
|
</BasePlotLayout>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { BasePlotProps } from '../../types/plots/props';
|
|
2
|
+
import type { AxisBasedScalesConfig } from '../../types/layout/scales';
|
|
2
3
|
import type { SeriesProps, DataProps } from '../../types/plots/data/common';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type { BarSegmentStyle } from '../../types/plots/segments/common';
|
|
6
|
-
import type { Marker } from '../../types/markers/common';
|
|
4
|
+
import type { BasePlotStylesConfig } from '../../types/layout/styles';
|
|
5
|
+
import type { AxisBasedMarkersConfig } from '../../types/markers/common';
|
|
7
6
|
declare function $$render<TData extends Record<string, unknown>>(): {
|
|
8
|
-
props: BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData,
|
|
7
|
+
props: BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, BasePlotStylesConfig, import("../..").AreaStyle, AxisBasedMarkersConfig, AxisBasedScalesConfig<TData>>;
|
|
9
8
|
exports: {};
|
|
10
9
|
bindings: "";
|
|
11
10
|
slots: {};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Text } from 'svelteplot';
|
|
3
3
|
import { resolveAccessor } from '../utils/accessors';
|
|
4
4
|
import type { Series } from '../../types/plots/data/common';
|
|
5
|
-
import type { ValuesStyle } from '../../types/
|
|
5
|
+
import type { ValuesStyle } from '../../types/layout/styles';
|
|
6
6
|
import type { ValueAnchor } from '../../types/plots/constants';
|
|
7
7
|
import type { BarSegmentStyle } from '../../types/plots/segments/common';
|
|
8
8
|
import type { VisualGroup } from '../../types/plots/segments/config';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Series } from '../../types/plots/data/common';
|
|
2
|
-
import type { ValuesStyle } from '../../types/
|
|
2
|
+
import type { ValuesStyle } from '../../types/layout/styles';
|
|
3
3
|
import type { ValueAnchor } from '../../types/plots/constants';
|
|
4
4
|
import type { BarSegmentStyle } from '../../types/plots/segments/common';
|
|
5
5
|
import type { VisualGroup } from '../../types/plots/segments/config';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Series } from '../../types/plots/data/common';
|
|
2
|
+
import type { BarSegmentStyle } from '../../types/plots/segments/common';
|
|
3
|
+
import type { VisualGroup } from '../../types/plots/segments/config';
|
|
4
|
+
import type { BarMarkerConfig } from '../../types/markers/common';
|
|
5
|
+
/**
|
|
6
|
+
* Every `'bar'` marker for one PyramidPlot render — reuses `BarMarkerConfig`
|
|
7
|
+
* directly, always horizontal (category on y, signed magnitude on x) and
|
|
8
|
+
* with no insets. Emits no `role: 'hitArea'` markers, since PyramidPlot's
|
|
9
|
+
* hover matches nearest points rather than hit-testing category bands.
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildPyramidBarMarkers<TData extends Record<string, unknown>, S extends Series<TData>>(args: {
|
|
12
|
+
groupedSeries: VisualGroup<S, BarSegmentStyle>[];
|
|
13
|
+
valueFor: (series: S, d: TData) => number;
|
|
14
|
+
colorFor: (series: S) => string;
|
|
15
|
+
disabledFillFor: (seriesName: string) => {
|
|
16
|
+
fill?: string;
|
|
17
|
+
fillOpacity?: number;
|
|
18
|
+
} | undefined;
|
|
19
|
+
}): BarMarkerConfig[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { resolveAccessor } from '../utils/accessors';
|
|
2
|
+
/**
|
|
3
|
+
* Every `'bar'` marker for one PyramidPlot render — reuses `BarMarkerConfig`
|
|
4
|
+
* directly, always horizontal (category on y, signed magnitude on x) and
|
|
5
|
+
* with no insets. Emits no `role: 'hitArea'` markers, since PyramidPlot's
|
|
6
|
+
* hover matches nearest points rather than hit-testing category bands.
|
|
7
|
+
*/
|
|
8
|
+
export function buildPyramidBarMarkers(args) {
|
|
9
|
+
const { groupedSeries, valueFor, colorFor, disabledFillFor } = args;
|
|
10
|
+
const markers = [];
|
|
11
|
+
for (const group of groupedSeries) {
|
|
12
|
+
const getCategory = resolveAccessor(group.series.x);
|
|
13
|
+
const defaultColor = colorFor(group.series);
|
|
14
|
+
const disabledFill = disabledFillFor(group.series.name);
|
|
15
|
+
for (const seg of group.visualSegments) {
|
|
16
|
+
markers.push({
|
|
17
|
+
type: 'bar',
|
|
18
|
+
role: 'segment',
|
|
19
|
+
isHorizontal: true,
|
|
20
|
+
data: seg.data,
|
|
21
|
+
y: getCategory,
|
|
22
|
+
x1: 0,
|
|
23
|
+
x2: (d) => valueFor(group.series, d),
|
|
24
|
+
style: {
|
|
25
|
+
fill: disabledFill?.fill ?? seg.style.fill ?? defaultColor,
|
|
26
|
+
fillOpacity: disabledFill?.fillOpacity ?? seg.style.fillOpacity ?? 1,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return markers;
|
|
32
|
+
}
|