@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
|
@@ -15,7 +15,7 @@ export const PARALLEL_MAX_AXES = 16;
|
|
|
15
15
|
const SCALE_PARAM_BYTES = 16;
|
|
16
16
|
export const UNIFORM_BYTES = {
|
|
17
17
|
dotsMarkConstants: 48,
|
|
18
|
-
rectsMarkConstants:
|
|
18
|
+
rectsMarkConstants: 64,
|
|
19
19
|
ruleXMarkConstants: 48,
|
|
20
20
|
ruleYMarkConstants: 48,
|
|
21
21
|
linesMarkConstants: 64,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { EntranceGate } from '../animation/EntranceGate';
|
|
1
2
|
import type { SelectionResponse } from '../components/rendering/activity-reads';
|
|
2
|
-
import type { FieldRef, LODConfig, SortConfig, ColorScheme, CurveType, Transform } from '../types';
|
|
3
|
+
import type { FieldRef, LODConfig, SortConfig, ColorScheme, CurveType, NullsResponse, Transform } from '../types';
|
|
3
4
|
import type { MarkLODSurface } from '../lod/rung-types';
|
|
4
5
|
export interface MarkEntry {
|
|
5
6
|
readonly id: string;
|
|
@@ -25,6 +26,9 @@ export interface MarkEntry {
|
|
|
25
26
|
transforms?: Transform[];
|
|
26
27
|
selection?: string;
|
|
27
28
|
selectionResponse?: SelectionResponse;
|
|
29
|
+
contributeDomain?: boolean;
|
|
30
|
+
nulls?: NullsResponse;
|
|
31
|
+
holdsEntrance?: boolean;
|
|
28
32
|
limit?: number;
|
|
29
33
|
preferredXScaleType?: string | null;
|
|
30
34
|
preferredYScaleType?: string | null;
|
|
@@ -59,6 +63,11 @@ export interface ChartProps {
|
|
|
59
63
|
}
|
|
60
64
|
export declare class ChartConfig {
|
|
61
65
|
#private;
|
|
66
|
+
/**
|
|
67
|
+
* Holds the chart's entrance until its marks have their first data. One per
|
|
68
|
+
* container, shared by its facet cells, as this config is.
|
|
69
|
+
*/
|
|
70
|
+
readonly entrance: EntranceGate;
|
|
62
71
|
/**
|
|
63
72
|
* Register a mark with prop getters for each configurable property.
|
|
64
73
|
* Returns the reactive entry that the mark reads from.
|
|
@@ -12,10 +12,17 @@
|
|
|
12
12
|
// The entry outlives MarkLifecycle — registerMark returns the existing entry
|
|
13
13
|
// on re-registration, preventing infinite loops.
|
|
14
14
|
// =============================================================================
|
|
15
|
+
import { untrack } from 'svelte';
|
|
15
16
|
import { SvelteMap } from 'svelte/reactivity';
|
|
17
|
+
import { EntranceGate } from '../animation/EntranceGate';
|
|
16
18
|
import { createOverridable } from './overridable.svelte';
|
|
17
19
|
// ---- ChartConfig ----
|
|
18
20
|
export class ChartConfig {
|
|
21
|
+
/**
|
|
22
|
+
* Holds the chart's entrance until its marks have their first data. One per
|
|
23
|
+
* container, shared by its facet cells, as this config is.
|
|
24
|
+
*/
|
|
25
|
+
entrance = new EntranceGate();
|
|
19
26
|
/** Overridable channels per mark, for reset support. */
|
|
20
27
|
#channels = new Map();
|
|
21
28
|
/** Reactive entries — SvelteMap so iteration/size reads are tracked. */
|
|
@@ -45,6 +52,14 @@ export class ChartConfig {
|
|
|
45
52
|
const existing = this.#entries.get(id);
|
|
46
53
|
if (existing)
|
|
47
54
|
return existing;
|
|
55
|
+
// A data mark holds the chart's entrance from the moment it mounts, which
|
|
56
|
+
// is now: its lifecycle is built later, in an effect that waits for the
|
|
57
|
+
// chart's scales, and until something holds the gate the chart looks
|
|
58
|
+
// like one with no data marks and enters on its first drawable layer.
|
|
59
|
+
if (untrack(() => propGetters.table?.()) &&
|
|
60
|
+
untrack(() => propGetters.holdsEntrance?.()) !== false) {
|
|
61
|
+
this.entrance.hold(id);
|
|
62
|
+
}
|
|
48
63
|
const channels = new Map();
|
|
49
64
|
const entry = { id, markType };
|
|
50
65
|
for (const [key, getter] of Object.entries(propGetters)) {
|
|
@@ -66,6 +81,8 @@ export class ChartConfig {
|
|
|
66
81
|
return entry;
|
|
67
82
|
}
|
|
68
83
|
unregisterMark(id) {
|
|
84
|
+
// A mark that leaves before its first data must not hold the chart.
|
|
85
|
+
this.entrance.release(id);
|
|
69
86
|
this.#entries.delete(id);
|
|
70
87
|
this.#channels.delete(id);
|
|
71
88
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { type TransitionRecord } from '../animation/transition-log';
|
|
2
|
+
import type { EntranceMode } from '../types';
|
|
3
|
+
import type { EntranceGate } from '../animation/EntranceGate';
|
|
1
4
|
import type { RendererDefinition } from './ScaleTemplateSystem';
|
|
2
5
|
import type { ScaleRegistry } from '../scales/ScaleRegistry.svelte';
|
|
3
6
|
import type { FilterGroupRegistry } from '../query-engine/FilterGroupRegistry.svelte';
|
|
@@ -88,6 +91,18 @@ interface ChartRegistrationConfig {
|
|
|
88
91
|
zIndex?: number;
|
|
89
92
|
facetIndex?: number;
|
|
90
93
|
facetScale?: FacetScaleRef | null;
|
|
94
|
+
/** How the chart's marks enter when its data first draws. Default 'auto'. */
|
|
95
|
+
entrance?: EntranceMode;
|
|
96
|
+
/** Holds the entrance until the chart's marks have their first data. */
|
|
97
|
+
entranceGate?: EntranceGate | null;
|
|
98
|
+
}
|
|
99
|
+
/** A chart's entrance starting, for observeEntrances. */
|
|
100
|
+
export interface ChartEntrance {
|
|
101
|
+
chartId: string;
|
|
102
|
+
/** The chart's canvas, to find it in the page (a label on an ancestor). */
|
|
103
|
+
canvas: HTMLCanvasElement;
|
|
104
|
+
/** performance.now() when the entrance started. */
|
|
105
|
+
time: number;
|
|
91
106
|
}
|
|
92
107
|
/**
|
|
93
108
|
* One chart's pixels as the coordinator rendered them, for the scale-source
|
|
@@ -142,6 +157,12 @@ export declare class GPUCoordinator {
|
|
|
142
157
|
* left alone.
|
|
143
158
|
*/
|
|
144
159
|
writeScaleParams(scaleId: string, view: Float32Array, offset: number): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Listen to every chart's entrance as it starts: when its marks have their
|
|
162
|
+
* first data and it first draws. For measuring load (how soon charts enter);
|
|
163
|
+
* returns the unsubscribe. Costs nothing while no one listens.
|
|
164
|
+
*/
|
|
165
|
+
observeEntrances(listener: (entrance: ChartEntrance) => void): () => void;
|
|
145
166
|
/**
|
|
146
167
|
* Configure canvases so the coordinator can copy from them. Test-only: set
|
|
147
168
|
* it before the charts mount, since a canvas reads it when it configures
|
|
@@ -263,10 +284,19 @@ export declare class GPUCoordinator {
|
|
|
263
284
|
removePhysicsCallback(fn: () => void): void;
|
|
264
285
|
registerChart(chartId: string, canvas: HTMLCanvasElement, config: ChartRegistrationConfig): ChartRegistrationResult;
|
|
265
286
|
unregisterChart(chartId: string): void;
|
|
287
|
+
/**
|
|
288
|
+
* Debug: every transition that starts, and whether it animates or lands at
|
|
289
|
+
* once (see transition-log). Returns the unsubscribe. Forwards to the
|
|
290
|
+
* page-wide log: records from every coordinator in the document arrive
|
|
291
|
+
* here, so filter by chart id.
|
|
292
|
+
*/
|
|
293
|
+
observeTransitions(listener: (record: TransitionRecord) => void): () => void;
|
|
294
|
+
/** Whether a registered chart is visible: in view (with the 200 px margin) and the page shown. */
|
|
295
|
+
isChartVisible(chartId: string): boolean;
|
|
266
296
|
/**
|
|
267
297
|
* Register a callback invoked when a chart's effective visibility changes.
|
|
268
298
|
* Effective visibility = IntersectionObserver visible AND page visible.
|
|
269
|
-
* Used by ChartCell to
|
|
299
|
+
* Used by ChartCell to report into the chart's ChartVisibility.
|
|
270
300
|
*/
|
|
271
301
|
setVisibilityCallback(chartId: string, callback: (visible: boolean) => void): () => void;
|
|
272
302
|
invalidateChart(chartId: string): void;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { observeTransitions } from '../animation/transition-log';
|
|
1
2
|
import { setContext, getContext } from 'svelte';
|
|
2
3
|
import { AnimationLoop } from '../animation';
|
|
4
|
+
import { TransitionClock, ENTRANCE_FADE_STIFFNESS, ENTRANCE_GROW_STIFFNESS } from '../animation/TransitionClock';
|
|
3
5
|
import { scaleTemplateSystem, CHART_SCALE_IMMEDIATE_SIZE } from './ScaleTemplateSystem';
|
|
4
6
|
import { isCategoricalScale } from '../scales/scale-categories';
|
|
5
7
|
import { MAX_SIZE_SLOTS } from './SizeScaleShaderLib';
|
|
@@ -19,8 +21,23 @@ export const COLOR_RAMP_RESOLUTION = 256;
|
|
|
19
21
|
function layerCanDraw(layer, chartScalesKnown) {
|
|
20
22
|
return (!!layer.renderer?.perDataBindGroup && (chartScalesKnown || layer.readsChartScales === false));
|
|
21
23
|
}
|
|
24
|
+
/** A guide (a grid line) rather than data: it neither enters nor starts the entrance. */
|
|
25
|
+
function isGuideLayer(layer) {
|
|
26
|
+
return layer.markType.startsWith('grid-line-');
|
|
27
|
+
}
|
|
22
28
|
/** No fields to pack, for a coordinator without filter groups. */
|
|
23
29
|
const NO_FIELDS = [];
|
|
30
|
+
/**
|
|
31
|
+
* A chart's entrance once the viewer's preference is applied: under reduced
|
|
32
|
+
* motion, 'auto' fades rather than grows. Opacity is not motion, so a fade
|
|
33
|
+
* stays; an author's explicit 'fade' or 'none' is kept as is.
|
|
34
|
+
*/
|
|
35
|
+
function resolveEntrance(mode) {
|
|
36
|
+
const chosen = mode ?? 'auto';
|
|
37
|
+
if (chosen !== 'auto' || typeof matchMedia === 'undefined')
|
|
38
|
+
return chosen;
|
|
39
|
+
return matchMedia('(prefers-reduced-motion: reduce)').matches ? 'fade' : 'auto';
|
|
40
|
+
}
|
|
24
41
|
// =============================================================================
|
|
25
42
|
// HELPER CLASSES
|
|
26
43
|
// =============================================================================
|
|
@@ -477,10 +494,6 @@ export class GPUCoordinator {
|
|
|
477
494
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
478
495
|
});
|
|
479
496
|
}
|
|
480
|
-
/**
|
|
481
|
-
* Fill CPU buffer with current scale GPU state.
|
|
482
|
-
* Zero-allocation hot path.
|
|
483
|
-
*/
|
|
484
497
|
/**
|
|
485
498
|
* Buffers for the slot table and its per-frame resolve.
|
|
486
499
|
*
|
|
@@ -746,8 +759,115 @@ export class GPUCoordinator {
|
|
|
746
759
|
this.#device.queue.writeBuffer(buffer, 0, view);
|
|
747
760
|
last.set(view);
|
|
748
761
|
}
|
|
749
|
-
/** Reused per pass: the chart's x and y ScaleParam, pushed as immediates. */
|
|
762
|
+
/** Reused per pass: the chart's x and y ScaleParam and entrance, pushed as immediates. */
|
|
750
763
|
#chartScaleImmediates = new Float32Array(CHART_SCALE_IMMEDIATE_SIZE / 4);
|
|
764
|
+
/** Debug listeners for chart entrances (observeEntrances). */
|
|
765
|
+
#entranceObservers = new Set();
|
|
766
|
+
/**
|
|
767
|
+
* Listen to every chart's entrance as it starts: when its marks have their
|
|
768
|
+
* first data and it first draws. For measuring load (how soon charts enter);
|
|
769
|
+
* returns the unsubscribe. Costs nothing while no one listens.
|
|
770
|
+
*/
|
|
771
|
+
observeEntrances(listener) {
|
|
772
|
+
this.#entranceObservers.add(listener);
|
|
773
|
+
return () => this.#entranceObservers.delete(listener);
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Begin a chart's entrance on the first pass that draws data in it.
|
|
777
|
+
*
|
|
778
|
+
* Per chart, not per mark: every mark in the chart reads the same immediate,
|
|
779
|
+
* so a bar chart and the line drawn over it enter together. Marks normally
|
|
780
|
+
* land in one query batch; one landing mid-entrance joins at the current t,
|
|
781
|
+
* and one landing after it simply appears.
|
|
782
|
+
*
|
|
783
|
+
* Started here rather than on registration, so an off-screen chart enters
|
|
784
|
+
* when it is first drawn, which is when it can be seen.
|
|
785
|
+
*/
|
|
786
|
+
#startEntranceIfDrawing(chart, scalesKnown) {
|
|
787
|
+
// Every mark's first data first, so the chart enters once, whole. Only
|
|
788
|
+
// this chart's marks: a chart sharing a scale that lands later springs
|
|
789
|
+
// the domain to the combined extent, as any later data would.
|
|
790
|
+
const gate = chart.entranceGate;
|
|
791
|
+
if (gate) {
|
|
792
|
+
if (!gate.canEnter)
|
|
793
|
+
return;
|
|
794
|
+
gate.open();
|
|
795
|
+
}
|
|
796
|
+
const plan = chart.renderPlan;
|
|
797
|
+
let drawing = false;
|
|
798
|
+
for (let i = 0; i < plan.length; i++) {
|
|
799
|
+
// Data marks only: a grid line draws as soon as the scales exist, which
|
|
800
|
+
// is usually before the query has answered, and would start the
|
|
801
|
+
// entrance with nothing in it.
|
|
802
|
+
if (isGuideLayer(plan[i]))
|
|
803
|
+
continue;
|
|
804
|
+
if (layerCanDraw(plan[i], scalesKnown)) {
|
|
805
|
+
drawing = true;
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
if (!drawing)
|
|
810
|
+
return;
|
|
811
|
+
chart.entranceStarted = true;
|
|
812
|
+
if (this.#entranceObservers.size > 0) {
|
|
813
|
+
const entrance = {
|
|
814
|
+
chartId: chart.chartId,
|
|
815
|
+
canvas: chart.canvas,
|
|
816
|
+
time: performance.now()
|
|
817
|
+
};
|
|
818
|
+
for (const observe of this.#entranceObservers) {
|
|
819
|
+
try {
|
|
820
|
+
observe(entrance);
|
|
821
|
+
}
|
|
822
|
+
catch (e) {
|
|
823
|
+
console.error('[GPUCoordinator] entrance observer threw:', e);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
if (chart.entranceMode === 'none')
|
|
828
|
+
return;
|
|
829
|
+
const clock = new TransitionClock({
|
|
830
|
+
loop: this,
|
|
831
|
+
stiffness: ENTRANCE_GROW_STIFFNESS,
|
|
832
|
+
charts: () => chart.entranceCharts,
|
|
833
|
+
onRest: () => {
|
|
834
|
+
if (chart.entranceClock === clock)
|
|
835
|
+
chart.entranceClock = null;
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
chart.entranceClock = clock;
|
|
839
|
+
// Ease-out: growth should move from its first frame.
|
|
840
|
+
clock.restartEaseOut();
|
|
841
|
+
const fade = new TransitionClock({
|
|
842
|
+
loop: this,
|
|
843
|
+
stiffness: ENTRANCE_FADE_STIFFNESS,
|
|
844
|
+
charts: () => chart.entranceCharts,
|
|
845
|
+
onRest: () => {
|
|
846
|
+
if (chart.entranceFadeClock === fade)
|
|
847
|
+
chart.entranceFadeClock = null;
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
chart.entranceFadeClock = fade;
|
|
851
|
+
// From rest: a soft S-curve for opacity.
|
|
852
|
+
fade.restart();
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* The entrance immediates: x = growth, y = a growing mark's opacity, z = a
|
|
856
|
+
* fading mark's opacity. The mode is folded in here, so a mark only says
|
|
857
|
+
* whether it grows or fades.
|
|
858
|
+
*/
|
|
859
|
+
#writeEntrance(chart, view) {
|
|
860
|
+
// Before the entrance starts the chart draws nothing, so 0 is never
|
|
861
|
+
// seen; after it, the clocks are gone and everything is at 1.
|
|
862
|
+
const idle = chart.entranceStarted ? 1 : 0;
|
|
863
|
+
const grow = chart.entranceClock ? chart.entranceClock.t : idle;
|
|
864
|
+
const fade = chart.entranceFadeClock ? chart.entranceFadeClock.t : idle;
|
|
865
|
+
const mode = chart.entranceMode;
|
|
866
|
+
view[8] = mode === 'auto' ? grow : 1;
|
|
867
|
+
view[9] = mode === 'fade' ? fade : 1;
|
|
868
|
+
view[10] = mode === 'none' ? 1 : fade;
|
|
869
|
+
view[11] = 0;
|
|
870
|
+
}
|
|
751
871
|
// =========================================================================
|
|
752
872
|
// READBACK (test-only)
|
|
753
873
|
// =========================================================================
|
|
@@ -996,6 +1116,9 @@ export class GPUCoordinator {
|
|
|
996
1116
|
// known: a layer that does not read them still needs every byte set
|
|
997
1117
|
// before it may draw.
|
|
998
1118
|
const scalesKnown = this.#writeChartScales(chartConfig, this.#chartScaleImmediates);
|
|
1119
|
+
if (!chartConfig.entranceStarted)
|
|
1120
|
+
this.#startEntranceIfDrawing(chartConfig, scalesKnown);
|
|
1121
|
+
this.#writeEntrance(chartConfig, this.#chartScaleImmediates);
|
|
999
1122
|
passEncoder.setImmediates(0, this.#chartScaleImmediates);
|
|
1000
1123
|
if (chartConfig.perFrameBindGroup) {
|
|
1001
1124
|
passEncoder.setBindGroup(0, chartConfig.perFrameBindGroup);
|
|
@@ -1501,8 +1624,19 @@ export class GPUCoordinator {
|
|
|
1501
1624
|
renderPassDescriptor: null,
|
|
1502
1625
|
msaa: null,
|
|
1503
1626
|
_lastRenderFrame: -1,
|
|
1504
|
-
_isDirty: false
|
|
1627
|
+
_isDirty: false,
|
|
1628
|
+
entranceMode: resolveEntrance(config.entrance),
|
|
1629
|
+
entranceStarted: false,
|
|
1630
|
+
entranceClock: null,
|
|
1631
|
+
entranceFadeClock: null,
|
|
1632
|
+
entranceCharts: [chartId],
|
|
1633
|
+
entranceGate: config.entranceGate ?? null,
|
|
1634
|
+
entranceGateOff: null
|
|
1505
1635
|
};
|
|
1636
|
+
// The gate opens on a mark's data or a timeout, neither of which need
|
|
1637
|
+
// redraw this chart. Without a frame the entrance would wait for one.
|
|
1638
|
+
chartConfig.entranceGateOff =
|
|
1639
|
+
chartConfig.entranceGate?.onOpen(() => this.invalidateChart(chartId)) ?? null;
|
|
1506
1640
|
this.#registeredCharts.set(chartId, chartConfig);
|
|
1507
1641
|
// Observe canvas for viewport visibility
|
|
1508
1642
|
if (this.#visibilityObserver) {
|
|
@@ -1552,6 +1686,12 @@ export class GPUCoordinator {
|
|
|
1552
1686
|
const chartConfig = this.#registeredCharts.get(chartId);
|
|
1553
1687
|
if (chartConfig) {
|
|
1554
1688
|
chartConfig._isDirty = false;
|
|
1689
|
+
chartConfig.entranceClock?.stop();
|
|
1690
|
+
chartConfig.entranceClock = null;
|
|
1691
|
+
chartConfig.entranceFadeClock?.stop();
|
|
1692
|
+
chartConfig.entranceFadeClock = null;
|
|
1693
|
+
chartConfig.entranceGateOff?.();
|
|
1694
|
+
chartConfig.entranceGateOff = null;
|
|
1555
1695
|
if (chartConfig.frameUniformsBuffer) {
|
|
1556
1696
|
chartConfig.frameUniformsBuffer.destroy();
|
|
1557
1697
|
}
|
|
@@ -1580,13 +1720,30 @@ export class GPUCoordinator {
|
|
|
1580
1720
|
// =========================================================================
|
|
1581
1721
|
// VIEWPORT VISIBILITY
|
|
1582
1722
|
// =========================================================================
|
|
1723
|
+
/**
|
|
1724
|
+
* Debug: every transition that starts, and whether it animates or lands at
|
|
1725
|
+
* once (see transition-log). Returns the unsubscribe. Forwards to the
|
|
1726
|
+
* page-wide log: records from every coordinator in the document arrive
|
|
1727
|
+
* here, so filter by chart id.
|
|
1728
|
+
*/
|
|
1729
|
+
observeTransitions(listener) {
|
|
1730
|
+
return observeTransitions(listener);
|
|
1731
|
+
}
|
|
1732
|
+
/** Whether a registered chart is visible: in view (with the 200 px margin) and the page shown. */
|
|
1733
|
+
isChartVisible(chartId) {
|
|
1734
|
+
return this.#registeredCharts.get(chartId)?.visible ?? false;
|
|
1735
|
+
}
|
|
1583
1736
|
/**
|
|
1584
1737
|
* Register a callback invoked when a chart's effective visibility changes.
|
|
1585
1738
|
* Effective visibility = IntersectionObserver visible AND page visible.
|
|
1586
|
-
* Used by ChartCell to
|
|
1739
|
+
* Used by ChartCell to report into the chart's ChartVisibility.
|
|
1587
1740
|
*/
|
|
1588
1741
|
setVisibilityCallback(chartId, callback) {
|
|
1589
1742
|
this.#visibilityCallbacks.set(chartId, callback);
|
|
1743
|
+
// Callbacks hear changes only. One set after the chart was already found
|
|
1744
|
+
// off screen would otherwise go on assuming it visible.
|
|
1745
|
+
if (this.#registeredCharts.get(chartId)?.visible === false)
|
|
1746
|
+
callback(false);
|
|
1590
1747
|
return () => this.#visibilityCallbacks.delete(chartId);
|
|
1591
1748
|
}
|
|
1592
1749
|
#handleVisibilityChange(chartId, ioVisible) {
|
|
@@ -1,31 +1,4 @@
|
|
|
1
1
|
import { TransitionClock, type ClockLoop } from '../animation/TransitionClock';
|
|
2
|
-
/**
|
|
3
|
-
* Channels of one mark that morph between data updates rather than replacing
|
|
4
|
-
* outright.
|
|
5
|
-
*
|
|
6
|
-
* Each holds three buffers where a static channel holds one: `from` and `to` are
|
|
7
|
-
* read by a compute pass, and `resolved = mix(from, to, t)` is what the vertex
|
|
8
|
-
* stage binds — in place of the static buffer, not in addition to it. So
|
|
9
|
-
* animating a channel costs the vertex stage nothing, which is what makes it
|
|
10
|
-
* affordable on a mark already at the device's storage-buffer limit.
|
|
11
|
-
*
|
|
12
|
-
* THE FOLD. When a transition restarts, whatever is on screen becomes the new
|
|
13
|
-
* `from`. On screen is the resolved buffer as last dispatched, so the fold is a
|
|
14
|
-
* buffer copy, and it reads neither `from` nor `to` — which is what lets data
|
|
15
|
-
* land at any moment, in any order relative to anything else. Writing it as
|
|
16
|
-
* `from = mix(from, to, t)` would need the OLD `to`, making the order of two
|
|
17
|
-
* writes load-bearing and silently wrong if they ever swap.
|
|
18
|
-
*
|
|
19
|
-
* THE SNAP. Some updates have nothing to travel from: the first one, a buffer
|
|
20
|
-
* that had to be reallocated, and a row set that is not the one being animated.
|
|
21
|
-
* Those copy `to` over `from`, which makes the mix the identity for every t.
|
|
22
|
-
*
|
|
23
|
-
* THE CLOCK. A mark ADOPTS the band scale's clock when it has one, so a bar's
|
|
24
|
-
* height travels on the same number as its slot — two clocks with two velocities
|
|
25
|
-
* desynchronise on a retarget, and the bar reaches its rank before or after it
|
|
26
|
-
* finishes growing. It OWNS one otherwise. Adoption is safe across marks because
|
|
27
|
-
* a mark with no new data folds to where it already is and does not move.
|
|
28
|
-
*/
|
|
29
2
|
/**
|
|
30
3
|
* The coordinator's slice this needs. Structural, so tests can supply a fake.
|
|
31
4
|
* It is also the loop an owned clock joins — the clock does that itself.
|
|
@@ -61,6 +34,10 @@ export interface MorphedChannelsOptions {
|
|
|
61
34
|
* travelling to its neighbour's value and back. So the claim is checked, and a
|
|
62
35
|
* change snaps rather than interpolates. A hash rather than a comparison
|
|
63
36
|
* because it costs one pass and no retained copy.
|
|
37
|
+
*
|
|
38
|
+
* Over the values' bits, read through a view of the same buffer: a
|
|
39
|
+
* histogram's rows are keyed by bin edges, fractions a sum would truncate
|
|
40
|
+
* away, so a re-bin could otherwise hash like the bins it replaced.
|
|
64
41
|
*/
|
|
65
42
|
export declare function alignmentKey(ids: ArrayLike<number>): number;
|
|
66
43
|
export declare class MorphedChannels {
|
|
@@ -85,8 +62,14 @@ export declare class MorphedChannels {
|
|
|
85
62
|
*
|
|
86
63
|
* All channels in one call, so one update starts one transition. Returns
|
|
87
64
|
* whether any buffer was (re)allocated, which the caller must rebind.
|
|
65
|
+
*
|
|
66
|
+
* `land`: bindings whose new values take effect at once while the rest
|
|
67
|
+
* travel. For a channel whose change is shown some other way at that moment
|
|
68
|
+
* (an Other bar's split, when both sides of it look the same): sliding it
|
|
69
|
+
* would draw a movement nothing asked for. `'all'`: the whole update lands,
|
|
70
|
+
* for a catch-up result (MarkHandle.resultCause).
|
|
88
71
|
*/
|
|
89
|
-
write(rowIds: ArrayLike<number>, channels: readonly (readonly [number, AllowSharedBufferSource])[]): boolean;
|
|
72
|
+
write(rowIds: ArrayLike<number>, channels: readonly (readonly [number, AllowSharedBufferSource])[], land?: readonly number[] | 'all'): boolean;
|
|
90
73
|
/**
|
|
91
74
|
* Stop morphing a channel and release its buffers. Returns whether it was
|
|
92
75
|
* morphing, in which case the caller's binding has lost its buffer.
|
|
@@ -1,6 +1,36 @@
|
|
|
1
|
+
import { noteTransition, transitionsObserved } from '../animation/transition-log';
|
|
1
2
|
import { RESOLVE_IMMEDIATE_SIZE, RESOLVE_WORKGROUP, resolvePipelineFor } from './ResolveShader';
|
|
2
3
|
import { TransitionClock } from '../animation/TransitionClock';
|
|
3
4
|
import { immediatesSupported } from './immediates';
|
|
5
|
+
/**
|
|
6
|
+
* Channels of one mark that morph between data updates rather than replacing
|
|
7
|
+
* outright.
|
|
8
|
+
*
|
|
9
|
+
* Each holds three buffers where a static channel holds one: `from` and `to` are
|
|
10
|
+
* read by a compute pass, and `resolved = mix(from, to, t)` is what the vertex
|
|
11
|
+
* stage binds — in place of the static buffer, not in addition to it. So
|
|
12
|
+
* animating a channel costs the vertex stage nothing, which is what makes it
|
|
13
|
+
* affordable on a mark already at the device's storage-buffer limit.
|
|
14
|
+
*
|
|
15
|
+
* THE FOLD. When a transition restarts, whatever is on screen becomes the new
|
|
16
|
+
* `from`. On screen is the resolved buffer as last dispatched, so the fold is a
|
|
17
|
+
* buffer copy, and it reads neither `from` nor `to` — which is what lets data
|
|
18
|
+
* land at any moment, in any order relative to anything else. Writing it as
|
|
19
|
+
* `from = mix(from, to, t)` would need the OLD `to`, making the order of two
|
|
20
|
+
* writes load-bearing and silently wrong if they ever swap.
|
|
21
|
+
*
|
|
22
|
+
* THE SNAP. Some updates have nothing to travel from: the first one, a buffer
|
|
23
|
+
* that had to be reallocated, and a row set that is not the one being animated.
|
|
24
|
+
* Those copy `to` over `from`, which makes the mix the identity for every t.
|
|
25
|
+
*
|
|
26
|
+
* THE CLOCK. A mark ADOPTS the band scale's clock when it has one, so a bar's
|
|
27
|
+
* height travels on the same number as its slot — two clocks with two velocities
|
|
28
|
+
* desynchronise on a retarget, and the bar reaches its rank before or after it
|
|
29
|
+
* finishes growing. It OWNS one otherwise. Adoption is safe across marks because
|
|
30
|
+
* a mark with no new data folds to where it already is and does not move.
|
|
31
|
+
*/
|
|
32
|
+
/** No bindings: the default for `write`'s `land`. */
|
|
33
|
+
const NO_BINDINGS = [];
|
|
4
34
|
/**
|
|
5
35
|
* A cheap fingerprint of the band ids, per update.
|
|
6
36
|
*
|
|
@@ -10,11 +40,16 @@ import { immediatesSupported } from './immediates';
|
|
|
10
40
|
* travelling to its neighbour's value and back. So the claim is checked, and a
|
|
11
41
|
* change snaps rather than interpolates. A hash rather than a comparison
|
|
12
42
|
* because it costs one pass and no retained copy.
|
|
43
|
+
*
|
|
44
|
+
* Over the values' bits, read through a view of the same buffer: a
|
|
45
|
+
* histogram's rows are keyed by bin edges, fractions a sum would truncate
|
|
46
|
+
* away, so a re-bin could otherwise hash like the bins it replaced.
|
|
13
47
|
*/
|
|
14
48
|
export function alignmentKey(ids) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
49
|
+
const bits = ids instanceof Float32Array ? new Uint32Array(ids.buffer, ids.byteOffset, ids.length) : ids;
|
|
50
|
+
let hash = bits.length;
|
|
51
|
+
for (let i = 0; i < bits.length; i++)
|
|
52
|
+
hash = (Math.imul(hash, 31) + bits[i]) | 0;
|
|
18
53
|
return hash;
|
|
19
54
|
}
|
|
20
55
|
export class MorphedChannels {
|
|
@@ -87,8 +122,14 @@ export class MorphedChannels {
|
|
|
87
122
|
*
|
|
88
123
|
* All channels in one call, so one update starts one transition. Returns
|
|
89
124
|
* whether any buffer was (re)allocated, which the caller must rebind.
|
|
125
|
+
*
|
|
126
|
+
* `land`: bindings whose new values take effect at once while the rest
|
|
127
|
+
* travel. For a channel whose change is shown some other way at that moment
|
|
128
|
+
* (an Other bar's split, when both sides of it look the same): sliding it
|
|
129
|
+
* would draw a movement nothing asked for. `'all'`: the whole update lands,
|
|
130
|
+
* for a catch-up result (MarkHandle.resultCause).
|
|
90
131
|
*/
|
|
91
|
-
write(rowIds, channels) {
|
|
132
|
+
write(rowIds, channels, land = NO_BINDINGS) {
|
|
92
133
|
const key = alignmentKey(rowIds);
|
|
93
134
|
let travels = this.#alignmentKey === key;
|
|
94
135
|
this.#alignmentKey = key;
|
|
@@ -100,6 +141,7 @@ export class MorphedChannels {
|
|
|
100
141
|
reallocated = true;
|
|
101
142
|
}
|
|
102
143
|
channel.count = data.byteLength >> 2;
|
|
144
|
+
channel.land = land === 'all' || land.includes(binding);
|
|
103
145
|
this.#device.queue.writeBuffer(channel.to, 0, data);
|
|
104
146
|
}
|
|
105
147
|
// A fresh buffer holds nothing that was ever on screen, so there is
|
|
@@ -107,10 +149,29 @@ export class MorphedChannels {
|
|
|
107
149
|
if (reallocated)
|
|
108
150
|
travels = false;
|
|
109
151
|
this.#dirty = true;
|
|
110
|
-
|
|
152
|
+
// Every channel landing travels nothing, so it starts no transition: on
|
|
153
|
+
// a shared band clock a restart would set every sibling folding for a
|
|
154
|
+
// transition with nowhere to go.
|
|
155
|
+
// A loop, not `every`: this runs on each data update of a brush, and
|
|
156
|
+
// the callback would allocate per write.
|
|
157
|
+
let allLand = land === 'all';
|
|
158
|
+
if (land !== 'all' && land.length > 0) {
|
|
159
|
+
allLand = true;
|
|
160
|
+
for (let i = 0; i < channels.length; i++) {
|
|
161
|
+
if (!land.includes(channels[i][0])) {
|
|
162
|
+
allLand = false;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (travels && !allLand)
|
|
111
168
|
this.#startTransition();
|
|
112
|
-
else
|
|
169
|
+
else if (!travels)
|
|
113
170
|
this.#snapPending = true;
|
|
171
|
+
if (transitionsObserved()) {
|
|
172
|
+
// Snaps when the row set changed or a buffer grew, or every channel lands.
|
|
173
|
+
noteTransition('morph', !travels || allLand, this.#affectedCharts, this.#label);
|
|
174
|
+
}
|
|
114
175
|
if (!this.#registered) {
|
|
115
176
|
this.#registered = true;
|
|
116
177
|
this.#host.registerComputeWork(this.#label, (encoder) => this.encode(encoder));
|
|
@@ -158,8 +219,10 @@ export class MorphedChannels {
|
|
|
158
219
|
return;
|
|
159
220
|
for (let i = 0; i < channels.length; i++) {
|
|
160
221
|
const channel = channels[i];
|
|
161
|
-
if (snap) {
|
|
222
|
+
if (snap || channel.land) {
|
|
223
|
+
// A landed channel: from = to, so the mix is its new value at any t.
|
|
162
224
|
encoder.copyBufferToBuffer(channel.to, 0, channel.from, 0, channel.size);
|
|
225
|
+
channel.land = false;
|
|
163
226
|
}
|
|
164
227
|
else if (this.#foldPending) {
|
|
165
228
|
// A transition interrupted mid-flight continues from where it is,
|
|
@@ -225,7 +288,8 @@ export class MorphedChannels {
|
|
|
225
288
|
resolved: make('resolved'),
|
|
226
289
|
size,
|
|
227
290
|
count: 0,
|
|
228
|
-
bindGroup: null
|
|
291
|
+
bindGroup: null,
|
|
292
|
+
land: false
|
|
229
293
|
};
|
|
230
294
|
this.#channels.set(binding, channel);
|
|
231
295
|
this.#channelList = [...this.#channels.values()];
|
|
@@ -33,14 +33,14 @@ interface ShaderResult {
|
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Bytes of immediate data every render pipeline declares: the chart's x and y
|
|
36
|
-
* `ScaleParam`, 16 bytes each. Every layout declares the same size because a
|
|
36
|
+
* `ScaleParam`, 16 bytes each, and its entrance, a vec4. Every layout declares the same size because a
|
|
37
37
|
* draw requires every declared byte to have been set, and the pass sets them
|
|
38
38
|
* once, before its first draw.
|
|
39
39
|
*
|
|
40
40
|
* Immediates carry state shared across the pass and read by several marks: the
|
|
41
41
|
* chart's scales and settings. 64 bytes are available on M-series Macs.
|
|
42
42
|
*/
|
|
43
|
-
export declare const CHART_SCALE_IMMEDIATE_SIZE =
|
|
43
|
+
export declare const CHART_SCALE_IMMEDIATE_SIZE = 48;
|
|
44
44
|
/**
|
|
45
45
|
* Main template system class
|
|
46
46
|
*/
|
|
@@ -69,6 +69,24 @@ export declare class ScaleTemplateSystem {
|
|
|
69
69
|
* @private
|
|
70
70
|
*/
|
|
71
71
|
_buildDeclarations(xFragment: ScaleFragment, yFragment: ScaleFragment): string;
|
|
72
|
+
/**
|
|
73
|
+
* The chart's entrance, for marks to apply in the vertex stage.
|
|
74
|
+
*
|
|
75
|
+
* A mark either GROWS along one axis (bars, histograms and areas, from the
|
|
76
|
+
* value 0 on their measure axis) or FADES (everything else). Which one is
|
|
77
|
+
* the mark's to say, as `axis`: 0 fades, 1 grows along x, 2 along y. The
|
|
78
|
+
* chart's mode is already folded into the immediates, so a chart set to
|
|
79
|
+
* fade hands a growing mark g = 1 and its opacity instead.
|
|
80
|
+
*
|
|
81
|
+
* The base a mark grows from is where 0 sits on screen, clamped to the plot:
|
|
82
|
+
* a domain that leaves 0 out grows from the edge, which is where its bars
|
|
83
|
+
* visibly start anyway. A log axis has no 0 and grows from its low edge.
|
|
84
|
+
* Decided per scale type here, so no shader evaluates log(0).
|
|
85
|
+
*/
|
|
86
|
+
_buildEntranceHelpers(scaleTypes: {
|
|
87
|
+
x: string;
|
|
88
|
+
y: string;
|
|
89
|
+
}): string;
|
|
72
90
|
/**
|
|
73
91
|
* `bandActivityX(value, group)` and `bandActivityY(value, group)`: how
|
|
74
92
|
* selected a band or point axis's category is in the mark's filter group,
|