@fundar/data-chart-telling 0.0.14 → 0.0.15
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.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 +1 -1
- package/dist/configuration/themes/index.d.ts +56 -40
- package/dist/index.d.ts +26 -12
- 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/DiscreteSection.svelte +1 -1
- 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 +66 -0
- package/dist/plots/bar/BarSegments.svelte.d.ts +36 -0
- package/dist/plots/bar/Plot.svelte +132 -76
- 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 +548 -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 +129 -47
- package/dist/plots/heatmap/Plot.svelte.d.ts +7 -3
- package/dist/plots/line/Plot.svelte +44 -16
- package/dist/plots/line/Plot.svelte.d.ts +7 -3
- package/dist/plots/pyramid/Plot.svelte +70 -25
- 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/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 +1 -1
- package/dist/types/charts/props.d.ts +9 -6
- package/dist/types/configuration/styling.d.ts +11 -5
- 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/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/charts/{Chart.svelte → BaseChart.svelte} +0 -0
- /package/dist/types/{plots → markers}/common.js +0 -0
- /package/dist/types/{plots/markers.js → markers/geo.js} +0 -0
- /package/dist/types/{plots/styles.js → markers/props.js} +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { geoAzimuthalEquidistant } from 'd3-geo';
|
|
2
|
+
import { pointsToFitFeature } from './fit';
|
|
3
|
+
// Representative extremity points — not real border geometry (which stays
|
|
4
|
+
// out of `src/lib`, see stories/plots/geo/data.ts), just enough for
|
|
5
|
+
// `fitSize` to frame Argentina's full territorial claim sensibly. These are
|
|
6
|
+
// plain real-world coordinates, not derived from any particular dataset, so
|
|
7
|
+
// they work the same way regardless of which Argentina GeoJSON actually
|
|
8
|
+
// gets drawn through this projection.
|
|
9
|
+
const MAINLAND_POINTS = [
|
|
10
|
+
[-65.3, -21.8], // La Quiaca (north)
|
|
11
|
+
[-68.3, -54.8], // Ushuaia / Tierra del Fuego (south)
|
|
12
|
+
[-53.7, -25.6], // Puerto Iguazú (east)
|
|
13
|
+
[-73.4, -50.3], // Los Glaciares, Santa Cruz (west)
|
|
14
|
+
[-71.8, -41.1], // Bariloche (west, mid-latitude bulge)
|
|
15
|
+
];
|
|
16
|
+
const ANTARCTIC_POINTS = [
|
|
17
|
+
[-61.2, -51.0], // Malvinas (north tip)
|
|
18
|
+
[-57.8, -52.3], // Malvinas (east tip)
|
|
19
|
+
[-38.0, -53.9], // Georgias del Sur
|
|
20
|
+
[-26.5, -59.5], // Sandwich del Sur
|
|
21
|
+
[-74, -60], // Antarctic sector, western meridian (60°S treaty boundary)
|
|
22
|
+
[-25, -60], // Antarctic sector, eastern meridian (60°S treaty boundary)
|
|
23
|
+
[-49.5, -89.9], // South Pole, on the sector's central meridian
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Argentina's territory in one unbroken frame: the mainland and the
|
|
27
|
+
* Antarctic/South Atlantic sector both visible, related to each other at
|
|
28
|
+
* true scale (azimuthal-equidistant, rotated so the split falls to the
|
|
29
|
+
* sides rather than through the middle of either half).
|
|
30
|
+
*/
|
|
31
|
+
export const argentinaBicontinental = ({ width, height }) => {
|
|
32
|
+
const projection = geoAzimuthalEquidistant().rotate([60, 70]);
|
|
33
|
+
projection.fitSize([width, height], pointsToFitFeature([...MAINLAND_POINTS, ...ANTARCTIC_POINTS]));
|
|
34
|
+
return projection;
|
|
35
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a handful of representative `[lon, lat]` points as a `MultiPoint`
|
|
3
|
+
* Feature, just so `projection.fitExtent`/`fitSize` has something to
|
|
4
|
+
* measure. Custom projections built on these live in `src/lib` (see
|
|
5
|
+
* `stories/plots/geo/data.ts` for why real border geometry doesn't), so a
|
|
6
|
+
* few hand-picked extremity points stand in for a region's true extent.
|
|
7
|
+
*/
|
|
8
|
+
export declare function pointsToFitFeature(points: [number, number][]): GeoJSON.Feature;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a handful of representative `[lon, lat]` points as a `MultiPoint`
|
|
3
|
+
* Feature, just so `projection.fitExtent`/`fitSize` has something to
|
|
4
|
+
* measure. Custom projections built on these live in `src/lib` (see
|
|
5
|
+
* `stories/plots/geo/data.ts` for why real border geometry doesn't), so a
|
|
6
|
+
* few hand-picked extremity points stand in for a region's true extent.
|
|
7
|
+
*/
|
|
8
|
+
export function pointsToFitFeature(points) {
|
|
9
|
+
return {
|
|
10
|
+
type: 'Feature',
|
|
11
|
+
properties: null,
|
|
12
|
+
geometry: { type: 'MultiPoint', coordinates: points },
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type GeoRotate = [number, number, number];
|
|
2
|
+
/**
|
|
3
|
+
* Wires drag-to-rotate onto a DOM node for orthographic-style projections,
|
|
4
|
+
* exposing the resulting `[lambda, phi, gamma]` as reactive Svelte state —
|
|
5
|
+
* the caller feeds it back into the projection's own `rotate` config (see
|
|
6
|
+
* `GeoPlot`'s own `Plot.svelte`). Plain pointer events rather than d3-drag: a
|
|
7
|
+
* single-pointer drag-delta-to-rotation-delta conversion doesn't need
|
|
8
|
+
* d3-drag's multi-touch gesture machinery, and this package doesn't
|
|
9
|
+
* otherwise depend on it.
|
|
10
|
+
*
|
|
11
|
+
* Sensitivity is a fixed degrees-per-pixel constant scaled by the current
|
|
12
|
+
* pan/zoom `scale` (so dragging feels consistent whether zoomed in or out)
|
|
13
|
+
* — not derived from the projection's own fitted scale, which isn't
|
|
14
|
+
* exposed back up to this layer. Known v1 simplification, in the same
|
|
15
|
+
* spirit as `createGeoZoom`'s own "v1 limitation" — good enough to spin
|
|
16
|
+
* the globe, not tuned to feel identical across wildly different
|
|
17
|
+
* width/height/domain combinations.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createGeoRotate(args: {
|
|
20
|
+
enabled: () => boolean;
|
|
21
|
+
baseRotate: () => GeoRotate;
|
|
22
|
+
scale: () => number;
|
|
23
|
+
node: () => HTMLElement | null;
|
|
24
|
+
}): {
|
|
25
|
+
readonly rotate: GeoRotate;
|
|
26
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wires drag-to-rotate onto a DOM node for orthographic-style projections,
|
|
3
|
+
* exposing the resulting `[lambda, phi, gamma]` as reactive Svelte state —
|
|
4
|
+
* the caller feeds it back into the projection's own `rotate` config (see
|
|
5
|
+
* `GeoPlot`'s own `Plot.svelte`). Plain pointer events rather than d3-drag: a
|
|
6
|
+
* single-pointer drag-delta-to-rotation-delta conversion doesn't need
|
|
7
|
+
* d3-drag's multi-touch gesture machinery, and this package doesn't
|
|
8
|
+
* otherwise depend on it.
|
|
9
|
+
*
|
|
10
|
+
* Sensitivity is a fixed degrees-per-pixel constant scaled by the current
|
|
11
|
+
* pan/zoom `scale` (so dragging feels consistent whether zoomed in or out)
|
|
12
|
+
* — not derived from the projection's own fitted scale, which isn't
|
|
13
|
+
* exposed back up to this layer. Known v1 simplification, in the same
|
|
14
|
+
* spirit as `createGeoZoom`'s own "v1 limitation" — good enough to spin
|
|
15
|
+
* the globe, not tuned to feel identical across wildly different
|
|
16
|
+
* width/height/domain combinations.
|
|
17
|
+
*/
|
|
18
|
+
export function createGeoRotate(args) {
|
|
19
|
+
let rotate = $state(args.baseRotate());
|
|
20
|
+
// Reset to the configured base rotation whenever it changes (e.g. a
|
|
21
|
+
// Storybook control edit) — but only while not actively enabled, so this
|
|
22
|
+
// doesn't fight the user's own in-progress drag.
|
|
23
|
+
$effect(() => {
|
|
24
|
+
if (!args.enabled())
|
|
25
|
+
rotate = args.baseRotate();
|
|
26
|
+
});
|
|
27
|
+
$effect(() => {
|
|
28
|
+
const el = args.node();
|
|
29
|
+
if (!args.enabled() || !el)
|
|
30
|
+
return;
|
|
31
|
+
// `dragging`/`start`/`startRotate` are deliberately plain closure
|
|
32
|
+
// variables, not `$state` — this effect must NOT read the reactive
|
|
33
|
+
// `rotate` value anywhere in its own synchronous body (only inside the
|
|
34
|
+
// event-handler closures below, which aren't part of dependency
|
|
35
|
+
// tracking). Reading it here would make every `rotate` write from
|
|
36
|
+
// `onPointerMove` re-trigger this very effect mid-drag, tearing down
|
|
37
|
+
// and rebuilding the listeners — and losing `dragging`'s `true` state
|
|
38
|
+
// — on every pixel of movement.
|
|
39
|
+
let dragging = false;
|
|
40
|
+
let start = { x: 0, y: 0 };
|
|
41
|
+
let startRotate = [0, 0, 0];
|
|
42
|
+
function onPointerDown(event) {
|
|
43
|
+
if (event.button !== 0)
|
|
44
|
+
return;
|
|
45
|
+
dragging = true;
|
|
46
|
+
start = { x: event.clientX, y: event.clientY };
|
|
47
|
+
startRotate = rotate;
|
|
48
|
+
el.setPointerCapture(event.pointerId);
|
|
49
|
+
}
|
|
50
|
+
function onPointerMove(event) {
|
|
51
|
+
if (!dragging)
|
|
52
|
+
return;
|
|
53
|
+
const degPerPixel = 0.3 / Math.max(args.scale(), 0.1);
|
|
54
|
+
const dLambda = (event.clientX - start.x) * degPerPixel;
|
|
55
|
+
const dPhi = (event.clientY - start.y) * degPerPixel;
|
|
56
|
+
const [lambda0, phi0, gamma0] = startRotate;
|
|
57
|
+
rotate = [lambda0 + dLambda, Math.max(-90, Math.min(90, phi0 - dPhi)), gamma0];
|
|
58
|
+
}
|
|
59
|
+
function onPointerUp(event) {
|
|
60
|
+
dragging = false;
|
|
61
|
+
el.releasePointerCapture(event.pointerId);
|
|
62
|
+
}
|
|
63
|
+
el.addEventListener('pointerdown', onPointerDown);
|
|
64
|
+
el.addEventListener('pointermove', onPointerMove);
|
|
65
|
+
el.addEventListener('pointerup', onPointerUp);
|
|
66
|
+
el.addEventListener('pointercancel', onPointerUp);
|
|
67
|
+
return () => {
|
|
68
|
+
el.removeEventListener('pointerdown', onPointerDown);
|
|
69
|
+
el.removeEventListener('pointermove', onPointerMove);
|
|
70
|
+
el.removeEventListener('pointerup', onPointerUp);
|
|
71
|
+
el.removeEventListener('pointercancel', onPointerUp);
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
get rotate() {
|
|
76
|
+
return rotate;
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { GeoZoomConfig } from '../../types/plots/styles/geo';
|
|
2
|
+
export type GeoZoomTransform = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
k: number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Wires drag-pan + scroll-zoom onto a DOM node via d3-zoom, exposing the
|
|
9
|
+
* resulting transform as reactive Svelte state. The caller applies it as an
|
|
10
|
+
* SVG `<g transform="translate(x,y) scale(k)">` wrapper — cheap, since the
|
|
11
|
+
* underlying `d3-geo` projection is computed once by svelteplot and never
|
|
12
|
+
* recomputed per zoom tick.
|
|
13
|
+
*
|
|
14
|
+
* Known v1 limitation: svelteplot's own `<Pointer>` hit-tests in the plot's
|
|
15
|
+
* pre-zoom projected coordinate space, so hover/tooltip matching does not
|
|
16
|
+
* compensate for an active pan/zoom transform — it still works, but targets
|
|
17
|
+
* a shape's un-zoomed position rather than its currently-visible one.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createGeoZoom(args: {
|
|
20
|
+
enabled: () => boolean;
|
|
21
|
+
config: () => GeoZoomConfig | undefined;
|
|
22
|
+
node: () => HTMLElement | null;
|
|
23
|
+
/**
|
|
24
|
+
* When true, drag/touch gestures are left for something else to handle
|
|
25
|
+
* (see `createGeoRotate`) — only wheel/pinch scaling stays wired to this
|
|
26
|
+
* behavior. Checked per-event, so toggling it doesn't need to tear down
|
|
27
|
+
* and recreate the underlying d3-zoom behavior.
|
|
28
|
+
*/
|
|
29
|
+
disableDrag?: () => boolean;
|
|
30
|
+
}): {
|
|
31
|
+
readonly transform: GeoZoomTransform;
|
|
32
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { select } from 'd3-selection';
|
|
2
|
+
import { zoom as d3zoom, zoomIdentity } from 'd3-zoom';
|
|
3
|
+
/**
|
|
4
|
+
* Wires drag-pan + scroll-zoom onto a DOM node via d3-zoom, exposing the
|
|
5
|
+
* resulting transform as reactive Svelte state. The caller applies it as an
|
|
6
|
+
* SVG `<g transform="translate(x,y) scale(k)">` wrapper — cheap, since the
|
|
7
|
+
* underlying `d3-geo` projection is computed once by svelteplot and never
|
|
8
|
+
* recomputed per zoom tick.
|
|
9
|
+
*
|
|
10
|
+
* Known v1 limitation: svelteplot's own `<Pointer>` hit-tests in the plot's
|
|
11
|
+
* pre-zoom projected coordinate space, so hover/tooltip matching does not
|
|
12
|
+
* compensate for an active pan/zoom transform — it still works, but targets
|
|
13
|
+
* a shape's un-zoomed position rather than its currently-visible one.
|
|
14
|
+
*/
|
|
15
|
+
export function createGeoZoom(args) {
|
|
16
|
+
let transform = $state({ x: 0, y: 0, k: 1 });
|
|
17
|
+
$effect(() => {
|
|
18
|
+
const el = args.node();
|
|
19
|
+
if (!args.enabled() || !el)
|
|
20
|
+
return;
|
|
21
|
+
const cfg = args.config();
|
|
22
|
+
const behavior = d3zoom()
|
|
23
|
+
.scaleExtent([cfg?.min ?? 1, cfg?.max ?? 8])
|
|
24
|
+
.filter((event) => {
|
|
25
|
+
if (args.disableDrag?.() && event.type !== 'wheel')
|
|
26
|
+
return false;
|
|
27
|
+
// d3-zoom's own default filter, minus the part this replaces.
|
|
28
|
+
return (!event.ctrlKey || event.type === 'wheel') && !event.button;
|
|
29
|
+
})
|
|
30
|
+
.on('zoom', (event) => {
|
|
31
|
+
transform = { x: event.transform.x, y: event.transform.y, k: event.transform.k };
|
|
32
|
+
});
|
|
33
|
+
const selection = select(el).call(behavior);
|
|
34
|
+
const initial = cfg?.initial;
|
|
35
|
+
if (initial) {
|
|
36
|
+
behavior.transform(selection, zoomIdentity.translate(initial.x ?? 0, initial.y ?? 0).scale(initial.k ?? 1));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
transform = { x: 0, y: 0, k: 1 };
|
|
40
|
+
}
|
|
41
|
+
return () => {
|
|
42
|
+
selection.on('.zoom', null);
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
get transform() {
|
|
47
|
+
return transform;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
<script lang="ts" generics="TData extends Record<string, unknown>">
|
|
2
2
|
import { Cell, Text } from 'svelteplot';
|
|
3
3
|
import { resolveAccessor } from '../utils/accessors';
|
|
4
|
+
import { validateSegments } from '../utils/segments';
|
|
4
5
|
import { buildSeries } from '../../utils/grouping';
|
|
5
6
|
import { makeColorScale } from '../../utils/color';
|
|
6
7
|
import { getConfiguration } from '../../configuration/config.svelte';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
8
|
+
import BasePlotLayout from '../../layout/plot/BasePlotLayout.svelte';
|
|
9
|
+
import AxisLayout from '../../layout/plot/AxisLayout.svelte';
|
|
10
|
+
import GridLayout from '../../layout/plot/GridLayout.svelte';
|
|
11
|
+
import RuleLayout from '../../layout/plot/RuleLayout.svelte';
|
|
12
|
+
import { hasHoverMarker, resolveHoverStrategy, resolveHoverSync } from '../../layout/tooltip/utils';
|
|
13
|
+
import type { BasePlotProps } from '../../types/plots/props';
|
|
14
|
+
import type { AxisValue } from '../../types/plots/axis';
|
|
15
|
+
import type { SeriesProps, DataProps } from '../../types/plots/data/common';
|
|
16
|
+
import type { AxisBasedScalesConfig } from '../../types/plots/props';
|
|
17
|
+
import type { BasePlotStyles } from '../../types/plots/styles/common';
|
|
18
|
+
import type { CellSegmentStyle } from '../../types/plots/segments/common';
|
|
19
|
+
import type { Marker } from '../../types/markers/common';
|
|
11
20
|
|
|
12
21
|
/**
|
|
13
22
|
* A categorical grid of value-coloured cells. Accepts either a pre-built
|
|
@@ -18,6 +27,15 @@
|
|
|
18
27
|
* The colour domain is read from `scales.z.domain`; when absent it is derived
|
|
19
28
|
* from the visible slice of data.
|
|
20
29
|
*/
|
|
30
|
+
type Props = BasePlotProps<
|
|
31
|
+
SeriesProps<TData> | DataProps<TData>,
|
|
32
|
+
TData,
|
|
33
|
+
BasePlotStyles,
|
|
34
|
+
CellSegmentStyle,
|
|
35
|
+
Marker,
|
|
36
|
+
AxisBasedScalesConfig<TData>
|
|
37
|
+
>;
|
|
38
|
+
|
|
21
39
|
let {
|
|
22
40
|
width,
|
|
23
41
|
height,
|
|
@@ -32,9 +50,10 @@
|
|
|
32
50
|
margins,
|
|
33
51
|
markers = [],
|
|
34
52
|
tooltip = undefined,
|
|
35
|
-
}:
|
|
53
|
+
}: Props = $props();
|
|
36
54
|
|
|
37
55
|
$effect(() => {
|
|
56
|
+
validateSegments(segments);
|
|
38
57
|
const scoped = markers.filter(
|
|
39
58
|
(m) => (m.type === 'hover' || m.type === 'component') && m.series,
|
|
40
59
|
);
|
|
@@ -43,12 +62,10 @@
|
|
|
43
62
|
'HeatmapPlot: markers scoped to a `series` are ignored — heatmaps have no series concept.',
|
|
44
63
|
);
|
|
45
64
|
}
|
|
46
|
-
const seriesKeys = segments.
|
|
47
|
-
Object.keys(g as Record<string, unknown>).filter((k) => k !== 'default'),
|
|
48
|
-
);
|
|
65
|
+
const seriesKeys = Object.keys(segments).filter((k) => k !== 'default');
|
|
49
66
|
if (seriesKeys.length > 0) {
|
|
50
67
|
console.warn(
|
|
51
|
-
`HeatmapPlot: segment groups have series-specific keys (${
|
|
68
|
+
`HeatmapPlot: segment groups have series-specific keys (${seriesKeys.join(', ')}) — heatmaps have no named series. Use the 'default' key instead.`,
|
|
52
69
|
);
|
|
53
70
|
}
|
|
54
71
|
});
|
|
@@ -58,6 +75,9 @@
|
|
|
58
75
|
const maxColor = $derived(styles.colors?.max ?? cfg.continuous.max);
|
|
59
76
|
const showVals = $derived(styles.values?.show ?? true);
|
|
60
77
|
const fmtVal = $derived(styles.values?.format ?? ((v: number) => `${v}`));
|
|
78
|
+
// 'outside' is a per-point escape hatch resolved by HoverMarker; heatmaps
|
|
79
|
+
// have no signed axis to resolve it against, so treat it as unset.
|
|
80
|
+
const resolvedTextAnchor = $derived(styles.values?.textAnchor === 'outside' ? undefined : styles.values?.textAnchor);
|
|
61
81
|
|
|
62
82
|
const resolvedSeries = $derived(series ?? buildSeries(data!, x!, y!, undefined));
|
|
63
83
|
const flat = $derived(resolvedSeries.flatMap((s) => s.data));
|
|
@@ -90,29 +110,39 @@
|
|
|
90
110
|
makeColorScale(valueDomain[0], valueDomain[1], minColor, maxColor),
|
|
91
111
|
);
|
|
92
112
|
|
|
93
|
-
const segList = $derived(segments.
|
|
113
|
+
const segList = $derived(segments.default ?? []);
|
|
94
114
|
|
|
115
|
+
/**
|
|
116
|
+
* A catch-all (no `areas`) always matches, so evaluating segments in plain
|
|
117
|
+
* array order and merging every match — as this used to do — makes a
|
|
118
|
+
* catch-all listed *after* an area-specific one (the documented, and only
|
|
119
|
+
* demonstrated, convention: baseline first, highlight second) overwrite it
|
|
120
|
+
* on every cell, since it's applied last unconditionally. Area-specific
|
|
121
|
+
* segments must always win over the catch-all regardless of list order —
|
|
122
|
+
* so the catch-all is applied once as the baseline, and only
|
|
123
|
+
* area-specific segments can override it on top, mirroring the same
|
|
124
|
+
* catch-all/area-specific priority every other plot kind's segments
|
|
125
|
+
* already follow (see `resolveSeriesSegments` in `utils/segments.ts`).
|
|
126
|
+
*/
|
|
95
127
|
const segStyleMap = $derived.by(() => {
|
|
96
128
|
const map = new Map<string, CellSegmentStyle>();
|
|
97
129
|
if (!segList.length) return map;
|
|
130
|
+
const catchAll = segList.find((s) => !s.areas || s.areas.length === 0);
|
|
131
|
+
const areaSegs = segList.filter((s) => s.areas && s.areas.length > 0);
|
|
98
132
|
for (const d of flat) {
|
|
99
133
|
const cx = getX(d) as AxisValue;
|
|
100
134
|
const cy = getY(d) as AxisValue;
|
|
101
135
|
const key = `${String(cx)}::${String(cy)}`;
|
|
102
136
|
if (!map.has(key)) {
|
|
103
|
-
let style: CellSegmentStyle = {};
|
|
104
|
-
for (const seg of
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
!
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
|
-
const yOk = !area.y || ((area.y.from === undefined || (cy as any) >= area.y.from) && (area.y.to === undefined || (cy as any) <= area.y.to));
|
|
114
|
-
return xOk && yOk;
|
|
115
|
-
});
|
|
137
|
+
let style: CellSegmentStyle = catchAll?.style ? { ...catchAll.style } : {};
|
|
138
|
+
for (const seg of areaSegs) {
|
|
139
|
+
const matches = seg.areas!.some((area) => {
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
141
|
+
const xOk = !area.x || ((area.x.from === undefined || (cx as any) >= area.x.from) && (area.x.to === undefined || (cx as any) <= area.x.to));
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
143
|
+
const yOk = !area.y || ((area.y.from === undefined || (cy as any) >= area.y.from) && (area.y.to === undefined || (cy as any) <= area.y.to));
|
|
144
|
+
return xOk && yOk;
|
|
145
|
+
});
|
|
116
146
|
if (matches) style = { ...style, ...seg.style };
|
|
117
147
|
}
|
|
118
148
|
map.set(key, style);
|
|
@@ -124,37 +154,83 @@
|
|
|
124
154
|
const getCellStyle = $derived(
|
|
125
155
|
(d: TData) => segStyleMap.get(`${String(getX(d))}::${String(getY(d))}`) ?? {},
|
|
126
156
|
);
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* One `<Cell>` call per *distinct resolved style*, not one call for the
|
|
160
|
+
* whole dataset. svelteplot registers `fillOpacity`/`strokeWidth` under
|
|
161
|
+
* its shared "opacity"/numeric scale machinery — passed as a per-row
|
|
162
|
+
* accessor that genuinely varies within a single mark instance, that
|
|
163
|
+
* scale collapses every row to the same (wrong) value instead of the
|
|
164
|
+
* literal numbers set on each segment. A literal, per-call constant (one
|
|
165
|
+
* call per style bucket) bypasses that entirely, which is exactly how
|
|
166
|
+
* bar/line avoid the same trap (one mark per visual segment). `fill`
|
|
167
|
+
* stays a per-cell accessor within each group — unlike fillOpacity, it
|
|
168
|
+
* must keep varying continuously with the underlying value wherever a
|
|
169
|
+
* segment doesn't explicitly override it.
|
|
170
|
+
*/
|
|
171
|
+
type StyleGroup = { style: CellSegmentStyle; data: TData[] };
|
|
172
|
+
const styleGroups = $derived.by((): StyleGroup[] => {
|
|
173
|
+
const groups = new Map<string, StyleGroup>();
|
|
174
|
+
for (const d of flat) {
|
|
175
|
+
const style = getCellStyle(d);
|
|
176
|
+
const key = JSON.stringify(style);
|
|
177
|
+
let group = groups.get(key);
|
|
178
|
+
if (!group) {
|
|
179
|
+
group = { style, data: [] };
|
|
180
|
+
groups.set(key, group);
|
|
181
|
+
}
|
|
182
|
+
group.data.push(d);
|
|
183
|
+
}
|
|
184
|
+
return [...groups.values()];
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// The single, fully-resolved scales object BasePlotLayout reads for
|
|
188
|
+
// everything (ticks, grid, sort, and the real svelteplot scale) — avoids
|
|
189
|
+
// keeping a second, separately-defaulted copy of `scales.x`/`scales.y`
|
|
190
|
+
// (our own band-scale + domain defaults) out of sync with the one
|
|
191
|
+
// actually forwarded.
|
|
192
|
+
const resolvedScales = $derived<AxisBasedScalesConfig<TData>>({
|
|
193
|
+
...scales,
|
|
194
|
+
x: { type: 'band', labelAnchor: 'right', domain: xDomain, ...(scales.x ?? {}) },
|
|
195
|
+
y: { type: 'band', domain: yDomain, ...(scales.y ?? {}) },
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const hoverActive = $derived(tooltip != null || hasHoverMarker(markers));
|
|
199
|
+
const hoverStrategy = $derived(resolveHoverStrategy(tooltip?.strategy, markers, 'punctual'));
|
|
200
|
+
const hoverSync = $derived(resolveHoverSync(tooltip?.sync, markers));
|
|
127
201
|
</script>
|
|
128
202
|
|
|
129
|
-
<
|
|
203
|
+
<BasePlotLayout
|
|
130
204
|
{width}
|
|
131
205
|
{height}
|
|
132
|
-
x={{ type: 'band', labelAnchor: 'right', domain: xDomain, ...(scales.x ?? {}) }}
|
|
133
|
-
y={{ type: 'band', domain: yDomain, ...(scales.y ?? {}) }}
|
|
134
206
|
data={flat}
|
|
135
207
|
{getX}
|
|
136
208
|
{getY}
|
|
137
|
-
matchY={getY}
|
|
138
209
|
{hoverPoints}
|
|
139
210
|
label={(d) => fmtVal(Number(getZ(d)), '')}
|
|
140
211
|
{tooltip}
|
|
141
|
-
{
|
|
142
|
-
|
|
143
|
-
|
|
212
|
+
{hoverActive}
|
|
213
|
+
{hoverStrategy}
|
|
214
|
+
{hoverSync}
|
|
215
|
+
scales={resolvedScales}
|
|
144
216
|
{margins}
|
|
145
|
-
showHoverLabels={false}
|
|
146
|
-
defaultStrategy="punctual"
|
|
147
217
|
>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
218
|
+
{#snippet children({ matchedPoints, ruleX, ruleY, impliesRuleX, impliesRuleY, numericMargins })}
|
|
219
|
+
<AxisLayout data={flat} {getX} {getY} {width} {height} {numericMargins} scales={resolvedScales} />
|
|
220
|
+
<GridLayout scales={resolvedScales} />
|
|
221
|
+
<RuleLayout {markers} seriesData={resolvedSeries} {matchedPoints} {ruleX} {ruleY} {impliesRuleX} {impliesRuleY} showHoverLabels={false}>
|
|
222
|
+
{#each styleGroups as group, i (i)}
|
|
223
|
+
<Cell
|
|
224
|
+
data={group.data as unknown as Record<string | symbol, never>[]}
|
|
225
|
+
x={getX}
|
|
226
|
+
y={getY}
|
|
227
|
+
fill={(d) => group.style.fill ?? colorScale(Number(getZ(d as TData)))}
|
|
228
|
+
fillOpacity={group.style.fillOpacity ?? 1}
|
|
229
|
+
stroke={group.style.stroke}
|
|
230
|
+
strokeWidth={group.style.strokeWidth ?? 0}
|
|
231
|
+
inset={0.5}
|
|
232
|
+
/>
|
|
233
|
+
{/each}
|
|
158
234
|
|
|
159
235
|
{#if showVals}
|
|
160
236
|
<Text
|
|
@@ -162,17 +238,23 @@
|
|
|
162
238
|
x={getX}
|
|
163
239
|
y={getY}
|
|
164
240
|
text={(d) => fmtVal(Number(getZ(d)), '')}
|
|
165
|
-
fill={cfg.continuous.labelColor}
|
|
166
|
-
fontSize={12}
|
|
167
|
-
fontWeight={600}
|
|
168
|
-
|
|
241
|
+
fill={styles.values?.fill ?? cfg.continuous.labelColor}
|
|
242
|
+
fontSize={styles.values?.fontSize ?? 12}
|
|
243
|
+
fontWeight={styles.values?.fontWeight ?? 600}
|
|
244
|
+
fontStyle={styles.values?.fontStyle}
|
|
245
|
+
textAnchor={resolvedTextAnchor ?? 'middle'}
|
|
169
246
|
lineAnchor={styles.values?.lineAnchor ?? 'middle'}
|
|
170
247
|
dx={styles.values?.dx ?? 0}
|
|
171
248
|
dy={styles.values?.dy ?? 0}
|
|
172
249
|
lineHeight={styles.values?.lineHeight}
|
|
173
250
|
rotate={styles.values?.rotate}
|
|
251
|
+
stroke={styles.values?.stroke}
|
|
252
|
+
strokeWidth={styles.values?.strokeWidth}
|
|
253
|
+
paintOrder={styles.values?.paintOrder}
|
|
174
254
|
class={styles.values?.class}
|
|
175
255
|
textClass={styles.values?.textClass}
|
|
176
256
|
/>
|
|
177
257
|
{/if}
|
|
178
|
-
</
|
|
258
|
+
</RuleLayout>
|
|
259
|
+
{/snippet}
|
|
260
|
+
</BasePlotLayout>
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { BasePlotProps } from '../../types/plots/props';
|
|
2
|
+
import type { SeriesProps, DataProps } from '../../types/plots/data/common';
|
|
3
|
+
import type { AxisBasedScalesConfig } from '../../types/plots/props';
|
|
4
|
+
import type { BasePlotStyles } from '../../types/plots/styles/common';
|
|
5
|
+
import type { CellSegmentStyle } from '../../types/plots/segments/common';
|
|
6
|
+
import type { Marker } from '../../types/markers/common';
|
|
3
7
|
declare function $$render<TData extends Record<string, unknown>>(): {
|
|
4
|
-
props:
|
|
8
|
+
props: BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, BasePlotStyles, CellSegmentStyle, Marker, AxisBasedScalesConfig<TData>>;
|
|
5
9
|
exports: {};
|
|
6
10
|
bindings: "";
|
|
7
11
|
slots: {};
|
|
@@ -8,13 +8,30 @@
|
|
|
8
8
|
import { getConfiguration } from '../../configuration/config.svelte';
|
|
9
9
|
import { paletteColor } from '../../utils/color';
|
|
10
10
|
import { buildSeries } from '../../utils/grouping';
|
|
11
|
-
import
|
|
12
|
-
import
|
|
11
|
+
import BasePlotLayout from '../../layout/plot/BasePlotLayout.svelte';
|
|
12
|
+
import AxisLayout from '../../layout/plot/AxisLayout.svelte';
|
|
13
|
+
import GridLayout from '../../layout/plot/GridLayout.svelte';
|
|
14
|
+
import RuleLayout from '../../layout/plot/RuleLayout.svelte';
|
|
15
|
+
import HoverMarker from '../../markers/HoverMarker.svelte';
|
|
16
|
+
import { hasHoverMarker, resolveHoverStrategy, resolveHoverSync } from '../../layout/tooltip/utils';
|
|
13
17
|
import { buildGroupedSeries, validateSegments, resolveSegmentsForSeries, matchesSegmentX, getDataForSegments } from '../utils/segments';
|
|
14
|
-
import type {
|
|
15
|
-
import type {
|
|
16
|
-
import type {
|
|
17
|
-
import type {
|
|
18
|
+
import type { BasePlotProps } from '../../types/plots/props';
|
|
19
|
+
import type { AxisValue } from '../../types/plots/axis';
|
|
20
|
+
import type { Series, SeriesProps, DataProps } from '../../types/plots/data/common';
|
|
21
|
+
import type { AxisBasedScalesConfig } from '../../types/plots/props';
|
|
22
|
+
import type { BasePlotStyles } from '../../types/plots/styles/common';
|
|
23
|
+
import type { ValueAnchor } from '../../types/plots/constants';
|
|
24
|
+
import type { LineSegmentStyle } from '../../types/plots/segments/common';
|
|
25
|
+
import type { Marker } from '../../types/markers/common';
|
|
26
|
+
|
|
27
|
+
type Props = BasePlotProps<
|
|
28
|
+
SeriesProps<TData> | DataProps<TData>,
|
|
29
|
+
TData,
|
|
30
|
+
BasePlotStyles,
|
|
31
|
+
LineSegmentStyle,
|
|
32
|
+
Marker,
|
|
33
|
+
AxisBasedScalesConfig<TData>
|
|
34
|
+
>;
|
|
18
35
|
|
|
19
36
|
let {
|
|
20
37
|
width,
|
|
@@ -30,7 +47,7 @@
|
|
|
30
47
|
scales = {},
|
|
31
48
|
margins,
|
|
32
49
|
tooltip = undefined,
|
|
33
|
-
}:
|
|
50
|
+
}: Props = $props();
|
|
34
51
|
|
|
35
52
|
const resolvedSeries = $derived(series ?? buildSeries(data!, x!, y!, z));
|
|
36
53
|
|
|
@@ -57,6 +74,10 @@
|
|
|
57
74
|
styles.values?.format ?? ((v: number, name: string) => `${name} - ${v}`),
|
|
58
75
|
);
|
|
59
76
|
const valAnchor = $derived<ValueAnchor>(styles.values?.anchor ?? 'start');
|
|
77
|
+
// 'outside' is a per-point escape hatch resolved by HoverMarker; line's own
|
|
78
|
+
// value labels already have their own `anchor: 'outside'` concept above,
|
|
79
|
+
// so treat it as unset here.
|
|
80
|
+
const resolvedTextAnchor = $derived(styles.values?.textAnchor === 'outside' ? undefined : styles.values?.textAnchor);
|
|
60
81
|
|
|
61
82
|
const xAcc = $derived(resolveAccessor(resolvedSeries[0]?.x ?? ((d: TData) => d)));
|
|
62
83
|
const yAcc = $derived(resolveAccessor(resolvedSeries[0]?.y ?? ((d: TData) => d)));
|
|
@@ -82,26 +103,32 @@
|
|
|
82
103
|
.map((s, idx) => ({ series: s, lastRow: s.data[s.data.length - 1], seriesIndex: idx }))
|
|
83
104
|
.filter(({ lastRow }) => lastRow !== undefined),
|
|
84
105
|
);
|
|
106
|
+
|
|
107
|
+
const hoverActive = $derived(tooltip != null || hasHoverMarker(markers));
|
|
108
|
+
const hoverStrategy = $derived(resolveHoverStrategy(tooltip?.strategy, markers, 'x'));
|
|
109
|
+
const hoverSync = $derived(resolveHoverSync(tooltip?.sync, markers));
|
|
85
110
|
</script>
|
|
86
111
|
|
|
87
|
-
<
|
|
112
|
+
<BasePlotLayout
|
|
88
113
|
{width}
|
|
89
114
|
{height}
|
|
90
|
-
x={scales.x}
|
|
91
|
-
y={scales.y}
|
|
92
115
|
data={flat}
|
|
93
116
|
getX={xAcc}
|
|
94
117
|
getY={(d) => Number(yAcc(d))}
|
|
95
118
|
{hoverPoints}
|
|
96
119
|
label={(r) => String(yAcc(r))}
|
|
97
120
|
{tooltip}
|
|
98
|
-
{
|
|
99
|
-
|
|
121
|
+
{hoverActive}
|
|
122
|
+
{hoverStrategy}
|
|
123
|
+
{hoverSync}
|
|
100
124
|
{scales}
|
|
101
125
|
{margins}
|
|
102
|
-
|
|
126
|
+
xTickRotate={scales?.x?.tickRotate}
|
|
103
127
|
>
|
|
104
|
-
{#snippet children({ matchedPoints, ruleX, ruleY, impliesRuleX, impliesRuleY })}
|
|
128
|
+
{#snippet children({ matchedPoints, ruleX, ruleY, impliesRuleX, impliesRuleY, numericMargins })}
|
|
129
|
+
<AxisLayout data={flat} getX={xAcc} getY={(d) => Number(yAcc(d))} {width} {height} {numericMargins} {scales} />
|
|
130
|
+
<GridLayout {scales} />
|
|
131
|
+
<RuleLayout {markers} seriesData={resolvedSeries} {matchedPoints} {ruleX} {ruleY} {impliesRuleX} {impliesRuleY}>
|
|
105
132
|
{#each groupedSeries as group, seriesIndex (group.series.name)}
|
|
106
133
|
{@const defaultColor = paletteColor(seriesIndex, cfg.palette)}
|
|
107
134
|
{#each group.visualSegments as seg, i (`${group.series.name}-${i}`)}
|
|
@@ -221,7 +248,7 @@
|
|
|
221
248
|
text={() => fmtVal(Number(yFn(lastRow)), s.name)}
|
|
222
249
|
dx={styles.values?.dx ?? defaultDx}
|
|
223
250
|
dy={styles.values?.dy ?? defaultDy}
|
|
224
|
-
textAnchor={
|
|
251
|
+
textAnchor={resolvedTextAnchor ?? defaultTA}
|
|
225
252
|
lineAnchor={styles.values?.lineAnchor ?? defaultLA}
|
|
226
253
|
lineHeight={styles.values?.lineHeight}
|
|
227
254
|
rotate={styles.values?.rotate}
|
|
@@ -232,5 +259,6 @@
|
|
|
232
259
|
/>
|
|
233
260
|
{/each}
|
|
234
261
|
{/if}
|
|
262
|
+
</RuleLayout>
|
|
235
263
|
{/snippet}
|
|
236
|
-
</
|
|
264
|
+
</BasePlotLayout>
|