@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.
- package/README.md +121 -17
- package/dist/charts/{Chart.svelte → BaseChart.svelte} +2 -0
- package/dist/charts/{Chart.svelte.d.ts → BaseChart.svelte.d.ts} +3 -3
- package/dist/charts/bar/Chart.svelte +5 -5
- package/dist/charts/bar/Chart.svelte.d.ts +1 -2
- package/dist/charts/heatmap/Chart.svelte +8 -7
- package/dist/charts/heatmap/Chart.svelte.d.ts +2 -3
- package/dist/charts/line/Chart.svelte +5 -5
- package/dist/charts/line/Chart.svelte.d.ts +1 -2
- package/dist/charts/pyramid/Chart.svelte +7 -6
- package/dist/charts/pyramid/Chart.svelte.d.ts +2 -3
- package/dist/configuration/config.svelte.js +2 -1
- package/dist/configuration/themes/index.d.ts +60 -40
- package/dist/index.d.ts +27 -13
- package/dist/index.js +12 -7
- package/dist/layout/facet/FacetLayout.svelte +1 -1
- package/dist/layout/facet/FacetLayout.svelte.d.ts +1 -1
- package/dist/layout/geo/GeoLayout.svelte +47 -0
- package/dist/layout/geo/GeoLayout.svelte.d.ts +22 -0
- package/dist/layout/geo/resolveProjection.d.ts +10 -0
- package/dist/layout/geo/resolveProjection.js +48 -0
- package/dist/layout/legend/ContinuousSection.svelte +158 -17
- package/dist/layout/legend/DiscreteSection.svelte +56 -4
- package/dist/layout/legend/interaction.svelte.d.ts +7 -0
- package/dist/layout/legend/interaction.svelte.js +24 -0
- package/dist/layout/plot/AxisLayout.svelte +95 -0
- package/dist/layout/plot/AxisLayout.svelte.d.ts +39 -0
- package/dist/layout/plot/BasePlotLayout.svelte +302 -0
- package/dist/layout/plot/BasePlotLayout.svelte.d.ts +95 -0
- package/dist/layout/plot/GridLayout.svelte +30 -0
- package/dist/layout/plot/GridLayout.svelte.d.ts +27 -0
- package/dist/layout/plot/RuleLayout.svelte +111 -0
- package/dist/layout/plot/RuleLayout.svelte.d.ts +40 -0
- package/dist/layout/plot/margins.d.ts +34 -0
- package/dist/layout/plot/margins.js +26 -0
- package/dist/layout/timeline/TimelineLayout.svelte +1 -1
- package/dist/layout/timeline/TimelineLayout.svelte.d.ts +1 -1
- package/dist/layout/tooltip/Tooltip.svelte +15 -0
- package/dist/layout/tooltip/Tooltip.svelte.d.ts +7 -0
- package/dist/layout/tooltip/TooltipLayout.svelte +45 -0
- package/dist/layout/tooltip/TooltipLayout.svelte.d.ts +41 -0
- package/dist/layout/tooltip/controller.svelte.d.ts +4 -3
- package/dist/layout/tooltip/controller.svelte.js +5 -6
- package/dist/layout/tooltip/hover.svelte.d.ts +1 -1
- package/dist/layout/tooltip/hover.svelte.js +1 -1
- package/dist/layout/tooltip/utils.d.ts +2 -2
- package/dist/markers/ContourClipMarker.svelte +77 -0
- package/dist/markers/ContourClipMarker.svelte.d.ts +10 -0
- package/dist/{plots/markers → markers}/DeltaMarker.svelte +4 -4
- package/dist/{plots/markers → markers}/DeltaMarker.svelte.d.ts +3 -3
- package/dist/{plots/markers → markers}/DotMarker.svelte +3 -3
- package/dist/{plots/markers → markers}/DotMarker.svelte.d.ts +3 -3
- package/dist/markers/HoverMarker.svelte +136 -0
- package/dist/{plots/markers → markers}/HoverMarker.svelte.d.ts +4 -4
- package/dist/{plots/markers → markers}/PeakMarker.svelte +2 -2
- package/dist/{plots/markers → markers}/PeakMarker.svelte.d.ts +2 -2
- package/dist/{plots/markers → markers}/TextMarker.svelte +11 -4
- package/dist/{plots/markers → markers}/TextMarker.svelte.d.ts +3 -3
- package/dist/markers/inset/InsetMarker.svelte +170 -0
- package/dist/markers/inset/InsetMarker.svelte.d.ts +51 -0
- package/dist/markers/inset/insetLayout.d.ts +25 -0
- package/dist/markers/inset/insetLayout.js +39 -0
- package/dist/markers/inset/insetProjection.d.ts +8 -0
- package/dist/markers/inset/insetProjection.js +39 -0
- package/dist/plots/bar/BarSegments.svelte +69 -0
- package/dist/plots/bar/BarSegments.svelte.d.ts +40 -0
- package/dist/plots/bar/Plot.svelte +140 -74
- package/dist/plots/bar/Plot.svelte.d.ts +7 -3
- package/dist/plots/bar/ValueLabels.svelte +89 -0
- package/dist/plots/bar/ValueLabels.svelte.d.ts +39 -0
- package/dist/plots/bar/hoverPoints.d.ts +15 -0
- package/dist/plots/bar/hoverPoints.js +35 -0
- package/dist/plots/bar/layout.svelte.d.ts +37 -0
- package/dist/plots/bar/layout.svelte.js +132 -0
- package/dist/plots/geo/Plot.svelte +577 -0
- package/dist/plots/geo/Plot.svelte.d.ts +29 -0
- package/dist/plots/geo/TileLayer.svelte +77 -0
- package/dist/plots/geo/TileLayer.svelte.d.ts +11 -0
- package/dist/plots/geo/projections/argentina.d.ts +8 -0
- package/dist/plots/geo/projections/argentina.js +35 -0
- package/dist/plots/geo/projections/fit.d.ts +8 -0
- package/dist/plots/geo/projections/fit.js +14 -0
- package/dist/plots/geo/rotate.svelte.d.ts +26 -0
- package/dist/plots/geo/rotate.svelte.js +79 -0
- package/dist/plots/geo/zoom.svelte.d.ts +32 -0
- package/dist/plots/geo/zoom.svelte.js +50 -0
- package/dist/plots/heatmap/Plot.svelte +171 -58
- package/dist/plots/heatmap/Plot.svelte.d.ts +7 -3
- package/dist/plots/line/Plot.svelte +67 -30
- package/dist/plots/line/Plot.svelte.d.ts +7 -3
- package/dist/plots/pyramid/Plot.svelte +88 -35
- package/dist/plots/pyramid/Plot.svelte.d.ts +7 -3
- package/dist/plots/utils/delta.d.ts +1 -1
- package/dist/plots/utils/geoAccessors.d.ts +64 -0
- package/dist/plots/utils/geoAccessors.js +188 -0
- package/dist/plots/utils/geoSegments.d.ts +14 -0
- package/dist/plots/utils/geoSegments.js +17 -0
- package/dist/plots/utils/legendDisabled.d.ts +15 -0
- package/dist/plots/utils/legendDisabled.js +41 -0
- package/dist/plots/utils/segments.d.ts +14 -5
- package/dist/plots/utils/segments.js +25 -13
- package/dist/plots/utils/tiles.d.ts +89 -0
- package/dist/plots/utils/tiles.js +159 -0
- package/dist/plots/utils/topojson.d.ts +9 -0
- package/dist/plots/utils/topojson.js +30 -0
- package/dist/types/charts/common.d.ts +2 -1
- package/dist/types/charts/legend.d.ts +32 -1
- package/dist/types/charts/props.d.ts +9 -6
- package/dist/types/configuration/styling.d.ts +13 -5
- package/dist/types/layout/legend.d.ts +26 -0
- package/dist/types/layout/tooltip.d.ts +14 -21
- package/dist/types/{plots/markers.d.ts → markers/common.d.ts} +2 -18
- package/dist/types/markers/geo.d.ts +237 -0
- package/dist/types/markers/props.d.ts +11 -0
- package/dist/types/markers/props.js +1 -0
- package/dist/types/plots/axis.d.ts +55 -0
- package/dist/types/plots/axis.js +1 -0
- package/dist/types/plots/constants.d.ts +30 -0
- package/dist/types/plots/constants.js +1 -0
- package/dist/types/plots/data/common.d.ts +40 -0
- package/dist/types/plots/data/common.js +1 -0
- package/dist/types/plots/data/geo.d.ts +74 -0
- package/dist/types/plots/data/geo.js +1 -0
- package/dist/types/plots/delta.d.ts +2 -2
- package/dist/types/plots/props.d.ts +105 -16
- package/dist/types/plots/scales/geo.d.ts +44 -0
- package/dist/types/plots/scales/geo.js +1 -0
- package/dist/types/plots/segments/common.d.ts +25 -0
- package/dist/types/plots/segments/common.js +1 -0
- package/dist/types/plots/segments/config.d.ts +51 -0
- package/dist/types/plots/segments/config.js +1 -0
- package/dist/types/plots/styles/common.d.ts +37 -0
- package/dist/types/plots/styles/common.js +1 -0
- package/dist/types/plots/styles/geo.d.ts +42 -0
- package/dist/types/plots/styles/geo.js +1 -0
- package/dist/types/plots/styling.d.ts +45 -0
- package/dist/types/plots/styling.js +1 -0
- package/dist/utils/grouping.d.ts +2 -1
- package/dist/utils/interpolate.d.ts +2 -1
- package/package.json +27 -13
- package/dist/layout/plot/PlotLayout.svelte +0 -294
- package/dist/layout/plot/PlotLayout.svelte.d.ts +0 -70
- package/dist/plots/markers/HoverMarker.svelte +0 -98
- package/dist/types/plots/common.d.ts +0 -97
- package/dist/types/plots/styles.d.ts +0 -187
- /package/dist/types/{plots/common.js → layout/legend.js} +0 -0
- /package/dist/types/{plots/markers.js → markers/common.js} +0 -0
- /package/dist/types/{plots/styles.js → markers/geo.js} +0 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
+
import type { ComponentProps, Snippet } from 'svelte';
|
|
3
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
4
|
+
import { Plot, Pointer } from 'svelteplot';
|
|
5
|
+
import { getConfiguration } from '../../configuration/config.svelte';
|
|
6
|
+
import { AUTO_MARGIN_ESTIMATE, numericMargin } from './margins';
|
|
7
|
+
import { getHover, createHover } from '../tooltip/hover.svelte';
|
|
8
|
+
import { createHoverController } from '../tooltip/controller.svelte';
|
|
9
|
+
import TooltipLayout from '../tooltip/TooltipLayout.svelte';
|
|
10
|
+
import type { AxisValue, AxisScale } from '../../types/plots/axis';
|
|
11
|
+
import type { AxisBasedScalesConfig } from '../../types/plots/props';
|
|
12
|
+
import type { GeoProjectionConfig } from '../../types/plots/scales/geo';
|
|
13
|
+
import type { HoverStrategy, HoverPoint } from '../../types/layout/tooltip';
|
|
14
|
+
import type { MarginConfig, TooltipConfig } from '../../types/plots/props';
|
|
15
|
+
|
|
16
|
+
type SveltePlotProps = ComponentProps<typeof Plot>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Shared chrome around every plot kind's svelteplot markup: the pointer-event
|
|
20
|
+
* wrapper, the hover/tooltip state machine, the `<Plot>` element itself, and
|
|
21
|
+
* the floating tooltip. Deliberately marker/axis-agnostic — axis-having plot
|
|
22
|
+
* kinds (line/bar/heatmap/pyramid) additionally compose `AxisLayout` /
|
|
23
|
+
* `GridLayout` / `RuleLayout` inside `children`; `GeoPlot` composes `GeoLayout`
|
|
24
|
+
* instead, since a map has no x/y axis pair. Every plot kind supplies its own
|
|
25
|
+
* `<Plot x y projection>` scale config (either directly via `x`/`y`/`projection`,
|
|
26
|
+
* or by leaving `x`/`y` unset so this component derives them from `scales`) and
|
|
27
|
+
* its own marks/markers through `children`.
|
|
28
|
+
*/
|
|
29
|
+
let {
|
|
30
|
+
width,
|
|
31
|
+
height,
|
|
32
|
+
data,
|
|
33
|
+
getX,
|
|
34
|
+
getY,
|
|
35
|
+
hoverPoints,
|
|
36
|
+
label,
|
|
37
|
+
tooltip = undefined,
|
|
38
|
+
hoverActive,
|
|
39
|
+
hoverStrategy = undefined,
|
|
40
|
+
hoverSync = undefined,
|
|
41
|
+
x = undefined,
|
|
42
|
+
y = undefined,
|
|
43
|
+
scales = undefined,
|
|
44
|
+
projection = undefined,
|
|
45
|
+
margins,
|
|
46
|
+
marginEstimate = AUTO_MARGIN_ESTIMATE,
|
|
47
|
+
xTickRotate = undefined,
|
|
48
|
+
excludeHover = undefined,
|
|
49
|
+
touchAction = undefined,
|
|
50
|
+
containerEl = $bindable(undefined),
|
|
51
|
+
children,
|
|
52
|
+
}: {
|
|
53
|
+
width: number;
|
|
54
|
+
height: number;
|
|
55
|
+
/** Flat rows fed to svelteplot's `<Pointer>` for nearest-point matching. */
|
|
56
|
+
data: TData[];
|
|
57
|
+
getX: (d: TData) => AxisValue;
|
|
58
|
+
getY: (d: TData) => AxisValue;
|
|
59
|
+
hoverPoints: HoverPoint<TData>[];
|
|
60
|
+
label: (row: TData) => string;
|
|
61
|
+
tooltip?: TooltipConfig<TData>;
|
|
62
|
+
/** Whether the pointer/hover/tooltip machinery should mount at all. */
|
|
63
|
+
hoverActive: boolean;
|
|
64
|
+
/** Resolved hover strategy for the *local* hover store (ignored once a shared store is in scope). */
|
|
65
|
+
hoverStrategy?: HoverStrategy;
|
|
66
|
+
/** Resolved sync flag for the *local* hover store (ignored once a shared store is in scope). */
|
|
67
|
+
hoverSync?: boolean;
|
|
68
|
+
/** Explicit `<Plot x>` override — bypasses `scales`-derived resolution (e.g. GeoPlot's fixed lon/lat domain). */
|
|
69
|
+
x?: SveltePlotProps['x'];
|
|
70
|
+
/** Explicit `<Plot y>` override — see `x`. */
|
|
71
|
+
y?: SveltePlotProps['y'];
|
|
72
|
+
/** Scale config `x`/`y` are derived from when not given directly. */
|
|
73
|
+
scales?: AxisBasedScalesConfig<TData>;
|
|
74
|
+
/** Forwarded to `<Plot projection>` — GeoPlot only. */
|
|
75
|
+
projection?: GeoProjectionConfig;
|
|
76
|
+
/** Partial margin override — merged on top of the theme. */
|
|
77
|
+
margins?: MarginConfig;
|
|
78
|
+
/** Numeric fallback for a margin side that resolved to `'auto'` — see `numericMargin`'s doc comment. */
|
|
79
|
+
marginEstimate?: Record<'top' | 'right' | 'bottom' | 'left', number>;
|
|
80
|
+
/** Boosts the bottom margin for a rotated x tick label — axis-having plot kinds only. */
|
|
81
|
+
xTickRotate?: number;
|
|
82
|
+
/**
|
|
83
|
+
* When it returns `true` for a pointer event, that event is treated as a
|
|
84
|
+
* leave instead of a move — lets a nested layout (e.g. GeoLayout's inset
|
|
85
|
+
* markers) opt specific screen regions out of this plot's own hover
|
|
86
|
+
* matching without this component needing to know why.
|
|
87
|
+
*/
|
|
88
|
+
excludeHover?: (e: PointerEvent) => boolean;
|
|
89
|
+
/** Forwarded to the wrapper div's `touch-action` CSS — GeoPlot's zoom/pan only. */
|
|
90
|
+
touchAction?: string;
|
|
91
|
+
/** The wrapper div's own element — bind for a nested layout that needs it for its own gesture handling (e.g. GeoLayout's zoom/rotate). */
|
|
92
|
+
containerEl?: HTMLDivElement;
|
|
93
|
+
/**
|
|
94
|
+
* `matchedPoints` carries the source `row` alongside the display fields
|
|
95
|
+
* — needed by plot kinds whose semantic value isn't tied to a fixed
|
|
96
|
+
* visual axis (e.g. `BarPlot`'s category, which can be drawn on either
|
|
97
|
+
* axis depending on orientation), so a template can resolve it straight
|
|
98
|
+
* off `row` instead of assuming which of `.x`/`.y` it landed on.
|
|
99
|
+
* `impliesRuleX`/`impliesRuleY` tell the plot kind whether the active
|
|
100
|
+
* strategy implies a crosshair rule on each axis by default.
|
|
101
|
+
* `numericMargins` lets a nested layout align itself with the plot's own
|
|
102
|
+
* content box without recomputing margins itself.
|
|
103
|
+
*/
|
|
104
|
+
children: Snippet<
|
|
105
|
+
[{
|
|
106
|
+
matchedPoints: HoverPoint<TData>[];
|
|
107
|
+
ruleX: AxisValue | null;
|
|
108
|
+
ruleY: AxisValue | null;
|
|
109
|
+
impliesRuleX: boolean;
|
|
110
|
+
impliesRuleY: boolean;
|
|
111
|
+
numericMargins: { top: number; right: number; bottom: number; left: number };
|
|
112
|
+
}]
|
|
113
|
+
>;
|
|
114
|
+
} = $props();
|
|
115
|
+
|
|
116
|
+
const cfg = $derived(getConfiguration());
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Margins passed straight to `<Plot margin={…}>`. Each side defaults to
|
|
120
|
+
* `'auto'` (from the theme), which lets svelteplot size it to whatever it
|
|
121
|
+
* actually renders there — tick labels, an axis title, rotated ticks —
|
|
122
|
+
* rather than a fixed guess that either clips content or wastes space.
|
|
123
|
+
* `margins`/`cfg.margins` can still pin a side to an exact number.
|
|
124
|
+
*/
|
|
125
|
+
const computedMargins = $derived.by(() => {
|
|
126
|
+
const base = { ...cfg.margins, ...margins };
|
|
127
|
+
// Auto margins already measure the real (rotated) label bounding box, so
|
|
128
|
+
// this manual boost is only needed when the caller pinned bottom to a
|
|
129
|
+
// fixed number, which bypasses that measurement.
|
|
130
|
+
if (!xTickRotate || typeof base.bottom !== 'number') return base;
|
|
131
|
+
const rad = Math.abs(xTickRotate) * Math.PI / 180;
|
|
132
|
+
return {
|
|
133
|
+
...base,
|
|
134
|
+
bottom: base.bottom + Math.ceil(Math.sin(rad) * 20),
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const numericMargins = $derived({
|
|
139
|
+
top: numericMargin('top', computedMargins.top, marginEstimate),
|
|
140
|
+
right: numericMargin('right', computedMargins.right, marginEstimate),
|
|
141
|
+
bottom: numericMargin('bottom', computedMargins.bottom, marginEstimate),
|
|
142
|
+
left: numericMargin('left', computedMargins.left, marginEstimate),
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
/** One representative row per unique axis value (first occurrence in `data`). */
|
|
146
|
+
function uniqueRows(rows: TData[], getAxisValue: (d: TData) => AxisValue): TData[] {
|
|
147
|
+
const seen = new SvelteSet<AxisValue>();
|
|
148
|
+
const out: TData[] = [];
|
|
149
|
+
for (const row of rows) {
|
|
150
|
+
const v = getAxisValue(row);
|
|
151
|
+
if (seen.has(v)) continue;
|
|
152
|
+
seen.add(v);
|
|
153
|
+
out.push(row);
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* svelteplot's own `sort` scale option only toggles a fixed ascending sort
|
|
160
|
+
* (lexicographic for strings) — it can't take a custom comparator. When the
|
|
161
|
+
* caller supplies one via `scales.x.sort`/`scales.y.sort` for a string-valued
|
|
162
|
+
* axis (e.g. dates formatted as text, or categories ordered by another
|
|
163
|
+
* field), compute the ordered domain ourselves and hand it to the scale as
|
|
164
|
+
* an explicit `domain`, which svelteplot does respect as-is for ordinal
|
|
165
|
+
* scales. The comparator receives one representative row per unique axis
|
|
166
|
+
* value, not just the axis value itself, so it can sort by this axis's own
|
|
167
|
+
* value or by any other field on the row.
|
|
168
|
+
*/
|
|
169
|
+
function sortedScale(scale: AxisScale<TData> | undefined, rows: TData[], getAxisValue: (d: TData) => AxisValue): AxisScale<TData> | undefined {
|
|
170
|
+
const sort = scale?.sort;
|
|
171
|
+
if (!sort || scale?.domain) return scale;
|
|
172
|
+
const reps = uniqueRows(rows, getAxisValue);
|
|
173
|
+
if (reps.length === 0 || !reps.every((r) => typeof getAxisValue(r) === 'string')) return scale;
|
|
174
|
+
const domain = [...reps].sort(sort).map(getAxisValue);
|
|
175
|
+
return { ...scale, domain };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* `grid`/`seriesLayout`/`seriesPadding` and a vertical `label` are rendered
|
|
180
|
+
* by `GridLayout`/`AxisLayout` themselves rather than passed through to
|
|
181
|
+
* svelteplot (which only draws a fixed-style implicit grid, and never
|
|
182
|
+
* rotates the axis title) — stripped here so they don't also trigger
|
|
183
|
+
* svelteplot's own (duplicate, unstyled) rendering of them. Also the single
|
|
184
|
+
* place a plot kind's fully-resolved `scales.x`/`scales.y` (defaults
|
|
185
|
+
* already merged in by the plot itself) turns into what svelteplot's own,
|
|
186
|
+
* narrower scale option type actually accepts.
|
|
187
|
+
*/
|
|
188
|
+
function finalizeScale(scale: AxisScale<TData> | undefined, rows: TData[], getAxisValue: (d: TData) => AxisValue): AxisScale<TData> | undefined {
|
|
189
|
+
const sorted = sortedScale(scale, rows, getAxisValue);
|
|
190
|
+
if (!sorted) return sorted;
|
|
191
|
+
const out = { ...sorted };
|
|
192
|
+
delete out.grid;
|
|
193
|
+
delete out.seriesLayout;
|
|
194
|
+
delete out.seriesPadding;
|
|
195
|
+
if (scale?.labelOrientation === 'vertical') delete out.label;
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Cast to svelteplot's own (narrower, axis-specific) scale option type:
|
|
200
|
+
// finalizeScale has already stripped the fields that don't exist there
|
|
201
|
+
// (grid, the vertical label config, BarPlot's series-layout knobs).
|
|
202
|
+
const resolvedX = $derived(x !== undefined ? x : (finalizeScale(scales?.x, data, getX) as SveltePlotProps['x']));
|
|
203
|
+
const resolvedY = $derived(y !== undefined ? y : (finalizeScale(scales?.y, data, getY) as SveltePlotProps['y']));
|
|
204
|
+
|
|
205
|
+
// ── Hover / tooltip ───────────────────────────────────────────────────────
|
|
206
|
+
const sharedHover = getHover();
|
|
207
|
+
const localHover = createHover();
|
|
208
|
+
const hover = $derived(sharedHover ?? localHover);
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Which axes svelteplot's `<Pointer>` should search along — derived from
|
|
212
|
+
* the *active* strategy rather than taken as separate props. Passing
|
|
213
|
+
* `undefined` for an axis collapses every point to the same coordinate on
|
|
214
|
+
* that axis in the search quadtree, making the nearest-neighbor match
|
|
215
|
+
* ignore it entirely: `'x'` (line/bar) searches x only, `'y'` (pyramid —
|
|
216
|
+
* its category sits on y, and a bar's own magnitude on x shouldn't pull in
|
|
217
|
+
* a *different* row just because that row's bar tip is nearer in x)
|
|
218
|
+
* searches y only, and `'punctual'` (heatmap/geo's 2D grid) needs both.
|
|
219
|
+
* Reactive to `hover.strategy`, so a caller overriding `tooltip.strategy`/a
|
|
220
|
+
* hover marker's `strategy` away from the plot kind's default gets
|
|
221
|
+
* correctly-dimensioned matching too.
|
|
222
|
+
*/
|
|
223
|
+
const pointerMatchX = $derived(hover.strategy === 'y' ? undefined : getX);
|
|
224
|
+
const pointerMatchY = $derived(hover.strategy === 'x' ? undefined : getY);
|
|
225
|
+
|
|
226
|
+
$effect(() => {
|
|
227
|
+
if (sharedHover) return;
|
|
228
|
+
localHover.strategy = hoverStrategy ?? 'x';
|
|
229
|
+
localHover.sync = hoverSync ?? false;
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const ctrl = createHoverController<TData>({
|
|
233
|
+
hover: () => hover,
|
|
234
|
+
facetId: () => tooltip?.facetId ?? '',
|
|
235
|
+
points: () => hoverPoints,
|
|
236
|
+
getX: () => getX,
|
|
237
|
+
getY: () => getY,
|
|
238
|
+
label: () => label,
|
|
239
|
+
seriesFilter: () => tooltip?.series,
|
|
240
|
+
width: () => width,
|
|
241
|
+
height: () => height,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
function onMove(e: PointerEvent) {
|
|
245
|
+
if (excludeHover?.(e)) {
|
|
246
|
+
ctrl.onLeave();
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
ctrl.onMove(e);
|
|
250
|
+
}
|
|
251
|
+
</script>
|
|
252
|
+
|
|
253
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
254
|
+
<div
|
|
255
|
+
class="dct-plot"
|
|
256
|
+
bind:this={containerEl}
|
|
257
|
+
style:color={cfg.axis.color}
|
|
258
|
+
style:touch-action={touchAction}
|
|
259
|
+
onpointermove={hoverActive ? onMove : undefined}
|
|
260
|
+
onpointerleave={hoverActive ? ctrl.onLeave : undefined}
|
|
261
|
+
>
|
|
262
|
+
<Plot
|
|
263
|
+
{width}
|
|
264
|
+
{height}
|
|
265
|
+
margin={computedMargins}
|
|
266
|
+
x={resolvedX}
|
|
267
|
+
y={resolvedY}
|
|
268
|
+
projection={projection as SveltePlotProps['projection']}
|
|
269
|
+
>
|
|
270
|
+
{@render children({
|
|
271
|
+
matchedPoints: ctrl.points,
|
|
272
|
+
ruleX: ctrl.ruleX,
|
|
273
|
+
ruleY: ctrl.ruleY,
|
|
274
|
+
impliesRuleX: ctrl.impliesRuleX,
|
|
275
|
+
impliesRuleY: ctrl.impliesRuleY,
|
|
276
|
+
numericMargins,
|
|
277
|
+
})}
|
|
278
|
+
|
|
279
|
+
{#if hoverActive}
|
|
280
|
+
<Pointer {data} x={pointerMatchX} y={pointerMatchY} maxDistance={400} onupdate={ctrl.onPointer} />
|
|
281
|
+
{/if}
|
|
282
|
+
</Plot>
|
|
283
|
+
|
|
284
|
+
{#if tooltip}
|
|
285
|
+
<TooltipLayout
|
|
286
|
+
visible={ctrl.showTooltip && ctrl.tooltipPosition != null}
|
|
287
|
+
x={ctrl.tooltipPosition?.x ?? 0}
|
|
288
|
+
y={ctrl.tooltipPosition?.y ?? 0}
|
|
289
|
+
bounds={{ width, height }}
|
|
290
|
+
rows={ctrl.matchedRows.map((p) => p.row)}
|
|
291
|
+
format={tooltip.format}
|
|
292
|
+
content={tooltip.content}
|
|
293
|
+
/>
|
|
294
|
+
{/if}
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
<style>
|
|
298
|
+
.dct-plot {
|
|
299
|
+
position: relative;
|
|
300
|
+
line-height: 0;
|
|
301
|
+
}
|
|
302
|
+
</style>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { AxisValue } from '../../types/plots/axis';
|
|
3
|
+
import type { AxisBasedScalesConfig } from '../../types/plots/props';
|
|
4
|
+
import type { GeoProjectionConfig } from '../../types/plots/scales/geo';
|
|
5
|
+
import type { HoverStrategy, HoverPoint } from '../../types/layout/tooltip';
|
|
6
|
+
import type { MarginConfig, TooltipConfig } from '../../types/plots/props';
|
|
7
|
+
declare function $$render<TData extends Record<string, unknown>>(): {
|
|
8
|
+
props: {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
/** Flat rows fed to svelteplot's `<Pointer>` for nearest-point matching. */
|
|
12
|
+
data: TData[];
|
|
13
|
+
getX: (d: TData) => AxisValue;
|
|
14
|
+
getY: (d: TData) => AxisValue;
|
|
15
|
+
hoverPoints: HoverPoint<TData>[];
|
|
16
|
+
label: (row: TData) => string;
|
|
17
|
+
tooltip?: TooltipConfig<TData>;
|
|
18
|
+
/** Whether the pointer/hover/tooltip machinery should mount at all. */
|
|
19
|
+
hoverActive: boolean;
|
|
20
|
+
/** Resolved hover strategy for the *local* hover store (ignored once a shared store is in scope). */
|
|
21
|
+
hoverStrategy?: HoverStrategy;
|
|
22
|
+
/** Resolved sync flag for the *local* hover store (ignored once a shared store is in scope). */
|
|
23
|
+
hoverSync?: boolean;
|
|
24
|
+
/** Explicit `<Plot x>` override — bypasses `scales`-derived resolution (e.g. GeoPlot's fixed lon/lat domain). */
|
|
25
|
+
x?: false | Partial<import("svelteplot/types/scale.js").XScaleOptions> | import("svelteplot/types/data.js").RawValue[] | undefined;
|
|
26
|
+
/** Explicit `<Plot y>` override — see `x`. */
|
|
27
|
+
y?: false | import("svelteplot/types/data.js").RawValue[] | Partial<import("svelteplot/types/scale.js").YScaleOptions> | undefined;
|
|
28
|
+
/** Scale config `x`/`y` are derived from when not given directly. */
|
|
29
|
+
scales?: AxisBasedScalesConfig<TData>;
|
|
30
|
+
/** Forwarded to `<Plot projection>` — GeoPlot only. */
|
|
31
|
+
projection?: GeoProjectionConfig;
|
|
32
|
+
/** Partial margin override — merged on top of the theme. */
|
|
33
|
+
margins?: MarginConfig;
|
|
34
|
+
/** Numeric fallback for a margin side that resolved to `'auto'` — see `numericMargin`'s doc comment. */
|
|
35
|
+
marginEstimate?: Record<"top" | "right" | "bottom" | "left", number>;
|
|
36
|
+
/** Boosts the bottom margin for a rotated x tick label — axis-having plot kinds only. */
|
|
37
|
+
xTickRotate?: number;
|
|
38
|
+
/**
|
|
39
|
+
* When it returns `true` for a pointer event, that event is treated as a
|
|
40
|
+
* leave instead of a move — lets a nested layout (e.g. GeoLayout's inset
|
|
41
|
+
* markers) opt specific screen regions out of this plot's own hover
|
|
42
|
+
* matching without this component needing to know why.
|
|
43
|
+
*/
|
|
44
|
+
excludeHover?: (e: PointerEvent) => boolean;
|
|
45
|
+
/** Forwarded to the wrapper div's `touch-action` CSS — GeoPlot's zoom/pan only. */
|
|
46
|
+
touchAction?: string;
|
|
47
|
+
/** The wrapper div's own element — bind for a nested layout that needs it for its own gesture handling (e.g. GeoLayout's zoom/rotate). */
|
|
48
|
+
containerEl?: HTMLDivElement;
|
|
49
|
+
/**
|
|
50
|
+
* `matchedPoints` carries the source `row` alongside the display fields
|
|
51
|
+
* — needed by plot kinds whose semantic value isn't tied to a fixed
|
|
52
|
+
* visual axis (e.g. `BarPlot`'s category, which can be drawn on either
|
|
53
|
+
* axis depending on orientation), so a template can resolve it straight
|
|
54
|
+
* off `row` instead of assuming which of `.x`/`.y` it landed on.
|
|
55
|
+
* `impliesRuleX`/`impliesRuleY` tell the plot kind whether the active
|
|
56
|
+
* strategy implies a crosshair rule on each axis by default.
|
|
57
|
+
* `numericMargins` lets a nested layout align itself with the plot's own
|
|
58
|
+
* content box without recomputing margins itself.
|
|
59
|
+
*/
|
|
60
|
+
children: Snippet<[{
|
|
61
|
+
matchedPoints: HoverPoint<TData>[];
|
|
62
|
+
ruleX: AxisValue | null;
|
|
63
|
+
ruleY: AxisValue | null;
|
|
64
|
+
impliesRuleX: boolean;
|
|
65
|
+
impliesRuleY: boolean;
|
|
66
|
+
numericMargins: {
|
|
67
|
+
top: number;
|
|
68
|
+
right: number;
|
|
69
|
+
bottom: number;
|
|
70
|
+
left: number;
|
|
71
|
+
};
|
|
72
|
+
}]>;
|
|
73
|
+
};
|
|
74
|
+
exports: {};
|
|
75
|
+
bindings: "containerEl";
|
|
76
|
+
slots: {};
|
|
77
|
+
events: {};
|
|
78
|
+
};
|
|
79
|
+
declare class __sveltets_Render<TData extends Record<string, unknown>> {
|
|
80
|
+
props(): ReturnType<typeof $$render<TData>>['props'];
|
|
81
|
+
events(): ReturnType<typeof $$render<TData>>['events'];
|
|
82
|
+
slots(): ReturnType<typeof $$render<TData>>['slots'];
|
|
83
|
+
bindings(): "containerEl";
|
|
84
|
+
exports(): {};
|
|
85
|
+
}
|
|
86
|
+
interface $$IsomorphicComponent {
|
|
87
|
+
new <TData extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
|
|
88
|
+
$$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
|
|
89
|
+
} & ReturnType<__sveltets_Render<TData>['exports']>;
|
|
90
|
+
<TData extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
|
|
91
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
92
|
+
}
|
|
93
|
+
declare const BasePlotLayout: $$IsomorphicComponent;
|
|
94
|
+
type BasePlotLayout<TData extends Record<string, unknown>> = InstanceType<typeof BasePlotLayout<TData>>;
|
|
95
|
+
export default BasePlotLayout;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
+
import { GridX, GridY } from 'svelteplot';
|
|
3
|
+
import type { AxisBasedScalesConfig } from '../../types/plots/props';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Grid lines for the plot kinds that have an x/y axis pair — opt-in via
|
|
7
|
+
* `scales.x.grid`/`scales.y.grid` (svelteplot's own implicit grid is a
|
|
8
|
+
* fixed, unstyled default, so this is drawn instead of that, not on top of
|
|
9
|
+
* it — see `BasePlotLayout`'s `finalizeScale`, which strips `grid` from what
|
|
10
|
+
* actually reaches `<Plot x y>`).
|
|
11
|
+
*/
|
|
12
|
+
let { scales }: { scales?: AxisBasedScalesConfig<TData> } = $props();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
{#if scales?.x?.grid}
|
|
16
|
+
<GridX
|
|
17
|
+
stroke={typeof scales.x.grid === 'object' ? scales.x.grid.stroke : undefined}
|
|
18
|
+
strokeWidth={typeof scales.x.grid === 'object' ? scales.x.grid.strokeWidth : undefined}
|
|
19
|
+
strokeOpacity={typeof scales.x.grid === 'object' ? scales.x.grid.strokeOpacity : undefined}
|
|
20
|
+
strokeDasharray={typeof scales.x.grid === 'object' ? scales.x.grid.strokeDasharray : undefined}
|
|
21
|
+
/>
|
|
22
|
+
{/if}
|
|
23
|
+
{#if scales?.y?.grid}
|
|
24
|
+
<GridY
|
|
25
|
+
stroke={typeof scales.y.grid === 'object' ? scales.y.grid.stroke : undefined}
|
|
26
|
+
strokeWidth={typeof scales.y.grid === 'object' ? scales.y.grid.strokeWidth : undefined}
|
|
27
|
+
strokeOpacity={typeof scales.y.grid === 'object' ? scales.y.grid.strokeOpacity : undefined}
|
|
28
|
+
strokeDasharray={typeof scales.y.grid === 'object' ? scales.y.grid.strokeDasharray : undefined}
|
|
29
|
+
/>
|
|
30
|
+
{/if}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AxisBasedScalesConfig } from '../../types/plots/props';
|
|
2
|
+
declare function $$render<TData extends Record<string, unknown>>(): {
|
|
3
|
+
props: {
|
|
4
|
+
scales?: AxisBasedScalesConfig<TData>;
|
|
5
|
+
};
|
|
6
|
+
exports: {};
|
|
7
|
+
bindings: "";
|
|
8
|
+
slots: {};
|
|
9
|
+
events: {};
|
|
10
|
+
};
|
|
11
|
+
declare class __sveltets_Render<TData extends Record<string, unknown>> {
|
|
12
|
+
props(): ReturnType<typeof $$render<TData>>['props'];
|
|
13
|
+
events(): ReturnType<typeof $$render<TData>>['events'];
|
|
14
|
+
slots(): ReturnType<typeof $$render<TData>>['slots'];
|
|
15
|
+
bindings(): "";
|
|
16
|
+
exports(): {};
|
|
17
|
+
}
|
|
18
|
+
interface $$IsomorphicComponent {
|
|
19
|
+
new <TData extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
|
|
20
|
+
$$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
|
|
21
|
+
} & ReturnType<__sveltets_Render<TData>['exports']>;
|
|
22
|
+
<TData extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
|
|
23
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
24
|
+
}
|
|
25
|
+
declare const GridLayout: $$IsomorphicComponent;
|
|
26
|
+
type GridLayout<TData extends Record<string, unknown>> = InstanceType<typeof GridLayout<TData>>;
|
|
27
|
+
export default GridLayout;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { RuleX, RuleY } from 'svelteplot';
|
|
4
|
+
import HoverMarker from '../../markers/HoverMarker.svelte';
|
|
5
|
+
import type { AxisValue } from '../../types/plots/axis';
|
|
6
|
+
import type { Series } from '../../types/plots/data/common';
|
|
7
|
+
import type { Marker } from '../../types/markers/common';
|
|
8
|
+
import type { HoverPoint } from '../../types/layout/tooltip';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Standalone rule markers (`ruleX`/`ruleY`/un-scoped `component`) plus the
|
|
12
|
+
* unscoped hover crosshair+dot+label — the plot kinds with an x/y axis pair
|
|
13
|
+
* only (line/bar/heatmap/pyramid); `GeoPlot` has no rule/crosshair concept
|
|
14
|
+
* of its own. Wraps `children` (the plot kind's actual marks) so both draw
|
|
15
|
+
* in the same order as before this was split out of `BasePlotLayout`: marks
|
|
16
|
+
* first, then rules/hover marker on top of them.
|
|
17
|
+
*/
|
|
18
|
+
let {
|
|
19
|
+
markers = [],
|
|
20
|
+
seriesData = [],
|
|
21
|
+
matchedPoints,
|
|
22
|
+
ruleX,
|
|
23
|
+
ruleY,
|
|
24
|
+
impliesRuleX,
|
|
25
|
+
impliesRuleY,
|
|
26
|
+
showHoverLabels = true,
|
|
27
|
+
children,
|
|
28
|
+
}: {
|
|
29
|
+
markers?: Marker[];
|
|
30
|
+
/** All resolved series, forwarded to unscoped component markers (e.g. DeltaMarker). */
|
|
31
|
+
seriesData?: Series<TData>[];
|
|
32
|
+
matchedPoints: HoverPoint<TData>[];
|
|
33
|
+
ruleX: AxisValue | null;
|
|
34
|
+
ruleY: AxisValue | null;
|
|
35
|
+
impliesRuleX: boolean;
|
|
36
|
+
impliesRuleY: boolean;
|
|
37
|
+
showHoverLabels?: boolean;
|
|
38
|
+
children: Snippet;
|
|
39
|
+
} = $props();
|
|
40
|
+
|
|
41
|
+
const topLevelMarkers = $derived(
|
|
42
|
+
markers.filter(
|
|
43
|
+
(marker) =>
|
|
44
|
+
marker.type === 'ruleX' ||
|
|
45
|
+
marker.type === 'ruleY' ||
|
|
46
|
+
(marker.type === 'component' && !marker.series),
|
|
47
|
+
),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
/** The unscoped (no `series`) hover marker, if any. */
|
|
51
|
+
const unscopedHoverMarker = $derived(
|
|
52
|
+
markers.find((m) => m.type === 'hover' && !m.series) as
|
|
53
|
+
| Extract<Marker, { type: 'hover' }>
|
|
54
|
+
| undefined,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Gate ruleX display: shows when the strategy implies it (default) or the
|
|
59
|
+
* marker explicitly requests it (`ruleX: true`), and is never suppressed
|
|
60
|
+
* unless the marker explicitly disables it (`ruleX: false`).
|
|
61
|
+
*/
|
|
62
|
+
const showRuleX = $derived(
|
|
63
|
+
unscopedHoverMarker != null &&
|
|
64
|
+
unscopedHoverMarker.ruleX !== false &&
|
|
65
|
+
(impliesRuleX || unscopedHoverMarker.ruleX === true),
|
|
66
|
+
);
|
|
67
|
+
const showRuleY = $derived(
|
|
68
|
+
unscopedHoverMarker != null &&
|
|
69
|
+
unscopedHoverMarker.ruleY !== false &&
|
|
70
|
+
(impliesRuleY || unscopedHoverMarker.ruleY === true),
|
|
71
|
+
);
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
{@render children()}
|
|
75
|
+
|
|
76
|
+
{#each topLevelMarkers as marker, i (marker.type === 'ruleX' ? `${marker.type}-${marker.x}` : marker.type === 'ruleY' ? `${marker.type}-${marker.y}` : `${marker.type}-${i}`)}
|
|
77
|
+
{#if marker.type === 'ruleX'}
|
|
78
|
+
<RuleX
|
|
79
|
+
data={[{ xValue: marker.x }]}
|
|
80
|
+
x={(d) => d.xValue}
|
|
81
|
+
stroke={marker.style?.stroke ?? 'currentColor'}
|
|
82
|
+
strokeWidth={marker.style?.strokeWidth ?? 1}
|
|
83
|
+
strokeOpacity={marker.style?.strokeOpacity ?? 1}
|
|
84
|
+
strokeDasharray={marker.style?.strokeDasharray}
|
|
85
|
+
/>
|
|
86
|
+
{:else if marker.type === 'ruleY'}
|
|
87
|
+
<RuleY
|
|
88
|
+
data={[{ yValue: marker.y }]}
|
|
89
|
+
y={(d) => d.yValue}
|
|
90
|
+
stroke={marker.style?.stroke ?? 'currentColor'}
|
|
91
|
+
strokeWidth={marker.style?.strokeWidth ?? 1}
|
|
92
|
+
strokeOpacity={marker.style?.strokeOpacity ?? 1}
|
|
93
|
+
strokeDasharray={marker.style?.strokeDasharray}
|
|
94
|
+
/>
|
|
95
|
+
{:else if marker.type === 'component'}
|
|
96
|
+
<marker.component {...marker.props} data={marker.data ?? seriesData} />
|
|
97
|
+
{/if}
|
|
98
|
+
{/each}
|
|
99
|
+
|
|
100
|
+
{#if unscopedHoverMarker}
|
|
101
|
+
<HoverMarker
|
|
102
|
+
data={matchedPoints}
|
|
103
|
+
ruleX={showRuleX ? ruleX : null}
|
|
104
|
+
ruleY={showRuleY ? ruleY : null}
|
|
105
|
+
showLabels={unscopedHoverMarker.showLabels ?? showHoverLabels}
|
|
106
|
+
format={unscopedHoverMarker.format}
|
|
107
|
+
ruleStyle={unscopedHoverMarker.ruleStyle}
|
|
108
|
+
dotStyle={unscopedHoverMarker.dotStyle}
|
|
109
|
+
fontStyle={unscopedHoverMarker.fontStyle}
|
|
110
|
+
/>
|
|
111
|
+
{/if}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { AxisValue } from '../../types/plots/axis';
|
|
3
|
+
import type { Series } from '../../types/plots/data/common';
|
|
4
|
+
import type { Marker } from '../../types/markers/common';
|
|
5
|
+
import type { HoverPoint } from '../../types/layout/tooltip';
|
|
6
|
+
declare function $$render<TData extends Record<string, unknown>>(): {
|
|
7
|
+
props: {
|
|
8
|
+
markers?: Marker[];
|
|
9
|
+
/** All resolved series, forwarded to unscoped component markers (e.g. DeltaMarker). */
|
|
10
|
+
seriesData?: Series<TData>[];
|
|
11
|
+
matchedPoints: HoverPoint<TData>[];
|
|
12
|
+
ruleX: AxisValue | null;
|
|
13
|
+
ruleY: AxisValue | null;
|
|
14
|
+
impliesRuleX: boolean;
|
|
15
|
+
impliesRuleY: boolean;
|
|
16
|
+
showHoverLabels?: boolean;
|
|
17
|
+
children: Snippet;
|
|
18
|
+
};
|
|
19
|
+
exports: {};
|
|
20
|
+
bindings: "";
|
|
21
|
+
slots: {};
|
|
22
|
+
events: {};
|
|
23
|
+
};
|
|
24
|
+
declare class __sveltets_Render<TData extends Record<string, unknown>> {
|
|
25
|
+
props(): ReturnType<typeof $$render<TData>>['props'];
|
|
26
|
+
events(): ReturnType<typeof $$render<TData>>['events'];
|
|
27
|
+
slots(): ReturnType<typeof $$render<TData>>['slots'];
|
|
28
|
+
bindings(): "";
|
|
29
|
+
exports(): {};
|
|
30
|
+
}
|
|
31
|
+
interface $$IsomorphicComponent {
|
|
32
|
+
new <TData extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
|
|
33
|
+
$$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
|
|
34
|
+
} & ReturnType<__sveltets_Render<TData>['exports']>;
|
|
35
|
+
<TData extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
|
|
36
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
37
|
+
}
|
|
38
|
+
declare const RuleLayout: $$IsomorphicComponent;
|
|
39
|
+
type RuleLayout<TData extends Record<string, unknown>> = InstanceType<typeof RuleLayout<TData>>;
|
|
40
|
+
export default RuleLayout;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const AUTO_MARGIN_ESTIMATE: {
|
|
2
|
+
readonly top: 20;
|
|
3
|
+
readonly right: 20;
|
|
4
|
+
readonly bottom: 30;
|
|
5
|
+
readonly left: 40;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* GeoPlot's own margin default — a small, uniform gap on every side, unlike
|
|
9
|
+
* `AUTO_MARGIN_ESTIMATE`'s asymmetric axis-tick-label estimate (extra room
|
|
10
|
+
* on the left/bottom for y tick labels and an x-axis title). A map has no
|
|
11
|
+
* axes to make room for, so borrowing that estimate just left GeoPlot with
|
|
12
|
+
* a lopsided, oversized margin — most visibly a much taller gap under the
|
|
13
|
+
* map than an `inset` marker's own default `margin` (see `insetLayout.ts`),
|
|
14
|
+
* even though both are meant to read as the same edge gap. Matching this
|
|
15
|
+
* constant to that 8px inset default keeps the two visually aligned.
|
|
16
|
+
*/
|
|
17
|
+
export declare const GEO_MARGIN_ESTIMATE: {
|
|
18
|
+
readonly top: 8;
|
|
19
|
+
readonly right: 8;
|
|
20
|
+
readonly bottom: 8;
|
|
21
|
+
readonly left: 8;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Best-effort numeric fallback for a margin side that resolved to `'auto'`.
|
|
25
|
+
* Used for layout heuristics that need *a* number before svelteplot has
|
|
26
|
+
* measured the real rendered content (tick labels, axis title) — e.g.
|
|
27
|
+
* capping tick count, or estimating a band's pixel width for the bar plot's
|
|
28
|
+
* 'grouped' series layout. Not exact: an `'auto'` side can end up wider than
|
|
29
|
+
* this once svelteplot measures unusually long tick labels.
|
|
30
|
+
*
|
|
31
|
+
* `estimate` defaults to `AUTO_MARGIN_ESTIMATE`; pass `GEO_MARGIN_ESTIMATE`
|
|
32
|
+
* for GeoPlot, which has no axes for that estimate's asymmetry to apply to.
|
|
33
|
+
*/
|
|
34
|
+
export declare function numericMargin(side: keyof typeof AUTO_MARGIN_ESTIMATE, value: number | 'auto' | undefined, estimate?: Record<keyof typeof AUTO_MARGIN_ESTIMATE, number>): number;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const AUTO_MARGIN_ESTIMATE = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
2
|
+
/**
|
|
3
|
+
* GeoPlot's own margin default — a small, uniform gap on every side, unlike
|
|
4
|
+
* `AUTO_MARGIN_ESTIMATE`'s asymmetric axis-tick-label estimate (extra room
|
|
5
|
+
* on the left/bottom for y tick labels and an x-axis title). A map has no
|
|
6
|
+
* axes to make room for, so borrowing that estimate just left GeoPlot with
|
|
7
|
+
* a lopsided, oversized margin — most visibly a much taller gap under the
|
|
8
|
+
* map than an `inset` marker's own default `margin` (see `insetLayout.ts`),
|
|
9
|
+
* even though both are meant to read as the same edge gap. Matching this
|
|
10
|
+
* constant to that 8px inset default keeps the two visually aligned.
|
|
11
|
+
*/
|
|
12
|
+
export const GEO_MARGIN_ESTIMATE = { top: 8, right: 8, bottom: 8, left: 8 };
|
|
13
|
+
/**
|
|
14
|
+
* Best-effort numeric fallback for a margin side that resolved to `'auto'`.
|
|
15
|
+
* Used for layout heuristics that need *a* number before svelteplot has
|
|
16
|
+
* measured the real rendered content (tick labels, axis title) — e.g.
|
|
17
|
+
* capping tick count, or estimating a band's pixel width for the bar plot's
|
|
18
|
+
* 'grouped' series layout. Not exact: an `'auto'` side can end up wider than
|
|
19
|
+
* this once svelteplot measures unusually long tick labels.
|
|
20
|
+
*
|
|
21
|
+
* `estimate` defaults to `AUTO_MARGIN_ESTIMATE`; pass `GEO_MARGIN_ESTIMATE`
|
|
22
|
+
* for GeoPlot, which has no axes for that estimate's asymmetry to apply to.
|
|
23
|
+
*/
|
|
24
|
+
export function numericMargin(side, value, estimate = AUTO_MARGIN_ESTIMATE) {
|
|
25
|
+
return typeof value === 'number' ? value : estimate[side];
|
|
26
|
+
}
|