@fjader/svelte 0.2.3 → 0.2.5
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 +3 -1
- package/dist/animation/EntranceGate.d.ts +52 -0
- package/dist/animation/EntranceGate.js +93 -0
- package/dist/animation/TransitionClock.d.ts +61 -30
- package/dist/animation/TransitionClock.js +67 -29
- package/dist/animation/transition-log.d.ts +41 -0
- package/dist/animation/transition-log.js +57 -0
- package/dist/components/axes/AxisBottom.svelte +27 -8
- package/dist/components/axes/AxisBottom.svelte.d.ts +10 -0
- package/dist/components/axes/AxisCenter.svelte +4 -2
- package/dist/components/axes/AxisLeft.svelte +81 -10
- package/dist/components/axes/AxisLeft.svelte.d.ts +17 -0
- package/dist/components/axes/BandAxisTicks.svelte +4 -3
- package/dist/components/axes/axis-title.d.ts +30 -0
- package/dist/components/axes/axis-title.js +77 -0
- package/dist/components/charts/ChartCell.svelte +33 -6
- package/dist/components/charts/ChartCell.svelte.d.ts +9 -0
- package/dist/components/charts/ChartContainer.svelte +55 -5
- package/dist/components/charts/ChartContainer.svelte.d.ts +14 -1
- package/dist/components/charts/ChartHover.svelte.d.ts +14 -0
- package/dist/components/charts/ChartHover.svelte.js +22 -0
- package/dist/components/charts/ChartVisibility.svelte.d.ts +43 -0
- package/dist/components/charts/ChartVisibility.svelte.js +67 -0
- package/dist/components/guides/Grid.svelte +12 -1
- package/dist/components/guides/legend/ContinuousColorLegend.svelte +7 -1
- package/dist/components/guides/legend/OrdinalColorLegend.svelte +8 -5
- package/dist/components/marks/AreaMarkX.svelte +18 -4
- package/dist/components/marks/AreaMarkY.svelte +18 -4
- package/dist/components/marks/BarMarkX.svelte +20 -4
- package/dist/components/marks/BarMarkY.svelte +20 -4
- package/dist/components/marks/DotsMark.svelte +8 -3
- package/dist/components/marks/LineMark.svelte +13 -6
- package/dist/components/marks/ParallelCoordinatesMark.svelte +11 -2
- package/dist/components/marks/ParallelCoordinatesMark.svelte.d.ts +4 -0
- package/dist/components/marks/RectMark.svelte +8 -3
- package/dist/components/marks/RectXMark.svelte +9 -3
- package/dist/components/marks/RectYMark.svelte +9 -3
- package/dist/components/marks/RuleMarkX.svelte +31 -25
- package/dist/components/marks/RuleMarkY.svelte +31 -25
- package/dist/components/marks/TextMark.svelte +52 -14
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.d.ts +22 -1
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.js +579 -66
- package/dist/components/marks/lifecycle/domain-queries.d.ts +13 -2
- package/dist/components/marks/lifecycle/domain-queries.js +43 -11
- package/dist/components/marks/lifecycle/domain-registration.d.ts +6 -1
- package/dist/components/marks/lifecycle/domain-registration.js +17 -20
- package/dist/components/marks/lifecycle/other-rows.svelte.d.ts +112 -0
- package/dist/components/marks/lifecycle/other-rows.svelte.js +193 -0
- package/dist/components/marks/lifecycle/other-split.d.ts +80 -0
- package/dist/components/marks/lifecycle/other-split.js +112 -0
- package/dist/components/marks/lifecycle/query-builder.d.ts +53 -3
- package/dist/components/marks/lifecycle/query-builder.js +46 -23
- package/dist/components/marks/utils/MarkColor.svelte.d.ts +3 -1
- package/dist/components/marks/utils/MarkColor.svelte.js +33 -3
- package/dist/components/marks/utils/MarkSeries.svelte.d.ts +14 -1
- package/dist/components/marks/utils/MarkSeries.svelte.js +25 -1
- package/dist/components/marks/utils/MarkSize.svelte.js +4 -0
- package/dist/components/marks/utils/reactive-config.d.ts +1 -1
- package/dist/components/marks/utils/reactive-config.js +9 -0
- package/dist/components/marks/utils/tooltip-helpers.d.ts +4 -1
- package/dist/components/marks/utils/tooltip-helpers.js +2 -1
- package/dist/components/rendering/Areas.svelte +57 -19
- package/dist/components/rendering/Areas.svelte.d.ts +12 -0
- package/dist/components/rendering/BaseGPURenderer.svelte.d.ts +3 -1
- package/dist/components/rendering/BaseGPURenderer.svelte.js +4 -2
- package/dist/components/rendering/Dots.svelte +23 -3
- package/dist/components/rendering/Dots.svelte.d.ts +6 -0
- package/dist/components/rendering/GridLine.svelte +13 -1
- package/dist/components/rendering/GridLine.svelte.d.ts +5 -0
- package/dist/components/rendering/Lines.svelte +48 -13
- package/dist/components/rendering/Lines.svelte.d.ts +12 -0
- package/dist/components/rendering/ParallelLines.svelte +5 -5
- package/dist/components/rendering/Rects.svelte +164 -30
- package/dist/components/rendering/Rects.svelte.d.ts +23 -2
- package/dist/components/rendering/RuleX.svelte +1 -1
- package/dist/components/rendering/RuleY.svelte +1 -1
- package/dist/components/rendering/WebGPUCanvas.svelte +4 -2
- package/dist/components/rendering/activity-reads.d.ts +47 -12
- package/dist/components/rendering/activity-reads.js +61 -19
- package/dist/components/rendering/uniform-sizes.d.ts +1 -1
- package/dist/components/rendering/uniform-sizes.js +1 -1
- package/dist/config/ChartConfig.svelte.d.ts +10 -1
- package/dist/config/ChartConfig.svelte.js +17 -0
- package/dist/gpu/GPUCoordinator.svelte.d.ts +31 -1
- package/dist/gpu/GPUCoordinator.svelte.js +164 -7
- package/dist/gpu/MorphedChannels.d.ts +11 -28
- package/dist/gpu/MorphedChannels.js +72 -8
- package/dist/gpu/ScaleTemplateSystem.d.ts +20 -2
- package/dist/gpu/ScaleTemplateSystem.js +83 -6
- package/dist/index.d.ts +19 -4
- package/dist/index.js +22 -4
- package/dist/interactors/Interval1D.svelte +6 -1
- package/dist/interactors/Interval2D.svelte +6 -1
- package/dist/interactors/ParallelAxisSource.svelte +10 -1
- package/dist/interactors/Toggle.svelte +32 -3
- package/dist/interactors/Tooltip.svelte +138 -41
- package/dist/interactors/TooltipManager.svelte.d.ts +20 -5
- package/dist/interactors/TooltipManager.svelte.js +46 -12
- package/dist/interactors/other-tooltip.d.ts +16 -0
- package/dist/interactors/other-tooltip.js +22 -0
- package/dist/query-engine/CrossfilterSelection.svelte.d.ts +4 -2
- package/dist/query-engine/CrossfilterSelection.svelte.js +2 -0
- package/dist/query-engine/FieldActivity.svelte.d.ts +49 -1
- package/dist/query-engine/FieldActivity.svelte.js +175 -5
- package/dist/query-engine/FilterGroup.svelte.d.ts +23 -1
- package/dist/query-engine/FilterGroup.svelte.js +43 -3
- package/dist/query-engine/FilterGroupRegistry.svelte.d.ts +31 -3
- package/dist/query-engine/FilterGroupRegistry.svelte.js +62 -15
- package/dist/query-engine/MarkHandle.svelte.d.ts +28 -1
- package/dist/query-engine/MarkHandle.svelte.js +33 -1
- package/dist/query-engine/QueryEngine.d.ts +225 -5
- package/dist/query-engine/QueryEngine.js +697 -47
- package/dist/query-engine/categorical-identity.d.ts +41 -0
- package/dist/query-engine/categorical-identity.js +145 -65
- package/dist/query-engine/debug/query-log.d.ts +39 -0
- package/dist/query-engine/debug/query-log.js +90 -0
- package/dist/query-engine/duckdb.d.ts +55 -8
- package/dist/query-engine/duckdb.js +82 -30
- package/dist/query-engine/index.d.ts +7 -4
- package/dist/query-engine/index.js +3 -3
- package/dist/query-engine/preagg/BuildQueue.d.ts +33 -13
- package/dist/query-engine/preagg/BuildQueue.js +51 -15
- package/dist/query-engine/preagg/Preagg.d.ts +46 -3
- package/dist/query-engine/preagg/Preagg.js +159 -31
- package/dist/query-engine/preagg/plan.d.ts +33 -1
- package/dist/query-engine/preagg/plan.js +158 -14
- package/dist/query-engine/sliced-lane.d.ts +108 -0
- package/dist/query-engine/sliced-lane.js +299 -0
- package/dist/query-engine/source-routing.d.ts +106 -0
- package/dist/query-engine/source-routing.js +189 -0
- package/dist/query-engine/toggle-predicate.d.ts +21 -0
- package/dist/query-engine/toggle-predicate.js +29 -1
- package/dist/scales/ActivityTable.d.ts +5 -1
- package/dist/scales/ActivityTable.js +12 -3
- package/dist/scales/BandScaleState.svelte.d.ts +22 -9
- package/dist/scales/BandScaleState.svelte.js +39 -21
- package/dist/scales/ChartScales.svelte.d.ts +3 -0
- package/dist/scales/ChartScales.svelte.js +26 -8
- package/dist/scales/ColorScaleState.svelte.d.ts +18 -2
- package/dist/scales/ColorScaleState.svelte.js +138 -26
- package/dist/scales/LinearScaleState.svelte.d.ts +7 -10
- package/dist/scales/LinearScaleState.svelte.js +21 -39
- package/dist/scales/ScaleGeneration.svelte.d.ts +48 -0
- package/dist/scales/ScaleGeneration.svelte.js +42 -0
- package/dist/scales/ScaleRegistry.svelte.js +3 -1
- package/dist/scales/SlotTransition.d.ts +15 -1
- package/dist/scales/SlotTransition.js +33 -4
- package/dist/scales/TimeScaleState.svelte.d.ts +7 -3
- package/dist/scales/TimeScaleState.svelte.js +7 -7
- package/dist/scales/color-utils.d.ts +0 -3
- package/dist/scales/color-utils.js +0 -3
- package/dist/scales/entered.d.ts +8 -0
- package/dist/scales/entered.js +10 -0
- package/dist/spec/LazyQueryEngine.js +2 -19
- package/dist/spec/MarkRegistry.d.ts +3 -1
- package/dist/spec/MarkRegistry.js +13 -1
- package/dist/spec/PlotFromSpec.svelte +1 -0
- package/dist/spec/export.js +11 -2
- package/dist/spec/types.d.ts +43 -13
- package/dist/sql/bin.d.ts +25 -0
- package/dist/sql/bin.js +108 -5
- package/dist/theme.css +5 -4
- package/dist/transforms/TransformCompiler.d.ts +47 -2
- package/dist/transforms/TransformCompiler.js +70 -1
- package/dist/transforms/index.js +176 -42
- package/dist/types.d.ts +177 -2
- package/package.json +4 -3
|
@@ -1,16 +1,42 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { hasEntered } from '../../scales/entered';
|
|
2
3
|
import { getContext } from 'svelte';
|
|
3
4
|
import type { ChartContext } from '../../types';
|
|
4
5
|
import type { BandScaleState } from '../../scales/BandScaleState.svelte';
|
|
5
6
|
import BandAxisTicks from './BandAxisTicks.svelte';
|
|
6
7
|
import type { ContinuousScaleState } from '../../types';
|
|
8
|
+
import { categoryLabel } from '../../query-engine/categorical-identity';
|
|
9
|
+
import { clearTitleOffset, sameTicks, textWidth } from './axis-title';
|
|
7
10
|
|
|
8
11
|
interface Props {
|
|
9
12
|
ticksNumber?: number;
|
|
10
13
|
tickFormat?: ((value: unknown) => string) | null;
|
|
14
|
+
/**
|
|
15
|
+
* Draw the scale's label as the axis title (default). `false` draws none; the
|
|
16
|
+
* label still names the scale, so charts sharing it still link their zoom.
|
|
17
|
+
*/
|
|
18
|
+
title?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* How far left of the axis the title sits, in px (default 32), or `'auto'`:
|
|
21
|
+
* clear of the widest tick label, as far as the chart's left margin allows.
|
|
22
|
+
*/
|
|
23
|
+
titleOffset?: number | 'auto';
|
|
24
|
+
/**
|
|
25
|
+
* Where the title goes: `'side'` (default), rotated beside the tick labels, or
|
|
26
|
+
* `'top'`, horizontal above the plot at the axis. `'top'` cannot meet the tick
|
|
27
|
+
* labels, so it needs no `titleOffset` and no room in the left margin; it takes
|
|
28
|
+
* the space above the plot (the chart's top margin).
|
|
29
|
+
*/
|
|
30
|
+
titlePlacement?: 'side' | 'top';
|
|
11
31
|
}
|
|
12
32
|
|
|
13
|
-
let {
|
|
33
|
+
let {
|
|
34
|
+
ticksNumber = 5,
|
|
35
|
+
tickFormat = null,
|
|
36
|
+
title = true,
|
|
37
|
+
titleOffset = 32,
|
|
38
|
+
titlePlacement = 'side'
|
|
39
|
+
}: Props = $props();
|
|
14
40
|
const c = getContext<ChartContext>('chart');
|
|
15
41
|
|
|
16
42
|
// Propagate custom format to scale state once it exists (for MarginLabel, tooltips, etc.)
|
|
@@ -20,9 +46,10 @@
|
|
|
20
46
|
(s as ContinuousScaleState).setCustomFormat(tickFormat);
|
|
21
47
|
});
|
|
22
48
|
|
|
23
|
-
// Continuous scales (linear, time): use scaleState.getTicks()
|
|
49
|
+
// Continuous scales (linear, time): use scaleState.getTicks(). None until the
|
|
50
|
+
// scale has entered: before that its domain is a placeholder.
|
|
24
51
|
const continuousTicks = $derived(
|
|
25
|
-
c.yScaleState?.getTicks ? c.yScaleState.getTicks(ticksNumber) : []
|
|
52
|
+
c.yScaleState?.getTicks && hasEntered(c.yScaleState) ? c.yScaleState.getTicks(ticksNumber) : []
|
|
26
53
|
);
|
|
27
54
|
|
|
28
55
|
// Band scales: the categories on screen NOW, at their current fractional slots,
|
|
@@ -34,6 +61,43 @@
|
|
|
34
61
|
|
|
35
62
|
// Unified formatter interface - all scale states have tickFormat()
|
|
36
63
|
const tickFormatter = $derived(c.yScaleState?.tickFormat ? c.yScaleState.tickFormat() : String);
|
|
64
|
+
|
|
65
|
+
// The title's distance from the axis. Measured only for 'auto', from the labels
|
|
66
|
+
// drawn (each distinct string once, then cached). It follows the widest label
|
|
67
|
+
// seen on this scale and never moves back in: pan and zoom change the ticks
|
|
68
|
+
// all the time, and a title that followed them would jitter. Taking the
|
|
69
|
+
// maximum is idempotent, so re-evaluating this changes nothing.
|
|
70
|
+
let widestSeen = 0;
|
|
71
|
+
let widestScale: unknown = null;
|
|
72
|
+
// The ticks and formatter the widest was last taken from: a pan that only moves
|
|
73
|
+
// the same ticks measures (and formats) nothing.
|
|
74
|
+
let measuredTicks: ArrayLike<unknown> | null = null;
|
|
75
|
+
let measuredFormatter: unknown = null;
|
|
76
|
+
const titleX = $derived.by(() => {
|
|
77
|
+
if (titleOffset !== 'auto') return titleOffset;
|
|
78
|
+
const scale = c.yScaleState;
|
|
79
|
+
if (scale !== widestScale) {
|
|
80
|
+
widestScale = scale;
|
|
81
|
+
widestSeen = 0;
|
|
82
|
+
measuredTicks = null;
|
|
83
|
+
}
|
|
84
|
+
const band = c.scaleTypes?.y === 'band';
|
|
85
|
+
const ticks: ArrayLike<unknown> = band ? bandTicks : continuousTicks;
|
|
86
|
+
if (!sameTicks(measuredTicks, ticks) || (!band && measuredFormatter !== tickFormatter)) {
|
|
87
|
+
if (band) {
|
|
88
|
+
for (const tick of bandTicks) {
|
|
89
|
+
widestSeen = Math.max(widestSeen, textWidth(String(categoryLabel(tick.value))));
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
for (const tick of continuousTicks) {
|
|
93
|
+
widestSeen = Math.max(widestSeen, textWidth(String(tickFormatter(tick))));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
measuredTicks = ticks;
|
|
97
|
+
measuredFormatter = tickFormatter;
|
|
98
|
+
}
|
|
99
|
+
return clearTitleOffset(widestSeen, c.margin.left);
|
|
100
|
+
});
|
|
37
101
|
</script>
|
|
38
102
|
|
|
39
103
|
{#if c.isReady && c.scaleTypes}
|
|
@@ -47,10 +111,6 @@
|
|
|
47
111
|
{tickFormatter(tick)}
|
|
48
112
|
</text>
|
|
49
113
|
{/each}
|
|
50
|
-
|
|
51
|
-
<text text-anchor="middle" transform={`translate(-32, ${c.innerHeight / 2}) rotate(-90)`}>
|
|
52
|
-
{c.yLabel}
|
|
53
|
-
</text>
|
|
54
114
|
{:else if c.scaleTypes.y === 'band' && c.yScale}
|
|
55
115
|
<BandAxisTicks
|
|
56
116
|
scale={c.yScaleState as BandScaleState}
|
|
@@ -60,10 +120,21 @@
|
|
|
60
120
|
dir={-1}
|
|
61
121
|
textAnchor="end"
|
|
62
122
|
/>
|
|
123
|
+
{/if}
|
|
63
124
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
125
|
+
{#if title && c.yScale}
|
|
126
|
+
{#if titlePlacement === 'top'}
|
|
127
|
+
<text text-anchor="start" x={0} y={-18}>
|
|
128
|
+
{c.yLabel}
|
|
129
|
+
</text>
|
|
130
|
+
{:else}
|
|
131
|
+
<text
|
|
132
|
+
text-anchor="middle"
|
|
133
|
+
transform={`translate(${-titleX}, ${c.innerHeight / 2}) rotate(-90)`}
|
|
134
|
+
>
|
|
135
|
+
{c.yLabel}
|
|
136
|
+
</text>
|
|
137
|
+
{/if}
|
|
67
138
|
{/if}
|
|
68
139
|
</g>
|
|
69
140
|
{/if}
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
interface Props {
|
|
2
2
|
ticksNumber?: number;
|
|
3
3
|
tickFormat?: ((value: unknown) => string) | null;
|
|
4
|
+
/**
|
|
5
|
+
* Draw the scale's label as the axis title (default). `false` draws none; the
|
|
6
|
+
* label still names the scale, so charts sharing it still link their zoom.
|
|
7
|
+
*/
|
|
8
|
+
title?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* How far left of the axis the title sits, in px (default 32), or `'auto'`:
|
|
11
|
+
* clear of the widest tick label, as far as the chart's left margin allows.
|
|
12
|
+
*/
|
|
13
|
+
titleOffset?: number | 'auto';
|
|
14
|
+
/**
|
|
15
|
+
* Where the title goes: `'side'` (default), rotated beside the tick labels, or
|
|
16
|
+
* `'top'`, horizontal above the plot at the axis. `'top'` cannot meet the tick
|
|
17
|
+
* labels, so it needs no `titleOffset` and no room in the left margin; it takes
|
|
18
|
+
* the space above the plot (the chart's top margin).
|
|
19
|
+
*/
|
|
20
|
+
titlePlacement?: 'side' | 'top';
|
|
4
21
|
}
|
|
5
22
|
declare const AxisLeft: import("svelte").Component<Props, {}, "">;
|
|
6
23
|
type AxisLeft = ReturnType<typeof AxisLeft>;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import type { ChartContext } from '../../types';
|
|
5
5
|
import { categoryLabel } from '../../query-engine/categorical-identity';
|
|
6
6
|
import type { FilterGroupRegistry } from '../../query-engine/FilterGroupRegistry.svelte';
|
|
7
|
+
import { dimsBySelection } from '../rendering/activity-reads';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* The labels on a band axis, wherever that axis is drawn.
|
|
@@ -71,8 +72,8 @@
|
|
|
71
72
|
if (!chart || !filterGroups) return [];
|
|
72
73
|
const indices: number[] = [];
|
|
73
74
|
for (const entry of chart.config.entries.values()) {
|
|
74
|
-
// A 'filter' mark never dims; its labels follow it.
|
|
75
|
-
if (entry.selectionResponse
|
|
75
|
+
// A 'filter' or 'ignore' mark never dims; its labels follow it.
|
|
76
|
+
if (!dimsBySelection(entry.selectionResponse)) continue;
|
|
76
77
|
const index = filterGroups.get(entry.selection).index;
|
|
77
78
|
if (!indices.includes(index)) indices.push(index);
|
|
78
79
|
}
|
|
@@ -105,7 +106,7 @@
|
|
|
105
106
|
</script>
|
|
106
107
|
|
|
107
108
|
{#each ticks as tick (tick.key)}
|
|
108
|
-
{@const pos = scale.tickPosition(tick.key, rangeSize
|
|
109
|
+
{@const pos = scale.tickPosition(tick.key, rangeSize)}
|
|
109
110
|
<g opacity={opacityOf(tick)}>
|
|
110
111
|
{#if axis === 'x'}
|
|
111
112
|
<line x1={pos} x2={pos} y1={base} y2={tickEnd} />
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an axis title sits relative to its tick labels.
|
|
3
|
+
*
|
|
4
|
+
* The left axis puts its tick labels right-anchored 9px from the axis line and
|
|
5
|
+
* its title, rotated, to the left of them. A fixed offset is right for short
|
|
6
|
+
* labels and runs into wide ones (`40,000`, a band name). `'auto'` places the
|
|
7
|
+
* title clear of the widest label, within the margin the chart gave it.
|
|
8
|
+
*/
|
|
9
|
+
/** The title's offset when nothing says otherwise, and the least `'auto'` uses. */
|
|
10
|
+
export declare const DEFAULT_TITLE_OFFSET = 32;
|
|
11
|
+
/**
|
|
12
|
+
* The width of a tick label in px. Measured on a canvas, once per distinct
|
|
13
|
+
* string (a band axis has the same labels frame after frame); 6px a character
|
|
14
|
+
* where there is no document. An estimate by design: the page's own font can
|
|
15
|
+
* differ a little, and CLEARANCE covers that.
|
|
16
|
+
*/
|
|
17
|
+
export declare function textWidth(text: string): number;
|
|
18
|
+
/**
|
|
19
|
+
* How far left of the axis line the title's baseline goes, clear of a label
|
|
20
|
+
* `widest` px wide: never less than the default, and never so far that its body
|
|
21
|
+
* leaves the margin. A margin too narrow for the labels leaves them overlapping,
|
|
22
|
+
* and only a wider margin fixes that.
|
|
23
|
+
*/
|
|
24
|
+
export declare function clearTitleOffset(widest: number, marginLeft: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Whether two tick lists are the same ticks: equal values, or band ticks of the
|
|
27
|
+
* same key. A loop with no allocation, to skip re-measuring labels when a pan
|
|
28
|
+
* moved the ticks but did not change them.
|
|
29
|
+
*/
|
|
30
|
+
export declare function sameTicks(a: ArrayLike<unknown> | null, b: ArrayLike<unknown>): boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an axis title sits relative to its tick labels.
|
|
3
|
+
*
|
|
4
|
+
* The left axis puts its tick labels right-anchored 9px from the axis line and
|
|
5
|
+
* its title, rotated, to the left of them. A fixed offset is right for short
|
|
6
|
+
* labels and runs into wide ones (`40,000`, a band name). `'auto'` places the
|
|
7
|
+
* title clear of the widest label, within the margin the chart gave it.
|
|
8
|
+
*/
|
|
9
|
+
/** Where the tick labels end, from the axis line: AxisLeft's text x and BandAxisTicks' labelGap. */
|
|
10
|
+
const TICK_GAP = 9;
|
|
11
|
+
/** Between the widest label and the title's baseline; the title's descenders reach into it. */
|
|
12
|
+
const CLEARANCE = 12;
|
|
13
|
+
/** A rotated title's glyphs sit on the far side of its baseline, away from the axis. */
|
|
14
|
+
const TITLE_BODY = 10;
|
|
15
|
+
/** The title's offset when nothing says otherwise, and the least `'auto'` uses. */
|
|
16
|
+
export const DEFAULT_TITLE_OFFSET = 32;
|
|
17
|
+
const FONT = '10px system-ui, sans-serif';
|
|
18
|
+
const FALLBACK_CHAR_WIDTH = 6;
|
|
19
|
+
const CACHE_LIMIT = 2000;
|
|
20
|
+
let context;
|
|
21
|
+
const widths = new Map();
|
|
22
|
+
/**
|
|
23
|
+
* The width of a tick label in px. Measured on a canvas, once per distinct
|
|
24
|
+
* string (a band axis has the same labels frame after frame); 6px a character
|
|
25
|
+
* where there is no document. An estimate by design: the page's own font can
|
|
26
|
+
* differ a little, and CLEARANCE covers that.
|
|
27
|
+
*/
|
|
28
|
+
export function textWidth(text) {
|
|
29
|
+
const known = widths.get(text);
|
|
30
|
+
if (known !== undefined)
|
|
31
|
+
return known;
|
|
32
|
+
if (context === undefined) {
|
|
33
|
+
context =
|
|
34
|
+
typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d');
|
|
35
|
+
if (context)
|
|
36
|
+
context.font = FONT;
|
|
37
|
+
}
|
|
38
|
+
const width = context ? context.measureText(text).width : text.length * FALLBACK_CHAR_WIDTH;
|
|
39
|
+
if (widths.size >= CACHE_LIMIT)
|
|
40
|
+
widths.clear();
|
|
41
|
+
widths.set(text, width);
|
|
42
|
+
return width;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* How far left of the axis line the title's baseline goes, clear of a label
|
|
46
|
+
* `widest` px wide: never less than the default, and never so far that its body
|
|
47
|
+
* leaves the margin. A margin too narrow for the labels leaves them overlapping,
|
|
48
|
+
* and only a wider margin fixes that.
|
|
49
|
+
*/
|
|
50
|
+
export function clearTitleOffset(widest, marginLeft) {
|
|
51
|
+
const wanted = Math.max(TICK_GAP + widest + CLEARANCE, DEFAULT_TITLE_OFFSET);
|
|
52
|
+
return Math.max(0, Math.min(wanted, marginLeft - TITLE_BODY));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether two tick lists are the same ticks: equal values, or band ticks of the
|
|
56
|
+
* same key. A loop with no allocation, to skip re-measuring labels when a pan
|
|
57
|
+
* moved the ticks but did not change them.
|
|
58
|
+
*/
|
|
59
|
+
export function sameTicks(a, b) {
|
|
60
|
+
if (!a || a.length !== b.length)
|
|
61
|
+
return false;
|
|
62
|
+
for (let i = 0; i < b.length; i++) {
|
|
63
|
+
const x = a[i];
|
|
64
|
+
const y = b[i];
|
|
65
|
+
if (x === y)
|
|
66
|
+
continue;
|
|
67
|
+
if (typeof x === 'object' &&
|
|
68
|
+
typeof y === 'object' &&
|
|
69
|
+
x !== null &&
|
|
70
|
+
y !== null &&
|
|
71
|
+
x.key !== undefined &&
|
|
72
|
+
x.key === y.key)
|
|
73
|
+
continue;
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { ScaleGeneration } from '../../scales/ScaleGeneration.svelte';
|
|
3
|
+
import type { ChartVisibility } from './ChartVisibility.svelte';
|
|
4
|
+
import type { ChartHover } from './ChartHover.svelte';
|
|
2
5
|
import { setContext, getContext, onMount } from 'svelte';
|
|
3
6
|
import type { Snippet } from 'svelte';
|
|
4
7
|
import { ChartLayout } from '../../layout/ChartLayout.svelte';
|
|
@@ -43,6 +46,12 @@
|
|
|
43
46
|
height?: number;
|
|
44
47
|
clipPadding?: number;
|
|
45
48
|
scales: ChartScales;
|
|
49
|
+
/** The chart's scale replacements; owned by the container, which outlives its ChartScales. */
|
|
50
|
+
scaleGeneration: ScaleGeneration;
|
|
51
|
+
/** Whether any of the chart's cells is on screen; this cell reports into it. */
|
|
52
|
+
chartVisibility: ChartVisibility;
|
|
53
|
+
/** Whether the pointer is over any of the chart's cells; this cell reports into it. */
|
|
54
|
+
chartHover: ChartHover;
|
|
46
55
|
chartConfig: ChartConfig;
|
|
47
56
|
facetingProps?: FacetingProps;
|
|
48
57
|
gpuCoordinator: GPUCoordinator;
|
|
@@ -63,6 +72,9 @@
|
|
|
63
72
|
height = 250,
|
|
64
73
|
clipPadding = 0,
|
|
65
74
|
scales,
|
|
75
|
+
scaleGeneration,
|
|
76
|
+
chartVisibility,
|
|
77
|
+
chartHover,
|
|
66
78
|
chartConfig,
|
|
67
79
|
facetingProps = {
|
|
68
80
|
fx: null,
|
|
@@ -222,12 +234,15 @@
|
|
|
222
234
|
};
|
|
223
235
|
});
|
|
224
236
|
|
|
225
|
-
// --- Viewport visibility
|
|
226
|
-
const removeVisibilityCallback = gpuCoordinator.setVisibilityCallback(
|
|
227
|
-
layout.chartId,
|
|
228
|
-
(_visible) => {}
|
|
237
|
+
// --- Viewport visibility: this cell reports into the chart's ---
|
|
238
|
+
const removeVisibilityCallback = gpuCoordinator.setVisibilityCallback(layout.chartId, (visible) =>
|
|
239
|
+
chartVisibility.set(layout.chartId, visible)
|
|
229
240
|
);
|
|
230
|
-
onMount(() =>
|
|
241
|
+
onMount(() => () => {
|
|
242
|
+
removeVisibilityCallback();
|
|
243
|
+
chartVisibility.remove(layout.chartId);
|
|
244
|
+
chartHover.set(layout.chartId, false);
|
|
245
|
+
});
|
|
231
246
|
onMount(() => () => hoverSettle.leave());
|
|
232
247
|
|
|
233
248
|
// --- Scale readiness effect ---
|
|
@@ -358,6 +373,16 @@
|
|
|
358
373
|
get xScaleState() {
|
|
359
374
|
return scales?.xScaleState;
|
|
360
375
|
},
|
|
376
|
+
get scaleGeneration() {
|
|
377
|
+
return scaleGeneration.value;
|
|
378
|
+
},
|
|
379
|
+
get visible() {
|
|
380
|
+
return chartVisibility.visible;
|
|
381
|
+
},
|
|
382
|
+
shownElsewhere: (scale) => chartVisibility.shownElsewhere(scale),
|
|
383
|
+
get hovered() {
|
|
384
|
+
return chartHover.hovered;
|
|
385
|
+
},
|
|
361
386
|
get yScaleState() {
|
|
362
387
|
return scales?.yScaleState;
|
|
363
388
|
},
|
|
@@ -546,6 +571,7 @@
|
|
|
546
571
|
}
|
|
547
572
|
|
|
548
573
|
function handleChartPointerEnter(event: PointerEvent) {
|
|
574
|
+
chartHover.set(layout.chartId, true);
|
|
549
575
|
activateSources();
|
|
550
576
|
hoverSettle.enter();
|
|
551
577
|
refreshSvgOrigin();
|
|
@@ -564,6 +590,7 @@
|
|
|
564
590
|
}
|
|
565
591
|
|
|
566
592
|
function handleChartPointerLeave() {
|
|
593
|
+
chartHover.set(layout.chartId, false);
|
|
567
594
|
pointerInside = false;
|
|
568
595
|
pointerOverSvg = false;
|
|
569
596
|
hoverSettle.leave();
|
|
@@ -897,7 +924,7 @@
|
|
|
897
924
|
if (overBrush) {
|
|
898
925
|
tooltipManager?.updatePosition(null, null);
|
|
899
926
|
} else {
|
|
900
|
-
tooltipManager?.
|
|
927
|
+
tooltipManager?.updatePointerClient(x + svgLeft, y + svgTop);
|
|
901
928
|
tooltipManager?.updatePosition(
|
|
902
929
|
scales.xScaleState?.currentDataPoint,
|
|
903
930
|
scales.yScaleState?.currentDataPoint
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { ScaleGeneration } from '../../scales/ScaleGeneration.svelte';
|
|
2
|
+
import type { ChartVisibility } from './ChartVisibility.svelte';
|
|
3
|
+
import type { ChartHover } from './ChartHover.svelte';
|
|
1
4
|
import type { Snippet } from 'svelte';
|
|
2
5
|
import type { Margin } from '../../types';
|
|
3
6
|
import type { FieldRef } from '../../types';
|
|
@@ -27,6 +30,12 @@ interface Props {
|
|
|
27
30
|
height?: number;
|
|
28
31
|
clipPadding?: number;
|
|
29
32
|
scales: ChartScales;
|
|
33
|
+
/** The chart's scale replacements; owned by the container, which outlives its ChartScales. */
|
|
34
|
+
scaleGeneration: ScaleGeneration;
|
|
35
|
+
/** Whether any of the chart's cells is on screen; this cell reports into it. */
|
|
36
|
+
chartVisibility: ChartVisibility;
|
|
37
|
+
/** Whether the pointer is over any of the chart's cells; this cell reports into it. */
|
|
38
|
+
chartHover: ChartHover;
|
|
30
39
|
chartConfig: ChartConfig;
|
|
31
40
|
facetingProps?: FacetingProps;
|
|
32
41
|
gpuCoordinator: GPUCoordinator;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { ScaleGeneration } from '../../scales/ScaleGeneration.svelte';
|
|
3
|
+
import { ChartVisibility } from './ChartVisibility.svelte';
|
|
4
|
+
import { ChartHover } from './ChartHover.svelte';
|
|
2
5
|
import { setContext, getContext, onDestroy } from 'svelte';
|
|
3
6
|
import type { Snippet } from 'svelte';
|
|
4
7
|
import { ChartLayout } from '../../layout/ChartLayout.svelte';
|
|
@@ -6,8 +9,8 @@
|
|
|
6
9
|
import { ChartScales } from '../../scales/ChartScales.svelte';
|
|
7
10
|
import { ChartConfig } from '../../config';
|
|
8
11
|
import { getGPUContext } from '../../gpu';
|
|
9
|
-
import type { ScaleRegistry } from '../../scales/ScaleRegistry.svelte';
|
|
10
|
-
import type { ChartContext, FieldRef } from '../../types';
|
|
12
|
+
import type { ScaleRegistry, AnyScaleState } from '../../scales/ScaleRegistry.svelte';
|
|
13
|
+
import type { ChartContext, EntranceMode, FieldRef } from '../../types';
|
|
11
14
|
import type { BandScaleState } from '../../scales/BandScaleState.svelte';
|
|
12
15
|
import type { DimValue } from '../../query-engine/categorical-identity';
|
|
13
16
|
import { identityKeyFor } from '../../query-engine/identity-key';
|
|
@@ -78,6 +81,19 @@
|
|
|
78
81
|
clipPadding?: number;
|
|
79
82
|
useXSelection?: boolean;
|
|
80
83
|
useYSelection?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The tooltip's colours against the color-scheme the chart inherits:
|
|
86
|
+
* `contrast` is the opposite scheme (dark on a light page), `follow` the
|
|
87
|
+
* same. Unset, the nearest `data-fjader-tooltip` ancestor decides, else
|
|
88
|
+
* contrast. `--fjader-tooltip-bg`/`-text` set by the app override both.
|
|
89
|
+
*/
|
|
90
|
+
tooltipScheme?: 'contrast' | 'follow';
|
|
91
|
+
/**
|
|
92
|
+
* How the marks enter when data first draws: 'auto' grows bars and
|
|
93
|
+
* areas from 0 and fades the rest, 'fade' fades everything, 'none'
|
|
94
|
+
* shows them at once. Reduced motion turns 'auto' into 'fade'.
|
|
95
|
+
*/
|
|
96
|
+
entrance?: EntranceMode;
|
|
81
97
|
}
|
|
82
98
|
|
|
83
99
|
let {
|
|
@@ -94,6 +110,7 @@
|
|
|
94
110
|
interactors = undefined,
|
|
95
111
|
legend = undefined,
|
|
96
112
|
legendPosition = 'top',
|
|
113
|
+
entrance = 'auto',
|
|
97
114
|
wheelInteraction = {
|
|
98
115
|
dwellTimeMs: 250,
|
|
99
116
|
momentumThreshold: 150,
|
|
@@ -108,7 +125,8 @@
|
|
|
108
125
|
margin: marginOverride = {},
|
|
109
126
|
clipPadding = 0,
|
|
110
127
|
useXSelection = false,
|
|
111
|
-
useYSelection = false
|
|
128
|
+
useYSelection = false,
|
|
129
|
+
tooltipScheme = undefined
|
|
112
130
|
}: Props = $props();
|
|
113
131
|
|
|
114
132
|
const defaultMargin = { top: 30, right: 50, bottom: 35, left: 75 };
|
|
@@ -204,6 +222,19 @@
|
|
|
204
222
|
|
|
205
223
|
// --- ChartScales ---
|
|
206
224
|
let scales = $state<ChartScales | null>(null);
|
|
225
|
+
// Survives `scales` being recreated: see ScaleGeneration.
|
|
226
|
+
const scaleGeneration = new ScaleGeneration(() => scales);
|
|
227
|
+
// Whether any cell is on screen; the cells report into it.
|
|
228
|
+
const chartVisibility = new ChartVisibility(
|
|
229
|
+
gpuCoordinator
|
|
230
|
+
? {
|
|
231
|
+
chartsUsing: (scale) => scaleRegistry.chartsUsing(scale as AnyScaleState),
|
|
232
|
+
isChartVisible: (chartId) => gpuCoordinator.isChartVisible(chartId)
|
|
233
|
+
}
|
|
234
|
+
: null
|
|
235
|
+
);
|
|
236
|
+
// Whether the pointer is over any cell; the cells report into it.
|
|
237
|
+
const chartHover = new ChartHover();
|
|
207
238
|
|
|
208
239
|
// Queue for scale registrations that arrive before ChartScales is created.
|
|
209
240
|
// Marks mount synchronously during render, but ChartScales is created in an
|
|
@@ -239,7 +270,8 @@
|
|
|
239
270
|
xDisableZoom,
|
|
240
271
|
yDisableZoom,
|
|
241
272
|
useXSelection,
|
|
242
|
-
useYSelection
|
|
273
|
+
useYSelection,
|
|
274
|
+
entranceGate: chartConfig.entrance
|
|
243
275
|
});
|
|
244
276
|
|
|
245
277
|
// Replay any scale registrations that were queued before scales existed
|
|
@@ -266,9 +298,11 @@
|
|
|
266
298
|
|
|
267
299
|
// --- ChartConfig (reactive configuration store) ---
|
|
268
300
|
const chartConfig = new ChartConfig();
|
|
301
|
+
onDestroy(() => chartConfig.entrance.destroy());
|
|
269
302
|
|
|
270
303
|
// Register chart-level props for palette overrides
|
|
271
304
|
chartConfig.registerChart({
|
|
305
|
+
entrance: () => entrance,
|
|
272
306
|
marginTop: () => cellMargin.top,
|
|
273
307
|
marginRight: () => cellMargin.right,
|
|
274
308
|
marginBottom: () => cellMargin.bottom,
|
|
@@ -365,6 +399,16 @@
|
|
|
365
399
|
get xScaleState() {
|
|
366
400
|
return scales?.xScaleState;
|
|
367
401
|
},
|
|
402
|
+
get scaleGeneration() {
|
|
403
|
+
return scaleGeneration.value;
|
|
404
|
+
},
|
|
405
|
+
get visible() {
|
|
406
|
+
return chartVisibility.visible;
|
|
407
|
+
},
|
|
408
|
+
shownElsewhere: (scale) => chartVisibility.shownElsewhere(scale),
|
|
409
|
+
get hovered() {
|
|
410
|
+
return chartHover.hovered;
|
|
411
|
+
},
|
|
368
412
|
get yScaleState() {
|
|
369
413
|
return scales?.yScaleState;
|
|
370
414
|
},
|
|
@@ -452,7 +496,7 @@
|
|
|
452
496
|
setContext('legend-position', () => legendPosition);
|
|
453
497
|
</script>
|
|
454
498
|
|
|
455
|
-
<div class="figure-container" bind:clientWidth={layout.width}>
|
|
499
|
+
<div class="figure-container" bind:clientWidth={layout.width} data-fjader-tooltip={tooltipScheme}>
|
|
456
500
|
{#if legend && legendPosition === 'top'}
|
|
457
501
|
<div
|
|
458
502
|
class="legend-container legend-top"
|
|
@@ -485,6 +529,9 @@
|
|
|
485
529
|
facetLabel={String(categoryLabel(cat))}
|
|
486
530
|
margin={{ top: 20, right: 10, bottom: 35, left: 55 }}
|
|
487
531
|
{scales}
|
|
532
|
+
{scaleGeneration}
|
|
533
|
+
{chartVisibility}
|
|
534
|
+
{chartHover}
|
|
488
535
|
{chartConfig}
|
|
489
536
|
{facetingProps}
|
|
490
537
|
{gpuCoordinator}
|
|
@@ -507,6 +554,9 @@
|
|
|
507
554
|
margin={cellMargin}
|
|
508
555
|
{clipPadding}
|
|
509
556
|
{scales}
|
|
557
|
+
{scaleGeneration}
|
|
558
|
+
{chartVisibility}
|
|
559
|
+
{chartHover}
|
|
510
560
|
{chartConfig}
|
|
511
561
|
{facetingProps}
|
|
512
562
|
{gpuCoordinator}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { Margin } from '../../types';
|
|
3
|
-
import type { FieldRef } from '../../types';
|
|
3
|
+
import type { EntranceMode, FieldRef } from '../../types';
|
|
4
4
|
import type { DimValue } from '../../query-engine/categorical-identity';
|
|
5
5
|
interface Props {
|
|
6
6
|
xLabel?: string | null;
|
|
@@ -69,6 +69,19 @@ interface Props {
|
|
|
69
69
|
clipPadding?: number;
|
|
70
70
|
useXSelection?: boolean;
|
|
71
71
|
useYSelection?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* The tooltip's colours against the color-scheme the chart inherits:
|
|
74
|
+
* `contrast` is the opposite scheme (dark on a light page), `follow` the
|
|
75
|
+
* same. Unset, the nearest `data-fjader-tooltip` ancestor decides, else
|
|
76
|
+
* contrast. `--fjader-tooltip-bg`/`-text` set by the app override both.
|
|
77
|
+
*/
|
|
78
|
+
tooltipScheme?: 'contrast' | 'follow';
|
|
79
|
+
/**
|
|
80
|
+
* How the marks enter when data first draws: 'auto' grows bars and
|
|
81
|
+
* areas from 0 and fades the rest, 'fade' fades everything, 'none'
|
|
82
|
+
* shows them at once. Reduced motion turns 'auto' into 'fade'.
|
|
83
|
+
*/
|
|
84
|
+
entrance?: EntranceMode;
|
|
72
85
|
}
|
|
73
86
|
declare const ChartContainer: import("svelte").Component<Props, {}, "">;
|
|
74
87
|
type ChartContainer = ReturnType<typeof ChartContainer>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the pointer is over any of a chart's cells: hover intent, for work
|
|
3
|
+
* worth doing only when someone is about to hover a mark, such as writing its
|
|
4
|
+
* tooltip table.
|
|
5
|
+
*
|
|
6
|
+
* Owned by the chart container, which in facet mode holds the marks for many
|
|
7
|
+
* cells, as ChartVisibility is. Cells report pointer enter and leave.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ChartHover {
|
|
10
|
+
#private;
|
|
11
|
+
set(cellId: string, hovered: boolean): void;
|
|
12
|
+
/** True while the pointer is over any cell. Reactive. */
|
|
13
|
+
get hovered(): boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
2
|
+
/**
|
|
3
|
+
* Whether the pointer is over any of a chart's cells: hover intent, for work
|
|
4
|
+
* worth doing only when someone is about to hover a mark, such as writing its
|
|
5
|
+
* tooltip table.
|
|
6
|
+
*
|
|
7
|
+
* Owned by the chart container, which in facet mode holds the marks for many
|
|
8
|
+
* cells, as ChartVisibility is. Cells report pointer enter and leave.
|
|
9
|
+
*/
|
|
10
|
+
export class ChartHover {
|
|
11
|
+
#cells = new SvelteSet();
|
|
12
|
+
set(cellId, hovered) {
|
|
13
|
+
if (hovered)
|
|
14
|
+
this.#cells.add(cellId);
|
|
15
|
+
else
|
|
16
|
+
this.#cells.delete(cellId);
|
|
17
|
+
}
|
|
18
|
+
/** True while the pointer is over any cell. Reactive. */
|
|
19
|
+
get hovered() {
|
|
20
|
+
return this.#cells.size > 0;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** What `shownElsewhere` asks: which charts draw a scale, and which are visible. */
|
|
2
|
+
export interface ChartVisibilityPeers {
|
|
3
|
+
chartsUsing(scale: object): readonly string[];
|
|
4
|
+
isChartVisible(chartId: string): boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Whether any of a chart's cells is on screen, for its marks to stop
|
|
8
|
+
* re-querying while it is not (see MarkHandle.active).
|
|
9
|
+
*
|
|
10
|
+
* Owned by the chart container, which in facet mode holds the marks for many
|
|
11
|
+
* cells: the marks stay active while any cell is visible. Each cell reports
|
|
12
|
+
* what the GPU coordinator's IntersectionObserver and page visibility say
|
|
13
|
+
* about it; the observer has a 200 px margin, so a chart counts as visible
|
|
14
|
+
* just before it scrolls in. A cell that has not reported counts as visible,
|
|
15
|
+
* as it does for the coordinator, so nothing is held back before the first
|
|
16
|
+
* report.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ChartVisibility {
|
|
19
|
+
#private;
|
|
20
|
+
constructor(peers?: ChartVisibilityPeers | null);
|
|
21
|
+
/** A cell's visibility changed. */
|
|
22
|
+
set(cellId: string, visible: boolean): void;
|
|
23
|
+
/** A cell unmounted. */
|
|
24
|
+
remove(cellId: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* True while any cell is visible, or none has reported. Reactive: it reads
|
|
27
|
+
* the SvelteMap. A getter, not a derived, since a chart has few cells.
|
|
28
|
+
*/
|
|
29
|
+
get visible(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Whether a chart other than this one is visible and draws `scale`, so
|
|
32
|
+
* that changing the scale moves something in view. A chart catching up on
|
|
33
|
+
* its return snaps its own parts but springs a scale like this: the chart
|
|
34
|
+
* being watched moves through the scale, as it would for any change.
|
|
35
|
+
*
|
|
36
|
+
* Asked when a result lands, not when it was sent: visibility changes
|
|
37
|
+
* during a scroll. "Visible" is the coordinator's: it includes the 200 px
|
|
38
|
+
* margin, so a chart in the margin, which nobody sees yet, still counts and
|
|
39
|
+
* keeps the spring. Untracked: a point-in-time answer, asked from inside
|
|
40
|
+
* effects that must not re-run when a cell scrolls.
|
|
41
|
+
*/
|
|
42
|
+
shownElsewhere(scale: object): boolean;
|
|
43
|
+
}
|