@fundar/data-chart-telling 1.18.0 → 1.20.0
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/CHANGELOG.md +53 -0
- package/README.md +2 -1
- package/dist/configuration/config.svelte.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/layout/coordinates/CoordinatesLayout.svelte +3 -1
- package/dist/layout/facet/FacetLayout.svelte +54 -41
- package/dist/layout/geometry/GeometryLayout.svelte +57 -22
- package/dist/layout/geometry/ScaleFreeContext.d.ts +31 -0
- package/dist/layout/geometry/ScaleFreeContext.js +65 -0
- package/dist/layout/geometry/ScaleFreeMarks.svelte +14 -0
- package/dist/layout/geometry/ScaleFreeMarks.svelte.d.ts +7 -0
- package/dist/layout/geometry/ScaleGate.svelte.d.ts +8 -0
- package/dist/layout/geometry/ScaleGate.svelte.js +95 -0
- package/dist/layout/geometry/ScaleGateMarks.svelte +15 -0
- package/dist/layout/geometry/ScaleGateMarks.svelte.d.ts +7 -0
- package/dist/layout/hover/HoverShapes.d.ts +20 -8
- package/dist/layout/hover/HoverShapes.js +119 -59
- package/dist/layout/legend/ContinuousSection.svelte +10 -0
- package/dist/layout/legend/LegendState.svelte.d.ts +13 -1
- package/dist/layout/legend/LegendState.svelte.js +32 -0
- package/dist/layout/margins/Box.d.ts +4 -0
- package/dist/layout/margins/Box.js +14 -0
- package/dist/layout/margins/PlotMargins.svelte.js +26 -1
- package/dist/layout/plot/{Plot.svelte → AbstractPlot.svelte} +83 -6
- package/dist/layout/plot/{Plot.svelte.d.ts → AbstractPlot.svelte.d.ts} +4 -4
- package/dist/layout/plot/PublicPlotContext.d.ts +5 -0
- package/dist/layout/plot/PublicPlotContext.js +7 -0
- package/dist/layout/styles/ValueLabels.d.ts +109 -58
- package/dist/layout/styles/ValueLabels.js +299 -141
- package/dist/markers/MarkerKinds.d.ts +79 -1
- package/dist/markers/MarkerKinds.js +149 -23
- package/dist/markers/area/AreaMarker.svelte +1 -1
- package/dist/markers/band/BandMarker.svelte +2 -1
- package/dist/markers/bar/BarMarker.svelte +8 -6
- package/dist/markers/bollinger/BollingerMarker.svelte +1 -1
- package/dist/markers/box/BoxMarker.svelte +1 -1
- package/dist/markers/dot/DotRadius.d.ts +11 -0
- package/dist/markers/dot/DotRadius.js +21 -0
- package/dist/markers/geo/GeoHoverMarker.svelte +14 -11
- package/dist/markers/labels/CurveLabel.svelte +56 -0
- package/dist/markers/labels/CurveLabel.svelte.d.ts +9 -0
- package/dist/markers/labels/LabelMerge.d.ts +11 -0
- package/dist/markers/labels/LabelMerge.js +87 -0
- package/dist/markers/labels/MarkerLabel.svelte +36 -0
- package/dist/markers/labels/MarkerLabel.svelte.d.ts +10 -0
- package/dist/markers/labels/MarkerLabels.d.ts +52 -0
- package/dist/markers/labels/MarkerLabels.js +97 -0
- package/dist/markers/labels/geometry/BoxGeometry.d.ts +8 -0
- package/dist/markers/labels/geometry/BoxGeometry.js +101 -0
- package/dist/markers/labels/geometry/CurveGeometry.d.ts +34 -0
- package/dist/markers/labels/geometry/CurveGeometry.js +193 -0
- package/dist/markers/labels/geometry/PointGeometry.d.ts +9 -0
- package/dist/markers/labels/geometry/PointGeometry.js +22 -0
- package/dist/markers/labels/layouts/BoxLayout.d.ts +10 -0
- package/dist/markers/labels/layouts/BoxLayout.js +49 -0
- package/dist/markers/labels/layouts/PathLayout.d.ts +11 -0
- package/dist/markers/labels/layouts/PathLayout.js +91 -0
- package/dist/markers/labels/layouts/PointLayout.d.ts +19 -0
- package/dist/markers/labels/layouts/PointLayout.js +94 -0
- package/dist/markers/regression/RegressionMarker.svelte +1 -1
- package/dist/markers/text/Covering.d.ts +13 -0
- package/dist/markers/text/Covering.js +29 -0
- package/dist/markers/text/Declutter.d.ts +24 -3
- package/dist/markers/text/Declutter.js +46 -3
- package/dist/markers/text/TextMarker.svelte +90 -17
- package/dist/markers/text/TextMarker.svelte.d.ts +1 -1
- package/dist/markers/tick/TickMarker.svelte +1 -1
- package/dist/markers/utils/MarkerChannels.d.ts +1 -1
- package/dist/markers/utils/MarkerChannels.js +3 -2
- package/dist/markers/violin/ViolinMarker.svelte +1 -1
- package/dist/markers/waffle/WaffleMarker.svelte +1 -1
- package/dist/phases/context/RowContext.d.ts +2 -0
- package/dist/phases/context/RowContext.js +4 -2
- package/dist/phases/context/rowContextKey.d.ts +2 -0
- package/dist/phases/context/rowContextKey.js +2 -0
- package/dist/phases/markers/MarkerStyles.js +14 -11
- package/dist/phases/markers/MarkersPhase.d.ts +2 -3
- package/dist/phases/markers/MarkersPhase.js +17 -11
- package/dist/phases/sharedScales/SharedStepScales.d.ts +10 -0
- package/dist/phases/sharedScales/SharedStepScales.js +43 -0
- package/dist/phases/statistics/MarkerGrouping.js +5 -32
- package/dist/phases/statistics/MarkerInheritance.d.ts +11 -0
- package/dist/phases/statistics/MarkerInheritance.js +25 -0
- package/dist/phases/statistics/MarkerOrientation.d.ts +26 -0
- package/dist/phases/statistics/MarkerOrientation.js +29 -0
- package/dist/phases/statistics/StatisticsPhase.js +15 -15
- package/dist/phases/transforms/TransformsPhase.js +5 -3
- package/dist/plots/correlation/heatmap/Plot.svelte +2 -2
- package/dist/plots/correlation/heatmap/Plot.svelte.d.ts +0 -1
- package/dist/plots/correlation/heatmap/defaults.js +14 -1
- package/dist/plots/correlation/heatmap/markers.d.ts +0 -6
- package/dist/plots/correlation/heatmap/markers.js +5 -9
- package/dist/plots/correlation/scatter/Plot.svelte +2 -2
- package/dist/plots/correlation/scatter/Plot.svelte.d.ts +0 -1
- package/dist/plots/correlation/scatter/defaults.js +9 -3
- package/dist/plots/correlation/scatter/markers.d.ts +0 -9
- package/dist/plots/correlation/scatter/markers.js +21 -28
- package/dist/plots/distribution/box/BoxSummaries.d.ts +5 -0
- package/dist/plots/distribution/box/BoxSummaries.js +9 -0
- package/dist/plots/distribution/box/Plot.svelte +2 -2
- package/dist/plots/distribution/box/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/box/defaults.js +11 -0
- package/dist/plots/distribution/box/markers.js +10 -1
- package/dist/plots/distribution/density/Plot.svelte +2 -2
- package/dist/plots/distribution/density/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/density/defaults.js +16 -0
- package/dist/plots/distribution/density/markers.js +5 -1
- package/dist/plots/distribution/histogram/Plot.svelte +2 -2
- package/dist/plots/distribution/histogram/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/histogram/defaults.js +16 -11
- package/dist/plots/distribution/histogram/markers.js +3 -3
- package/dist/plots/distribution/pyramid/Plot.svelte +2 -2
- package/dist/plots/distribution/pyramid/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/pyramid/defaults.js +9 -2
- package/dist/plots/distribution/pyramid/markers.d.ts +0 -8
- package/dist/plots/distribution/pyramid/markers.js +6 -16
- package/dist/plots/distribution/violin/Plot.svelte +2 -2
- package/dist/plots/distribution/violin/Plot.svelte.d.ts +0 -1
- package/dist/plots/distribution/violin/defaults.js +11 -0
- package/dist/plots/distribution/violin/markers.js +27 -3
- package/dist/plots/evolution/area/Plot.svelte +2 -2
- package/dist/plots/evolution/area/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/area/defaults.js +4 -7
- package/dist/plots/evolution/area/markers.js +3 -1
- package/dist/plots/evolution/line/Plot.svelte +2 -2
- package/dist/plots/evolution/line/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/line/defaults.js +4 -6
- package/dist/plots/evolution/line/markers.js +3 -1
- package/dist/plots/evolution/slope/Plot.svelte +2 -2
- package/dist/plots/evolution/slope/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/slope/defaults.js +4 -3
- package/dist/plots/evolution/slope/markers.d.ts +4 -3
- package/dist/plots/evolution/slope/markers.js +16 -9
- package/dist/plots/evolution/sparkline/Plot.svelte +2 -2
- package/dist/plots/evolution/sparkline/Plot.svelte.d.ts +0 -1
- package/dist/plots/evolution/sparkline/defaults.js +1 -1
- package/dist/plots/evolution/sparkline/markers.js +3 -1
- package/dist/plots/generic/Plot.svelte +42 -0
- package/dist/plots/generic/Plot.svelte.d.ts +25 -0
- package/dist/plots/generic/defaults.d.ts +4 -0
- package/dist/plots/generic/defaults.js +7 -0
- package/dist/plots/map/geo/Core.svelte +29 -6
- package/dist/plots/map/geo/Plot.svelte +40 -12
- package/dist/plots/map/geo/Plot.svelte.d.ts +0 -1
- package/dist/plots/map/geo/phases/data.d.ts +2 -1
- package/dist/plots/map/geo/phases/data.js +8 -2
- package/dist/plots/map/geo/phases/scales.js +6 -2
- package/dist/plots/map/geo/slices.d.ts +27 -3
- package/dist/plots/map/geo/slices.js +58 -5
- package/dist/plots/part-of-a-whole/treemap/Plot.svelte +2 -2
- package/dist/plots/part-of-a-whole/treemap/Plot.svelte.d.ts +0 -1
- package/dist/plots/part-of-a-whole/treemap/defaults.js +2 -2
- package/dist/plots/ranking/bar/Plot.svelte +2 -2
- package/dist/plots/ranking/bar/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/bar/defaults.js +13 -3
- package/dist/plots/ranking/bar/markers.js +12 -29
- package/dist/plots/ranking/bullet/Plot.svelte +2 -2
- package/dist/plots/ranking/bullet/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/bullet/defaults.js +20 -0
- package/dist/plots/ranking/bullet/markers.js +7 -1
- package/dist/plots/ranking/cleveland/ClevelandMarkers.d.ts +2 -9
- package/dist/plots/ranking/cleveland/ClevelandMarkers.js +65 -47
- package/dist/plots/ranking/cleveland/Plot.svelte +2 -2
- package/dist/plots/ranking/cleveland/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/cleveland/defaults.js +33 -2
- package/dist/plots/ranking/dumbbell/Plot.svelte +2 -2
- package/dist/plots/ranking/dumbbell/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/forest/Plot.svelte +2 -2
- package/dist/plots/ranking/forest/Plot.svelte.d.ts +0 -1
- package/dist/plots/ranking/lollipop/Plot.svelte +2 -2
- package/dist/plots/ranking/lollipop/Plot.svelte.d.ts +0 -1
- package/dist/types/layout/context.d.ts +2 -0
- package/dist/types/layout/plot.d.ts +2 -0
- package/dist/types/layout/styles/bullet.d.ts +4 -1
- package/dist/types/layout/styles/geo.d.ts +3 -3
- package/dist/types/layout/styles/values.d.ts +51 -11
- package/dist/types/markers/axis/area.d.ts +5 -1
- package/dist/types/markers/axis/bar.d.ts +5 -2
- package/dist/types/markers/axis/bollinger.d.ts +2 -1
- package/dist/types/markers/axis/box.d.ts +2 -1
- package/dist/types/markers/axis/cell.d.ts +4 -1
- package/dist/types/markers/axis/line.d.ts +4 -1
- package/dist/types/markers/axis/rect.d.ts +4 -1
- package/dist/types/markers/axis/regression.d.ts +2 -1
- package/dist/types/markers/axis/tick.d.ts +2 -1
- package/dist/types/markers/axis/trail.d.ts +4 -1
- package/dist/types/markers/axis/violin.d.ts +2 -1
- package/dist/types/markers/axis/waffle.d.ts +5 -1
- package/dist/types/markers/basic/dot.d.ts +4 -1
- package/dist/types/markers/basic/text.d.ts +25 -21
- package/dist/types/markers/channels/commonMarkerConfigWithLabel.d.ts +5 -9
- package/dist/types/markers/channels/commonMarkerConfigWithOrientation.d.ts +5 -0
- package/dist/types/markers/channels/commonMarkerConfigWithOrientation.js +1 -0
- package/dist/types/markers/labels/box.d.ts +57 -0
- package/dist/types/markers/labels/box.js +1 -0
- package/dist/types/markers/labels/common.d.ts +15 -0
- package/dist/types/markers/labels/common.js +1 -0
- package/dist/types/markers/labels/path.d.ts +52 -0
- package/dist/types/markers/labels/path.js +1 -0
- package/dist/types/markers/labels/point.d.ts +40 -0
- package/dist/types/markers/labels/point.js +1 -0
- package/dist/types/markers/traits.d.ts +10 -0
- package/dist/types/phases/markers/phase.d.ts +1 -8
- package/dist/types/phases/statistics/phase.d.ts +8 -3
- package/dist/types/phases/styles/phase.d.ts +15 -3
- package/dist/types/phases/transforms/phase.d.ts +2 -0
- package/dist/types/plots/constants.d.ts +0 -12
- package/dist/types/plots/correlation/heatmap/props.d.ts +3 -2
- package/dist/types/plots/correlation/scatter/props.d.ts +3 -2
- package/dist/types/plots/data/geo.d.ts +19 -5
- package/dist/types/plots/distribution/box/props.d.ts +6 -2
- package/dist/types/plots/distribution/density/props.d.ts +2 -1
- package/dist/types/plots/distribution/histogram/props.d.ts +3 -2
- package/dist/types/plots/distribution/pyramid/props.d.ts +3 -2
- package/dist/types/plots/distribution/violin/props.d.ts +4 -1
- package/dist/types/plots/evolution/area/props.d.ts +3 -2
- package/dist/types/plots/evolution/line/props.d.ts +3 -2
- package/dist/types/plots/generic/props.d.ts +16 -0
- package/dist/types/plots/generic/props.js +1 -0
- package/dist/types/plots/generic/state.d.ts +4 -0
- package/dist/types/plots/generic/state.js +1 -0
- package/dist/types/plots/map/geo/props.d.ts +9 -3
- package/dist/types/plots/map/geo/state.d.ts +3 -1
- package/dist/types/plots/part-of-a-whole/treemap/props.d.ts +4 -2
- package/dist/types/plots/ranking/bar/props.d.ts +3 -2
- package/dist/types/plots/ranking/cleveland/props.d.ts +3 -2
- package/dist/types/plots/ranking/dumbbell/props.d.ts +3 -2
- package/dist/types/plots/ranking/forest/props.d.ts +5 -2
- package/dist/types/plots/ranking/lollipop/props.d.ts +3 -2
- package/dist/utils/ConfigEquality.d.ts +11 -0
- package/dist/utils/ConfigEquality.js +37 -0
- package/docs/architecture.md +9 -9
- package/docs/facets.md +12 -0
- package/docs/geo.md +35 -7
- package/docs/legend.md +6 -0
- package/docs/markers.md +2 -4
- package/docs/plots/ranking/bar.md +1 -1
- package/docs/plots/ranking/cleveland.md +1 -1
- package/docs/state.md +1 -1
- package/docs/styles-and-segments.md +1 -14
- package/docs/timeline.md +1 -1
- package/docs/transforms-and-statistics.md +1 -1
- package/docs/value-labels.md +159 -0
- package/examples/BarValues.svelte +1 -1
- package/llms-full.txt +5 -5
- package/llms.txt +1 -0
- package/package.json +3 -1
- package/dist/markers/utils/BoxLabel.d.ts +0 -58
- package/dist/markers/utils/BoxLabel.js +0 -175
- package/dist/markers/utils/MarkerLabel.svelte +0 -33
- package/dist/markers/utils/MarkerLabel.svelte.d.ts +0 -10
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getContext, setContext, type Snippet } from 'svelte';
|
|
3
|
+
import { ScaleGate } from './ScaleGate.svelte';
|
|
4
|
+
import type { SvelteplotContext } from './ScaleFreeContext';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Hands every mark drawn under it to svelteplot's plot behind a gate: the plot works its scales out again when a
|
|
8
|
+
* mark's rows hold something new, not each time the mark copies them. See `ScaleGate`.
|
|
9
|
+
*/
|
|
10
|
+
let { children }: { children: Snippet } = $props();
|
|
11
|
+
|
|
12
|
+
setContext('svelteplot', ScaleGate.of(getContext<SvelteplotContext>('svelteplot')));
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
{@render children()}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
children: Snippet;
|
|
4
|
+
};
|
|
5
|
+
declare const ScaleGateMarks: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type ScaleGateMarks = ReturnType<typeof ScaleGateMarks>;
|
|
7
|
+
export default ScaleGateMarks;
|
|
@@ -16,15 +16,15 @@ export type HoverShapesReach = {
|
|
|
16
16
|
dimmed: (row: Row) => boolean;
|
|
17
17
|
cfg: PlotStylesConfig;
|
|
18
18
|
};
|
|
19
|
-
/** One part of a marker: its rows that the hover styles alike, keyed by how. */
|
|
20
|
-
export type HoverShapesPart<T> = {
|
|
21
|
-
key: string;
|
|
22
|
-
marker: T;
|
|
23
|
-
};
|
|
24
19
|
/**
|
|
25
20
|
* The look the plot's hover markers give the shapes of every marker linked to the hover (`hover: true` or
|
|
26
21
|
* `'style'`): the hovered ones take `active`, the others `others`, each over the shape's own style. A shape
|
|
27
22
|
* the legend dims keeps its own fill and opacities; one the hover cannot reach (hidden, omitted) is untouched.
|
|
23
|
+
*
|
|
24
|
+
* The marker stays one marker over all its rows, whatever is hovered: each style the hover sets is a function of
|
|
25
|
+
* the row that asks the hover how it reaches it. Moving the pointer then only draws the marker's shapes again in
|
|
26
|
+
* their new look - their rows and options do not change, so svelteplot never works the plot's scales out again
|
|
27
|
+
* (it does so from every mark's data and options, and a style with no scale is never read for them).
|
|
28
28
|
*/
|
|
29
29
|
export declare class HoverShapes {
|
|
30
30
|
#private;
|
|
@@ -36,9 +36,21 @@ export declare class HoverShapes {
|
|
|
36
36
|
/** Whether `marker`'s shapes take the hover's styles. */
|
|
37
37
|
static links(marker: object): boolean;
|
|
38
38
|
/**
|
|
39
|
-
* `marker`
|
|
40
|
-
*
|
|
39
|
+
* `marker` with each style the hover sets as a function of the row: the hovered rows take `active`, the others
|
|
40
|
+
* `others`, and while nothing is hovered every row its own style. A marker the hover does not style is returned
|
|
41
|
+
* as it is. `rows` are what the marker draws without `data` of its own.
|
|
42
|
+
*
|
|
43
|
+
* The outline `active` sets is not the shape's own: {@link outline} draws it over every shape, whole.
|
|
44
|
+
*/
|
|
45
|
+
styled<T extends object>(marker: T, rows: readonly unknown[], reach: HoverShapesReach): T;
|
|
46
|
+
/** Whether any rule outlines the hovered shapes: an `active` that sets one of the stroke's fields. */
|
|
47
|
+
get outlines(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The outline of `marker`'s hovered shapes, to draw over every shape of the plot: the marker over its hovered
|
|
50
|
+
* rows only, with no fill, no label and no pointer of its own. A shape is drawn in its marker's order, so its
|
|
51
|
+
* neighbours drawn after it would cover part of its outline - a treemap's tile, a heatmap's cell with no gap.
|
|
52
|
+
* `undefined` when no rule outlines the shapes or nothing of the marker is hovered.
|
|
41
53
|
*/
|
|
42
|
-
|
|
54
|
+
outline<T extends object>(marker: T, rows: readonly unknown[], reach: HoverShapesReach): T | undefined;
|
|
43
55
|
}
|
|
44
56
|
export {};
|
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
import { MarkerStyles } from '../../phases/markers/MarkerStyles';
|
|
2
2
|
import { SERIES_KEY } from '../../phases/transforms/TransformsPhase';
|
|
3
|
+
import { RowStyle } from '../../markers/utils/RowStyle';
|
|
3
4
|
/**
|
|
4
5
|
* The look the plot's hover markers give the shapes of every marker linked to the hover (`hover: true` or
|
|
5
6
|
* `'style'`): the hovered ones take `active`, the others `others`, each over the shape's own style. A shape
|
|
6
7
|
* the legend dims keeps its own fill and opacities; one the hover cannot reach (hidden, omitted) is untouched.
|
|
8
|
+
*
|
|
9
|
+
* The marker stays one marker over all its rows, whatever is hovered: each style the hover sets is a function of
|
|
10
|
+
* the row that asks the hover how it reaches it. Moving the pointer then only draws the marker's shapes again in
|
|
11
|
+
* their new look - their rows and options do not change, so svelteplot never works the plot's scales out again
|
|
12
|
+
* (it does so from every mark's data and options, and a style with no scale is never read for them).
|
|
7
13
|
*/
|
|
8
14
|
export class HoverShapes {
|
|
9
15
|
/** What the legend owns on a dimmed shape. */
|
|
10
|
-
static #LEGEND_KEYS = ['fill', 'fillOpacity', 'strokeOpacity'];
|
|
16
|
+
static #LEGEND_KEYS = new Set(['fill', 'fillOpacity', 'strokeOpacity']);
|
|
17
|
+
/** The fields that draw a shape's outline. */
|
|
18
|
+
static #OUTLINE_KEYS = [
|
|
19
|
+
'stroke',
|
|
20
|
+
'strokeWidth',
|
|
21
|
+
'strokeOpacity',
|
|
22
|
+
'strokeDasharray'
|
|
23
|
+
];
|
|
24
|
+
/** The fields that hold an opacity, fully opaque unless set. */
|
|
25
|
+
static #OPACITY_KEYS = new Set(['fillOpacity', 'strokeOpacity']);
|
|
26
|
+
/** The fields that hold a color: a string is the field of the rows it names, else the color itself. */
|
|
27
|
+
static #COLOR_KEYS = new Set(['fill', 'stroke']);
|
|
11
28
|
/** A shape style's field as a `dot` marker names it. */
|
|
12
29
|
static #DOT_KEYS = {
|
|
13
30
|
fill: 'dotFill',
|
|
@@ -18,8 +35,15 @@ export class HoverShapes {
|
|
|
18
35
|
strokeDasharray: 'dotStrokeDasharray'
|
|
19
36
|
};
|
|
20
37
|
#rules;
|
|
38
|
+
/** The fields any rule sets, in either role. */
|
|
39
|
+
#fields;
|
|
21
40
|
constructor(markers) {
|
|
22
41
|
this.#rules = markers.filter((m) => m.type === 'hover' && !!(m.active || m.others));
|
|
42
|
+
this.#fields = [
|
|
43
|
+
...new Set(this.#rules.flatMap((rule) => [rule.active, rule.others].flatMap((style) => Object.entries(style ?? {})
|
|
44
|
+
.filter(([, value]) => value !== undefined)
|
|
45
|
+
.map(([name]) => name))))
|
|
46
|
+
];
|
|
23
47
|
}
|
|
24
48
|
/** Whether any hover marker restyles shapes. */
|
|
25
49
|
get any() {
|
|
@@ -31,73 +55,109 @@ export class HoverShapes {
|
|
|
31
55
|
return hover === true || hover === 'style';
|
|
32
56
|
}
|
|
33
57
|
/**
|
|
34
|
-
* `marker`
|
|
35
|
-
*
|
|
58
|
+
* `marker` with each style the hover sets as a function of the row: the hovered rows take `active`, the others
|
|
59
|
+
* `others`, and while nothing is hovered every row its own style. A marker the hover does not style is returned
|
|
60
|
+
* as it is. `rows` are what the marker draws without `data` of its own.
|
|
61
|
+
*
|
|
62
|
+
* The outline `active` sets is not the shape's own: {@link outline} draws it over every shape, whole.
|
|
36
63
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
64
|
+
styled(marker, rows, reach) {
|
|
65
|
+
return this.#styled(marker, rows, reach, false);
|
|
66
|
+
}
|
|
67
|
+
/** {@link styled}, with `active`'s outline on the shapes themselves when `outlined`. */
|
|
68
|
+
#styled(marker, rows, reach, outlined) {
|
|
39
69
|
if (!this.any || !HoverShapes.links(marker))
|
|
40
|
-
return
|
|
70
|
+
return marker;
|
|
71
|
+
const own = { ...marker.styles };
|
|
41
72
|
const data = (marker.data ?? rows);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
73
|
+
const isDot = marker.type === 'dot';
|
|
74
|
+
const styles = { ...own };
|
|
75
|
+
for (const field of this.#fields) {
|
|
76
|
+
const name = isDot ? HoverShapes.#DOT_KEYS[field] : field;
|
|
77
|
+
const base = HoverShapes.#reader(field, own[name], data);
|
|
78
|
+
styles[name] = (row, index) => {
|
|
79
|
+
const value = this.#hovered(field, row, index, reach, outlined);
|
|
80
|
+
return value === undefined ? base(row, index) : value;
|
|
81
|
+
};
|
|
47
82
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.map(([key, part]) => ({
|
|
54
|
-
key,
|
|
55
|
-
marker: key === '' ? { ...marker, data: part } : this.#restyled(marker, part, key, reach)
|
|
56
|
-
}));
|
|
83
|
+
return MarkerStyles.restyle({ ...marker, styles }, { cfg: reach.cfg, rows: [...data] });
|
|
84
|
+
}
|
|
85
|
+
/** Whether any rule outlines the hovered shapes: an `active` that sets one of the stroke's fields. */
|
|
86
|
+
get outlines() {
|
|
87
|
+
return this.#rules.some((rule) => HoverShapes.#outlining(rule));
|
|
57
88
|
}
|
|
58
89
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
90
|
+
* The outline of `marker`'s hovered shapes, to draw over every shape of the plot: the marker over its hovered
|
|
91
|
+
* rows only, with no fill, no label and no pointer of its own. A shape is drawn in its marker's order, so its
|
|
92
|
+
* neighbours drawn after it would cover part of its outline - a treemap's tile, a heatmap's cell with no gap.
|
|
93
|
+
* `undefined` when no rule outlines the shapes or nothing of the marker is hovered.
|
|
61
94
|
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return
|
|
95
|
+
outline(marker, rows, reach) {
|
|
96
|
+
if (!this.outlines || !HoverShapes.links(marker))
|
|
97
|
+
return undefined;
|
|
98
|
+
const rules = this.#rules.filter((rule) => HoverShapes.#outlining(rule));
|
|
99
|
+
const data = (marker.data ?? rows).filter((row) => rules.some((rule) => (rule.series === undefined || row?.[SERIES_KEY] === rule.series) &&
|
|
100
|
+
reach.roleOf(row, rule.series) === 'active'));
|
|
101
|
+
if (data.length === 0)
|
|
102
|
+
return undefined;
|
|
103
|
+
const styled = this.#styled(marker, rows, reach, true);
|
|
104
|
+
const isDot = marker.type === 'dot';
|
|
105
|
+
const unfilled = isDot
|
|
106
|
+
? { dotFill: 'none', dotFillOpacity: 0 }
|
|
107
|
+
: { fill: 'none', fillOpacity: 0 };
|
|
108
|
+
const rest = Object.fromEntries(Object.entries(styled).filter(([key]) => key !== 'label' && key !== 'hover' && !key.startsWith('on')));
|
|
109
|
+
return {
|
|
110
|
+
...rest,
|
|
111
|
+
data,
|
|
112
|
+
styles: { ...styled.styles, ...unfilled }
|
|
113
|
+
};
|
|
77
114
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const styles = this.#rules.reduce((merged, rule, i) => {
|
|
82
|
-
const role = key[i];
|
|
83
|
-
const style = role === 'a' ? rule.active : role === 'o' ? rule.others : undefined;
|
|
84
|
-
return {
|
|
85
|
-
...merged,
|
|
86
|
-
...HoverShapes.#named(HoverShapes.#defined(style, dimmed), marker)
|
|
87
|
-
};
|
|
88
|
-
}, { ...marker.styles });
|
|
89
|
-
return MarkerStyles.restyle({ ...marker, data: rows, styles }, { cfg: reach.cfg, rows });
|
|
115
|
+
static #outlining(rule) {
|
|
116
|
+
const active = rule.active ?? {};
|
|
117
|
+
return HoverShapes.#OUTLINE_KEYS.some((key) => active[key] !== undefined);
|
|
90
118
|
}
|
|
91
|
-
/**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
119
|
+
/**
|
|
120
|
+
* What the hover sets `field` to on `row` - the last rule that reaches the row and sets it wins - or `undefined`
|
|
121
|
+
* when none does: the row is not hovered, or the legend dims it and `field` is the legend's. An outline `active`
|
|
122
|
+
* sets is left to the outline drawn over every shape, unless `outlined`.
|
|
123
|
+
*/
|
|
124
|
+
#hovered(field, row, index, reach, outlined) {
|
|
125
|
+
let value;
|
|
126
|
+
let dimmed;
|
|
127
|
+
for (const rule of this.#rules) {
|
|
128
|
+
if (rule.series !== undefined && row?.[SERIES_KEY] !== rule.series)
|
|
129
|
+
continue;
|
|
130
|
+
const role = reach.roleOf(row, rule.series);
|
|
131
|
+
const style = role === 'active' ? rule.active : role === 'other' ? rule.others : undefined;
|
|
132
|
+
const own = style?.[field];
|
|
133
|
+
if (own === undefined)
|
|
134
|
+
continue;
|
|
135
|
+
if (role === 'active' &&
|
|
136
|
+
!outlined &&
|
|
137
|
+
HoverShapes.#OUTLINE_KEYS.includes(field) &&
|
|
138
|
+
HoverShapes.#outlining(rule))
|
|
139
|
+
continue;
|
|
140
|
+
dimmed ??= HoverShapes.#LEGEND_KEYS.has(field) && reach.dimmed(row);
|
|
141
|
+
if (dimmed)
|
|
142
|
+
return undefined;
|
|
143
|
+
value = typeof own === 'function' ? own(row, index) : own;
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
97
146
|
}
|
|
98
|
-
/** `style`
|
|
99
|
-
static #
|
|
100
|
-
|
|
101
|
-
|
|
147
|
+
/** How the shape's own `style` for `field` reads on a row, as the marker would draw it. */
|
|
148
|
+
static #reader(field, style, rows) {
|
|
149
|
+
if (typeof style === 'function')
|
|
150
|
+
return style;
|
|
151
|
+
// An opacity is a channel of the mark, and svelteplot leaves out a row whose channel reads nothing.
|
|
152
|
+
if (style === undefined && HoverShapes.#OPACITY_KEYS.has(field))
|
|
153
|
+
return () => 1;
|
|
154
|
+
if (typeof style !== 'string' || field === 'strokeDasharray')
|
|
155
|
+
return () => style;
|
|
156
|
+
if (HoverShapes.#COLOR_KEYS.has(field)) {
|
|
157
|
+
const color = RowStyle.colorOf(style, rows);
|
|
158
|
+
return color ? (row) => color(row) : () => style;
|
|
159
|
+
}
|
|
160
|
+
// A number (an opacity, a width) a string names the field of.
|
|
161
|
+
return (row) => row?.[style];
|
|
102
162
|
}
|
|
103
163
|
}
|
|
@@ -153,6 +153,16 @@
|
|
|
153
153
|
};
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
+
// What a range set from code (`LegendState.setRange`) takes from this section.
|
|
157
|
+
$effect(() => {
|
|
158
|
+
if (!isInteractive) return;
|
|
159
|
+
interaction.narrowing = {
|
|
160
|
+
mode: section.interactive?.mode ?? 'filter',
|
|
161
|
+
disabledStyle: section.interactive?.disabledStyle ?? { opacity: cfg.legend.disabledOpacity },
|
|
162
|
+
domain: [section.min, section.max]
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
|
|
156
166
|
// Mirrors an externally-set `interaction.range` into lo/hi.
|
|
157
167
|
$effect(() => {
|
|
158
168
|
if (!isInteractive) return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SvelteMap } from 'svelte/reactivity';
|
|
2
|
-
import type { LegendDisabledAction, LegendEntry, LegendExtension, LegendPlot, LegendRange, LegendSection } from '../../types/layout/legend';
|
|
2
|
+
import type { LegendDisabledAction, LegendDisabledStyle, LegendEntry, LegendExtension, LegendPlot, LegendRange, LegendSection } from '../../types/layout/legend';
|
|
3
3
|
/**
|
|
4
4
|
* A figure's legend, shared by every plot and legend under it: what the
|
|
5
5
|
* reader turned off - each series' {@link LegendDisabledAction}, and the
|
|
@@ -14,6 +14,18 @@ export declare class LegendState {
|
|
|
14
14
|
readonly disabled: SvelteMap<string, LegendDisabledAction>;
|
|
15
15
|
/** The narrowed range of the first interactive continuous section, or `null`. */
|
|
16
16
|
range: LegendRange | null;
|
|
17
|
+
/** How narrowing the range acts, and the span it narrows, as the interactive continuous section sets them - for a range set from code to act the same. */
|
|
18
|
+
narrowing: {
|
|
19
|
+
mode: LegendRange["mode"];
|
|
20
|
+
disabledStyle: LegendDisabledStyle;
|
|
21
|
+
domain: [number, number];
|
|
22
|
+
} | null;
|
|
23
|
+
/**
|
|
24
|
+
* Narrows the range as dragging the interactive section's handles would: `[min, max]` in the ramp's own
|
|
25
|
+
* values, or `null` for the whole of it. Its `mode` is the section's (`'filter'` without one), unless given.
|
|
26
|
+
* A span that is not a pair of numbers is left alone.
|
|
27
|
+
*/
|
|
28
|
+
setRange(bounds: [number, number] | null, mode?: LegendRange['mode']): void;
|
|
17
29
|
/** The enclosing figure's legend, or `null` outside one. Call during component init. */
|
|
18
30
|
static current(): LegendState | null;
|
|
19
31
|
/** A new legend, shared with everything below. Call during component init. */
|
|
@@ -19,9 +19,41 @@ export class LegendState {
|
|
|
19
19
|
disabled = new SvelteMap();
|
|
20
20
|
/** The narrowed range of the first interactive continuous section, or `null`. */
|
|
21
21
|
range = $state(null);
|
|
22
|
+
/** How narrowing the range acts, and the span it narrows, as the interactive continuous section sets them - for a range set from code to act the same. */
|
|
23
|
+
narrowing = $state(null);
|
|
22
24
|
#sources = new SvelteMap();
|
|
23
25
|
/** What {@link setOff} last turned off, to turn back on what it no longer lists. */
|
|
24
26
|
#managed = new SvelteMap();
|
|
27
|
+
/**
|
|
28
|
+
* Narrows the range as dragging the interactive section's handles would: `[min, max]` in the ramp's own
|
|
29
|
+
* values, or `null` for the whole of it. Its `mode` is the section's (`'filter'` without one), unless given.
|
|
30
|
+
* A span that is not a pair of numbers is left alone.
|
|
31
|
+
*/
|
|
32
|
+
setRange(bounds, mode) {
|
|
33
|
+
if (bounds === null) {
|
|
34
|
+
this.range = null;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const [a, b] = bounds;
|
|
38
|
+
if (!Number.isFinite(a) || !Number.isFinite(b))
|
|
39
|
+
return;
|
|
40
|
+
const { narrowing } = this;
|
|
41
|
+
const min = Math.min(a, b);
|
|
42
|
+
const max = Math.max(a, b);
|
|
43
|
+
// What spans the whole ramp is no narrowing: the section resets its handles the same way.
|
|
44
|
+
if (narrowing && min <= narrowing.domain[0] && max >= narrowing.domain[1]) {
|
|
45
|
+
this.range = null;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.range = {
|
|
49
|
+
min,
|
|
50
|
+
max,
|
|
51
|
+
mode: mode ?? narrowing?.mode ?? 'filter',
|
|
52
|
+
disabledStyle: narrowing?.disabledStyle ?? {
|
|
53
|
+
opacity: getConfiguration().legend.disabledOpacity
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
25
57
|
/** The enclosing figure's legend, or `null` outside one. Call during component init. */
|
|
26
58
|
static current() {
|
|
27
59
|
return getContext(LEGEND_KEY) ?? null;
|
|
@@ -37,6 +37,10 @@ export declare class Box {
|
|
|
37
37
|
get empty(): boolean;
|
|
38
38
|
/** How far this box reaches out from its origin (the point it sits around), in whole pixels. */
|
|
39
39
|
get reach(): Margins;
|
|
40
|
+
/** Whether this box and `other` share any area. */
|
|
41
|
+
intersects(other: Box): boolean;
|
|
42
|
+
/** Whether this box lies wholly inside `bounds`. */
|
|
43
|
+
inside(bounds: Box): boolean;
|
|
40
44
|
/** This box grown by `px` on every side. */
|
|
41
45
|
pad(px: number): Box;
|
|
42
46
|
/**
|
|
@@ -61,6 +61,20 @@ export class Box {
|
|
|
61
61
|
get reach() {
|
|
62
62
|
return this.overflow(Box.size(0, 0));
|
|
63
63
|
}
|
|
64
|
+
/** Whether this box and `other` share any area. */
|
|
65
|
+
intersects(other) {
|
|
66
|
+
return (this.left < other.right &&
|
|
67
|
+
other.left < this.right &&
|
|
68
|
+
this.top < other.bottom &&
|
|
69
|
+
other.top < this.bottom);
|
|
70
|
+
}
|
|
71
|
+
/** Whether this box lies wholly inside `bounds`. */
|
|
72
|
+
inside(bounds) {
|
|
73
|
+
return (this.left >= bounds.left &&
|
|
74
|
+
this.right <= bounds.right &&
|
|
75
|
+
this.top >= bounds.top &&
|
|
76
|
+
this.bottom <= bounds.bottom);
|
|
77
|
+
}
|
|
64
78
|
/** This box grown by `px` on every side. */
|
|
65
79
|
pad(px) {
|
|
66
80
|
return new Box(this.x - px, this.y - px, this.width + 2 * px, this.height + 2 * px);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { get } from 'svelte/store';
|
|
2
3
|
import { Margins } from './Margins';
|
|
3
4
|
import { Box } from './Box';
|
|
4
5
|
import { CellAlignment } from '../grid/GridAlignment.svelte';
|
|
@@ -27,6 +28,17 @@ export class PlotMargins {
|
|
|
27
28
|
#settled;
|
|
28
29
|
/** What svelteplot's own `<Plot>` lays the plot out by, once {@link follow} is handed it. */
|
|
29
30
|
#plot = $state.raw();
|
|
31
|
+
/** The room svelteplot's axes ask of each side, whether or not it is `'auto'`, once {@link follow} reads it. */
|
|
32
|
+
#autoMargins = $state.raw();
|
|
33
|
+
#auto = $derived.by(() => {
|
|
34
|
+
const maps = this.#autoMargins;
|
|
35
|
+
if (!maps)
|
|
36
|
+
return {};
|
|
37
|
+
return Object.fromEntries(Margins.SIDES.flatMap((side) => {
|
|
38
|
+
const values = [...maps[side].values()];
|
|
39
|
+
return values.length ? [[side, Math.max(...values)]] : [];
|
|
40
|
+
}));
|
|
41
|
+
});
|
|
30
42
|
constructor(inputs) {
|
|
31
43
|
this.#inputs = inputs;
|
|
32
44
|
setContext(PLOT_MARGINS_KEY, this);
|
|
@@ -124,6 +136,10 @@ export class PlotMargins {
|
|
|
124
136
|
*/
|
|
125
137
|
follow(plot) {
|
|
126
138
|
this.#plot = plot;
|
|
139
|
+
const stores = getContext('svelteplot/autoMargins');
|
|
140
|
+
if (stores) {
|
|
141
|
+
this.#autoMargins = Object.fromEntries(Margins.SIDES.map((side) => [side, get(stores[PlotMargins.#AUTO_STORE[side]])]));
|
|
142
|
+
}
|
|
127
143
|
const cell = this.#cell;
|
|
128
144
|
if (!cell)
|
|
129
145
|
return;
|
|
@@ -132,6 +148,12 @@ export class PlotMargins {
|
|
|
132
148
|
cell.report(new Margins(Number(marginTop) || 0, Number(marginRight) || 0, Number(marginBottom) || 0, Number(marginLeft) || 0));
|
|
133
149
|
});
|
|
134
150
|
}
|
|
151
|
+
static #AUTO_STORE = {
|
|
152
|
+
top: 'autoMarginTop',
|
|
153
|
+
right: 'autoMarginRight',
|
|
154
|
+
bottom: 'autoMarginBottom',
|
|
155
|
+
left: 'autoMarginLeft'
|
|
156
|
+
};
|
|
135
157
|
/** The room the `reserve` boxes take past the edges their points can sit on. */
|
|
136
158
|
#reserved = $derived.by(() => this.#inputs.reserve().reduce((room, { box, edges }) => {
|
|
137
159
|
const reach = box.reach;
|
|
@@ -143,7 +165,10 @@ export class PlotMargins {
|
|
|
143
165
|
const settled = this.#settled;
|
|
144
166
|
const { width, height } = this.#inputs.size();
|
|
145
167
|
const growth = this.#measured.max(this.#reserved).min(Margins.half(width, height));
|
|
146
|
-
|
|
168
|
+
// A side grows from at least the room svelteplot's axes take on it: their ticks and title.
|
|
169
|
+
const estimate = this.#inputs
|
|
170
|
+
.estimate()
|
|
171
|
+
.map((value, side) => Math.max(value, this.#auto[side] ?? 0));
|
|
147
172
|
const out = {};
|
|
148
173
|
for (const side of Margins.SIDES) {
|
|
149
174
|
const own = author?.[side];
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
lang="ts"
|
|
3
3
|
generics="TRow extends Record<string, unknown>, TScales extends object, TCore extends PlotCoreBase"
|
|
4
4
|
>
|
|
5
|
-
import type
|
|
5
|
+
import { untrack, type Component } from 'svelte';
|
|
6
6
|
import Figure from '../figure/Figure.svelte';
|
|
7
7
|
import TimelineLayout from '../timeline/TimelineLayout.svelte';
|
|
8
8
|
import FacetLayout from '../facet/FacetLayout.svelte';
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
import { merge } from '../../utils/merge';
|
|
19
19
|
import { Pipeline } from '../../phases/Pipeline';
|
|
20
20
|
import { Slice } from './Slice';
|
|
21
|
+
import { SharedStepScales } from '../../phases/sharedScales/SharedStepScales';
|
|
22
|
+
import { TimelineTime } from '../timeline/TimelineTime';
|
|
23
|
+
import { TimelineSteps } from '../timeline/TimelineSteps';
|
|
24
|
+
import { resolveAccessor } from '../../utils/accessors';
|
|
25
|
+
import { ConfigEquality } from '../../utils/ConfigEquality';
|
|
21
26
|
import { FacetScope } from '../facet/scope';
|
|
22
27
|
import type { TooltipProp } from '../../types/layout/tooltip';
|
|
23
28
|
import type { MarginConfig, PlotChromeConfig } from '../../types/plots/props';
|
|
@@ -130,12 +135,82 @@
|
|
|
130
135
|
return (r: TRow[], f: FacetConfig<TRow> | undefined, legend: LegendState | null) =>
|
|
131
136
|
run.runData(core ?? {}, r, f as never, legend, cfg);
|
|
132
137
|
});
|
|
133
|
-
//
|
|
138
|
+
// What sets a timeline's steps, as values that change only when they do: a moving `progress` makes a new
|
|
139
|
+
// `timeline` object, which these do not follow, so the frame is not run again for it.
|
|
140
|
+
const stepAccessor = $derived(timeline?.accessor);
|
|
141
|
+
const stepDateFormat = $derived(timeline?.dateFormat);
|
|
142
|
+
const stepValues = $derived(timeline?.values);
|
|
143
|
+
const stepMode = $derived(slicing.filterMode);
|
|
144
|
+
|
|
145
|
+
// The plot's own props: one array that is the same object while none of them changed. Rows are compared as
|
|
146
|
+
// the same object, the rest - `segments`, `styles`, `scales` - as they hold, so a parent that builds the
|
|
147
|
+
// same configuration again does not make the data phases run again.
|
|
148
|
+
const ROW_PROPS = new Set(['data', 'series']);
|
|
149
|
+
let propsSeen: unknown[] = [];
|
|
150
|
+
const propsKey = $derived.by(() => {
|
|
151
|
+
const now = core
|
|
152
|
+
? Object.keys(core).flatMap((key) => [key, (core as Record<string, unknown>)[key]])
|
|
153
|
+
: [];
|
|
154
|
+
const same =
|
|
155
|
+
now.length === propsSeen.length &&
|
|
156
|
+
now.every(
|
|
157
|
+
(value, i) =>
|
|
158
|
+
Object.is(value, propsSeen[i]) ||
|
|
159
|
+
(i % 2 === 1 &&
|
|
160
|
+
!ROW_PROPS.has(String(now[i - 1])) &&
|
|
161
|
+
ConfigEquality.same(value, propsSeen[i]))
|
|
162
|
+
);
|
|
163
|
+
if (same) return propsSeen;
|
|
164
|
+
propsSeen = now;
|
|
165
|
+
return now;
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The frame: the run over every row. With a timeline that shows each step's own rows, the domains it
|
|
170
|
+
* shares are the widest any step reaches - a step's rows stack, aggregate or bin among themselves, so the
|
|
171
|
+
* extent over every row at once would be wider than any step's.
|
|
172
|
+
*
|
|
173
|
+
* It is run again when what the runs read changes - the plot's props (`segments` among them), the
|
|
174
|
+
* configuration, the rows, the facet, what sets the steps - and for nothing else: a moving timeline, or
|
|
175
|
+
* a pointer, never makes it run again.
|
|
176
|
+
*/
|
|
134
177
|
let frame: { inputs: unknown[]; state: DataRunState | undefined } | undefined;
|
|
135
|
-
const frameState = $derived.by(() => {
|
|
136
|
-
const inputs = [
|
|
137
|
-
|
|
138
|
-
|
|
178
|
+
const frameState = $derived.by((): DataRunState | undefined => {
|
|
179
|
+
const inputs = [
|
|
180
|
+
propsKey,
|
|
181
|
+
cfg,
|
|
182
|
+
dataRun,
|
|
183
|
+
rows,
|
|
184
|
+
facet,
|
|
185
|
+
stepAccessor,
|
|
186
|
+
stepDateFormat,
|
|
187
|
+
stepValues,
|
|
188
|
+
stepMode
|
|
189
|
+
];
|
|
190
|
+
// Svelte may ask again with the same inputs: the answer is the one it has.
|
|
191
|
+
if (frame?.inputs.every((input, i) => Object.is(input, inputs[i]))) return frame.state;
|
|
192
|
+
const state = untrack(() => {
|
|
193
|
+
if (!dataRun || !rows) return undefined;
|
|
194
|
+
const whole = dataRun(rows, facet, null);
|
|
195
|
+
if (stepAccessor === undefined) return whole;
|
|
196
|
+
const reader = new TimelineTime(stepDateFormat);
|
|
197
|
+
const get = resolveAccessor<TRow>(stepAccessor as never) as (row: TRow) => unknown;
|
|
198
|
+
const timeOf = (row: TRow) => reader.toTime(get(row));
|
|
199
|
+
const named = stepValues?.map((v) => reader.toTime(v)).filter((t) => t !== undefined);
|
|
200
|
+
const steps = TimelineSteps.of(named, rows, (row) => timeOf(row) ?? NaN);
|
|
201
|
+
const perStep = steps.values
|
|
202
|
+
.filter((step) => !Number.isNaN(step))
|
|
203
|
+
.map((step) => {
|
|
204
|
+
// A row without a step shows in every one.
|
|
205
|
+
const shown = rows.filter((row) => {
|
|
206
|
+
const at = timeOf(row);
|
|
207
|
+
return at === undefined || TimelineSteps.matches(at, step, stepMode);
|
|
208
|
+
});
|
|
209
|
+
return dataRun(shown, facet, null).sharedScales;
|
|
210
|
+
});
|
|
211
|
+
const bands = (whole as { axes?: { bands?: string[] } }).axes?.bands ?? [];
|
|
212
|
+
return { ...whole, sharedScales: SharedStepScales.over(whole.sharedScales, bands, perStep) };
|
|
213
|
+
});
|
|
139
214
|
frame = { inputs, state };
|
|
140
215
|
return state;
|
|
141
216
|
});
|
|
@@ -216,6 +291,7 @@
|
|
|
216
291
|
? FacetPanels.buildPanelState(panels, slicing.panelKey(place) ?? '')
|
|
217
292
|
: undefined,
|
|
218
293
|
facet: place,
|
|
294
|
+
time,
|
|
219
295
|
keep: slicing.keep({ time, facet: place })
|
|
220
296
|
})}
|
|
221
297
|
</HoverScope>
|
|
@@ -260,6 +336,7 @@
|
|
|
260
336
|
height: h,
|
|
261
337
|
tooltip: tooltipConfig,
|
|
262
338
|
scales: slicing.timelineScales<TScales>(sharedScales),
|
|
339
|
+
time,
|
|
263
340
|
keep: slicing.keep({ time })
|
|
264
341
|
})}
|
|
265
342
|
{/if}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Component } from 'svelte';
|
|
2
2
|
import { Pipeline } from '../../phases/Pipeline';
|
|
3
3
|
import type { TooltipProp } from '../../types/layout/tooltip';
|
|
4
4
|
import type { MarginConfig, PlotChromeConfig } from '../../types/plots/props';
|
|
@@ -45,6 +45,6 @@ interface $$IsomorphicComponent {
|
|
|
45
45
|
<TRow extends Record<string, unknown>, TScales extends object, TCore extends PlotCoreBase>(internal: unknown, props: ReturnType<__sveltets_Render<TRow, TScales, TCore>['props']> & {}): ReturnType<__sveltets_Render<TRow, TScales, TCore>['exports']>;
|
|
46
46
|
z_$$bindings?: ReturnType<__sveltets_Render<any, any, any>['bindings']>;
|
|
47
47
|
}
|
|
48
|
-
declare const
|
|
49
|
-
type
|
|
50
|
-
export default
|
|
48
|
+
declare const AbstractPlot: $$IsomorphicComponent;
|
|
49
|
+
type AbstractPlot<TRow extends Record<string, unknown>, TScales extends object, TCore extends PlotCoreBase> = InstanceType<typeof AbstractPlot<TRow, TScales, TCore>>;
|
|
50
|
+
export default AbstractPlot;
|
|
@@ -53,6 +53,11 @@ export declare class PublicLegend {
|
|
|
53
53
|
get entries(): LegendEntry[];
|
|
54
54
|
/** The range its continuous section narrows to, or `null`. */
|
|
55
55
|
get range(): LegendRange | null;
|
|
56
|
+
/**
|
|
57
|
+
* Narrows the continuous section to `[min, max]` as dragging its handles would, or resets it with `null`:
|
|
58
|
+
* its plots filter or rescale to it. `mode` is the section's own unless given.
|
|
59
|
+
*/
|
|
60
|
+
setRange(range: [number, number] | null, mode?: LegendRange['mode']): void;
|
|
56
61
|
/** The series that are turned off. */
|
|
57
62
|
get off(): string[];
|
|
58
63
|
isOff(series: string): boolean;
|
|
@@ -73,6 +73,13 @@ export class PublicLegend {
|
|
|
73
73
|
get range() {
|
|
74
74
|
return this.#state.range;
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Narrows the continuous section to `[min, max]` as dragging its handles would, or resets it with `null`:
|
|
78
|
+
* its plots filter or rescale to it. `mode` is the section's own unless given.
|
|
79
|
+
*/
|
|
80
|
+
setRange(range, mode) {
|
|
81
|
+
this.#state.setRange(range, mode);
|
|
82
|
+
}
|
|
76
83
|
/** The series that are turned off. */
|
|
77
84
|
get off() {
|
|
78
85
|
return [...this.#state.disabled.keys()];
|