@genome-spy/core 0.66.1 → 0.67.0

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 (44) hide show
  1. package/dist/bundle/index.es.js +6144 -5918
  2. package/dist/bundle/index.js +89 -89
  3. package/dist/src/data/flowHandle.d.ts +2 -0
  4. package/dist/src/data/flowHandle.d.ts.map +1 -1
  5. package/dist/src/data/flowHandle.js +1 -0
  6. package/dist/src/data/flowInit.d.ts +12 -4
  7. package/dist/src/data/flowInit.d.ts.map +1 -1
  8. package/dist/src/data/flowInit.js +114 -15
  9. package/dist/src/genomeSpy/viewDataInit.d.ts +10 -0
  10. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
  11. package/dist/src/genomeSpy/viewDataInit.js +121 -2
  12. package/dist/src/genomeSpy/viewDataInit.test.d.ts +2 -0
  13. package/dist/src/genomeSpy/viewDataInit.test.d.ts.map +1 -0
  14. package/dist/src/genomeSpy.d.ts +1 -0
  15. package/dist/src/genomeSpy.d.ts.map +1 -1
  16. package/dist/src/genomeSpy.js +23 -1
  17. package/dist/src/gl/dataToVertices.d.ts.map +1 -1
  18. package/dist/src/gl/dataToVertices.js +16 -4
  19. package/dist/src/scales/scaleDomainAggregator.d.ts +2 -2
  20. package/dist/src/scales/scaleDomainAggregator.d.ts.map +1 -1
  21. package/dist/src/scales/scaleDomainAggregator.js +15 -10
  22. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
  23. package/dist/src/scales/scaleInstanceManager.js +8 -4
  24. package/dist/src/scales/scaleResolution.d.ts +3 -2
  25. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  26. package/dist/src/scales/scaleResolution.js +90 -16
  27. package/dist/src/utils/domainArray.d.ts.map +1 -1
  28. package/dist/src/utils/domainArray.js +3 -0
  29. package/dist/src/utils/indexer.d.ts +3 -0
  30. package/dist/src/utils/indexer.d.ts.map +1 -1
  31. package/dist/src/utils/indexer.js +3 -0
  32. package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
  33. package/dist/src/view/containerMutationHelper.js +5 -1
  34. package/dist/src/view/flowBuilder.d.ts +5 -3
  35. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  36. package/dist/src/view/flowBuilder.js +69 -6
  37. package/dist/src/view/testUtils.d.ts.map +1 -1
  38. package/dist/src/view/testUtils.js +5 -0
  39. package/dist/src/view/unitView.d.ts.map +1 -1
  40. package/dist/src/view/unitView.js +17 -2
  41. package/dist/src/view/view.d.ts +12 -0
  42. package/dist/src/view/view.d.ts.map +1 -1
  43. package/dist/src/view/view.js +26 -0
  44. package/package.json +2 -2
@@ -2,6 +2,7 @@
2
2
  * @typedef {object} FlowHandle
3
3
  * @prop {import("./sources/dataSource.js").default} [dataSource]
4
4
  * @prop {import("./collector.js").default} [collector]
5
+ * @prop {import("./flowNode.js").default} [node]
5
6
  */
6
7
  /**
7
8
  * @param {FlowHandle} [handle]
@@ -11,5 +12,6 @@ export function createFlowHandle(handle?: FlowHandle): FlowHandle;
11
12
  export type FlowHandle = {
12
13
  dataSource?: import("./sources/dataSource.js").default;
13
14
  collector?: import("./collector.js").default;
15
+ node?: import("./flowNode.js").default;
14
16
  };
15
17
  //# sourceMappingURL=flowHandle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"flowHandle.d.ts","sourceRoot":"","sources":["../../../src/data/flowHandle.js"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,0CAHW,UAAU,GACR,UAAU,CAItB;;iBAVS,OAAO,yBAAyB,EAAE,OAAO;gBACzC,OAAO,gBAAgB,EAAE,OAAO"}
1
+ {"version":3,"file":"flowHandle.d.ts","sourceRoot":"","sources":["../../../src/data/flowHandle.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,0CAHW,UAAU,GACR,UAAU,CAItB;;iBAXS,OAAO,yBAAyB,EAAE,OAAO;gBACzC,OAAO,gBAAgB,EAAE,OAAO;WAChC,OAAO,eAAe,EAAE,OAAO"}
@@ -2,6 +2,7 @@
2
2
  * @typedef {object} FlowHandle
3
3
  * @prop {import("./sources/dataSource.js").default} [dataSource]
4
4
  * @prop {import("./collector.js").default} [collector]
5
+ * @prop {import("./flowNode.js").default} [node]
5
6
  */
6
7
 
7
8
  /**
@@ -43,6 +43,8 @@ export function syncFlowHandles(root: import("../view/view.js").default, canonic
43
43
  *
44
44
  * @param {import("../view/view.js").default} subtreeRoot
45
45
  * @param {import("./dataFlow.js").default} flow
46
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
47
+ * @param {(view: import("../view/view.js").default) => boolean} [viewInitializationPredicate]
46
48
  * @returns {{
47
49
  * dataFlow: import("./dataFlow.js").default,
48
50
  * unitViews: UnitView[],
@@ -50,7 +52,7 @@ export function syncFlowHandles(root: import("../view/view.js").default, canonic
50
52
  * graphicsPromises: Promise<import("../marks/mark.js").default>[]
51
53
  * }}
52
54
  */
53
- export function initializeViewSubtree(subtreeRoot: import("../view/view.js").default, flow: import("./dataFlow.js").default): {
55
+ export function initializeViewSubtree(subtreeRoot: import("../view/view.js").default, flow: import("./dataFlow.js").default, viewFilter?: (view: import("../view/view.js").default) => boolean, viewInitializationPredicate?: (view: import("../view/view.js").default) => boolean): {
54
56
  dataFlow: import("./dataFlow.js").default;
55
57
  unitViews: UnitView[];
56
58
  dataSources: Set<import("./sources/dataSource.js").default>;
@@ -61,25 +63,31 @@ export function initializeViewSubtree(subtreeRoot: import("../view/view.js").def
61
63
  * This includes sources that are overridden deeper in the hierarchy.
62
64
  *
63
65
  * @param {import("../view/view.js").default | import("../view/view.js").default[]} subtreeRoot
66
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
64
67
  * @returns {Set<import("./sources/dataSource.js").default>}
65
68
  */
66
- export function collectViewSubtreeDataSources(subtreeRoot: import("../view/view.js").default | import("../view/view.js").default[]): Set<import("./sources/dataSource.js").default>;
69
+ export function collectViewSubtreeDataSources(subtreeRoot: import("../view/view.js").default | import("../view/view.js").default[], viewFilter?: (view: import("../view/view.js").default) => boolean): Set<import("./sources/dataSource.js").default>;
67
70
  /**
68
71
  * Collects the nearest data sources under a subtree root.
69
72
  * These sources define data-ready boundaries for subtree-level loading.
70
73
  *
71
74
  * @param {import("../view/view.js").default} subtreeRoot
75
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
72
76
  * @returns {Set<import("./sources/dataSource.js").default>}
73
77
  */
74
- export function collectNearestViewSubtreeDataSources(subtreeRoot: import("../view/view.js").default): Set<import("./sources/dataSource.js").default>;
78
+ export function collectNearestViewSubtreeDataSources(subtreeRoot: import("../view/view.js").default, viewFilter?: (view: import("../view/view.js").default) => boolean): Set<import("./sources/dataSource.js").default>;
75
79
  /**
76
80
  * Loads the nearest data sources for a subtree.
77
81
  * Use the returned promise as a subtree-level "data ready" signal.
78
82
  *
79
83
  * @param {import("../view/view.js").default} subtreeRoot
80
84
  * @param {Set<import("./sources/dataSource.js").default>} [dataSources]
85
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
86
+ * @param {{ queueReload?: boolean }} [loadOptions]
81
87
  * @returns {Promise<void[]>}
82
88
  */
83
- export function loadViewSubtreeData(subtreeRoot: import("../view/view.js").default, dataSources?: Set<import("./sources/dataSource.js").default>): Promise<void[]>;
89
+ export function loadViewSubtreeData(subtreeRoot: import("../view/view.js").default, dataSources?: Set<import("./sources/dataSource.js").default>, viewFilter?: (view: import("../view/view.js").default) => boolean, loadOptions?: {
90
+ queueReload?: boolean;
91
+ }): Promise<void[]>;
84
92
  import UnitView from "../view/unitView.js";
85
93
  //# sourceMappingURL=flowInit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"flowInit.d.ts","sourceRoot":"","sources":["../../../src/data/flowInit.js"],"names":[],"mappings":"AAoCA;;;;;GAKG;AACH,sCAHW,OAAO,iBAAiB,EAAE,OAAO,qBACjC,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,EAAE,OAAO,yBAAyB,EAAE,OAAO,CAAC,QAcnG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,mDATW,OAAO,iBAAiB,EAAE,OAAO,QACjC,OAAO,eAAe,EAAE,OAAO,GAC7B;IACN,QAAQ,EAAE,OAAO,eAAe,EAAE,OAAO,CAAC;IAC1C,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,CAAC;IAC5D,gBAAgB,EAAE,OAAO,CAAC,OAAO,kBAAkB,EAAE,OAAO,CAAC,EAAE,CAAA;CAClE,CAsDH;AAED;;;;;;GAMG;AACH,2DAHW,OAAO,iBAAiB,EAAE,OAAO,GAAG,OAAO,iBAAiB,EAAE,OAAO,EAAE,GACrE,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,CAmB1D;AAED;;;;;;GAMG;AACH,kEAHW,OAAO,iBAAiB,EAAE,OAAO,GAC/B,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,CAY1D;AAED;;;;;;;GAOG;AACH,iDAJW,OAAO,iBAAiB,EAAE,OAAO,gBACjC,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,GAC5C,OAAO,CAAC,IAAI,EAAE,CAAC,CAe3B;qBA7NoB,qBAAqB"}
1
+ {"version":3,"file":"flowInit.d.ts","sourceRoot":"","sources":["../../../src/data/flowInit.js"],"names":[],"mappings":"AAyDA;;;;;GAKG;AACH,sCAHW,OAAO,iBAAiB,EAAE,OAAO,qBACjC,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,EAAE,OAAO,yBAAyB,EAAE,OAAO,CAAC,QAcnG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,mDAXW,OAAO,iBAAiB,EAAE,OAAO,QACjC,OAAO,eAAe,EAAE,OAAO,eAC/B,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,KAAK,OAAO,gCACpD,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,KAAK,OAAO,GAClD;IACN,QAAQ,EAAE,OAAO,eAAe,EAAE,OAAO,CAAC;IAC1C,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,CAAC;IAC5D,gBAAgB,EAAE,OAAO,CAAC,OAAO,kBAAkB,EAAE,OAAO,CAAC,EAAE,CAAA;CAClE,CA4FH;AAED;;;;;;;GAOG;AACH,2DAJW,OAAO,iBAAiB,EAAE,OAAO,GAAG,OAAO,iBAAiB,EAAE,OAAO,EAAE,eACvE,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,KAAK,OAAO,GAClD,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,CAsB1D;AAED;;;;;;;GAOG;AACH,kEAJW,OAAO,iBAAiB,EAAE,OAAO,eACjC,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,KAAK,OAAO,GAClD,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,CAe1D;AAED;;;;;;;;;GASG;AACH,iDANW,OAAO,iBAAiB,EAAE,OAAO,gBACjC,GAAG,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,eAC9C,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,KAAK,OAAO,gBACpD;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GACvB,OAAO,CAAC,IAAI,EAAE,CAAC,CAuB3B;qBA5SoB,qBAAqB"}
@@ -6,6 +6,8 @@ import { reconfigureScaleDomains } from "../scales/scaleResolution.js";
6
6
 
7
7
  /** @type {WeakMap<import("./sources/dataSource.js").default, Promise<void>>} */
8
8
  const inFlightLoads = new WeakMap();
9
+ /** @type {WeakMap<import("./sources/dataSource.js").default, Promise<void>>} */
10
+ const queuedReloads = new WeakMap();
9
11
 
10
12
  /**
11
13
  * Deduplicate concurrent loads for shared sources without changing propagation.
@@ -16,12 +18,31 @@ const inFlightLoads = new WeakMap();
16
18
  * promise settles, the source may be loaded again later as usual.
17
19
  *
18
20
  * @param {import("./sources/dataSource.js").default} dataSource
21
+ * @param {{ queueReload?: boolean }} [options]
19
22
  * @returns {Promise<void>}
20
23
  */
21
- function loadDataSourceOnce(dataSource) {
24
+ function loadDataSourceOnce(dataSource, options) {
22
25
  const existing = inFlightLoads.get(dataSource);
23
26
  if (existing) {
24
- return existing;
27
+ if (!options?.queueReload) {
28
+ return existing;
29
+ }
30
+ const queued = queuedReloads.get(dataSource);
31
+ if (queued) {
32
+ return queued;
33
+ }
34
+ const reload = existing
35
+ .catch(
36
+ /** @returns {void} */ () => {
37
+ // Nop: ensure a queued reload can proceed after a failure.
38
+ }
39
+ )
40
+ .then(() => loadDataSourceOnce(dataSource))
41
+ .finally(() => {
42
+ queuedReloads.delete(dataSource);
43
+ });
44
+ queuedReloads.set(dataSource, reload);
45
+ return reload;
25
46
  }
26
47
 
27
48
  const loadPromise = Promise.resolve()
@@ -92,6 +113,8 @@ export function syncFlowHandles(root, canonicalBySource) {
92
113
  *
93
114
  * @param {import("../view/view.js").default} subtreeRoot
94
115
  * @param {import("./dataFlow.js").default} flow
116
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
117
+ * @param {(view: import("../view/view.js").default) => boolean} [viewInitializationPredicate]
95
118
  * @returns {{
96
119
  * dataFlow: import("./dataFlow.js").default,
97
120
  * unitViews: UnitView[],
@@ -99,12 +122,44 @@ export function syncFlowHandles(root, canonicalBySource) {
99
122
  * graphicsPromises: Promise<import("../marks/mark.js").default>[]
100
123
  * }}
101
124
  */
102
- export function initializeViewSubtree(subtreeRoot, flow) {
103
- const dataFlow = buildDataFlow(subtreeRoot, flow);
104
- const canonicalBySource = optimizeDataFlow(dataFlow);
105
- syncFlowHandles(subtreeRoot, canonicalBySource);
106
- const subtreeViews = subtreeRoot.getDescendants();
107
- const dataSources = collectViewSubtreeDataSources(subtreeViews);
125
+ export function initializeViewSubtree(
126
+ subtreeRoot,
127
+ flow,
128
+ viewFilter,
129
+ viewInitializationPredicate
130
+ ) {
131
+ const shouldInitializeView = viewInitializationPredicate ?? (() => true);
132
+ const subtreeViews = collectSubtreeViews(subtreeRoot, viewFilter);
133
+ const viewsToInitialize = subtreeViews.filter(shouldInitializeView);
134
+ if (viewsToInitialize.length === 0) {
135
+ return {
136
+ dataFlow: flow,
137
+ unitViews: [],
138
+ dataSources: new Set(),
139
+ graphicsPromises: [],
140
+ };
141
+ }
142
+
143
+ const viewsToInitializeSet = new Set(viewsToInitialize);
144
+ for (const view of viewsToInitialize) {
145
+ view._setDataInitializationState("pending");
146
+ }
147
+
148
+ let dataFlow;
149
+ try {
150
+ dataFlow = buildDataFlow(subtreeRoot, flow, viewFilter, (view) =>
151
+ viewsToInitializeSet.has(view)
152
+ );
153
+ const canonicalBySource = optimizeDataFlow(dataFlow);
154
+ syncFlowHandles(subtreeRoot, canonicalBySource);
155
+ } catch (error) {
156
+ for (const view of viewsToInitialize) {
157
+ view._setDataInitializationState("none");
158
+ }
159
+ throw error;
160
+ }
161
+
162
+ const dataSources = collectViewSubtreeDataSources(viewsToInitialize);
108
163
 
109
164
  // Initialize flow nodes for the sources that belong to this subtree.
110
165
  for (const dataSource of dataSources) {
@@ -112,7 +167,9 @@ export function initializeViewSubtree(subtreeRoot, flow) {
112
167
  }
113
168
 
114
169
  /** @type {UnitView[]} */
115
- const unitViews = subtreeViews.filter((view) => view instanceof UnitView);
170
+ const unitViews = viewsToInitialize.filter(
171
+ (view) => view instanceof UnitView
172
+ );
116
173
 
117
174
  /** @type {Promise<import("../marks/mark.js").default>[]} */
118
175
  const graphicsPromises = [];
@@ -145,6 +202,10 @@ export function initializeViewSubtree(subtreeRoot, flow) {
145
202
  view.registerDisposer(view.flowHandle.collector.observe(observer));
146
203
  }
147
204
 
205
+ for (const view of viewsToInitialize) {
206
+ view._setDataInitializationState("ready");
207
+ }
208
+
148
209
  return {
149
210
  dataFlow,
150
211
  unitViews,
@@ -158,15 +219,19 @@ export function initializeViewSubtree(subtreeRoot, flow) {
158
219
  * This includes sources that are overridden deeper in the hierarchy.
159
220
  *
160
221
  * @param {import("../view/view.js").default | import("../view/view.js").default[]} subtreeRoot
222
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
161
223
  * @returns {Set<import("./sources/dataSource.js").default>}
162
224
  */
163
- export function collectViewSubtreeDataSources(subtreeRoot) {
225
+ export function collectViewSubtreeDataSources(subtreeRoot, viewFilter) {
164
226
  const subtreeViews = Array.isArray(subtreeRoot)
165
227
  ? subtreeRoot
166
- : subtreeRoot.getDescendants();
228
+ : collectSubtreeViews(subtreeRoot, viewFilter);
167
229
  /** @type {Set<import("./sources/dataSource.js").default>} */
168
230
  const dataSources = new Set();
169
231
  for (const view of subtreeViews) {
232
+ if (viewFilter && !viewFilter(view)) {
233
+ continue;
234
+ }
170
235
  // Walk up to the nearest view that owns a data source.
171
236
  let current = view;
172
237
  while (current && !current.flowHandle?.dataSource) {
@@ -184,12 +249,16 @@ export function collectViewSubtreeDataSources(subtreeRoot) {
184
249
  * These sources define data-ready boundaries for subtree-level loading.
185
250
  *
186
251
  * @param {import("../view/view.js").default} subtreeRoot
252
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
187
253
  * @returns {Set<import("./sources/dataSource.js").default>}
188
254
  */
189
- export function collectNearestViewSubtreeDataSources(subtreeRoot) {
255
+ export function collectNearestViewSubtreeDataSources(subtreeRoot, viewFilter) {
190
256
  /** @type {Set<import("./sources/dataSource.js").default>} */
191
257
  const dataSources = new Set();
192
258
  subtreeRoot.visit((view) => {
259
+ if (viewFilter && !viewFilter(view)) {
260
+ return VISIT_SKIP;
261
+ }
193
262
  if (view.flowHandle?.dataSource) {
194
263
  dataSources.add(view.flowHandle.dataSource);
195
264
  return VISIT_SKIP;
@@ -204,23 +273,53 @@ export function collectNearestViewSubtreeDataSources(subtreeRoot) {
204
273
  *
205
274
  * @param {import("../view/view.js").default} subtreeRoot
206
275
  * @param {Set<import("./sources/dataSource.js").default>} [dataSources]
276
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
277
+ * @param {{ queueReload?: boolean }} [loadOptions]
207
278
  * @returns {Promise<void[]>}
208
279
  */
209
280
  export function loadViewSubtreeData(
210
281
  subtreeRoot,
211
- dataSources = collectNearestViewSubtreeDataSources(subtreeRoot)
282
+ dataSources,
283
+ viewFilter,
284
+ loadOptions
212
285
  ) {
286
+ if (!dataSources) {
287
+ dataSources = collectNearestViewSubtreeDataSources(
288
+ subtreeRoot,
289
+ viewFilter
290
+ );
291
+ }
213
292
  return Promise.all(
214
293
  Array.from(dataSources).map((dataSource) =>
215
- loadDataSourceOnce(dataSource)
294
+ loadDataSourceOnce(dataSource, loadOptions)
216
295
  )
217
296
  ).then((results) => {
218
- reconfigureScaleDomains(subtreeRoot);
297
+ reconfigureScaleDomains(subtreeRoot, viewFilter);
219
298
  broadcastSubtreeDataReady(subtreeRoot);
220
299
  return results;
221
300
  });
222
301
  }
223
302
 
303
+ /**
304
+ * @param {import("../view/view.js").default} subtreeRoot
305
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
306
+ * @returns {import("../view/view.js").default[]}
307
+ */
308
+ function collectSubtreeViews(subtreeRoot, viewFilter) {
309
+ /** @type {import("../view/view.js").default[]} */
310
+ const views = [];
311
+ if (!viewFilter) {
312
+ return subtreeRoot.getDescendants();
313
+ }
314
+ subtreeRoot.visit((view) => {
315
+ if (!viewFilter(view)) {
316
+ return VISIT_SKIP;
317
+ }
318
+ views.push(view);
319
+ });
320
+ return views;
321
+ }
322
+
224
323
  /**
225
324
  * Broadcasts a subtree-scoped data-ready event to views within the subtree.
226
325
  *
@@ -9,4 +9,14 @@
9
9
  * @returns {Promise<import("../data/dataFlow.js").default>}
10
10
  */
11
11
  export function initializeViewData(viewRoot: import("../view/view.js").default, dataFlow: import("../data/dataFlow.js").default, fontManager: import("../fonts/bmFontManager.js").default, onDataFlowBuilt: (dataFlow: import("../data/dataFlow.js").default) => void): Promise<import("../data/dataFlow.js").default>;
12
+ /**
13
+ * Initializes data flow and graphics for visible views that were previously
14
+ * skipped. Intended for view-visibility toggles.
15
+ *
16
+ * @param {import("../view/view.js").default} viewRoot
17
+ * @param {import("../data/dataFlow.js").default} dataFlow
18
+ * @param {import("../fonts/bmFontManager.js").default} fontManager
19
+ * @returns {Promise<import("../data/dataFlow.js").default>}
20
+ */
21
+ export function initializeVisibleViewData(viewRoot: import("../view/view.js").default, dataFlow: import("../data/dataFlow.js").default, fontManager: import("../fonts/bmFontManager.js").default): Promise<import("../data/dataFlow.js").default>;
12
22
  //# sourceMappingURL=viewDataInit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"viewDataInit.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/viewDataInit.js"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AACH,6CANW,OAAO,iBAAiB,EAAE,OAAO,YACjC,OAAO,qBAAqB,EAAE,OAAO,eACrC,OAAO,2BAA2B,EAAE,OAAO,mBAC3C,CAAC,QAAQ,EAAE,OAAO,qBAAqB,EAAE,OAAO,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,qBAAqB,EAAE,OAAO,CAAC,CA0B1D"}
1
+ {"version":3,"file":"viewDataInit.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/viewDataInit.js"],"names":[],"mappings":"AAOA;;;;;;;;;GASG;AACH,6CANW,OAAO,iBAAiB,EAAE,OAAO,YACjC,OAAO,qBAAqB,EAAE,OAAO,eACrC,OAAO,2BAA2B,EAAE,OAAO,mBAC3C,CAAC,QAAQ,EAAE,OAAO,qBAAqB,EAAE,OAAO,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,qBAAqB,EAAE,OAAO,CAAC,CAkC1D;AAED;;;;;;;;GAQG;AACH,oDALW,OAAO,iBAAiB,EAAE,OAAO,YACjC,OAAO,qBAAqB,EAAE,OAAO,eACrC,OAAO,2BAA2B,EAAE,OAAO,GACzC,OAAO,CAAC,OAAO,qBAAqB,EAAE,OAAO,CAAC,CAgD1D"}
@@ -3,6 +3,7 @@ import {
3
3
  loadViewSubtreeData,
4
4
  } from "../data/flowInit.js";
5
5
  import { finalizeSubtreeGraphics } from "../view/viewUtils.js";
6
+ import { VISIT_SKIP } from "../view/view.js";
6
7
 
7
8
  /**
8
9
  * Initializes the view data pipeline: builds the flow graph, awaits fonts,
@@ -20,9 +21,13 @@ export async function initializeViewData(
20
21
  fontManager,
21
22
  onDataFlowBuilt
22
23
  ) {
24
+ const visibilityPredicate = (
25
+ /** @type {import("../view/view.js").default} */ view
26
+ ) => view.isConfiguredVisible();
23
27
  const { dataFlow: builtDataFlow, graphicsPromises } = initializeViewSubtree(
24
28
  viewRoot,
25
- dataFlow
29
+ dataFlow,
30
+ visibilityPredicate
26
31
  );
27
32
  onDataFlowBuilt(builtDataFlow);
28
33
 
@@ -33,9 +38,123 @@ export async function initializeViewData(
33
38
  await fontManager.waitUntilReady();
34
39
 
35
40
  // Find all data sources and initiate loading.
36
- await loadViewSubtreeData(viewRoot, new Set(builtDataFlow.dataSources));
41
+ await loadViewSubtreeData(
42
+ viewRoot,
43
+ new Set(builtDataFlow.dataSources),
44
+ visibilityPredicate
45
+ );
46
+
47
+ await finalizeSubtreeGraphics(graphicsPromises);
48
+
49
+ return builtDataFlow;
50
+ }
51
+
52
+ /**
53
+ * Initializes data flow and graphics for visible views that were previously
54
+ * skipped. Intended for view-visibility toggles.
55
+ *
56
+ * @param {import("../view/view.js").default} viewRoot
57
+ * @param {import("../data/dataFlow.js").default} dataFlow
58
+ * @param {import("../fonts/bmFontManager.js").default} fontManager
59
+ * @returns {Promise<import("../data/dataFlow.js").default>}
60
+ */
61
+ export async function initializeVisibleViewData(
62
+ viewRoot,
63
+ dataFlow,
64
+ fontManager
65
+ ) {
66
+ const visibilityPredicate = (
67
+ /** @type {import("../view/view.js").default} */ view
68
+ ) => view.isConfiguredVisible();
69
+ const visibleViews = collectVisibleViews(viewRoot, visibilityPredicate);
70
+ const viewsToInitialize = visibleViews.filter(
71
+ (view) => view.getDataInitializationState() === "none"
72
+ );
73
+
74
+ if (viewsToInitialize.length === 0) {
75
+ return dataFlow;
76
+ }
77
+
78
+ const viewsToInitializeSet = new Set(viewsToInitialize);
79
+ const viewInitializationPredicate = (
80
+ /** @type {import("../view/view.js").default} */ view
81
+ ) => viewsToInitializeSet.has(view);
82
+
83
+ const { dataFlow: builtDataFlow, graphicsPromises } = initializeViewSubtree(
84
+ viewRoot,
85
+ dataFlow,
86
+ visibilityPredicate,
87
+ viewInitializationPredicate
88
+ );
89
+
90
+ await fontManager.waitUntilReady();
91
+
92
+ const dataSourceRoots = collectDataSourceRoots(viewsToInitialize);
93
+ await Promise.all(
94
+ Array.from(dataSourceRoots.entries()).map(
95
+ ([subtreeRoot, dataSources]) =>
96
+ loadViewSubtreeData(subtreeRoot, dataSources, undefined, {
97
+ // If a source is already loading, schedule a reload so new branches
98
+ // added during lazy init receive a complete data propagation.
99
+ queueReload: true,
100
+ })
101
+ )
102
+ );
37
103
 
38
104
  await finalizeSubtreeGraphics(graphicsPromises);
39
105
 
40
106
  return builtDataFlow;
41
107
  }
108
+
109
+ /**
110
+ * @param {import("../view/view.js").default} viewRoot
111
+ * @param {(view: import("../view/view.js").default) => boolean} viewFilter
112
+ * @returns {import("../view/view.js").default[]}
113
+ */
114
+ function collectVisibleViews(viewRoot, viewFilter) {
115
+ /** @type {import("../view/view.js").default[]} */
116
+ const views = [];
117
+ viewRoot.visit((view) => {
118
+ if (!viewFilter(view)) {
119
+ return VISIT_SKIP;
120
+ }
121
+ views.push(view);
122
+ });
123
+ return views;
124
+ }
125
+
126
+ /**
127
+ * @param {import("../view/view.js").default[]} views
128
+ * @returns {Map<import("../view/view.js").default, Set<import("../data/sources/dataSource.js").default>>}
129
+ */
130
+ function collectDataSourceRoots(views) {
131
+ /** @type {Map<import("../view/view.js").default, Set<import("../data/sources/dataSource.js").default>>} */
132
+ const roots = new Map();
133
+
134
+ for (const view of views) {
135
+ let current = view;
136
+ while (current && !current.flowHandle?.dataSource) {
137
+ current = current.dataParent;
138
+ }
139
+
140
+ if (!current?.flowHandle?.dataSource) {
141
+ if (view.spec.data) {
142
+ throw new Error(
143
+ "No data source found for view " + view.getPathString()
144
+ );
145
+ }
146
+ // Some views are data-less (constants or references); they don't
147
+ // participate in data loading but still need graphics init.
148
+ continue;
149
+ }
150
+
151
+ let dataSources = roots.get(current);
152
+ if (!dataSources) {
153
+ dataSources = new Set();
154
+ roots.set(current, dataSources);
155
+ }
156
+ dataSources.add(current.flowHandle.dataSource);
157
+ }
158
+
159
+ return roots;
160
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=viewDataInit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewDataInit.test.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/viewDataInit.test.js"],"names":[],"mappings":""}
@@ -78,6 +78,7 @@ export default class GenomeSpy {
78
78
  * @returns {Promise<boolean>} true if the launch was successful
79
79
  */
80
80
  launch(): Promise<boolean>;
81
+ initializeVisibleViewData(): Promise<void>;
81
82
  registerMouseEvents(): void;
82
83
  /**
83
84
  * This method should be called in a mouseMove handler. If not called, the
@@ -1 +1 @@
1
- {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA0CA;IAkBI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA0CpD;IAvCG,uBAA0B;IAC1B,oDAAsB;IAItB,sCAAsC;IACtC,wCAAgB;IAEhB,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,CAAC,CAAS,IAAM,EAAN,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,yBAFU,CAAC,IAAI,kCAAM,KAAK,OAAO,CAE8B;IAE/D,oFAAoF;IACpF,iBADW,MAAM,CAAC,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAIzB,YAAkC;IAatC;;;OAGG;IACH,oCAFW,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAYf;IAED;;;OAGG;IACH,uBAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;OAGG;IACH,0BAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAMb;IAiEG,mCAAkD;IAKlD,sCAAwD;IACxD,iDAAsB;IAM1B;;OAEG;IACH,gBAmBC;IA8ID;;;OAGG;IACH,UAFa,OAAO,CAAC,OAAO,CAAC,CAgC5B;IAED,4BAEC;IAED;;;;;;;OAOG;IACH,cAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAKlF;IAED;;;;;;;;OAQG;IACH,4BANW,MAAM,kBACN,MAAM,qBACN,MAAM,eACN,MAAM,UAuBhB;IAED;;;MAEC;IAED,sBAEC;IAED,kBAEC;IAED,iCAEC;IAED,iCASC;IAED,uFAWC;;CACJ;;;;iCAlgBY,eAAe,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB;4BAZnC,uBAAuB;qBAR9C,qBAAqB;wBAElB,yBAAyB;qBAL5B,oBAAoB"}
1
+ {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA6CA;IAkBI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA0CpD;IAvCG,uBAA0B;IAC1B,oDAAsB;IAItB,sCAAsC;IACtC,wCAAgB;IAEhB,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,CAAC,CAAS,IAAM,EAAN,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,yBAFU,CAAC,IAAI,kCAAM,KAAK,OAAO,CAE8B;IAE/D,oFAAoF;IACpF,iBADW,MAAM,CAAC,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAIzB,YAAkC;IAatC;;;OAGG;IACH,oCAFW,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAYf;IAED;;;OAGG;IACH,uBAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;OAGG;IACH,0BAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAMb;IAiEG,mCAAkD;IAKlD,sCAAwD;IACxD,iDAAsB;IAM1B;;OAEG;IACH,gBAmBC;IA8ID;;;OAGG;IACH,UAFa,OAAO,CAAC,OAAO,CAAC,CAgC5B;IAED,2CAiBC;IAED,4BAEC;IAED;;;;;;;OAOG;IACH,cAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAKlF;IAED;;;;;;;;OAQG;IACH,4BANW,MAAM,kBACN,MAAM,qBACN,MAAM,eACN,MAAM,UAuBhB;IAED;;;MAEC;IAED,sBAEC;IAED,kBAEC;IAED,iCAEC;IAED,iCASC;IAED,uFAWC;;CACJ;;;;iCArhBY,eAAe,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB;4BAZnC,uBAAuB;qBAR9C,qBAAqB;wBAElB,yBAAyB;qBAL5B,oBAAoB"}
@@ -11,7 +11,10 @@ import EventListenerRegistry from "./genomeSpy/eventListenerRegistry.js";
11
11
  import InputBindingManager from "./genomeSpy/inputBindingManager.js";
12
12
 
13
13
  import { calculateCanvasSize } from "./view/viewUtils.js";
14
- import { initializeViewData } from "./genomeSpy/viewDataInit.js";
14
+ import {
15
+ initializeViewData,
16
+ initializeVisibleViewData,
17
+ } from "./genomeSpy/viewDataInit.js";
15
18
  import UnitView from "./view/unitView.js";
16
19
 
17
20
  import WebGLHelper from "./gl/webGLHelper.js";
@@ -463,6 +466,25 @@ export default class GenomeSpy {
463
466
  }
464
467
  }
465
468
 
469
+ async initializeVisibleViewData() {
470
+ if (!this.viewRoot) {
471
+ return;
472
+ }
473
+
474
+ await initializeVisibleViewData(
475
+ this.viewRoot,
476
+ this.viewRoot.context.dataFlow,
477
+ this.viewRoot.context.fontManager
478
+ );
479
+
480
+ // Visibility toggles can change sizes; ensure layout is recomputed even
481
+ // when callers don't explicitly request it.
482
+ this.viewRoot._invalidateCacheByPrefix("size", "progeny");
483
+ this.#glHelper.invalidateSize();
484
+ this.computeLayout();
485
+ this.animator.requestRender();
486
+ }
487
+
466
488
  registerMouseEvents() {
467
489
  this.#interactionController.registerMouseEvents();
468
490
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dataToVertices.d.ts","sourceRoot":"","sources":["../../../src/gl/dataToVertices.js"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH;IACI;;;OAGG;IAEH;;;;;;OAMG;IACH,mDALG;QAAsE,QAAQ,EAAtE,MAAM,CAAC,OAAO,oBAAoB,EAAE,OAAO,wCAAU;QACnC,UAAU,GAA5B,MAAM,EAAE;QACQ,WAAW,GAA3B,MAAM;KAEhB,EAqFA;IAnFG,8FAAwB;IAIxB,sGAQK;IAQL,0BAAoC;IAEpC,8BAAoD;IAyDpD,mBAAmB;IAEnB,yFAAyF;IACzF,UADW,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CACkB;IAGrD;;;;OAIG;IACH,mBAFW,GAAG,QAcb;IAED;;OAEG;IACH,oBAFW,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,QAM5B;IAED;;;OAGG;IACH,cAHW,GAAG,QACH,MAAM,EAAE,kCAYlB;IAED;;;;OAIG;IACH,sBAJW,OAAO,qBAAqB,EAAE,IAAI,OAClC,MAAM,OACN,MAAM,QAgEhB;IAED;;;;;OAKG;IACH,mBAFW,OAAO,qBAAqB,EAAE,KAAK,QAI7C;IAhEO;;;MAAyB;IAkEjC;QAEQ,kJAAkJ;gBAAvI,MAAM,CAAC,MAAM,EAAE;YAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAC,CAAC;QAE9I,8BAA8B;;QAE9B,8CAA8C;;;MAIrD;CACJ;AAED;IACI;;;;;;OAMG;IACH,gDAJG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EA8BA;IAnBG,qBAkBW;CA8BlB;AAED;IACI;;;;;;;;;OASG;IACH,sFAPG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,qBAAqB,GAArC,MAAM;QAEY,YAAY,GAA9B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EAuBA;IARG,uBAAgC;IAEhC,8BAA8D;IAE9D,6CAA+D;IAC/D,4CAA6D;CA6CpE;AAED;IACI;;;;;;OAMG;IACH,gDAJG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EAQA;CACJ;AAED;IACI;;;;;OAKG;IACH,gDAJG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EAQA;CAYJ;AAED;IACI;;;;;;;;;OASG;IACH,+EAPG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACkD,WAAW,EAArE,OAAO,2BAA2B,EAAE,aAAa;QACrB,UAAU,EAAtC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;QACH,aAAa,GAA7B,MAAM;QACW,WAAW,GAA5B,OAAO;KAAsB,EA6CvC;IA9BG,4DAA2B;IAC3B,2DAA0B;IAE1B,gCAA4B;IAO5B,qCAAqC;IACrC,cADW,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAMf;IAElB,oDAGC;IACD,qDAGC;IAED,8CAAiE;CAgJxE;;;;;;;;YAjnBS,MAAM;;;;WACN,MAAM;YACN,OAAO,yBAAyB,EAAE,MAAM;;yBAjBzB,mBAAmB"}
1
+ {"version":3,"file":"dataToVertices.d.ts","sourceRoot":"","sources":["../../../src/gl/dataToVertices.js"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH;IACI;;;OAGG;IAEH;;;;;;OAMG;IACH,mDALG;QAAsE,QAAQ,EAAtE,MAAM,CAAC,OAAO,oBAAoB,EAAE,OAAO,wCAAU;QACnC,UAAU,GAA5B,MAAM,EAAE;QACQ,WAAW,GAA3B,MAAM;KAEhB,EAiGA;IA/FG,8FAAwB;IAIxB,sGAQK;IAQL,0BAAoC;IAEpC,8BAAoD;IAqEpD,mBAAmB;IAEnB,yFAAyF;IACzF,UADW,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CACkB;IAGrD;;;;OAIG;IACH,mBAFW,GAAG,QAcb;IAED;;OAEG;IACH,oBAFW,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,QAM5B;IAED;;;OAGG;IACH,cAHW,GAAG,QACH,MAAM,EAAE,kCAYlB;IAED;;;;OAIG;IACH,sBAJW,OAAO,qBAAqB,EAAE,IAAI,OAClC,MAAM,OACN,MAAM,QAgEhB;IAED;;;;;OAKG;IACH,mBAFW,OAAO,qBAAqB,EAAE,KAAK,QAI7C;IAhEO;;;MAAyB;IAkEjC;QAEQ,kJAAkJ;gBAAvI,MAAM,CAAC,MAAM,EAAE;YAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAC,CAAC;QAE9I,8BAA8B;;QAE9B,8CAA8C;;;MAIrD;CACJ;AAED;IACI;;;;;;OAMG;IACH,gDAJG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EA8BA;IAnBG,qBAkBW;CA8BlB;AAED;IACI;;;;;;;;;OASG;IACH,sFAPG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,qBAAqB,GAArC,MAAM;QAEY,YAAY,GAA9B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EAuBA;IARG,uBAAgC;IAEhC,8BAA8D;IAE9D,6CAA+D;IAC/D,4CAA6D;CA6CpE;AAED;IACI;;;;;;OAMG;IACH,gDAJG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EAQA;CACJ;AAED;IACI;;;;;OAKG;IACH,gDAJG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACQ,QAAQ,GAAxB,MAAM;KAChB,EAQA;CAYJ;AAED;IACI;;;;;;;;;OASG;IACH,+EAPG;QAAwC,QAAQ,EAAxC,MAAM,CAAC,MAAM,wCAAU;QACN,UAAU,EAA3B,MAAM,EAAE;QACkD,WAAW,EAArE,OAAO,2BAA2B,EAAE,aAAa;QACrB,UAAU,EAAtC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;QACH,aAAa,GAA7B,MAAM;QACW,WAAW,GAA5B,OAAO;KAAsB,EA6CvC;IA9BG,4DAA2B;IAC3B,2DAA0B;IAE1B,gCAA4B;IAO5B,qCAAqC;IACrC,cADW,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAMf;IAElB,oDAGC;IACD,qDAGC;IAED,8CAAiE;CAgJxE;;;;;;;;YA7nBS,MAAM;;;;WACN,MAAM;YACN,OAAO,yBAAyB,EAAE,MAAM;;yBAjBzB,mBAAmB"}
@@ -82,11 +82,23 @@ export class GeometryBuilder {
82
82
  getAttributeAndArrayTypes(scale, channel);
83
83
  const largeHpArray = [0, 0];
84
84
 
85
- /** @type {ReturnType<typeof createIndexer>} */
85
+ /** @type {ReturnType<typeof createIndexer> | undefined} */
86
86
  let indexer;
87
- if (scale && discrete && "domain" in scale) {
88
- indexer = createIndexer();
89
- indexer.addAll(scale.domain());
87
+ if (scale && discrete) {
88
+ if (
89
+ "props" in scale &&
90
+ /** @type {any} */ (scale.props).domainIndexer
91
+ ) {
92
+ // domainIndexer is a runtime-only extension, not in VegaScale typings.
93
+ indexer = /** @type {any} */ (scale.props).domainIndexer;
94
+ } else if ("domain" in scale) {
95
+ indexer = createIndexer();
96
+ indexer.addAll(scale.domain());
97
+ } else {
98
+ throw new Error(
99
+ "Missing domain indexer for discrete scale."
100
+ );
101
+ }
90
102
  }
91
103
 
92
104
  /**
@@ -39,9 +39,9 @@ export default class ScaleDomainAggregator {
39
39
  /**
40
40
  * Extracts and unions the data domains of all participating views.
41
41
  *
42
- * @return {DomainArray}
42
+ * @return {DomainArray | undefined}
43
43
  */
44
- getDataDomain(): DomainArray;
44
+ getDataDomain(): DomainArray | undefined;
45
45
  /**
46
46
  * @param {import("../types/encoder.js").VegaScale} scale
47
47
  * @param {boolean} domainWasInitialized
@@ -1 +1 @@
1
- {"version":3,"file":"scaleDomainAggregator.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleDomainAggregator.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AAEH;IAgBI;;;;;;OAMG;IACH,0EALG;QAAkD,UAAU,EAApD,MAAM,GAAG,CAAC,qBAAqB,CAAC;QACiB,OAAO,EAAxD,MAAM,OAAO,oBAAoB,EAAE,IAAI;QACf,cAAc,EAAtC,MAAM,MAAM,EAAE;QACgD,mBAAmB,EAAjF,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa,KAAK,MAAM,EAAE;KAC9D,EAMA;IAED;;OAEG;IACH,6BAFa,GAAG,EAAE,CAIjB;IAED,+BAEC;IAED;;;;;OAKG;IACH,iDAHW,OAAO,GACL,GAAG,EAAE,CAYjB;IAED;;;;OAIG;IACH,uBAFY,WAAW,CAOtB;IAED;;;;OAIG;IACH,iBAFY,WAAW,CAItB;IAED;;;;OAIG;IACH,4BAJW,OAAO,qBAAqB,EAAE,SAAS,wBACvC,OAAO,GACL,OAAO,CAgBnB;;CACJ;0BA1GY,OAAO,yBAAyB,EAAE,WAAW;4BAC7C,OAAO,kBAAkB,EAAE,aAAa;2BACxC,OAAO,kBAAkB,EAAE,YAAY;oCACvC,OAAO,sBAAsB,EAAE,qBAAqB"}
1
+ {"version":3,"file":"scaleDomainAggregator.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleDomainAggregator.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AAEH;IAgBI;;;;;;OAMG;IACH,0EALG;QAAkD,UAAU,EAApD,MAAM,GAAG,CAAC,qBAAqB,CAAC;QACiB,OAAO,EAAxD,MAAM,OAAO,oBAAoB,EAAE,IAAI;QACf,cAAc,EAAtC,MAAM,MAAM,EAAE;QACgD,mBAAmB,EAAjF,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa,KAAK,MAAM,EAAE;KAC9D,EAMA;IAED;;OAEG;IACH,6BAFa,GAAG,EAAE,CAIjB;IAED,+BAEC;IAED;;;;;OAKG;IACH,iDAHW,OAAO,GACL,GAAG,EAAE,CAYjB;IAED;;;;OAIG;IACH,uBAFY,WAAW,CAOtB;IAED;;;;OAIG;IACH,iBAFY,WAAW,GAAG,SAAS,CAIlC;IAED;;;;OAIG;IACH,4BAJW,OAAO,qBAAqB,EAAE,SAAS,wBACvC,OAAO,GACL,OAAO,CAgBnB;;CACJ;0BA1GY,OAAO,yBAAyB,EAAE,WAAW;4BAC7C,OAAO,kBAAkB,EAAE,aAAa;2BACxC,OAAO,kBAAkB,EAAE,YAAY;oCACvC,OAAO,sBAAsB,EAAE,qBAAqB"}