@fjader/svelte 0.2.4 → 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 +1 -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 +4 -2
- package/dist/components/axes/AxisCenter.svelte +4 -2
- package/dist/components/axes/AxisLeft.svelte +4 -2
- package/dist/components/axes/BandAxisTicks.svelte +3 -2
- package/dist/components/charts/ChartCell.svelte +32 -5
- package/dist/components/charts/ChartCell.svelte.d.ts +9 -0
- package/dist/components/charts/ChartContainer.svelte +45 -3
- package/dist/components/charts/ChartContainer.svelte.d.ts +7 -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/marks/AreaMarkX.svelte +16 -4
- package/dist/components/marks/AreaMarkY.svelte +16 -4
- package/dist/components/marks/BarMarkX.svelte +7 -3
- package/dist/components/marks/BarMarkY.svelte +7 -3
- package/dist/components/marks/DotsMark.svelte +6 -3
- package/dist/components/marks/LineMark.svelte +11 -8
- package/dist/components/marks/ParallelCoordinatesMark.svelte +7 -2
- package/dist/components/marks/ParallelCoordinatesMark.svelte.d.ts +2 -0
- package/dist/components/marks/RectMark.svelte +6 -3
- package/dist/components/marks/RectXMark.svelte +7 -3
- package/dist/components/marks/RectYMark.svelte +7 -3
- package/dist/components/marks/RuleMarkX.svelte +30 -26
- package/dist/components/marks/RuleMarkY.svelte +30 -26
- package/dist/components/marks/TextMark.svelte +44 -5
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.d.ts +16 -0
- package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.js +398 -54
- package/dist/components/marks/lifecycle/domain-queries.d.ts +11 -2
- package/dist/components/marks/lifecycle/domain-queries.js +33 -6
- package/dist/components/marks/lifecycle/domain-registration.d.ts +6 -1
- package/dist/components/marks/lifecycle/domain-registration.js +15 -14
- package/dist/components/marks/lifecycle/other-rows.svelte.d.ts +9 -1
- package/dist/components/marks/lifecycle/other-rows.svelte.js +2 -2
- package/dist/components/marks/lifecycle/query-builder.d.ts +27 -2
- package/dist/components/marks/lifecycle/query-builder.js +23 -20
- 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 +3 -0
- 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 +1 -1
- 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 +51 -11
- package/dist/components/rendering/Rects.svelte.d.ts +16 -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 +41 -24
- package/dist/components/rendering/activity-reads.js +54 -31
- 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 +7 -0
- 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 -2
- package/dist/gpu/MorphedChannels.js +33 -11
- package/dist/gpu/ScaleTemplateSystem.d.ts +20 -2
- package/dist/gpu/ScaleTemplateSystem.js +58 -2
- package/dist/index.d.ts +17 -4
- package/dist/index.js +19 -4
- package/dist/interactors/TooltipManager.svelte.js +14 -5
- 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 +2 -3
- package/dist/query-engine/FieldActivity.svelte.js +1 -2
- 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 +671 -41
- package/dist/query-engine/categorical-identity.d.ts +34 -8
- package/dist/query-engine/categorical-identity.js +138 -73
- 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 +28 -1
- package/dist/query-engine/preagg/plan.js +128 -8
- 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/scales/BandScaleState.svelte.d.ts +9 -1
- package/dist/scales/BandScaleState.svelte.js +16 -5
- 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 +41 -13
- package/dist/sql/bin.d.ts +25 -0
- package/dist/sql/bin.js +108 -5
- package/dist/transforms/TransformCompiler.d.ts +10 -0
- package/dist/transforms/TransformCompiler.js +26 -0
- package/dist/transforms/index.js +144 -24
- package/dist/types.d.ts +136 -2
- package/package.json +2 -2
|
@@ -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';
|
|
@@ -85,6 +88,12 @@
|
|
|
85
88
|
* contrast. `--fjader-tooltip-bg`/`-text` set by the app override both.
|
|
86
89
|
*/
|
|
87
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;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
let {
|
|
@@ -101,6 +110,7 @@
|
|
|
101
110
|
interactors = undefined,
|
|
102
111
|
legend = undefined,
|
|
103
112
|
legendPosition = 'top',
|
|
113
|
+
entrance = 'auto',
|
|
104
114
|
wheelInteraction = {
|
|
105
115
|
dwellTimeMs: 250,
|
|
106
116
|
momentumThreshold: 150,
|
|
@@ -212,6 +222,19 @@
|
|
|
212
222
|
|
|
213
223
|
// --- ChartScales ---
|
|
214
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();
|
|
215
238
|
|
|
216
239
|
// Queue for scale registrations that arrive before ChartScales is created.
|
|
217
240
|
// Marks mount synchronously during render, but ChartScales is created in an
|
|
@@ -247,7 +270,8 @@
|
|
|
247
270
|
xDisableZoom,
|
|
248
271
|
yDisableZoom,
|
|
249
272
|
useXSelection,
|
|
250
|
-
useYSelection
|
|
273
|
+
useYSelection,
|
|
274
|
+
entranceGate: chartConfig.entrance
|
|
251
275
|
});
|
|
252
276
|
|
|
253
277
|
// Replay any scale registrations that were queued before scales existed
|
|
@@ -274,9 +298,11 @@
|
|
|
274
298
|
|
|
275
299
|
// --- ChartConfig (reactive configuration store) ---
|
|
276
300
|
const chartConfig = new ChartConfig();
|
|
301
|
+
onDestroy(() => chartConfig.entrance.destroy());
|
|
277
302
|
|
|
278
303
|
// Register chart-level props for palette overrides
|
|
279
304
|
chartConfig.registerChart({
|
|
305
|
+
entrance: () => entrance,
|
|
280
306
|
marginTop: () => cellMargin.top,
|
|
281
307
|
marginRight: () => cellMargin.right,
|
|
282
308
|
marginBottom: () => cellMargin.bottom,
|
|
@@ -373,6 +399,16 @@
|
|
|
373
399
|
get xScaleState() {
|
|
374
400
|
return scales?.xScaleState;
|
|
375
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
|
+
},
|
|
376
412
|
get yScaleState() {
|
|
377
413
|
return scales?.yScaleState;
|
|
378
414
|
},
|
|
@@ -493,6 +529,9 @@
|
|
|
493
529
|
facetLabel={String(categoryLabel(cat))}
|
|
494
530
|
margin={{ top: 20, right: 10, bottom: 35, left: 55 }}
|
|
495
531
|
{scales}
|
|
532
|
+
{scaleGeneration}
|
|
533
|
+
{chartVisibility}
|
|
534
|
+
{chartHover}
|
|
496
535
|
{chartConfig}
|
|
497
536
|
{facetingProps}
|
|
498
537
|
{gpuCoordinator}
|
|
@@ -515,6 +554,9 @@
|
|
|
515
554
|
margin={cellMargin}
|
|
516
555
|
{clipPadding}
|
|
517
556
|
{scales}
|
|
557
|
+
{scaleGeneration}
|
|
558
|
+
{chartVisibility}
|
|
559
|
+
{chartHover}
|
|
518
560
|
{chartConfig}
|
|
519
561
|
{facetingProps}
|
|
520
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;
|
|
@@ -76,6 +76,12 @@ interface Props {
|
|
|
76
76
|
* contrast. `--fjader-tooltip-bg`/`-text` set by the app override both.
|
|
77
77
|
*/
|
|
78
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;
|
|
79
85
|
}
|
|
80
86
|
declare const ChartContainer: import("svelte").Component<Props, {}, "">;
|
|
81
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
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
3
|
+
/**
|
|
4
|
+
* Whether any of a chart's cells is on screen, for its marks to stop
|
|
5
|
+
* re-querying while it is not (see MarkHandle.active).
|
|
6
|
+
*
|
|
7
|
+
* Owned by the chart container, which in facet mode holds the marks for many
|
|
8
|
+
* cells: the marks stay active while any cell is visible. Each cell reports
|
|
9
|
+
* what the GPU coordinator's IntersectionObserver and page visibility say
|
|
10
|
+
* about it; the observer has a 200 px margin, so a chart counts as visible
|
|
11
|
+
* just before it scrolls in. A cell that has not reported counts as visible,
|
|
12
|
+
* as it does for the coordinator, so nothing is held back before the first
|
|
13
|
+
* report.
|
|
14
|
+
*/
|
|
15
|
+
export class ChartVisibility {
|
|
16
|
+
#cells = new SvelteMap();
|
|
17
|
+
#peers;
|
|
18
|
+
constructor(peers = null) {
|
|
19
|
+
this.#peers = peers;
|
|
20
|
+
}
|
|
21
|
+
/** A cell's visibility changed. */
|
|
22
|
+
set(cellId, visible) {
|
|
23
|
+
this.#cells.set(cellId, visible);
|
|
24
|
+
}
|
|
25
|
+
/** A cell unmounted. */
|
|
26
|
+
remove(cellId) {
|
|
27
|
+
this.#cells.delete(cellId);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* True while any cell is visible, or none has reported. Reactive: it reads
|
|
31
|
+
* the SvelteMap. A getter, not a derived, since a chart has few cells.
|
|
32
|
+
*/
|
|
33
|
+
get visible() {
|
|
34
|
+
if (this.#cells.size === 0)
|
|
35
|
+
return true;
|
|
36
|
+
for (const v of this.#cells.values())
|
|
37
|
+
if (v)
|
|
38
|
+
return true;
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether a chart other than this one is visible and draws `scale`, so
|
|
43
|
+
* that changing the scale moves something in view. A chart catching up on
|
|
44
|
+
* its return snaps its own parts but springs a scale like this: the chart
|
|
45
|
+
* being watched moves through the scale, as it would for any change.
|
|
46
|
+
*
|
|
47
|
+
* Asked when a result lands, not when it was sent: visibility changes
|
|
48
|
+
* during a scroll. "Visible" is the coordinator's: it includes the 200 px
|
|
49
|
+
* margin, so a chart in the margin, which nobody sees yet, still counts and
|
|
50
|
+
* keeps the spring. Untracked: a point-in-time answer, asked from inside
|
|
51
|
+
* effects that must not re-run when a cell scrolls.
|
|
52
|
+
*/
|
|
53
|
+
shownElsewhere(scale) {
|
|
54
|
+
const peers = this.#peers;
|
|
55
|
+
if (!peers)
|
|
56
|
+
return false;
|
|
57
|
+
return untrack(() => {
|
|
58
|
+
for (const chartId of peers.chartsUsing(scale)) {
|
|
59
|
+
if (this.#cells.has(chartId))
|
|
60
|
+
continue;
|
|
61
|
+
if (peers.isChartVisible(chartId))
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { hasEntered } from '../../scales/entered';
|
|
2
3
|
import { getContext } from 'svelte';
|
|
3
4
|
import { GridLine } from '../rendering';
|
|
4
5
|
import type { ChartContext, ScaleStateInstance } from '../../types';
|
|
@@ -38,7 +39,9 @@
|
|
|
38
39
|
let yBuffer = new Float32Array(64);
|
|
39
40
|
|
|
40
41
|
function ticksOf(scale: ScaleStateInstance | null, which: 'x' | 'y'): Float32Array | null {
|
|
41
|
-
|
|
42
|
+
// None until the scale has entered: its domain is a placeholder before that.
|
|
43
|
+
const ticks =
|
|
44
|
+
scale?.getTicks && hasEntered(scale) ? (scale.getTicks() as ArrayLike<number>) : null;
|
|
42
45
|
if (!ticks || ticks.length === 0) return null;
|
|
43
46
|
let buffer = which === 'x' ? xBuffer : yBuffer;
|
|
44
47
|
if (buffer.length < ticks.length) {
|
|
@@ -58,6 +61,12 @@
|
|
|
58
61
|
const yTickValues = $derived(ticksOf(yScale, 'y'));
|
|
59
62
|
const xAlpha = $derived(visibilityOf(xScale, xBand));
|
|
60
63
|
const yAlpha = $derived(visibilityOf(yScale, yBand));
|
|
64
|
+
// A band axis's line opacity follows its layout: when that landed at once
|
|
65
|
+
// (a catch-up result), the opacity lands with it.
|
|
66
|
+
const landedOf = (scale: ScaleStateInstance | null, band: boolean) =>
|
|
67
|
+
band && scale ? (scale as BandScaleState).slotsLandedLayout : 0;
|
|
68
|
+
const xLands = $derived(landedOf(xScale, xBand));
|
|
69
|
+
const yLands = $derived(landedOf(yScale, yBand));
|
|
61
70
|
</script>
|
|
62
71
|
|
|
63
72
|
{#if xTickValues}
|
|
@@ -65,6 +74,7 @@
|
|
|
65
74
|
axis="x"
|
|
66
75
|
positions={xTickValues}
|
|
67
76
|
alpha={xAlpha}
|
|
77
|
+
landsFor={xLands}
|
|
68
78
|
bandAxis={xBand ? 'x' : null}
|
|
69
79
|
{color}
|
|
70
80
|
{lineWidth}
|
|
@@ -76,6 +86,7 @@
|
|
|
76
86
|
axis="y"
|
|
77
87
|
positions={yTickValues}
|
|
78
88
|
alpha={yAlpha}
|
|
89
|
+
landsFor={yLands}
|
|
79
90
|
bandAxis={yBand ? 'y' : null}
|
|
80
91
|
{color}
|
|
81
92
|
{lineWidth}
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
selection = undefined,
|
|
50
50
|
selectionResponse = undefined,
|
|
51
51
|
nulls = undefined,
|
|
52
|
+
holdsEntrance = undefined,
|
|
52
53
|
y,
|
|
53
54
|
x,
|
|
54
55
|
x1: x1Prop,
|
|
@@ -103,6 +104,7 @@
|
|
|
103
104
|
selection: () => selection,
|
|
104
105
|
selectionResponse: () => selectionResponse,
|
|
105
106
|
nulls: () => nulls,
|
|
107
|
+
holdsEntrance: () => holdsEntrance,
|
|
106
108
|
limit: () => limit,
|
|
107
109
|
preferredXScaleType: () => preferredXScaleType,
|
|
108
110
|
preferredYScaleType: () => preferredYScaleType,
|
|
@@ -148,7 +150,8 @@
|
|
|
148
150
|
seriesChannelKey,
|
|
149
151
|
() => setup,
|
|
150
152
|
scaleRegistry,
|
|
151
|
-
chartContext
|
|
153
|
+
chartContext,
|
|
154
|
+
() => markColor.scaleState
|
|
152
155
|
);
|
|
153
156
|
|
|
154
157
|
// Color: fill determines area color — reads from entry
|
|
@@ -239,8 +242,8 @@
|
|
|
239
242
|
resolveFitDomain: () => resolvedFitAxis
|
|
240
243
|
});
|
|
241
244
|
|
|
242
|
-
|
|
243
|
-
let
|
|
245
|
+
// Rebuild only when a scale is replaced, not on its first resolution.
|
|
246
|
+
let scaleGeneration = $derived(chartContext.scaleGeneration);
|
|
244
247
|
|
|
245
248
|
let instanceCount = $derived(computeInstanceCount(setup?.data, entry.y, x2));
|
|
246
249
|
|
|
@@ -307,7 +310,7 @@
|
|
|
307
310
|
// --- SETUP LIFECYCLE ---
|
|
308
311
|
|
|
309
312
|
$effect(() => {
|
|
310
|
-
(void config,
|
|
313
|
+
(void config, scaleGeneration);
|
|
311
314
|
untrack(() => {
|
|
312
315
|
if (setup) {
|
|
313
316
|
gpuCoordinator?.markForRetain(markId);
|
|
@@ -375,6 +378,8 @@
|
|
|
375
378
|
colorMode={markColor.colorMode}
|
|
376
379
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
377
380
|
groupIndex={setup?.groupIndex ?? 0}
|
|
381
|
+
activitySeriesMode={markSeries.activityMode}
|
|
382
|
+
activitySeriesScaleIndex={markSeries.activityScaleIndex}
|
|
378
383
|
constantColor={markColor.constantColor}
|
|
379
384
|
fillOpacity={entry.fillOpacity ?? 0.5}
|
|
380
385
|
dotRadius={effectiveDotRadius}
|
|
@@ -383,6 +388,7 @@
|
|
|
383
388
|
orientation="horizontal"
|
|
384
389
|
facetData={setup?.facetData}
|
|
385
390
|
dataVersion={setup?.dataVersion || 0}
|
|
391
|
+
grow={!hasExplicitBounds}
|
|
386
392
|
/>
|
|
387
393
|
{#if (entry.strokeWidth ?? 0) > 0}
|
|
388
394
|
<Lines
|
|
@@ -396,11 +402,14 @@
|
|
|
396
402
|
activityColorMode={outline.activityColorMode}
|
|
397
403
|
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
398
404
|
groupIndex={setup?.groupIndex ?? 0}
|
|
405
|
+
activitySeriesMode={markSeries.activityMode}
|
|
406
|
+
activitySeriesScaleIndex={markSeries.activityScaleIndex}
|
|
399
407
|
constantColor={strokeConstantColor}
|
|
400
408
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
401
409
|
zIndex={1}
|
|
402
410
|
facetData={setup?.facetData}
|
|
403
411
|
dataVersion={setup?.dataVersion || 0}
|
|
412
|
+
grow={hasExplicitBounds ? null : 'x'}
|
|
404
413
|
/>
|
|
405
414
|
{#if showBothBoundaries}
|
|
406
415
|
<Lines
|
|
@@ -414,11 +423,14 @@
|
|
|
414
423
|
activityColorMode={outline.activityColorMode}
|
|
415
424
|
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
416
425
|
groupIndex={setup?.groupIndex ?? 0}
|
|
426
|
+
activitySeriesMode={markSeries.activityMode}
|
|
427
|
+
activitySeriesScaleIndex={markSeries.activityScaleIndex}
|
|
417
428
|
constantColor={strokeConstantColor}
|
|
418
429
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
419
430
|
zIndex={1}
|
|
420
431
|
facetData={setup?.facetData}
|
|
421
432
|
dataVersion={setup?.dataVersion || 0}
|
|
433
|
+
grow={hasExplicitBounds ? null : 'x'}
|
|
422
434
|
/>
|
|
423
435
|
{/if}
|
|
424
436
|
{/if}
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
selection = undefined,
|
|
50
50
|
selectionResponse = undefined,
|
|
51
51
|
nulls = undefined,
|
|
52
|
+
holdsEntrance = undefined,
|
|
52
53
|
x,
|
|
53
54
|
y,
|
|
54
55
|
y1: y1Prop,
|
|
@@ -103,6 +104,7 @@
|
|
|
103
104
|
selection: () => selection,
|
|
104
105
|
selectionResponse: () => selectionResponse,
|
|
105
106
|
nulls: () => nulls,
|
|
107
|
+
holdsEntrance: () => holdsEntrance,
|
|
106
108
|
limit: () => limit,
|
|
107
109
|
preferredXScaleType: () => preferredXScaleType,
|
|
108
110
|
preferredYScaleType: () => preferredYScaleType,
|
|
@@ -148,7 +150,8 @@
|
|
|
148
150
|
seriesChannelKey,
|
|
149
151
|
() => setup,
|
|
150
152
|
scaleRegistry,
|
|
151
|
-
chartContext
|
|
153
|
+
chartContext,
|
|
154
|
+
() => markColor.scaleState
|
|
152
155
|
);
|
|
153
156
|
|
|
154
157
|
// Color: fill determines area color — reads from entry
|
|
@@ -239,8 +242,8 @@
|
|
|
239
242
|
resolveFitDomain: () => resolvedFitAxis
|
|
240
243
|
});
|
|
241
244
|
|
|
242
|
-
|
|
243
|
-
let
|
|
245
|
+
// Rebuild only when a scale is replaced, not on its first resolution.
|
|
246
|
+
let scaleGeneration = $derived(chartContext.scaleGeneration);
|
|
244
247
|
|
|
245
248
|
let instanceCount = $derived(computeInstanceCount(setup?.data, entry.x, y2));
|
|
246
249
|
|
|
@@ -306,7 +309,7 @@
|
|
|
306
309
|
// --- SETUP LIFECYCLE ---
|
|
307
310
|
|
|
308
311
|
$effect(() => {
|
|
309
|
-
(void config,
|
|
312
|
+
(void config, scaleGeneration);
|
|
310
313
|
untrack(() => {
|
|
311
314
|
if (setup) {
|
|
312
315
|
gpuCoordinator?.markForRetain(markId);
|
|
@@ -375,6 +378,8 @@
|
|
|
375
378
|
colorMode={markColor.colorMode}
|
|
376
379
|
colorScaleIndex={markColor.colorScaleIndex}
|
|
377
380
|
groupIndex={setup?.groupIndex ?? 0}
|
|
381
|
+
activitySeriesMode={markSeries.activityMode}
|
|
382
|
+
activitySeriesScaleIndex={markSeries.activityScaleIndex}
|
|
378
383
|
constantColor={markColor.constantColor}
|
|
379
384
|
fillOpacity={entry.fillOpacity ?? 0.5}
|
|
380
385
|
dotRadius={effectiveDotRadius}
|
|
@@ -383,6 +388,7 @@
|
|
|
383
388
|
orientation="vertical"
|
|
384
389
|
facetData={setup?.facetData}
|
|
385
390
|
dataVersion={setup?.dataVersion || 0}
|
|
391
|
+
grow={!hasExplicitBounds}
|
|
386
392
|
/>
|
|
387
393
|
{#if (entry.strokeWidth ?? 0) > 0}
|
|
388
394
|
<Lines
|
|
@@ -396,11 +402,14 @@
|
|
|
396
402
|
activityColorMode={outline.activityColorMode}
|
|
397
403
|
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
398
404
|
groupIndex={setup?.groupIndex ?? 0}
|
|
405
|
+
activitySeriesMode={markSeries.activityMode}
|
|
406
|
+
activitySeriesScaleIndex={markSeries.activityScaleIndex}
|
|
399
407
|
constantColor={strokeConstantColor}
|
|
400
408
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
401
409
|
zIndex={1}
|
|
402
410
|
facetData={setup?.facetData}
|
|
403
411
|
dataVersion={setup?.dataVersion || 0}
|
|
412
|
+
grow={hasExplicitBounds ? null : 'y'}
|
|
404
413
|
/>
|
|
405
414
|
{#if showBothBoundaries}
|
|
406
415
|
<Lines
|
|
@@ -414,11 +423,14 @@
|
|
|
414
423
|
activityColorMode={outline.activityColorMode}
|
|
415
424
|
activityColorScaleIndex={outline.activityColorScaleIndex}
|
|
416
425
|
groupIndex={setup?.groupIndex ?? 0}
|
|
426
|
+
activitySeriesMode={markSeries.activityMode}
|
|
427
|
+
activitySeriesScaleIndex={markSeries.activityScaleIndex}
|
|
417
428
|
constantColor={strokeConstantColor}
|
|
418
429
|
strokeWidth={entry.strokeWidth ?? 0}
|
|
419
430
|
zIndex={1}
|
|
420
431
|
facetData={setup?.facetData}
|
|
421
432
|
dataVersion={setup?.dataVersion || 0}
|
|
433
|
+
grow={hasExplicitBounds ? null : 'y'}
|
|
422
434
|
/>
|
|
423
435
|
{/if}
|
|
424
436
|
{/if}
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
selection = undefined,
|
|
43
43
|
selectionResponse = undefined,
|
|
44
44
|
nulls = undefined,
|
|
45
|
+
holdsEntrance = undefined,
|
|
45
46
|
contributeDomain = undefined,
|
|
46
47
|
x,
|
|
47
48
|
x1: x1Prop,
|
|
@@ -86,6 +87,7 @@
|
|
|
86
87
|
selection: () => selection,
|
|
87
88
|
selectionResponse: () => selectionResponse,
|
|
88
89
|
nulls: () => nulls,
|
|
90
|
+
holdsEntrance: () => holdsEntrance,
|
|
89
91
|
contributeDomain: () => contributeDomain,
|
|
90
92
|
limit: () => limit,
|
|
91
93
|
padding: () => padding,
|
|
@@ -178,8 +180,8 @@
|
|
|
178
180
|
|
|
179
181
|
const reactiveConfig = buildReactiveConfig(entry);
|
|
180
182
|
|
|
181
|
-
|
|
182
|
-
let
|
|
183
|
+
// Rebuild only when a scale is replaced, not on its first resolution.
|
|
184
|
+
let scaleGeneration = $derived(chartContext.scaleGeneration);
|
|
183
185
|
|
|
184
186
|
let instanceCount = $derived(computeInstanceCount(setup?.data, x2, entry.y));
|
|
185
187
|
|
|
@@ -242,7 +244,7 @@
|
|
|
242
244
|
// --- SETUP LIFECYCLE ---
|
|
243
245
|
|
|
244
246
|
$effect(() => {
|
|
245
|
-
(void config,
|
|
247
|
+
(void config, scaleGeneration);
|
|
246
248
|
untrack(() => {
|
|
247
249
|
if (setup) {
|
|
248
250
|
gpuCoordinator?.markForRetain(markId);
|
|
@@ -321,7 +323,9 @@
|
|
|
321
323
|
constantColor={markColor.constantColor}
|
|
322
324
|
facetData={setup?.facetData}
|
|
323
325
|
dataVersion={setup?.dataVersion || 0}
|
|
326
|
+
landsFor={setup?.landsFor ?? 0}
|
|
324
327
|
bandAxis={setup?.alignedBand ?? null}
|
|
328
|
+
grow={hasExplicitBounds ? null : 'x'}
|
|
325
329
|
inset={entry.inset ?? 0}
|
|
326
330
|
dx={entry.dx ?? 0}
|
|
327
331
|
dy={entry.dy ?? 0}
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
selection = undefined,
|
|
42
42
|
selectionResponse = undefined,
|
|
43
43
|
nulls = undefined,
|
|
44
|
+
holdsEntrance = undefined,
|
|
44
45
|
contributeDomain = undefined,
|
|
45
46
|
x,
|
|
46
47
|
y,
|
|
@@ -85,6 +86,7 @@
|
|
|
85
86
|
selection: () => selection,
|
|
86
87
|
selectionResponse: () => selectionResponse,
|
|
87
88
|
nulls: () => nulls,
|
|
89
|
+
holdsEntrance: () => holdsEntrance,
|
|
88
90
|
contributeDomain: () => contributeDomain,
|
|
89
91
|
limit: () => limit,
|
|
90
92
|
padding: () => padding,
|
|
@@ -179,8 +181,8 @@
|
|
|
179
181
|
|
|
180
182
|
const reactiveConfig = buildReactiveConfig(entry);
|
|
181
183
|
|
|
182
|
-
|
|
183
|
-
let
|
|
184
|
+
// Rebuild only when a scale is replaced, not on its first resolution.
|
|
185
|
+
let scaleGeneration = $derived(chartContext.scaleGeneration);
|
|
184
186
|
|
|
185
187
|
let instanceCount = $derived(computeInstanceCount(setup?.data, y2, entry.x));
|
|
186
188
|
|
|
@@ -243,7 +245,7 @@
|
|
|
243
245
|
// --- SETUP LIFECYCLE ---
|
|
244
246
|
|
|
245
247
|
$effect(() => {
|
|
246
|
-
(void config,
|
|
248
|
+
(void config, scaleGeneration);
|
|
247
249
|
untrack(() => {
|
|
248
250
|
if (setup) {
|
|
249
251
|
gpuCoordinator?.markForRetain(markId);
|
|
@@ -322,7 +324,9 @@
|
|
|
322
324
|
constantColor={markColor.constantColor}
|
|
323
325
|
facetData={setup?.facetData}
|
|
324
326
|
dataVersion={setup?.dataVersion || 0}
|
|
327
|
+
landsFor={setup?.landsFor ?? 0}
|
|
325
328
|
bandAxis={setup?.alignedBand ?? null}
|
|
329
|
+
grow={hasExplicitBounds ? null : 'y'}
|
|
326
330
|
inset={entry.inset ?? 0}
|
|
327
331
|
dx={entry.dx ?? 0}
|
|
328
332
|
dy={entry.dy ?? 0}
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
selection = undefined,
|
|
45
45
|
selectionResponse = undefined,
|
|
46
46
|
nulls = undefined,
|
|
47
|
+
holdsEntrance = undefined,
|
|
47
48
|
x,
|
|
48
49
|
y,
|
|
49
50
|
fill = null,
|
|
@@ -84,6 +85,7 @@
|
|
|
84
85
|
selection: () => selection,
|
|
85
86
|
selectionResponse: () => selectionResponse,
|
|
86
87
|
nulls: () => nulls,
|
|
88
|
+
holdsEntrance: () => holdsEntrance,
|
|
87
89
|
limit: () => limit,
|
|
88
90
|
preferredXScaleType: () => preferredXScaleType,
|
|
89
91
|
preferredYScaleType: () => preferredYScaleType,
|
|
@@ -177,8 +179,8 @@
|
|
|
177
179
|
resolveFitDomain: () => resolvedFitAxis
|
|
178
180
|
});
|
|
179
181
|
|
|
180
|
-
|
|
181
|
-
let
|
|
182
|
+
// Rebuild only when a scale is replaced, not on its first resolution.
|
|
183
|
+
let scaleGeneration = $derived(chartContext.scaleGeneration);
|
|
182
184
|
|
|
183
185
|
let instanceCount = $derived(computeInstanceCount(setup?.data, entry.x, entry.y));
|
|
184
186
|
|
|
@@ -246,7 +248,7 @@
|
|
|
246
248
|
// --- SETUP LIFECYCLE ---
|
|
247
249
|
|
|
248
250
|
$effect(() => {
|
|
249
|
-
(void config,
|
|
251
|
+
(void config, scaleGeneration);
|
|
250
252
|
untrack(() => {
|
|
251
253
|
if (setup) {
|
|
252
254
|
gpuCoordinator?.markForRetain(markId);
|
|
@@ -316,6 +318,7 @@
|
|
|
316
318
|
sizeScaleIndex={markSize.sizeScaleIndex}
|
|
317
319
|
facetData={setup?.facetData}
|
|
318
320
|
dataVersion={setup?.dataVersion || 0}
|
|
321
|
+
landsFor={setup?.landsFor ?? 0}
|
|
319
322
|
bandAxis={setup?.alignedBand ?? null}
|
|
320
323
|
/>
|
|
321
324
|
{/if}
|