@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
|
@@ -16,7 +16,14 @@ export declare function fetchCategoricalDomains(coordinator: QueryEngine, table:
|
|
|
16
16
|
y?: DimValue[];
|
|
17
17
|
} | null,
|
|
18
18
|
/** nulls="drop": the band and facet domains leave out the NULL category. */
|
|
19
|
-
dropNull?: boolean
|
|
19
|
+
dropNull?: boolean,
|
|
20
|
+
/**
|
|
21
|
+
* True once the setup run that called this has been superseded or its mark
|
|
22
|
+
* destroyed. Checked at every write, after each query returns: the scales
|
|
23
|
+
* it would write may have been dropped with a ChartScales the chart has
|
|
24
|
+
* since replaced.
|
|
25
|
+
*/
|
|
26
|
+
stale?: () => boolean): Promise<number>;
|
|
20
27
|
/**
|
|
21
28
|
* Fetch global min/max extents for aggregated fields using a "sidecar" query.
|
|
22
29
|
* Runs the same aggregation as the main query but without filters, wrapped
|
|
@@ -25,6 +32,8 @@ dropNull?: boolean): Promise<number>;
|
|
|
25
32
|
* Returns `{ globalAggregatesSet: true }` on success so the caller can
|
|
26
33
|
* update its reactive state.
|
|
27
34
|
*/
|
|
28
|
-
export declare function fetchGlobalAggregates(coordinator: QueryEngine, table: string, select: Record<string, unknown>, channelsNeedingDataDomain: Set<string>, autoBinNodeCount: number, buildQueryFn: (table: string, config: unknown, filter: unknown[], forMosaic: boolean) => Query, config: unknown, xScaleState: ContinuousScaleState | null, yScaleState: ContinuousScaleState | null, colorScaleState: ColorScaleState | null, markId: string
|
|
35
|
+
export declare function fetchGlobalAggregates(coordinator: QueryEngine, table: string, select: Record<string, unknown>, channelsNeedingDataDomain: Set<string>, autoBinNodeCount: number, buildQueryFn: (table: string, config: unknown, filter: unknown[], forMosaic: boolean) => Query, config: unknown, xScaleState: ContinuousScaleState | null, yScaleState: ContinuousScaleState | null, colorScaleState: ColorScaleState | null, markId: string,
|
|
36
|
+
/** As for fetchCategoricalDomains: checked before writing the extents. */
|
|
37
|
+
stale?: () => boolean): Promise<{
|
|
29
38
|
globalAggregatesSet: boolean;
|
|
30
39
|
}>;
|
|
@@ -12,7 +12,14 @@ import { identityKeyFor } from '../../../query-engine/identity-key';
|
|
|
12
12
|
*/
|
|
13
13
|
export async function fetchCategoricalDomains(coordinator, table, select, actualXScaleType, actualYScaleType, xScaleState, yScaleState, facetBandScale, fx, colorChannel, colorScaleState, sizeChannel, sizeScaleState, seriesScaleState, seriesChannel, bandDomainFromData, markId, explicitDomain,
|
|
14
14
|
/** nulls="drop": the band and facet domains leave out the NULL category. */
|
|
15
|
-
dropNull = false
|
|
15
|
+
dropNull = false,
|
|
16
|
+
/**
|
|
17
|
+
* True once the setup run that called this has been superseded or its mark
|
|
18
|
+
* destroyed. Checked at every write, after each query returns: the scales
|
|
19
|
+
* it would write may have been dropped with a ChartScales the chart has
|
|
20
|
+
* since replaced.
|
|
21
|
+
*/
|
|
22
|
+
stale = () => false) {
|
|
16
23
|
const categoriesOf = (key) => {
|
|
17
24
|
const categories = coordinator.categoryValues(key, table);
|
|
18
25
|
return dropNull ? categories.filter((c) => c !== null) : categories;
|
|
@@ -70,6 +77,8 @@ dropNull = false) {
|
|
|
70
77
|
fetches.push((async () => {
|
|
71
78
|
// Idempotent and coalesced — the mark's own setup calls this too.
|
|
72
79
|
await coordinator.ensureColumns(table, { categorical: [identityField] });
|
|
80
|
+
if (stale())
|
|
81
|
+
return;
|
|
73
82
|
// This table's categories: the dim spans every table on the field.
|
|
74
83
|
const categories = categoriesOf(identityField.key);
|
|
75
84
|
// A snapshot of the real categories. The scale adopts the live
|
|
@@ -128,6 +137,8 @@ dropNull = false) {
|
|
|
128
137
|
fetches.push((async () => {
|
|
129
138
|
// Idempotent and coalesced — the mark's own setup calls this too.
|
|
130
139
|
await coordinator.ensureColumns(table, { categorical: [facetKey] });
|
|
140
|
+
if (stale())
|
|
141
|
+
return;
|
|
131
142
|
const categories = categoriesOf(facetKey.key);
|
|
132
143
|
if (categories.length > 0)
|
|
133
144
|
facetBandScale.addMark(categories, markId);
|
|
@@ -150,7 +161,9 @@ dropNull = false) {
|
|
|
150
161
|
min_time: min(colExpr),
|
|
151
162
|
max_time: max(colExpr)
|
|
152
163
|
});
|
|
153
|
-
fetches.push(coordinator.query(q).then((result) => {
|
|
164
|
+
fetches.push(coordinator.query(q, { cache: true, source: table }).then((result) => {
|
|
165
|
+
if (stale())
|
|
166
|
+
return;
|
|
154
167
|
const row = Array.from(result)[0];
|
|
155
168
|
if (row && row.min_time != null && row.max_time != null) {
|
|
156
169
|
console.log(`[fetchCategoricalDomains] Time extent for ${axis}:`, [
|
|
@@ -192,6 +205,8 @@ dropNull = false) {
|
|
|
192
205
|
fetches.push((async () => {
|
|
193
206
|
// Idempotent and coalesced — the mark's own setup calls this too.
|
|
194
207
|
await coordinator.ensureColumns(table, { categorical: [colorIdentity] });
|
|
208
|
+
if (stale())
|
|
209
|
+
return;
|
|
195
210
|
const categories = coordinator.categoryValues(colorIdentity.key);
|
|
196
211
|
if (categories.length > 0) {
|
|
197
212
|
colorScaleState.setDomain(categories);
|
|
@@ -205,7 +220,9 @@ dropNull = false) {
|
|
|
205
220
|
min_color: cast(min(colExpr), 'REAL'),
|
|
206
221
|
max_color: cast(max(colExpr), 'REAL')
|
|
207
222
|
});
|
|
208
|
-
fetches.push(coordinator.query(q).then((result) => {
|
|
223
|
+
fetches.push(coordinator.query(q, { cache: true, source: table }).then((result) => {
|
|
224
|
+
if (stale())
|
|
225
|
+
return;
|
|
209
226
|
const row = Array.from(result)[0];
|
|
210
227
|
if (row && row.min_color != null && row.max_color != null) {
|
|
211
228
|
console.log(`[fetchCategoricalDomains] Color domain (sequential):`, [
|
|
@@ -226,7 +243,9 @@ dropNull = false) {
|
|
|
226
243
|
min_radius: cast(min(sqlColumn(String(sizeField))), 'REAL'),
|
|
227
244
|
max_radius: cast(max(sqlColumn(String(sizeField))), 'REAL')
|
|
228
245
|
});
|
|
229
|
-
fetches.push(coordinator.query(q).then((result) => {
|
|
246
|
+
fetches.push(coordinator.query(q, { cache: true, source: table }).then((result) => {
|
|
247
|
+
if (stale())
|
|
248
|
+
return;
|
|
230
249
|
const row = Array.from(result)[0];
|
|
231
250
|
if (row && row.min_radius != null && row.max_radius != null) {
|
|
232
251
|
sizeScaleState.setDomain([row.min_radius, row.max_radius]);
|
|
@@ -241,6 +260,8 @@ dropNull = false) {
|
|
|
241
260
|
if (seriesIdentity) {
|
|
242
261
|
fetches.push((async () => {
|
|
243
262
|
await coordinator.ensureColumns(table, { categorical: [seriesIdentity] });
|
|
263
|
+
if (stale())
|
|
264
|
+
return;
|
|
244
265
|
const categories = coordinator.categoryValues(seriesIdentity.key);
|
|
245
266
|
if (categories.length > 0) {
|
|
246
267
|
seriesScaleState.setDomain(categories);
|
|
@@ -250,6 +271,8 @@ dropNull = false) {
|
|
|
250
271
|
}
|
|
251
272
|
if (fetches.length > 0)
|
|
252
273
|
await Promise.all(fetches);
|
|
274
|
+
if (stale())
|
|
275
|
+
return fetches.length;
|
|
253
276
|
// Apply explicit domains after all async fetches — ViewManager columns
|
|
254
277
|
// from color/series scales are now registered, so the band view will
|
|
255
278
|
// include all necessary index columns.
|
|
@@ -272,7 +295,9 @@ dropNull = false) {
|
|
|
272
295
|
* Returns `{ globalAggregatesSet: true }` on success so the caller can
|
|
273
296
|
* update its reactive state.
|
|
274
297
|
*/
|
|
275
|
-
export async function fetchGlobalAggregates(coordinator, table, select, channelsNeedingDataDomain, autoBinNodeCount, buildQueryFn, config, xScaleState, yScaleState, colorScaleState, markId
|
|
298
|
+
export async function fetchGlobalAggregates(coordinator, table, select, channelsNeedingDataDomain, autoBinNodeCount, buildQueryFn, config, xScaleState, yScaleState, colorScaleState, markId,
|
|
299
|
+
/** As for fetchCategoricalDomains: checked before writing the extents. */
|
|
300
|
+
stale = () => false) {
|
|
276
301
|
// Only proceed if we have channels needing data-derived domains
|
|
277
302
|
if (channelsNeedingDataDomain.size === 0) {
|
|
278
303
|
console.log(`[${markId}] No aggregated channels, skipping sidecar query`);
|
|
@@ -334,7 +359,9 @@ export async function fetchGlobalAggregates(coordinator, table, select, channels
|
|
|
334
359
|
const sidecarQuery = Query.from(innerQuery).select(outerSelect);
|
|
335
360
|
console.log(`📊 [${markId}] Sidecar query SQL:`, sidecarQuery.toString());
|
|
336
361
|
// Step 3: Execute the query
|
|
337
|
-
const result = await coordinator.query(sidecarQuery);
|
|
362
|
+
const result = await coordinator.query(sidecarQuery, { cache: true, source: table });
|
|
363
|
+
if (stale())
|
|
364
|
+
return { globalAggregatesSet: false };
|
|
338
365
|
const extents = Array.from(result)[0];
|
|
339
366
|
console.log(`✅ [${markId}] Sidecar results:`, extents);
|
|
340
367
|
// Step 4: Apply extents to scales
|
|
@@ -39,5 +39,10 @@ export declare function setInitialContinuousDomains(fieldInfo: Record<string, Fi
|
|
|
39
39
|
export declare function registerDataDerivedDomains(data: DataAccessor, channelsNeedingDataDomain: Set<string>, additionalChannels: string[], skipDomainUpdateForAxis: string | null, zeroBaseline: {
|
|
40
40
|
x?: boolean;
|
|
41
41
|
y?: boolean;
|
|
42
|
-
} | undefined, actualXScaleType: string, actualYScaleType: string, xScaleState: ContinuousScaleState | null, yScaleState: ContinuousScaleState | null, bandDomainFromData: boolean, xBandScaleState: BandScaleState | null, yBandScaleState: BandScaleState | null, markId: string,
|
|
42
|
+
} | undefined, actualXScaleType: string, actualYScaleType: string, xScaleState: ContinuousScaleState | null, yScaleState: ContinuousScaleState | null, bandDomainFromData: boolean, xBandScaleState: BandScaleState | null, yBandScaleState: BandScaleState | null, markId: string,
|
|
43
|
+
/**
|
|
44
|
+
* Whether a scale's change from this result lands without animating: a
|
|
45
|
+
* catch-up result on a scale no other visible chart draws. Null: animate.
|
|
46
|
+
*/
|
|
47
|
+
instantFor: ((scale: object) => boolean) | null, colorScaleState?: ColorScaleState | null): RegisterDomainsResult;
|
|
43
48
|
export {};
|
|
@@ -100,7 +100,12 @@ export function setInitialContinuousDomains(fieldInfo, scaleMap, select, actualX
|
|
|
100
100
|
* Called from Effect 7 on each data update. Uses positional args to avoid
|
|
101
101
|
* object allocation on the crossfilter hot path.
|
|
102
102
|
*/
|
|
103
|
-
export function registerDataDerivedDomains(data, channelsNeedingDataDomain, additionalChannels, skipDomainUpdateForAxis, zeroBaseline, actualXScaleType, actualYScaleType, xScaleState, yScaleState, bandDomainFromData, xBandScaleState, yBandScaleState, markId,
|
|
103
|
+
export function registerDataDerivedDomains(data, channelsNeedingDataDomain, additionalChannels, skipDomainUpdateForAxis, zeroBaseline, actualXScaleType, actualYScaleType, xScaleState, yScaleState, bandDomainFromData, xBandScaleState, yBandScaleState, markId,
|
|
104
|
+
/**
|
|
105
|
+
* Whether a scale's change from this result lands without animating: a
|
|
106
|
+
* catch-up result on a scale no other visible chart draws. Null: animate.
|
|
107
|
+
*/
|
|
108
|
+
instantFor, colorScaleState) {
|
|
104
109
|
if (!data || data.length === 0) {
|
|
105
110
|
return { dataDerivedDomainsSet: false, skipDomainUpdateForAxis };
|
|
106
111
|
}
|
|
@@ -152,7 +157,8 @@ export function registerDataDerivedDomains(data, channelsNeedingDataDomain, addi
|
|
|
152
157
|
if (zeroBaseline?.x) {
|
|
153
158
|
extent = [Math.min(0, extent[0]), Math.max(0, extent[1])];
|
|
154
159
|
}
|
|
155
|
-
|
|
160
|
+
const instant = !!xScaleState && (instantFor?.(xScaleState) ?? false);
|
|
161
|
+
registerExtentOnScale(xScaleState, actualXScaleType, extent, markId, instant, 'X');
|
|
156
162
|
}
|
|
157
163
|
}
|
|
158
164
|
// Compute and register Y domain
|
|
@@ -166,7 +172,8 @@ export function registerDataDerivedDomains(data, channelsNeedingDataDomain, addi
|
|
|
166
172
|
if (zeroBaseline?.y) {
|
|
167
173
|
extent = [Math.min(0, extent[0]), Math.max(0, extent[1])];
|
|
168
174
|
}
|
|
169
|
-
|
|
175
|
+
const instant = !!yScaleState && (instantFor?.(yScaleState) ?? false);
|
|
176
|
+
registerExtentOnScale(yScaleState, actualYScaleType, extent, markId, instant, 'Y');
|
|
170
177
|
}
|
|
171
178
|
}
|
|
172
179
|
// Band scale domain from the query result, for a mark whose axis is decided
|
|
@@ -217,7 +224,7 @@ export function registerDataDerivedDomains(data, channelsNeedingDataDomain, addi
|
|
|
217
224
|
continue;
|
|
218
225
|
bandScale.addMark(categories, markId);
|
|
219
226
|
}
|
|
220
|
-
bandScale.updateDomainFromExtents();
|
|
227
|
+
bandScale.updateDomainFromExtents({ instant: instantFor?.(bandScale) ?? false });
|
|
221
228
|
}
|
|
222
229
|
}
|
|
223
230
|
// Color domain from query results (needed when sidecar is skipped, e.g. binned marks)
|
|
@@ -240,20 +247,14 @@ export function registerDataDerivedDomains(data, channelsNeedingDataDomain, addi
|
|
|
240
247
|
// ---------------------------------------------------------------------------
|
|
241
248
|
// Internal helper
|
|
242
249
|
// ---------------------------------------------------------------------------
|
|
243
|
-
function registerExtentOnScale(scaleState, scaleType, extent, markId,
|
|
250
|
+
function registerExtentOnScale(scaleState, scaleType, extent, markId, instant, axisLabel) {
|
|
244
251
|
if (scaleType === 'time' && scaleState?.addOffsetExtent) {
|
|
245
252
|
// Time scale: data is in offset form, use addOffsetExtent
|
|
246
253
|
console.log(`📊 [${markId}] Registering ${axisLabel} domain from data (time offsets):`, extent);
|
|
247
|
-
scaleState.addOffsetExtent(extent, markId);
|
|
254
|
+
scaleState.addOffsetExtent(extent, markId, { instant });
|
|
248
255
|
}
|
|
249
256
|
else if (scaleState?.addMark) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
console.log(`⚡ [${markId}] Instant ${axisLabel} domain update (rebinning):`, extent);
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
console.log(`📊 [${markId}] Registering ${axisLabel} domain from data:`, extent);
|
|
256
|
-
}
|
|
257
|
-
scaleState.addMark(extent, markId, { instant: isRebinning });
|
|
257
|
+
console.log(`📊 [${markId}] Registering ${axisLabel} domain from data:`, extent);
|
|
258
|
+
scaleState.addMark(extent, markId, { instant });
|
|
258
259
|
}
|
|
259
260
|
}
|
|
@@ -58,8 +58,16 @@ export interface OtherRowsDeps {
|
|
|
58
58
|
identity: () => Record<string, ChannelIdentity> | null;
|
|
59
59
|
/** The identity key of a band axis, or null when it has none. */
|
|
60
60
|
identityKey: (axis: 'x' | 'y') => string | null;
|
|
61
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* The mark is filtered by every selection (`'filter'`): its Other is
|
|
63
|
+
* recomputed inside the selection, so a click on it drills down.
|
|
64
|
+
*/
|
|
62
65
|
filtered: () => boolean;
|
|
66
|
+
/**
|
|
67
|
+
* A selection can dim the mark (`'auto'`). Not under `'filter'` or
|
|
68
|
+
* `'ignore'`, whose Other bars get no selected share.
|
|
69
|
+
*/
|
|
70
|
+
dims: () => boolean;
|
|
63
71
|
/** The mark's plan, or null before its setup completes. */
|
|
64
72
|
plan: () => SplitPlan | null;
|
|
65
73
|
/** The identity key of the mark's ordinal colour scale, or null. */
|
|
@@ -135,7 +135,7 @@ export class OtherRows {
|
|
|
135
135
|
* The band axis whose Other bar splits, or null. Only where a share is what
|
|
136
136
|
* it looks like:
|
|
137
137
|
* - a bar mark ('bary', 'barx') with a topN Other bucket, dimming (not
|
|
138
|
-
* 'filter', which never
|
|
138
|
+
* 'filter' or 'ignore', which never dim) and without JS transforms, whose rows would
|
|
139
139
|
* no longer line up with the query's;
|
|
140
140
|
* - whose length is the measure topN ranks by, which is what Other sums;
|
|
141
141
|
* - and that measure a bare COUNT or SUM, or a raw column: a mean or a max
|
|
@@ -143,7 +143,7 @@ export class OtherRows {
|
|
|
143
143
|
*/
|
|
144
144
|
get #splitAxis() {
|
|
145
145
|
const plan = this.#deps.plan();
|
|
146
|
-
if (!plan || this.#deps.
|
|
146
|
+
if (!plan || !this.#deps.dims())
|
|
147
147
|
return null;
|
|
148
148
|
if (!plan.hasOther || plan.hasJsTransforms)
|
|
149
149
|
return null;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { sum, Query, WindowNode, type ExprNode } from '@uwdata/mosaic-sql';
|
|
2
2
|
import type { TransformCompiler } from '../../../transforms/TransformCompiler';
|
|
3
3
|
import type { ColumnSchema } from '../../../query-engine/QueryEngine';
|
|
4
|
+
import type { BinPadding } from '../../../types';
|
|
4
5
|
interface OrderConfig {
|
|
5
6
|
seriesChannel: string | null;
|
|
6
7
|
dimensionChannel: string;
|
|
@@ -18,6 +19,14 @@ export interface QueryParts {
|
|
|
18
19
|
* combination, and cannot recover from a query topN has already wrapped.
|
|
19
20
|
*/
|
|
20
21
|
groupKeys: string[] | null;
|
|
22
|
+
/**
|
|
23
|
+
* The numeric `bin()` channels and their bins, set by the mark from the
|
|
24
|
+
* same resolution its bin expressions came from. With them `dense()` pads a
|
|
25
|
+
* histogram to every bin; preagg reads copy them, so both paths pad alike.
|
|
26
|
+
*/
|
|
27
|
+
bins?: Record<string, BinPadding> | null;
|
|
28
|
+
/** The query reads a preagg table that already holds its padding rows. */
|
|
29
|
+
padded?: boolean;
|
|
21
30
|
orderChannels: string[] | null;
|
|
22
31
|
aliasMap: Map<string, string>;
|
|
23
32
|
/** Channels whose raw config value was a column-name passthrough (string
|
|
@@ -74,8 +83,8 @@ export interface AssembleOptions {
|
|
|
74
83
|
/**
|
|
75
84
|
* Wrap an expression so DuckDB returns a Float32-compatible REAL with NULLs
|
|
76
85
|
* mapped to NaN: COALESCE(CAST(expr AS REAL), 'NaN'::REAL). Arrow columns then
|
|
77
|
-
* have nullCount=0 and clean buffers
|
|
78
|
-
* NaN and discard.
|
|
86
|
+
* have nullCount=0 and clean Float32 buffers that upload to the GPU as they are,
|
|
87
|
+
* with no per-row JS pass; shaders detect NaN and discard.
|
|
79
88
|
*/
|
|
80
89
|
export declare function castReal(expr: unknown): ExprNode;
|
|
81
90
|
/**
|
|
@@ -159,5 +168,21 @@ export declare function buildQueryParts(select: Record<string, unknown>, orderCo
|
|
|
159
168
|
* discarded one level up.
|
|
160
169
|
*/
|
|
161
170
|
export declare function outerOrder(preference: string[] | null, alignment: string[] | null): string[] | null;
|
|
171
|
+
/**
|
|
172
|
+
* Assemble a Query from cached parts + per-call filter.
|
|
173
|
+
*
|
|
174
|
+
* Order is fixed and shared by the flat, window-CTE, and preagg paths:
|
|
175
|
+
*
|
|
176
|
+
* SELECT parts.selectDef FROM table [GROUP BY dims]
|
|
177
|
+
* WHERE filter AND nullDrops — on the base scan, so transform CTEs
|
|
178
|
+
* (topN ranking etc.) see filtered rows
|
|
179
|
+
* → SQL transforms (CTE wrapping)
|
|
180
|
+
* → [window CTE: outer SELECT applies window fns over the inner result]
|
|
181
|
+
* → ORDER BY outerOrder(...) — alignment, then orderChannels; outermost
|
|
182
|
+
* → LIMIT
|
|
183
|
+
*
|
|
184
|
+
* Callers decide what is CAST-wrapped by preparing parts.selectDef with
|
|
185
|
+
* castNumeric(); assembly never inspects expression types.
|
|
186
|
+
*/
|
|
162
187
|
export declare function assembleQuery(opts: AssembleOptions): Query;
|
|
163
188
|
export {};
|
|
@@ -23,8 +23,8 @@ export function nullDropPredicates(drops, selectDef) {
|
|
|
23
23
|
/**
|
|
24
24
|
* Wrap an expression so DuckDB returns a Float32-compatible REAL with NULLs
|
|
25
25
|
* mapped to NaN: COALESCE(CAST(expr AS REAL), 'NaN'::REAL). Arrow columns then
|
|
26
|
-
* have nullCount=0 and clean buffers
|
|
27
|
-
* NaN and discard.
|
|
26
|
+
* have nullCount=0 and clean Float32 buffers that upload to the GPU as they are,
|
|
27
|
+
* with no per-row JS pass; shaders detect NaN and discard.
|
|
28
28
|
*/
|
|
29
29
|
export function castReal(expr) {
|
|
30
30
|
return coalesce(cast(expr, 'REAL'), sql `'NaN'::REAL`);
|
|
@@ -219,22 +219,6 @@ export function buildQueryParts(select, orderConfig, hasSQLTransforms, passthrou
|
|
|
219
219
|
// ---------------------------------------------------------------------------
|
|
220
220
|
// Assembly — the one sequence every query path follows
|
|
221
221
|
// ---------------------------------------------------------------------------
|
|
222
|
-
/**
|
|
223
|
-
* Assemble a Query from cached parts + per-call filter.
|
|
224
|
-
*
|
|
225
|
-
* Order is fixed and shared by the flat, window-CTE, and preagg paths:
|
|
226
|
-
*
|
|
227
|
-
* SELECT parts.selectDef FROM table [GROUP BY dims]
|
|
228
|
-
* WHERE filter AND nullDrops — on the base scan, so transform CTEs
|
|
229
|
-
* (topN ranking etc.) see filtered rows
|
|
230
|
-
* → SQL transforms (CTE wrapping)
|
|
231
|
-
* → [window CTE: outer SELECT applies window fns over the inner result]
|
|
232
|
-
* → ORDER BY outerOrder(...) — alignment, then orderChannels; outermost
|
|
233
|
-
* → LIMIT
|
|
234
|
-
*
|
|
235
|
-
* Callers decide what is CAST-wrapped by preparing parts.selectDef with
|
|
236
|
-
* castNumeric(); assembly never inspects expression types.
|
|
237
|
-
*/
|
|
238
222
|
/** Output aliases a query exposes to whatever wraps it. */
|
|
239
223
|
function selectAliases(query) {
|
|
240
224
|
const sel = query._select;
|
|
@@ -283,6 +267,22 @@ export function outerOrder(preference, alignment) {
|
|
|
283
267
|
add(channel);
|
|
284
268
|
return order;
|
|
285
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Assemble a Query from cached parts + per-call filter.
|
|
272
|
+
*
|
|
273
|
+
* Order is fixed and shared by the flat, window-CTE, and preagg paths:
|
|
274
|
+
*
|
|
275
|
+
* SELECT parts.selectDef FROM table [GROUP BY dims]
|
|
276
|
+
* WHERE filter AND nullDrops — on the base scan, so transform CTEs
|
|
277
|
+
* (topN ranking etc.) see filtered rows
|
|
278
|
+
* → SQL transforms (CTE wrapping)
|
|
279
|
+
* → [window CTE: outer SELECT applies window fns over the inner result]
|
|
280
|
+
* → ORDER BY outerOrder(...) — alignment, then orderChannels; outermost
|
|
281
|
+
* → LIMIT
|
|
282
|
+
*
|
|
283
|
+
* Callers decide what is CAST-wrapped by preparing parts.selectDef with
|
|
284
|
+
* castNumeric(); assembly never inspects expression types.
|
|
285
|
+
*/
|
|
286
286
|
export function assembleQuery(opts) {
|
|
287
287
|
const { table, parts, filter = [], transformCompiler, limit, window, skipRowFilters } = opts;
|
|
288
288
|
const { selectDef, nonAggregateGroupBy, hasAggregates, hasSQLTransforms, orderChannels } = parts;
|
|
@@ -299,7 +299,7 @@ export function assembleQuery(opts) {
|
|
|
299
299
|
}
|
|
300
300
|
let result = q;
|
|
301
301
|
if (hasSQLTransforms) {
|
|
302
|
-
result = transformCompiler.applyToQuery(q, { groupKeys: parts.groupKeys }, { skipRowFilters });
|
|
302
|
+
result = transformCompiler.applyToQuery(q, { groupKeys: parts.groupKeys, bins: parts.bins ?? null, padded: parts.padded ?? false }, { skipRowFilters });
|
|
303
303
|
}
|
|
304
304
|
if (window) {
|
|
305
305
|
const outerSelect = {};
|
|
@@ -327,7 +327,10 @@ export function assembleQuery(opts) {
|
|
|
327
327
|
.with({ [window.cteName]: result });
|
|
328
328
|
}
|
|
329
329
|
const alignment = hasSQLTransforms
|
|
330
|
-
? transformCompiler.alignment(Object.keys(selectDef), {
|
|
330
|
+
? transformCompiler.alignment(Object.keys(selectDef), {
|
|
331
|
+
groupKeys: parts.groupKeys,
|
|
332
|
+
bins: parts.bins ?? null
|
|
333
|
+
})
|
|
331
334
|
: null;
|
|
332
335
|
const order = outerOrder(orderChannels, alignment);
|
|
333
336
|
if (order) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ColorScaleState } from '../../../scales/ColorScaleState.svelte';
|
|
2
|
-
import type { ColorProp, ChartContext } from '../../../types';
|
|
2
|
+
import type { ColorDomainValue, ColorProp, ChartContext } from '../../../types';
|
|
3
3
|
import type { ScaleRegistry } from '../../../scales/ScaleRegistry.svelte';
|
|
4
4
|
import type { MarkSetupState } from './mark-types';
|
|
5
5
|
interface ColorConfig {
|
|
@@ -11,6 +11,8 @@ interface ColorConfig {
|
|
|
11
11
|
explicitType?: string;
|
|
12
12
|
constant?: number;
|
|
13
13
|
exponent?: number;
|
|
14
|
+
range?: readonly string[];
|
|
15
|
+
pinnedDomain?: readonly ColorDomainValue[];
|
|
14
16
|
}
|
|
15
17
|
export declare class MarkColor {
|
|
16
18
|
#private;
|
|
@@ -30,6 +30,10 @@ export class MarkColor {
|
|
|
30
30
|
const mode = this.#mode;
|
|
31
31
|
const field = this.#field;
|
|
32
32
|
const type = this.config.scaleType;
|
|
33
|
+
// Again when the chart's scales are replaced: the registry dropped
|
|
34
|
+
// this one with the old ChartScales (its GPU slots may already be
|
|
35
|
+
// someone else's), and holding it would write to a destroyed scale.
|
|
36
|
+
void this.#chartContext.scaleGeneration;
|
|
33
37
|
// Only create scale when type is known (not null)
|
|
34
38
|
if (mode === 'field' && field && this.#scaleRegistry && type !== null) {
|
|
35
39
|
untrack(() => {
|
|
@@ -42,7 +46,9 @@ export class MarkColor {
|
|
|
42
46
|
type: type,
|
|
43
47
|
scheme: this.config.scheme,
|
|
44
48
|
constant: this.config.constant,
|
|
45
|
-
exponent: this.config.exponent
|
|
49
|
+
exponent: this.config.exponent,
|
|
50
|
+
range: this.config.range,
|
|
51
|
+
pinnedDomain: this.config.pinnedDomain
|
|
46
52
|
}, this.#chartContext.chartId);
|
|
47
53
|
});
|
|
48
54
|
}
|
|
@@ -66,6 +72,21 @@ export class MarkColor {
|
|
|
66
72
|
this.scaleState.setScheme(scheme);
|
|
67
73
|
}
|
|
68
74
|
});
|
|
75
|
+
// 2a. Lifecycle: Update explicit colours (Fast Path - no scale recreation)
|
|
76
|
+
// Like the scheme, a mark without them leaves a shared scale's alone; one
|
|
77
|
+
// that drops them (an edited prop) clears what it set.
|
|
78
|
+
let hadRange = false;
|
|
79
|
+
$effect(() => {
|
|
80
|
+
const range = this.config.range;
|
|
81
|
+
const pinned = this.config.pinnedDomain;
|
|
82
|
+
const scale = this.scaleState;
|
|
83
|
+
if (!scale?.isOrdinal)
|
|
84
|
+
return;
|
|
85
|
+
const has = !!(range?.length || pinned?.length);
|
|
86
|
+
if (has || hadRange)
|
|
87
|
+
scale.setRange(range ?? null, pinned ?? null);
|
|
88
|
+
hadRange = has;
|
|
89
|
+
});
|
|
69
90
|
// 2b. Lifecycle: Update Transform (Fast Path - no scale recreation)
|
|
70
91
|
$effect(() => {
|
|
71
92
|
const type = this.config.explicitType;
|
|
@@ -148,6 +169,8 @@ export class MarkColor {
|
|
|
148
169
|
let explicitType;
|
|
149
170
|
let constant;
|
|
150
171
|
let exponent;
|
|
172
|
+
let range;
|
|
173
|
+
let pinnedDomain;
|
|
151
174
|
// Handle object wrapper format { field: "species", scheme: "dark2", type: "symlog" }
|
|
152
175
|
if (typeof c === 'object' && 'field' in c && !isNode(c)) {
|
|
153
176
|
field = c.field;
|
|
@@ -155,10 +178,15 @@ export class MarkColor {
|
|
|
155
178
|
explicitType = c.type;
|
|
156
179
|
constant = c.constant;
|
|
157
180
|
exponent = c.exponent;
|
|
181
|
+
range = c.range;
|
|
182
|
+
pinnedDomain = c.domain;
|
|
158
183
|
}
|
|
159
184
|
// 1. Determine Type from field semantics + schema (may return null if waiting for schema)
|
|
160
185
|
// If an explicit type is given (log/symlog/sqrt/pow), use it directly.
|
|
161
|
-
|
|
186
|
+
// Explicit colours or pinned values mean categories, whatever the column
|
|
187
|
+
// type: a 0/1 integer column would otherwise read as continuous.
|
|
188
|
+
const scaleType = explicitType ||
|
|
189
|
+
(range?.length || pinnedDomain?.length ? 'ordinal' : this.#resolveScaleType(field));
|
|
162
190
|
// 2. Pass explicit scheme if provided, otherwise undefined (registry will apply default)
|
|
163
191
|
return {
|
|
164
192
|
mode: 'field',
|
|
@@ -167,7 +195,9 @@ export class MarkColor {
|
|
|
167
195
|
scheme: explicitScheme, // undefined if not specified
|
|
168
196
|
explicitType,
|
|
169
197
|
constant,
|
|
170
|
-
exponent
|
|
198
|
+
exponent,
|
|
199
|
+
range,
|
|
200
|
+
pinnedDomain
|
|
171
201
|
};
|
|
172
202
|
});
|
|
173
203
|
// Separate derived for mode (independent of scheme to avoid unnecessary tracking)
|
|
@@ -12,8 +12,21 @@ import type { MarkSetupState } from './mark-types';
|
|
|
12
12
|
export declare class MarkSeries {
|
|
13
13
|
#private;
|
|
14
14
|
scaleState: ColorScaleState | null;
|
|
15
|
-
constructor(getSeries: () => string | object | null, channelName: string, getSetup: () => MarkSetupState, scaleRegistry: ScaleRegistry, chartContext: ChartContext);
|
|
15
|
+
constructor(getSeries: () => string | object | null, channelName: string, getSetup: () => MarkSetupState, scaleRegistry: ScaleRegistry, chartContext: ChartContext, getColorScale?: () => ColorScaleState | null);
|
|
16
16
|
selectField: string | object | null;
|
|
17
17
|
data: Float32Array | null;
|
|
18
|
+
/**
|
|
19
|
+
* Whether the renderer reads selection activity through the series scale:
|
|
20
|
+
* 1 for a `z` of its own, a field that carries ids, so a selection on it
|
|
21
|
+
* dims the other series. 0 without `z` (the series is the colour, read
|
|
22
|
+
* already), for a `z` on the colour field (the registry hands both
|
|
23
|
+
* channels one scale, and reading it twice is a load for nothing), and
|
|
24
|
+
* before the scale has an identity, while its values are not ids yet.
|
|
25
|
+
* Routing (MarkLifecycleV2's reads) lists the same field in the same
|
|
26
|
+
* cases, so the mark dims rather than filters exactly when this is 1.
|
|
27
|
+
*/
|
|
28
|
+
activityMode: number;
|
|
29
|
+
/** The series scale's colour config index, read when `activityMode` is 1. */
|
|
30
|
+
activityScaleIndex: number;
|
|
18
31
|
ready: boolean;
|
|
19
32
|
}
|
|
@@ -15,17 +15,23 @@ export class MarkSeries {
|
|
|
15
15
|
#setupState;
|
|
16
16
|
#scaleRegistry;
|
|
17
17
|
#chartContext;
|
|
18
|
+
#colorScale;
|
|
18
19
|
scaleState = $state(null);
|
|
19
|
-
constructor(getSeries, channelName, getSetup, scaleRegistry, chartContext) {
|
|
20
|
+
constructor(getSeries, channelName, getSetup, scaleRegistry, chartContext, getColorScale = () => null) {
|
|
20
21
|
this.#seriesProp = getSeries;
|
|
21
22
|
this.#channelName = channelName;
|
|
22
23
|
this.#setupState = getSetup;
|
|
23
24
|
this.#scaleRegistry = scaleRegistry;
|
|
24
25
|
this.#chartContext = chartContext;
|
|
26
|
+
this.#colorScale = getColorScale;
|
|
25
27
|
// Lifecycle: Create/Destroy Scale
|
|
26
28
|
// Series grouping is always ordinal
|
|
27
29
|
$effect(() => {
|
|
28
30
|
const field = this.#field;
|
|
31
|
+
// Again when the chart's scales are replaced: the registry dropped
|
|
32
|
+
// this one with the old ChartScales (its GPU slots may already be
|
|
33
|
+
// someone else's), and holding it would write to a destroyed scale.
|
|
34
|
+
void this.#chartContext.scaleGeneration;
|
|
29
35
|
if (field && this.#scaleRegistry) {
|
|
30
36
|
untrack(() => {
|
|
31
37
|
// Use raw field name - registry deduplicates automatically
|
|
@@ -89,6 +95,24 @@ export class MarkSeries {
|
|
|
89
95
|
}
|
|
90
96
|
return this.scaleState.processDataForGPU(raw);
|
|
91
97
|
});
|
|
98
|
+
/**
|
|
99
|
+
* Whether the renderer reads selection activity through the series scale:
|
|
100
|
+
* 1 for a `z` of its own, a field that carries ids, so a selection on it
|
|
101
|
+
* dims the other series. 0 without `z` (the series is the colour, read
|
|
102
|
+
* already), for a `z` on the colour field (the registry hands both
|
|
103
|
+
* channels one scale, and reading it twice is a load for nothing), and
|
|
104
|
+
* before the scale has an identity, while its values are not ids yet.
|
|
105
|
+
* Routing (MarkLifecycleV2's reads) lists the same field in the same
|
|
106
|
+
* cases, so the mark dims rather than filters exactly when this is 1.
|
|
107
|
+
*/
|
|
108
|
+
activityMode = $derived.by(() => {
|
|
109
|
+
const scale = this.scaleState;
|
|
110
|
+
if (this.#channelName !== 'z' || !scale?.hasIdentity)
|
|
111
|
+
return 0;
|
|
112
|
+
return scale === this.#colorScale() ? 0 : 1;
|
|
113
|
+
});
|
|
114
|
+
/** The series scale's colour config index, read when `activityMode` is 1. */
|
|
115
|
+
activityScaleIndex = $derived(this.scaleState?.gpuIndex ?? 0);
|
|
92
116
|
// Ready when: no field (single series) or scale is ready
|
|
93
117
|
ready = $derived(!this.#field || (this.scaleState?.ready ?? false));
|
|
94
118
|
}
|
|
@@ -18,6 +18,10 @@ export class MarkSize {
|
|
|
18
18
|
$effect(() => {
|
|
19
19
|
const mode = this.#mode;
|
|
20
20
|
const field = this.#field;
|
|
21
|
+
// Again when the chart's scales are replaced: the registry dropped
|
|
22
|
+
// this one with the old ChartScales (its GPU slots may already be
|
|
23
|
+
// someone else's), and holding it would write to a destroyed scale.
|
|
24
|
+
void this.#chartContext.scaleGeneration;
|
|
21
25
|
if (mode === 'field' && field && this.#scaleRegistry) {
|
|
22
26
|
untrack(() => {
|
|
23
27
|
this.scaleState = this.#scaleRegistry.getOrCreateScale(field, 'size', { range: this.#rangeProp() }, this.#chartContext.chartId);
|
|
@@ -12,6 +12,6 @@ import type { MarkEntry } from '../../../config/ChartConfig.svelte';
|
|
|
12
12
|
* @param entry - The mark entry (reactive props from ChartConfig)
|
|
13
13
|
* @param opts.resolveFitDomain - Getter for resolved fitDomain (deferred read)
|
|
14
14
|
*/
|
|
15
|
-
export declare function buildReactiveConfig(entry: Partial<Pick<MarkEntry, 'sort' | 'limit' | 'domain' | 'tooltip' | 'tip' | 'fitDomain' | 'selectionResponse' | 'nulls' | 'contributeDomain'>>, opts?: {
|
|
15
|
+
export declare function buildReactiveConfig(entry: Partial<Pick<MarkEntry, 'sort' | 'limit' | 'domain' | 'tooltip' | 'tip' | 'fitDomain' | 'selectionResponse' | 'nulls' | 'contributeDomain' | 'holdsEntrance'>>, opts?: {
|
|
16
16
|
resolveFitDomain?: () => 'x' | 'y' | boolean | undefined;
|
|
17
17
|
}): ReactiveConfig;
|