@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.
Files changed (167) hide show
  1. package/README.md +3 -1
  2. package/dist/animation/EntranceGate.d.ts +52 -0
  3. package/dist/animation/EntranceGate.js +93 -0
  4. package/dist/animation/TransitionClock.d.ts +61 -30
  5. package/dist/animation/TransitionClock.js +67 -29
  6. package/dist/animation/transition-log.d.ts +41 -0
  7. package/dist/animation/transition-log.js +57 -0
  8. package/dist/components/axes/AxisBottom.svelte +27 -8
  9. package/dist/components/axes/AxisBottom.svelte.d.ts +10 -0
  10. package/dist/components/axes/AxisCenter.svelte +4 -2
  11. package/dist/components/axes/AxisLeft.svelte +81 -10
  12. package/dist/components/axes/AxisLeft.svelte.d.ts +17 -0
  13. package/dist/components/axes/BandAxisTicks.svelte +4 -3
  14. package/dist/components/axes/axis-title.d.ts +30 -0
  15. package/dist/components/axes/axis-title.js +77 -0
  16. package/dist/components/charts/ChartCell.svelte +33 -6
  17. package/dist/components/charts/ChartCell.svelte.d.ts +9 -0
  18. package/dist/components/charts/ChartContainer.svelte +55 -5
  19. package/dist/components/charts/ChartContainer.svelte.d.ts +14 -1
  20. package/dist/components/charts/ChartHover.svelte.d.ts +14 -0
  21. package/dist/components/charts/ChartHover.svelte.js +22 -0
  22. package/dist/components/charts/ChartVisibility.svelte.d.ts +43 -0
  23. package/dist/components/charts/ChartVisibility.svelte.js +67 -0
  24. package/dist/components/guides/Grid.svelte +12 -1
  25. package/dist/components/guides/legend/ContinuousColorLegend.svelte +7 -1
  26. package/dist/components/guides/legend/OrdinalColorLegend.svelte +8 -5
  27. package/dist/components/marks/AreaMarkX.svelte +18 -4
  28. package/dist/components/marks/AreaMarkY.svelte +18 -4
  29. package/dist/components/marks/BarMarkX.svelte +20 -4
  30. package/dist/components/marks/BarMarkY.svelte +20 -4
  31. package/dist/components/marks/DotsMark.svelte +8 -3
  32. package/dist/components/marks/LineMark.svelte +13 -6
  33. package/dist/components/marks/ParallelCoordinatesMark.svelte +11 -2
  34. package/dist/components/marks/ParallelCoordinatesMark.svelte.d.ts +4 -0
  35. package/dist/components/marks/RectMark.svelte +8 -3
  36. package/dist/components/marks/RectXMark.svelte +9 -3
  37. package/dist/components/marks/RectYMark.svelte +9 -3
  38. package/dist/components/marks/RuleMarkX.svelte +31 -25
  39. package/dist/components/marks/RuleMarkY.svelte +31 -25
  40. package/dist/components/marks/TextMark.svelte +52 -14
  41. package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.d.ts +22 -1
  42. package/dist/components/marks/lifecycle/MarkLifecycleV2.svelte.js +579 -66
  43. package/dist/components/marks/lifecycle/domain-queries.d.ts +13 -2
  44. package/dist/components/marks/lifecycle/domain-queries.js +43 -11
  45. package/dist/components/marks/lifecycle/domain-registration.d.ts +6 -1
  46. package/dist/components/marks/lifecycle/domain-registration.js +17 -20
  47. package/dist/components/marks/lifecycle/other-rows.svelte.d.ts +112 -0
  48. package/dist/components/marks/lifecycle/other-rows.svelte.js +193 -0
  49. package/dist/components/marks/lifecycle/other-split.d.ts +80 -0
  50. package/dist/components/marks/lifecycle/other-split.js +112 -0
  51. package/dist/components/marks/lifecycle/query-builder.d.ts +53 -3
  52. package/dist/components/marks/lifecycle/query-builder.js +46 -23
  53. package/dist/components/marks/utils/MarkColor.svelte.d.ts +3 -1
  54. package/dist/components/marks/utils/MarkColor.svelte.js +33 -3
  55. package/dist/components/marks/utils/MarkSeries.svelte.d.ts +14 -1
  56. package/dist/components/marks/utils/MarkSeries.svelte.js +25 -1
  57. package/dist/components/marks/utils/MarkSize.svelte.js +4 -0
  58. package/dist/components/marks/utils/reactive-config.d.ts +1 -1
  59. package/dist/components/marks/utils/reactive-config.js +9 -0
  60. package/dist/components/marks/utils/tooltip-helpers.d.ts +4 -1
  61. package/dist/components/marks/utils/tooltip-helpers.js +2 -1
  62. package/dist/components/rendering/Areas.svelte +57 -19
  63. package/dist/components/rendering/Areas.svelte.d.ts +12 -0
  64. package/dist/components/rendering/BaseGPURenderer.svelte.d.ts +3 -1
  65. package/dist/components/rendering/BaseGPURenderer.svelte.js +4 -2
  66. package/dist/components/rendering/Dots.svelte +23 -3
  67. package/dist/components/rendering/Dots.svelte.d.ts +6 -0
  68. package/dist/components/rendering/GridLine.svelte +13 -1
  69. package/dist/components/rendering/GridLine.svelte.d.ts +5 -0
  70. package/dist/components/rendering/Lines.svelte +48 -13
  71. package/dist/components/rendering/Lines.svelte.d.ts +12 -0
  72. package/dist/components/rendering/ParallelLines.svelte +5 -5
  73. package/dist/components/rendering/Rects.svelte +164 -30
  74. package/dist/components/rendering/Rects.svelte.d.ts +23 -2
  75. package/dist/components/rendering/RuleX.svelte +1 -1
  76. package/dist/components/rendering/RuleY.svelte +1 -1
  77. package/dist/components/rendering/WebGPUCanvas.svelte +4 -2
  78. package/dist/components/rendering/activity-reads.d.ts +47 -12
  79. package/dist/components/rendering/activity-reads.js +61 -19
  80. package/dist/components/rendering/uniform-sizes.d.ts +1 -1
  81. package/dist/components/rendering/uniform-sizes.js +1 -1
  82. package/dist/config/ChartConfig.svelte.d.ts +10 -1
  83. package/dist/config/ChartConfig.svelte.js +17 -0
  84. package/dist/gpu/GPUCoordinator.svelte.d.ts +31 -1
  85. package/dist/gpu/GPUCoordinator.svelte.js +164 -7
  86. package/dist/gpu/MorphedChannels.d.ts +11 -28
  87. package/dist/gpu/MorphedChannels.js +72 -8
  88. package/dist/gpu/ScaleTemplateSystem.d.ts +20 -2
  89. package/dist/gpu/ScaleTemplateSystem.js +83 -6
  90. package/dist/index.d.ts +19 -4
  91. package/dist/index.js +22 -4
  92. package/dist/interactors/Interval1D.svelte +6 -1
  93. package/dist/interactors/Interval2D.svelte +6 -1
  94. package/dist/interactors/ParallelAxisSource.svelte +10 -1
  95. package/dist/interactors/Toggle.svelte +32 -3
  96. package/dist/interactors/Tooltip.svelte +138 -41
  97. package/dist/interactors/TooltipManager.svelte.d.ts +20 -5
  98. package/dist/interactors/TooltipManager.svelte.js +46 -12
  99. package/dist/interactors/other-tooltip.d.ts +16 -0
  100. package/dist/interactors/other-tooltip.js +22 -0
  101. package/dist/query-engine/CrossfilterSelection.svelte.d.ts +4 -2
  102. package/dist/query-engine/CrossfilterSelection.svelte.js +2 -0
  103. package/dist/query-engine/FieldActivity.svelte.d.ts +49 -1
  104. package/dist/query-engine/FieldActivity.svelte.js +175 -5
  105. package/dist/query-engine/FilterGroup.svelte.d.ts +23 -1
  106. package/dist/query-engine/FilterGroup.svelte.js +43 -3
  107. package/dist/query-engine/FilterGroupRegistry.svelte.d.ts +31 -3
  108. package/dist/query-engine/FilterGroupRegistry.svelte.js +62 -15
  109. package/dist/query-engine/MarkHandle.svelte.d.ts +28 -1
  110. package/dist/query-engine/MarkHandle.svelte.js +33 -1
  111. package/dist/query-engine/QueryEngine.d.ts +225 -5
  112. package/dist/query-engine/QueryEngine.js +697 -47
  113. package/dist/query-engine/categorical-identity.d.ts +41 -0
  114. package/dist/query-engine/categorical-identity.js +145 -65
  115. package/dist/query-engine/debug/query-log.d.ts +39 -0
  116. package/dist/query-engine/debug/query-log.js +90 -0
  117. package/dist/query-engine/duckdb.d.ts +55 -8
  118. package/dist/query-engine/duckdb.js +82 -30
  119. package/dist/query-engine/index.d.ts +7 -4
  120. package/dist/query-engine/index.js +3 -3
  121. package/dist/query-engine/preagg/BuildQueue.d.ts +33 -13
  122. package/dist/query-engine/preagg/BuildQueue.js +51 -15
  123. package/dist/query-engine/preagg/Preagg.d.ts +46 -3
  124. package/dist/query-engine/preagg/Preagg.js +159 -31
  125. package/dist/query-engine/preagg/plan.d.ts +33 -1
  126. package/dist/query-engine/preagg/plan.js +158 -14
  127. package/dist/query-engine/sliced-lane.d.ts +108 -0
  128. package/dist/query-engine/sliced-lane.js +299 -0
  129. package/dist/query-engine/source-routing.d.ts +106 -0
  130. package/dist/query-engine/source-routing.js +189 -0
  131. package/dist/query-engine/toggle-predicate.d.ts +21 -0
  132. package/dist/query-engine/toggle-predicate.js +29 -1
  133. package/dist/scales/ActivityTable.d.ts +5 -1
  134. package/dist/scales/ActivityTable.js +12 -3
  135. package/dist/scales/BandScaleState.svelte.d.ts +22 -9
  136. package/dist/scales/BandScaleState.svelte.js +39 -21
  137. package/dist/scales/ChartScales.svelte.d.ts +3 -0
  138. package/dist/scales/ChartScales.svelte.js +26 -8
  139. package/dist/scales/ColorScaleState.svelte.d.ts +18 -2
  140. package/dist/scales/ColorScaleState.svelte.js +138 -26
  141. package/dist/scales/LinearScaleState.svelte.d.ts +7 -10
  142. package/dist/scales/LinearScaleState.svelte.js +21 -39
  143. package/dist/scales/ScaleGeneration.svelte.d.ts +48 -0
  144. package/dist/scales/ScaleGeneration.svelte.js +42 -0
  145. package/dist/scales/ScaleRegistry.svelte.js +3 -1
  146. package/dist/scales/SlotTransition.d.ts +15 -1
  147. package/dist/scales/SlotTransition.js +33 -4
  148. package/dist/scales/TimeScaleState.svelte.d.ts +7 -3
  149. package/dist/scales/TimeScaleState.svelte.js +7 -7
  150. package/dist/scales/color-utils.d.ts +0 -3
  151. package/dist/scales/color-utils.js +0 -3
  152. package/dist/scales/entered.d.ts +8 -0
  153. package/dist/scales/entered.js +10 -0
  154. package/dist/spec/LazyQueryEngine.js +2 -19
  155. package/dist/spec/MarkRegistry.d.ts +3 -1
  156. package/dist/spec/MarkRegistry.js +13 -1
  157. package/dist/spec/PlotFromSpec.svelte +1 -0
  158. package/dist/spec/export.js +11 -2
  159. package/dist/spec/types.d.ts +43 -13
  160. package/dist/sql/bin.d.ts +25 -0
  161. package/dist/sql/bin.js +108 -5
  162. package/dist/theme.css +5 -4
  163. package/dist/transforms/TransformCompiler.d.ts +47 -2
  164. package/dist/transforms/TransformCompiler.js +70 -1
  165. package/dist/transforms/index.js +176 -42
  166. package/dist/types.d.ts +177 -2
  167. package/package.json +4 -3
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { activityReads, colorActivityWGSL } from './activity-reads';
2
+ import { activityReads, connectedActivityWGSL } from './activity-reads';
3
3
  import { UNIFORM_BYTES } from './uniform-sizes';
4
4
  import { getContext, onMount, onDestroy } from 'svelte';
5
5
  import { RendererHost } from './RendererHost.svelte';
@@ -38,7 +38,10 @@
38
38
  DOT_RADIUS: 36, // f32
39
39
  SHOW_BOTTOM_DOTS: 40, // u32 (0 or 1)
40
40
  FULL_DOMAIN_SPAN: 44, // f32
41
- GROUP_INDEX: 48 // u32
41
+ GROUP_INDEX: 48, // u32
42
+ ACTIVITY_SERIES_MODE: 52, // u32
43
+ ACTIVITY_SERIES_SCALE_INDEX: 56, // u32
44
+ ENTRANCE_AXIS: 60 // u32 (0 fades, 1 grows along x, 2 along y)
42
45
  };
43
46
 
44
47
  interface Props {
@@ -60,8 +63,20 @@
60
63
  colorScaleIndex?: number;
61
64
  /** The page-wide index of this mark's filter group: which run of a field's activity block it reads. */
62
65
  groupIndex?: number;
66
+ /**
67
+ * The series scale selection activity is also read through, from
68
+ * `seriesData`: mode 1 and its index when the mark groups by a `z` of
69
+ * its own, mode 0 (no read) otherwise. MarkSeries decides.
70
+ */
71
+ activitySeriesMode?: number;
72
+ activitySeriesScaleIndex?: number;
63
73
  constantColor?: [number, number, number, number];
64
74
  markId?: string;
75
+ /**
76
+ * Whether the area grows from 0 along its measure axis when its chart
77
+ * enters. False fades it in, for a band with bounds of its own.
78
+ */
79
+ grow?: boolean;
65
80
  }
66
81
 
67
82
  let {
@@ -82,8 +97,11 @@
82
97
  colorMode = 0,
83
98
  colorScaleIndex = 0,
84
99
  groupIndex = 0,
100
+ activitySeriesMode = 0,
101
+ activitySeriesScaleIndex = 0,
85
102
  constantColor = DEFAULT_FILL_COLOR,
86
- markId = ''
103
+ markId = '',
104
+ grow = false
87
105
  }: Props = $props();
88
106
 
89
107
  const chartContext = getContext<ChartContext>('chart');
@@ -152,9 +170,11 @@
152
170
  showBottomDots: u32,
153
171
  fullDomainSpan: f32,
154
172
  groupIndex: u32, // Page-wide filter group index, for activity reads
155
- _pad0: u32,
156
- _pad1: u32,
157
- _pad2: u32
173
+ // The series scale selection activity is also read through, for a z of
174
+ // its own; mode 0 reads nothing.
175
+ activitySeriesMode: u32,
176
+ activitySeriesScaleIndex: u32,
177
+ entranceAxis: u32 // 0 fades in, 1 grows along x, 2 along y
158
178
  };
159
179
  @group(1) @binding(5) var<uniform> markConstants: MarkConstants;
160
180
 
@@ -186,6 +206,12 @@
186
206
  }
187
207
  }
188
208
 
209
+ // A point projected to pixels as it is during the chart's entrance: pulled
210
+ // toward 0 on the measure axis while the area grows.
211
+ fn enterPx(p: vec2<f32>) -> vec2<f32> {
212
+ return entrancePosition(projectToPixels(p), markConstants.entranceAxis);
213
+ }
214
+
189
215
  const DISCARD_POS = vec4<f32>(2.0, 2.0, 2.0, 1.0);
190
216
 
191
217
  @vertex
@@ -220,7 +246,7 @@
220
246
  output.position = DISCARD_POS;
221
247
  return output;
222
248
  }
223
- let center = projectToPixels(makePoint(dim, boundary));
249
+ let center = enterPx(makePoint(dim, boundary));
224
250
 
225
251
  var circleR: f32;
226
252
  if (markConstants.dotRadius < 0.0) {
@@ -254,9 +280,11 @@
254
280
  var output: VertexOutput;
255
281
  output.position = pixelsToClip(pos);
256
282
  output.colorValue = colorValues[instanceIdx];
257
- output.alpha = selectionDim(
258
- ${colorActivityWGSL(ACTIVITY_READS, {
283
+ output.alpha = entranceAlpha(markConstants.entranceAxis) * selectionDim(
284
+ ${connectedActivityWGSL(ACTIVITY_READS, {
259
285
  color: 'markConstants.colorMode, markConstants.colorScaleIndex, colorValues[instanceIdx]',
286
+ series:
287
+ 'markConstants.activitySeriesMode, markConstants.activitySeriesScaleIndex, seriesValues[instanceIdx]',
260
288
  group: 'markConstants.groupIndex'
261
289
  })}
262
290
  );
@@ -304,10 +332,10 @@
304
332
  }
305
333
 
306
334
  // Project segment endpoints for adaptive resolution
307
- let topPxCurr = projectToPixels(makePoint(dimCurr, topCurr));
308
- let topPxNext = projectToPixels(makePoint(dimNext, topNext));
309
- let botPxCurr = projectToPixels(makePoint(dimCurr, botCurr));
310
- let botPxNext = projectToPixels(makePoint(dimNext, botNext));
335
+ let topPxCurr = enterPx(makePoint(dimCurr, topCurr));
336
+ let topPxNext = enterPx(makePoint(dimNext, topNext));
337
+ let botPxCurr = enterPx(makePoint(dimCurr, botCurr));
338
+ let botPxNext = enterPx(makePoint(dimNext, botNext));
311
339
 
312
340
  // Adaptive sub-segment resolution: more segments for longer pixel spans.
313
341
  // Use the longer of top/bottom chord for resolution calculation.
@@ -336,10 +364,10 @@
336
364
  let dimPrev = dimValues[prevIdx];
337
365
  let dimAfter = dimValues[afterIdx];
338
366
 
339
- let topPxPrev = projectToPixels(makePoint(dimPrev, topValues[prevIdx]));
340
- let topPxAfter = projectToPixels(makePoint(dimAfter, topValues[afterIdx]));
341
- let botPxPrev = projectToPixels(makePoint(dimPrev, bottomValues[prevIdx]));
342
- let botPxAfter = projectToPixels(makePoint(dimAfter, bottomValues[afterIdx]));
367
+ let topPxPrev = enterPx(makePoint(dimPrev, topValues[prevIdx]));
368
+ let topPxAfter = enterPx(makePoint(dimAfter, topValues[afterIdx]));
369
+ let botPxPrev = enterPx(makePoint(dimPrev, bottomValues[prevIdx]));
370
+ let botPxAfter = enterPx(makePoint(dimAfter, bottomValues[afterIdx]));
343
371
 
344
372
  // Compute t for this vertex from effective resolution (not geometry buffer)
345
373
  let subSegSize = 1.0 / f32(effectiveRes);
@@ -359,9 +387,11 @@
359
387
  var output: VertexOutput;
360
388
  output.position = pixelsToClip(finalPos);
361
389
  output.colorValue = colorValues[currIdx];
362
- output.alpha = markConstants.fillOpacity * selectionDim(
363
- ${colorActivityWGSL(ACTIVITY_READS, {
390
+ output.alpha = markConstants.fillOpacity * entranceAlpha(markConstants.entranceAxis) * selectionDim(
391
+ ${connectedActivityWGSL(ACTIVITY_READS, {
364
392
  color: 'markConstants.colorMode, markConstants.colorScaleIndex, colorValues[currIdx]',
393
+ series:
394
+ 'markConstants.activitySeriesMode, markConstants.activitySeriesScaleIndex, seriesValues[currIdx]',
365
395
  group: 'markConstants.groupIndex'
366
396
  })}
367
397
  );
@@ -471,7 +501,15 @@
471
501
  view.setUint32(UNIFORM_OFFSETS.COLOR_MODE, colorMode, LE);
472
502
  view.setUint32(UNIFORM_OFFSETS.COLOR_SCALE_INDEX, colorScaleIndex, LE);
473
503
  view.setUint32(UNIFORM_OFFSETS.GROUP_INDEX, groupIndex, LE);
504
+ view.setUint32(UNIFORM_OFFSETS.ACTIVITY_SERIES_MODE, activitySeriesMode, LE);
505
+ view.setUint32(UNIFORM_OFFSETS.ACTIVITY_SERIES_SCALE_INDEX, activitySeriesScaleIndex, LE);
474
506
  view.setUint32(UNIFORM_OFFSETS.ORIENTATION, orientation === 'horizontal' ? 1 : 0, LE);
507
+ // Grows along the boundary axis: y for a vertical area, x for a horizontal one.
508
+ view.setUint32(
509
+ UNIFORM_OFFSETS.ENTRANCE_AXIS,
510
+ grow ? (orientation === 'horizontal' ? 1 : 2) : 0,
511
+ LE
512
+ );
475
513
  view.setFloat32(UNIFORM_OFFSETS.CONSTANT_COLOR + 0, constantColor[0], LE);
476
514
  view.setFloat32(UNIFORM_OFFSETS.CONSTANT_COLOR + 4, constantColor[1], LE);
477
515
  view.setFloat32(UNIFORM_OFFSETS.CONSTANT_COLOR + 8, constantColor[2], LE);
@@ -18,8 +18,20 @@ interface Props {
18
18
  colorScaleIndex?: number;
19
19
  /** The page-wide index of this mark's filter group: which run of a field's activity block it reads. */
20
20
  groupIndex?: number;
21
+ /**
22
+ * The series scale selection activity is also read through, from
23
+ * `seriesData`: mode 1 and its index when the mark groups by a `z` of
24
+ * its own, mode 0 (no read) otherwise. MarkSeries decides.
25
+ */
26
+ activitySeriesMode?: number;
27
+ activitySeriesScaleIndex?: number;
21
28
  constantColor?: [number, number, number, number];
22
29
  markId?: string;
30
+ /**
31
+ * Whether the area grows from 0 along its measure axis when its chart
32
+ * enters. False fades it in, for a band with bounds of its own.
33
+ */
34
+ grow?: boolean;
23
35
  }
24
36
  declare const Areas: import("svelte").Component<Props, {}, "">;
25
37
  type Areas = ReturnType<typeof Areas>;
@@ -57,7 +57,9 @@ export declare class BaseGPURenderer {
57
57
  * the band axis's scale is whose clock these channels adopt. See
58
58
  * MorphedChannels for the fold, the snap and the clock.
59
59
  */
60
- writeMorphed(bandAxis: 'x' | 'y', bandIds: ArrayLike<number>, channels: readonly (readonly [number, AllowSharedBufferSource])[]): void;
60
+ writeMorphed(bandAxis: 'x' | 'y', bandIds: ArrayLike<number>, channels: readonly (readonly [number, AllowSharedBufferSource])[],
61
+ /** Bindings that land at once rather than travel (see MorphedChannels.write). */
62
+ land?: readonly number[] | 'all'): void;
61
63
  /**
62
64
  * Write data to a uniform binding.
63
65
  */
@@ -242,7 +242,9 @@ export class BaseGPURenderer {
242
242
  * the band axis's scale is whose clock these channels adopt. See
243
243
  * MorphedChannels for the fold, the snap and the clock.
244
244
  */
245
- writeMorphed(bandAxis, bandIds, channels) {
245
+ writeMorphed(bandAxis, bandIds, channels,
246
+ /** Bindings that land at once rather than travel (see MorphedChannels.write). */
247
+ land) {
246
248
  if (!this.#device)
247
249
  return;
248
250
  if (!MorphedChannels.supported) {
@@ -283,7 +285,7 @@ export class BaseGPURenderer {
283
285
  }
284
286
  }
285
287
  this.#morphAxis = bandAxis;
286
- if (this.#morphed.write(bandIds, channels) || rebind) {
288
+ if (this.#morphed.write(bandIds, channels, land) || rebind) {
287
289
  this.#scheduleBindGroupUpdate();
288
290
  }
289
291
  else if (!this.#bindGroupUpdateScheduled) {
@@ -43,6 +43,12 @@
43
43
  alphaData: Float32Array | null;
44
44
  facetData?: Float32Array | null;
45
45
  dataVersion: number;
46
+ /**
47
+ * The data version whose first write lands without morphing, or 0: a
48
+ * catch-up result (MarkLifecycleV2.landsFor). Later writes of that version
49
+ * animate as usual.
50
+ */
51
+ landsFor?: number;
46
52
  zIndex?: number;
47
53
  colorMode?: number;
48
54
  colorScaleIndex?: number;
@@ -74,6 +80,7 @@
74
80
  alphaData,
75
81
  facetData = null,
76
82
  dataVersion,
83
+ landsFor = 0,
77
84
  zIndex = 0,
78
85
  colorMode = 0,
79
86
  colorScaleIndex = 0,
@@ -188,7 +195,7 @@
188
195
  output.colorValue = colorValue;
189
196
  output.uv = quadPosition;
190
197
  output.radius = displayRadius;
191
- output.alpha = alpha * selectionDim(
198
+ output.alpha = alpha * entranceAlpha(0u) * selectionDim(
192
199
  ${markActivityWGSL(ACTIVITY_READS, {
193
200
  color: 'markConstants.colorMode, markConstants.colorScaleIndex, colorValue',
194
201
  x: 'x',
@@ -260,6 +267,18 @@
260
267
 
261
268
  // --- WRITING EFFECTS ---
262
269
 
270
+ // Whether this write lands: the first of the catch-up's data version
271
+ // (landsFor). Plain, not $state: only the write effect reads and sets it.
272
+ // Assumes a catch-up result is ONE morph write: should it ever take two
273
+ // (values, then band ids after the instant layout), the second springs.
274
+ // A morph SPRING right after a morph snap on a return points here.
275
+ let lastMorphedVersion = -1;
276
+ function landsNow(): boolean {
277
+ const first = dataVersion !== lastMorphedVersion;
278
+ lastMorphedVersion = dataVersion;
279
+ return first && landsFor !== 0 && landsFor === dataVersion;
280
+ }
281
+
263
282
  // The measure axis's single channel morphs, as ONE write per data update,
264
283
  // so one update starts one transition. The band's ids go with it: they are
265
284
  // how a row set that is not the one being animated gets noticed and snapped.
@@ -269,8 +288,9 @@
269
288
  // design question rather than a consequence of this one.
270
289
  $effect(() => {
271
290
  if (!renderer?.resourcesCreated || !bandAxis) return;
272
- if (bandAxis === 'x') renderer.writeMorphed('x', xData, [[BINDINGS.Y, yData]]);
273
- else renderer.writeMorphed('y', yData, [[BINDINGS.X, xData]]);
291
+ const land = landsNow() ? 'all' : undefined;
292
+ if (bandAxis === 'x') renderer.writeMorphed('x', xData, [[BINDINGS.Y, yData]], land);
293
+ else renderer.writeMorphed('y', yData, [[BINDINGS.X, xData]], land);
274
294
  });
275
295
  $effect(() => {
276
296
  if (renderer?.resourcesCreated && !morphX) renderer.writeAttribute(BINDINGS.X, xData);
@@ -6,6 +6,12 @@ interface Props {
6
6
  alphaData: Float32Array | null;
7
7
  facetData?: Float32Array | null;
8
8
  dataVersion: number;
9
+ /**
10
+ * The data version whose first write lands without morphing, or 0: a
11
+ * catch-up result (MarkLifecycleV2.landsFor). Later writes of that version
12
+ * animate as usual.
13
+ */
14
+ landsFor?: number;
9
15
  zIndex?: number;
10
16
  colorMode?: number;
11
17
  colorScaleIndex?: number;
@@ -44,6 +44,11 @@
44
44
  * way a bar's height is. Omitted, every line is fully drawn.
45
45
  */
46
46
  alpha?: Float32Array | null;
47
+ /**
48
+ * The band layout whose first opacity write lands without morphing, or 0
49
+ * (a layout that landed at once; see BandScaleState.slotsLandedLayout).
50
+ */
51
+ landsFor?: number;
47
52
  /** The band axis these lines belong to, when `alpha` should morph. */
48
53
  bandAxis?: 'x' | 'y' | null;
49
54
  color?: [number, number, number, number];
@@ -55,6 +60,7 @@
55
60
  axis,
56
61
  positions,
57
62
  alpha = null,
63
+ landsFor = 0,
58
64
  bandAxis = null,
59
65
  color = [0.8, 0.8, 0.8, 0.3],
60
66
  lineWidth = 1,
@@ -175,9 +181,15 @@ ${placement}
175
181
  // the positions are that id list — which is what writeMorphed checks rows
176
182
  // against.
177
183
  const morphs = $derived(!!bandAxis && !!alpha && alpha.length === positions?.length);
184
+ // The landed layout last written; plain, read and set by the write alone.
185
+ let lastLandedLayout = 0;
178
186
  $effect(() => {
179
187
  if (!renderer?.resourcesCreated || !morphs) return;
180
- renderer.writeMorphed(bandAxis!, positions, [[BINDINGS.ALPHA, alpha!]]);
188
+ // Only the first write after that layout lands: the opacity it changed.
189
+ const first = landsFor !== lastLandedLayout;
190
+ lastLandedLayout = landsFor;
191
+ const land = first && landsFor !== 0 ? 'all' : undefined;
192
+ renderer.writeMorphed(bandAxis!, positions, [[BINDINGS.ALPHA, alpha!]], land);
181
193
  });
182
194
 
183
195
  // Otherwise every line is fully drawn. Keyed on the line COUNT alone, because
@@ -9,6 +9,11 @@ interface Props {
9
9
  * way a bar's height is. Omitted, every line is fully drawn.
10
10
  */
11
11
  alpha?: Float32Array | null;
12
+ /**
13
+ * The band layout whose first opacity write lands without morphing, or 0
14
+ * (a layout that landed at once; see BandScaleState.slotsLandedLayout).
15
+ */
16
+ landsFor?: number;
12
17
  /** The band axis these lines belong to, when `alpha` should morph. */
13
18
  bandAxis?: 'x' | 'y' | null;
14
19
  color?: [number, number, number, number];
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { activityReads, colorActivityWGSL } from './activity-reads';
2
+ import { activityReads, connectedActivityWGSL } from './activity-reads';
3
3
  import { UNIFORM_BYTES } from './uniform-sizes';
4
4
  import { getContext, onMount, onDestroy } from 'svelte';
5
5
  import { RendererHost } from './RendererHost.svelte';
@@ -38,7 +38,10 @@
38
38
  GLOBAL_ALPHA: 36, // f32
39
39
  GROUP_INDEX: 40, // u32
40
40
  ACTIVITY_COLOR_MODE: 44, // u32
41
- ACTIVITY_COLOR_SCALE_INDEX: 48 // u32
41
+ ACTIVITY_COLOR_SCALE_INDEX: 48, // u32
42
+ ACTIVITY_SERIES_MODE: 52, // u32
43
+ ACTIVITY_SERIES_SCALE_INDEX: 56, // u32
44
+ ENTRANCE_AXIS: 60 // u32 (0 fades, 1 grows along x, 2 along y)
42
45
  };
43
46
 
44
47
  interface Props {
@@ -63,11 +66,23 @@
63
66
  */
64
67
  activityColorMode?: number | null;
65
68
  activityColorScaleIndex?: number | null;
69
+ /**
70
+ * The series scale selection activity is also read through, from
71
+ * `seriesData`: mode 1 and its index when the mark groups by a `z` of
72
+ * its own, mode 0 (no read) otherwise. MarkSeries decides.
73
+ */
74
+ activitySeriesMode?: number;
75
+ activitySeriesScaleIndex?: number;
66
76
  constantColor?: [number, number, number, number];
67
77
  m4Decimator?: M4Decimator | null;
68
78
  dotsRung?: import('../../lod/DotsRung.svelte').DotsRung | null;
69
79
  globalAlpha?: number;
70
80
  markId?: string;
81
+ /**
82
+ * The axis this line grows along when its chart enters, or null to fade
83
+ * in. A line mark fades; an area's outline grows with its fill.
84
+ */
85
+ grow?: 'x' | 'y' | null;
71
86
  }
72
87
 
73
88
  let {
@@ -86,11 +101,14 @@
86
101
  groupIndex = 0,
87
102
  activityColorMode = null,
88
103
  activityColorScaleIndex = null,
104
+ activitySeriesMode = 0,
105
+ activitySeriesScaleIndex = 0,
89
106
  constantColor = DEFAULT_STROKE_COLOR,
90
107
  m4Decimator = null,
91
108
  dotsRung = null,
92
109
  globalAlpha = 1.0,
93
- markId = ''
110
+ markId = '',
111
+ grow = null
94
112
  }: Props = $props();
95
113
 
96
114
  const chartContext = getContext<ChartContext>('chart');
@@ -164,10 +182,20 @@
164
182
  // own colour by default; an area's outline, drawn in a constant stroke,
165
183
  // reads its fill's so it dims with the fill.
166
184
  activityColorMode: u32,
167
- activityColorScaleIndex: u32
185
+ activityColorScaleIndex: u32,
186
+ // The series scale it is also read through, for a z of its own; mode 0
187
+ // reads nothing.
188
+ activitySeriesMode: u32,
189
+ activitySeriesScaleIndex: u32,
190
+ entranceAxis: u32 // 0 fades in, 1 grows along x, 2 along y
168
191
  };
169
192
  @group(1) @binding(4) var<uniform> markConstants: MarkConstants;
170
193
 
194
+ // A point projected to pixels as it is during the chart's entrance.
195
+ fn enterPx(p: vec2<f32>) -> vec2<f32> {
196
+ return entrancePosition(projectToPixels(p), markConstants.entranceAxis);
197
+ }
198
+
171
199
  struct VertexOutput {
172
200
  @builtin(position) position: vec4<f32>,
173
201
  @location(0) colorValue: f32,
@@ -211,7 +239,7 @@
211
239
  output.position = DISCARD_POS;
212
240
  return output;
213
241
  }
214
- let center = projectToPixels(vec2<f32>(x, y));
242
+ let center = enterPx(vec2<f32>(x, y));
215
243
 
216
244
  // JS computes dotRadius via DotsRung. 0 = no dots. >0 = show at this size.
217
245
  let circleR = select(halfWidth, markConstants.dotRadius * frameUniforms.devicePixelRatio,
@@ -221,10 +249,12 @@
221
249
  var output: VertexOutput;
222
250
  output.position = pixelsToClip(pos);
223
251
  output.colorValue = colorValues[instanceIdx];
224
- output.alpha = markConstants.globalAlpha * selectionDim(
225
- ${colorActivityWGSL(ACTIVITY_READS, {
252
+ output.alpha = markConstants.globalAlpha * entranceAlpha(markConstants.entranceAxis) * selectionDim(
253
+ ${connectedActivityWGSL(ACTIVITY_READS, {
226
254
  color:
227
255
  'markConstants.activityColorMode, markConstants.activityColorScaleIndex, colorValues[instanceIdx]',
256
+ series:
257
+ 'markConstants.activitySeriesMode, markConstants.activitySeriesScaleIndex, seriesValues[instanceIdx]',
228
258
  group: 'markConstants.groupIndex'
229
259
  })}
230
260
  );
@@ -258,8 +288,8 @@
258
288
  }
259
289
 
260
290
  // Project segment endpoints to pixel space
261
- let pCurr = projectToPixels(vec2<f32>(xCurr, yCurr));
262
- let pNext = projectToPixels(vec2<f32>(xNext, yNext));
291
+ let pCurr = enterPx(vec2<f32>(xCurr, yCurr));
292
+ let pNext = enterPx(vec2<f32>(xNext, yNext));
263
293
 
264
294
  // Adaptive sub-segment resolution: more segments for longer pixel spans.
265
295
  // Fixed-resolution curves (linear, step) have CURVE_RESOLUTION <= 3;
@@ -286,8 +316,8 @@
286
316
  nextIdx + 1u >= pointCount || seriesValues[nextIdx + 1u] != seriesNext);
287
317
 
288
318
  // Project neighbor control points
289
- let pPrev = projectToPixels(vec2<f32>(xValues[prevIdx], yValues[prevIdx]));
290
- let pAfter = projectToPixels(vec2<f32>(xValues[afterIdx], yValues[afterIdx]));
319
+ let pPrev = enterPx(vec2<f32>(xValues[prevIdx], yValues[prevIdx]));
320
+ let pAfter = enterPx(vec2<f32>(xValues[afterIdx], yValues[afterIdx]));
291
321
 
292
322
  // Compute t values from effective resolution (not geometry buffer)
293
323
  let subSegSize = 1.0 / f32(effectiveRes);
@@ -322,10 +352,12 @@
322
352
  var output: VertexOutput;
323
353
  output.position = pixelsToClip(finalPos);
324
354
  output.colorValue = colorValues[currIdx];
325
- output.alpha = markConstants.globalAlpha * selectionDim(
326
- ${colorActivityWGSL(ACTIVITY_READS, {
355
+ output.alpha = markConstants.globalAlpha * entranceAlpha(markConstants.entranceAxis) * selectionDim(
356
+ ${connectedActivityWGSL(ACTIVITY_READS, {
327
357
  color:
328
358
  'markConstants.activityColorMode, markConstants.activityColorScaleIndex, colorValues[currIdx]',
359
+ series:
360
+ 'markConstants.activitySeriesMode, markConstants.activitySeriesScaleIndex, seriesValues[currIdx]',
329
361
  group: 'markConstants.groupIndex'
330
362
  })}
331
363
  );
@@ -443,6 +475,9 @@
443
475
  view.setUint32(UNIFORM_OFFSETS.GROUP_INDEX, groupIndex, LE);
444
476
  view.setUint32(UNIFORM_OFFSETS.ACTIVITY_COLOR_MODE, activityMode, LE);
445
477
  view.setUint32(UNIFORM_OFFSETS.ACTIVITY_COLOR_SCALE_INDEX, activityScale, LE);
478
+ view.setUint32(UNIFORM_OFFSETS.ACTIVITY_SERIES_MODE, activitySeriesMode, LE);
479
+ view.setUint32(UNIFORM_OFFSETS.ACTIVITY_SERIES_SCALE_INDEX, activitySeriesScaleIndex, LE);
480
+ view.setUint32(UNIFORM_OFFSETS.ENTRANCE_AXIS, grow === 'x' ? 1 : grow === 'y' ? 2 : 0, LE);
446
481
  view.setFloat32(UNIFORM_OFFSETS.CONSTANT_COLOR + 0, constantColor[0], LE);
447
482
  view.setFloat32(UNIFORM_OFFSETS.CONSTANT_COLOR + 4, constantColor[1], LE);
448
483
  view.setFloat32(UNIFORM_OFFSETS.CONSTANT_COLOR + 8, constantColor[2], LE);
@@ -22,11 +22,23 @@ interface Props {
22
22
  */
23
23
  activityColorMode?: number | null;
24
24
  activityColorScaleIndex?: number | null;
25
+ /**
26
+ * The series scale selection activity is also read through, from
27
+ * `seriesData`: mode 1 and its index when the mark groups by a `z` of
28
+ * its own, mode 0 (no read) otherwise. MarkSeries decides.
29
+ */
30
+ activitySeriesMode?: number;
31
+ activitySeriesScaleIndex?: number;
25
32
  constantColor?: [number, number, number, number];
26
33
  m4Decimator?: M4Decimator | null;
27
34
  dotsRung?: import('../../lod/DotsRung.svelte').DotsRung | null;
28
35
  globalAlpha?: number;
29
36
  markId?: string;
37
+ /**
38
+ * The axis this line grows along when its chart enters, or null to fade
39
+ * in. A line mark fades; an area's outline grows with its fill.
40
+ */
41
+ grow?: 'x' | 'y' | null;
30
42
  }
31
43
  declare const Lines: import("svelte").Component<Props, {}, "">;
32
44
  type Lines = ReturnType<typeof Lines>;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { activityReads, colorActivityWGSL } from './activity-reads';
2
+ import { activityReads, connectedActivityWGSL } from './activity-reads';
3
3
  import { PARALLEL_MAX_AXES, UNIFORM_BYTES } from './uniform-sizes';
4
4
  import { getContext, onMount, onDestroy } from 'svelte';
5
5
  import { RendererHost } from './RendererHost.svelte';
@@ -199,8 +199,8 @@
199
199
  var output: VertexOutput;
200
200
  output.position = pixelsToClip(pos);
201
201
  output.colorValue = colorValues[rowIdx];
202
- output.alpha = config.opacity * selectionDim(
203
- ${colorActivityWGSL(ACTIVITY_READS, {
202
+ output.alpha = config.opacity * entranceAlpha(0u) * selectionDim(
203
+ ${connectedActivityWGSL(ACTIVITY_READS, {
204
204
  color: 'config.colorMode, config.colorScaleIndex, colorValues[rowIdx]',
205
205
  group: 'config.groupIndex'
206
206
  })}
@@ -283,8 +283,8 @@
283
283
  var output: VertexOutput;
284
284
  output.position = pixelsToClip(finalPos);
285
285
  output.colorValue = colorValues[rowIdx];
286
- output.alpha = config.opacity * selectionDim(
287
- ${colorActivityWGSL(ACTIVITY_READS, {
286
+ output.alpha = config.opacity * entranceAlpha(0u) * selectionDim(
287
+ ${connectedActivityWGSL(ACTIVITY_READS, {
288
288
  color: 'config.colorMode, config.colorScaleIndex, colorValues[rowIdx]',
289
289
  group: 'config.groupIndex'
290
290
  })}