@genome-spy/core 0.66.1 → 0.68.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.
- package/dist/bundle/index.es.js +7669 -6115
- package/dist/bundle/index.js +114 -133
- package/dist/schema.json +534 -132
- package/dist/src/data/collector.d.ts +20 -0
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +148 -0
- package/dist/src/data/dataFlow.d.ts +6 -0
- package/dist/src/data/dataFlow.d.ts.map +1 -1
- package/dist/src/data/dataFlow.js +10 -0
- package/dist/src/data/flowHandle.d.ts +2 -0
- package/dist/src/data/flowHandle.d.ts.map +1 -1
- package/dist/src/data/flowHandle.js +1 -0
- package/dist/src/data/flowInit.d.ts +12 -4
- package/dist/src/data/flowInit.d.ts.map +1 -1
- package/dist/src/data/flowInit.js +115 -17
- package/dist/src/data/flowNode.d.ts +8 -0
- package/dist/src/data/flowNode.d.ts.map +1 -1
- package/dist/src/data/flowNode.js +18 -0
- package/dist/src/data/keyIndex.d.ts +18 -0
- package/dist/src/data/keyIndex.d.ts.map +1 -0
- package/dist/src/data/keyIndex.js +241 -0
- package/dist/src/data/keyIndex.test.d.ts +2 -0
- package/dist/src/data/keyIndex.test.d.ts.map +1 -0
- package/dist/src/data/sources/dataSource.d.ts.map +1 -1
- package/dist/src/data/sources/dataSource.js +5 -1
- package/dist/src/data/sources/dataSourceFactory.d.ts +14 -12
- package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -1
- package/dist/src/data/sources/dataSourceFactory.js +52 -16
- package/dist/src/data/sources/lazy/mockLazySource.d.ts +29 -0
- package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -0
- package/dist/src/data/sources/lazy/mockLazySource.js +44 -0
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +22 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.js +34 -2
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +15 -0
- package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/tabixSource.js +15 -5
- package/dist/src/data/transforms/stack.d.ts.map +1 -1
- package/dist/src/data/transforms/stack.js +1 -0
- package/dist/src/encoder/accessor.d.ts +43 -0
- package/dist/src/encoder/accessor.d.ts.map +1 -1
- package/dist/src/encoder/accessor.js +164 -0
- package/dist/src/encoder/encoder.d.ts +11 -2
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +24 -4
- package/dist/src/encoder/metadataChannels.d.ts +15 -0
- package/dist/src/encoder/metadataChannels.d.ts.map +1 -0
- package/dist/src/encoder/metadataChannels.js +65 -0
- package/dist/src/encoder/metadataChannels.test.d.ts +2 -0
- package/dist/src/encoder/metadataChannels.test.d.ts.map +1 -0
- package/dist/src/genome/scaleLocus.d.ts.map +1 -1
- package/dist/src/genome/scaleLocus.js +14 -1
- package/dist/src/genomeSpy/containerUi.d.ts +0 -1
- package/dist/src/genomeSpy/containerUi.d.ts.map +1 -1
- package/dist/src/genomeSpy/containerUi.js +0 -14
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +3 -7
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -1
- package/dist/src/genomeSpy/loadingIndicatorManager.js +68 -20
- package/dist/src/genomeSpy/loadingStatusRegistry.d.ts +52 -0
- package/dist/src/genomeSpy/loadingStatusRegistry.d.ts.map +1 -0
- package/dist/src/genomeSpy/loadingStatusRegistry.js +86 -0
- package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewContextFactory.js +0 -1
- package/dist/src/genomeSpy/viewDataInit.d.ts +10 -0
- package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewDataInit.js +166 -2
- package/dist/src/genomeSpy/viewDataInit.test.d.ts +2 -0
- package/dist/src/genomeSpy/viewDataInit.test.d.ts.map +1 -0
- package/dist/src/genomeSpy.d.ts +1 -2
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +69 -27
- package/dist/src/gl/dataToVertices.d.ts.map +1 -1
- package/dist/src/gl/dataToVertices.js +16 -4
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +18 -11
- package/dist/src/marks/markUtils.js +1 -1
- package/dist/src/scale/scale.d.ts +6 -1
- package/dist/src/scale/scale.d.ts.map +1 -1
- package/dist/src/scale/scale.js +83 -23
- package/dist/src/scales/axisResolution.d.ts.map +1 -1
- package/dist/src/scales/axisResolution.js +10 -0
- package/dist/src/scales/{scaleDomainAggregator.d.ts → domainPlanner.d.ts} +8 -5
- package/dist/src/scales/domainPlanner.d.ts.map +1 -0
- package/dist/src/scales/domainPlanner.js +285 -0
- package/dist/src/scales/domainPlanner.test.d.ts +2 -0
- package/dist/src/scales/domainPlanner.test.d.ts.map +1 -0
- package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
- package/dist/src/scales/scaleInstanceManager.js +8 -4
- package/dist/src/scales/scaleInteractionController.d.ts +6 -0
- package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
- package/dist/src/scales/scaleInteractionController.js +41 -3
- package/dist/src/scales/scaleResolution.d.ts +19 -16
- package/dist/src/scales/scaleResolution.d.ts.map +1 -1
- package/dist/src/scales/scaleResolution.js +255 -70
- package/dist/src/scales/scaleResolution.test.d.ts.map +1 -1
- package/dist/src/selection/selection.d.ts +21 -0
- package/dist/src/selection/selection.d.ts.map +1 -1
- package/dist/src/selection/selection.js +82 -0
- package/dist/src/spec/channel.d.ts +52 -15
- package/dist/src/spec/data.d.ts +4 -0
- package/dist/src/spec/parameter.d.ts +16 -11
- package/dist/src/spec/testing.d.ts +12 -0
- package/dist/src/spec/testing.d.ts.map +1 -0
- package/dist/src/spec/testing.js +20 -0
- package/dist/src/spec/view.d.ts +45 -10
- package/dist/src/styles/genome-spy.css +3 -31
- package/dist/src/styles/genome-spy.css.d.ts +1 -1
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
- package/dist/src/styles/genome-spy.css.js +0 -29
- package/dist/src/types/encoder.d.ts +37 -2
- package/dist/src/types/rendering.d.ts +4 -3
- package/dist/src/types/viewContext.d.ts +0 -14
- package/dist/src/utils/domainArray.d.ts.map +1 -1
- package/dist/src/utils/domainArray.js +3 -0
- package/dist/src/utils/indexer.d.ts +3 -0
- package/dist/src/utils/indexer.d.ts.map +1 -1
- package/dist/src/utils/indexer.js +3 -0
- package/dist/src/utils/throttle.d.ts +4 -1
- package/dist/src/utils/throttle.d.ts.map +1 -1
- package/dist/src/utils/throttle.js +54 -23
- package/dist/src/utils/throttle.test.d.ts +2 -0
- package/dist/src/utils/throttle.test.d.ts.map +1 -0
- package/dist/src/utils/transition.d.ts +21 -0
- package/dist/src/utils/transition.d.ts.map +1 -1
- package/dist/src/utils/transition.js +28 -0
- package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
- package/dist/src/utils/ui/tooltip.js +7 -1
- package/dist/src/utils/ui/tooltip.test.d.ts +2 -0
- package/dist/src/utils/ui/tooltip.test.d.ts.map +1 -0
- package/dist/src/view/axisGridView.d.ts.map +1 -1
- package/dist/src/view/axisGridView.js +22 -5
- package/dist/src/view/axisView.d.ts.map +1 -1
- package/dist/src/view/axisView.js +20 -5
- package/dist/src/view/concatView.js +3 -3
- package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
- package/dist/src/view/containerMutationHelper.js +6 -2
- package/dist/src/view/containerView.d.ts +9 -5
- package/dist/src/view/containerView.d.ts.map +1 -1
- package/dist/src/view/containerView.js +34 -9
- package/dist/src/view/dataReadiness.d.ts +46 -0
- package/dist/src/view/dataReadiness.d.ts.map +1 -0
- package/dist/src/view/dataReadiness.js +267 -0
- package/dist/src/view/dataReadiness.test.d.ts +2 -0
- package/dist/src/view/dataReadiness.test.d.ts.map +1 -0
- package/dist/src/view/facetView.d.ts.map +1 -1
- package/dist/src/view/facetView.js +7 -5
- package/dist/src/view/flowBuilder.d.ts +5 -3
- package/dist/src/view/flowBuilder.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.js +74 -7
- package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
- package/dist/src/view/gridView/gridChild.js +8 -0
- package/dist/src/view/gridView/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView/gridView.js +119 -2
- package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
- package/dist/src/view/gridView/scrollbar.js +3 -0
- package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
- package/dist/src/view/gridView/selectionRect.js +20 -5
- package/dist/src/view/gridView/separatorView.d.ts +51 -0
- package/dist/src/view/gridView/separatorView.d.ts.map +1 -0
- package/dist/src/view/gridView/separatorView.js +275 -0
- package/dist/src/view/layerView.js +3 -3
- package/dist/src/view/layout/flexLayout.d.ts +0 -30
- package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
- package/dist/src/view/layout/flexLayout.js +0 -86
- package/dist/src/view/paramMediator.d.ts +19 -0
- package/dist/src/view/paramMediator.d.ts.map +1 -1
- package/dist/src/view/paramMediator.js +86 -19
- package/dist/src/view/testUtils.d.ts.map +1 -1
- package/dist/src/view/testUtils.js +11 -1
- package/dist/src/view/unitView.d.ts +8 -13
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +127 -43
- package/dist/src/view/view.d.ts +34 -14
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +119 -9
- package/dist/src/view/viewFactory.d.ts.map +1 -1
- package/dist/src/view/viewFactory.js +20 -1
- package/dist/src/view/viewSelectors.d.ts +148 -0
- package/dist/src/view/viewSelectors.d.ts.map +1 -0
- package/dist/src/view/viewSelectors.js +773 -0
- package/dist/src/view/viewSelectors.test.d.ts +2 -0
- package/dist/src/view/viewSelectors.test.d.ts.map +1 -0
- package/dist/src/view/viewUtils.d.ts +0 -8
- package/dist/src/view/viewUtils.d.ts.map +1 -1
- package/dist/src/view/viewUtils.js +1 -21
- package/package.json +3 -3
- package/dist/src/scales/scaleDomainAggregator.d.ts.map +0 -1
- package/dist/src/scales/scaleDomainAggregator.js +0 -162
- package/dist/src/scales/scaleDomainAggregator.test.d.ts +0 -2
- package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +0 -1
|
@@ -19,6 +19,19 @@ export default class Collector extends FlowNode {
|
|
|
19
19
|
* @returns {() => void}
|
|
20
20
|
*/
|
|
21
21
|
observe(listener: (arg0: Collector) => void): () => void;
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} domainKey
|
|
24
|
+
* @param {import("../spec/channel.js").Type} type
|
|
25
|
+
* @param {import("../types/encoder.js").Accessor} accessor
|
|
26
|
+
* @returns {import("../utils/domainArray.js").DomainArray}
|
|
27
|
+
*/
|
|
28
|
+
getDomain(domainKey: string, type: import("../spec/channel.js").Type, accessor: import("../types/encoder.js").Accessor): import("../utils/domainArray.js").DomainArray;
|
|
29
|
+
/**
|
|
30
|
+
* @param {string} domainKey
|
|
31
|
+
* @param {() => void} listener
|
|
32
|
+
* @returns {() => void}
|
|
33
|
+
*/
|
|
34
|
+
subscribeDomainChanges(domainKey: string, listener: () => void): () => void;
|
|
22
35
|
/**
|
|
23
36
|
* @returns {Iterable<Datum>}
|
|
24
37
|
*/
|
|
@@ -38,6 +51,13 @@ export default class Collector extends FlowNode {
|
|
|
38
51
|
* @param {number} uniqueId
|
|
39
52
|
*/
|
|
40
53
|
findDatumByUniqueId(uniqueId: number): import("./flowNode.js").Datum;
|
|
54
|
+
/**
|
|
55
|
+
* Uses a lazy index to find a datum by its key fields.
|
|
56
|
+
*
|
|
57
|
+
* @param {string[]} keyFields
|
|
58
|
+
* @param {import("../spec/channel.js").Scalar[]} keyTuple
|
|
59
|
+
*/
|
|
60
|
+
findDatumByKey(keyFields: string[], keyTuple: import("../spec/channel.js").Scalar[]): import("./flowNode.js").Datum;
|
|
41
61
|
#private;
|
|
42
62
|
}
|
|
43
63
|
import FlowNode from "./flowNode.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../../src/data/collector.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../../src/data/collector.js"],"names":[],"mappings":"AAYA;;;;;GAKG;AACH;IA6CI;;OAEG;IACH,qBAFW,OAAO,sBAAsB,EAAE,aAAa,EAiBtD;IAZG,qDAA2C;IAE3C,4CAA4C;IAC5C,WADW,GAAG,CAAC,CAAS,IAAS,EAAT,SAAS,KAAE,IAAI,CAAC,CACd;IAG1B,yFAAyF;IACzF,cADW,GAAG,CAAC,OAAO,oBAAoB,EAAE,MAAM,EAAE,+BAAO,CACN;IAwFzD;;;OAGG;IACH,kBAHW,CAAS,IAAS,EAAT,SAAS,KAAE,IAAI,GACtB,MAAM,IAAI,CAOtB;IAiCD;;;;;OAKG;IACH,qBALW,MAAM,QACN,OAAO,oBAAoB,EAAE,IAAI,YACjC,OAAO,qBAAqB,EAAE,QAAQ,GACpC,OAAO,yBAAyB,EAAE,WAAW,CAkBzD;IAED;;;;OAIG;IACH,kCAJW,MAAM,YACN,MAAM,IAAI,GACR,MAAM,IAAI,CAItB;IAED;;OAEG;IACH,WAFa,QAAQ,+BAAO,CAqB3B;IAED;;;OAGG;IACH,mBAFW,CAAC,KAAK,+BAAO,KAAK,IAAI,QAUhC;IAED;;OAEG;IACH,uBAMC;IAqDD;;;;OAIG;IACH,8BAFW,MAAM,iCA4BhB;IAED;;;;;OAKG;IACH,0BAHW,MAAM,EAAE,YACR,OAAO,oBAAoB,EAAE,MAAM,EAAE,iCAS/C;;CACJ;qBA9XyD,eAAe"}
|
|
@@ -7,6 +7,8 @@ import { field } from "../utils/field.js";
|
|
|
7
7
|
import { asArray } from "../utils/arrayUtils.js";
|
|
8
8
|
import { radixSortIntoLookupArray } from "../utils/radixSort.js";
|
|
9
9
|
import { UNIQUE_ID_KEY } from "./transforms/identifier.js";
|
|
10
|
+
import createDomain from "../utils/domainArray.js";
|
|
11
|
+
import KeyIndex from "./keyIndex.js";
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Collects (materializes) the data that flows through this node.
|
|
@@ -33,6 +35,9 @@ export default class Collector extends FlowNode {
|
|
|
33
35
|
*/
|
|
34
36
|
#uniqueIdIndex = [];
|
|
35
37
|
|
|
38
|
+
/** @type {KeyIndex} */
|
|
39
|
+
#keyIndex = new KeyIndex();
|
|
40
|
+
|
|
36
41
|
/**
|
|
37
42
|
* Start and end indices of all facets if they are concatenated into a single array.
|
|
38
43
|
* Used together with the uniqueIdIndex for looking up data items by their unique id.
|
|
@@ -45,6 +50,9 @@ export default class Collector extends FlowNode {
|
|
|
45
50
|
*/
|
|
46
51
|
#comparator;
|
|
47
52
|
|
|
53
|
+
/** @type {DomainCache} */
|
|
54
|
+
#domainCache = new DomainCache();
|
|
55
|
+
|
|
48
56
|
get behavior() {
|
|
49
57
|
return BEHAVIOR_COLLECTS;
|
|
50
58
|
}
|
|
@@ -76,6 +84,7 @@ export default class Collector extends FlowNode {
|
|
|
76
84
|
#init() {
|
|
77
85
|
this.#buffer = [];
|
|
78
86
|
this.#uniqueIdIndex = [];
|
|
87
|
+
this.#keyIndex.invalidate();
|
|
79
88
|
|
|
80
89
|
this.facetBatches.clear();
|
|
81
90
|
this.facetBatches.set(undefined, this.#buffer);
|
|
@@ -97,6 +106,8 @@ export default class Collector extends FlowNode {
|
|
|
97
106
|
* @param {import("../types/flowBatch.js").FlowBatch} flowBatch
|
|
98
107
|
*/
|
|
99
108
|
beginBatch(flowBatch) {
|
|
109
|
+
this.#keyIndex.invalidate();
|
|
110
|
+
|
|
100
111
|
if (isFacetBatch(flowBatch)) {
|
|
101
112
|
this.#buffer = [];
|
|
102
113
|
this.facetBatches.set(asArray(flowBatch.facetId), this.#buffer);
|
|
@@ -144,6 +155,8 @@ export default class Collector extends FlowNode {
|
|
|
144
155
|
|
|
145
156
|
super.complete();
|
|
146
157
|
|
|
158
|
+
this.#invalidateDomains();
|
|
159
|
+
|
|
147
160
|
for (const observer of this.observers) {
|
|
148
161
|
observer(this);
|
|
149
162
|
}
|
|
@@ -187,6 +200,41 @@ export default class Collector extends FlowNode {
|
|
|
187
200
|
for (const child of this.children) {
|
|
188
201
|
child.complete();
|
|
189
202
|
}
|
|
203
|
+
|
|
204
|
+
this.#invalidateDomains();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param {string} domainKey
|
|
209
|
+
* @param {import("../spec/channel.js").Type} type
|
|
210
|
+
* @param {import("../types/encoder.js").Accessor} accessor
|
|
211
|
+
* @returns {import("../utils/domainArray.js").DomainArray}
|
|
212
|
+
*/
|
|
213
|
+
getDomain(domainKey, type, accessor) {
|
|
214
|
+
return this.#domainCache.getDomain(domainKey, () => {
|
|
215
|
+
const domain = createDomain(type);
|
|
216
|
+
|
|
217
|
+
if (accessor.constant) {
|
|
218
|
+
domain.extend(accessor({}));
|
|
219
|
+
} else if (this.completed) {
|
|
220
|
+
for (const data of this.facetBatches.values()) {
|
|
221
|
+
for (let i = 0, n = data.length; i < n; i++) {
|
|
222
|
+
domain.extend(accessor(data[i]));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return domain;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param {string} domainKey
|
|
233
|
+
* @param {() => void} listener
|
|
234
|
+
* @returns {() => void}
|
|
235
|
+
*/
|
|
236
|
+
subscribeDomainChanges(domainKey, listener) {
|
|
237
|
+
return this.#domainCache.subscribe(domainKey, listener);
|
|
190
238
|
}
|
|
191
239
|
|
|
192
240
|
/**
|
|
@@ -246,6 +294,13 @@ export default class Collector extends FlowNode {
|
|
|
246
294
|
}
|
|
247
295
|
}
|
|
248
296
|
|
|
297
|
+
#invalidateDomains() {
|
|
298
|
+
if (this.#domainCache.hasCachedDomains()) {
|
|
299
|
+
this.#domainCache.clear();
|
|
300
|
+
}
|
|
301
|
+
this.#domainCache.notify();
|
|
302
|
+
}
|
|
303
|
+
|
|
249
304
|
/**
|
|
250
305
|
* Builds an index for looking up data items by their unique id.
|
|
251
306
|
* Using a sorted index and binary search for O(log n) complexity.
|
|
@@ -314,6 +369,99 @@ export default class Collector extends FlowNode {
|
|
|
314
369
|
}
|
|
315
370
|
}
|
|
316
371
|
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Uses a lazy index to find a datum by its key fields.
|
|
375
|
+
*
|
|
376
|
+
* @param {string[]} keyFields
|
|
377
|
+
* @param {import("../spec/channel.js").Scalar[]} keyTuple
|
|
378
|
+
*/
|
|
379
|
+
findDatumByKey(keyFields, keyTuple) {
|
|
380
|
+
this.#checkStatus();
|
|
381
|
+
return this.#keyIndex.findDatum(
|
|
382
|
+
keyFields,
|
|
383
|
+
keyTuple,
|
|
384
|
+
this.facetBatches.values()
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Manages cached domains and subscriptions for invalidation.
|
|
391
|
+
*/
|
|
392
|
+
class DomainCache {
|
|
393
|
+
/** @type {Map<string, import("../utils/domainArray.js").DomainArray>} */
|
|
394
|
+
#cache = new Map();
|
|
395
|
+
|
|
396
|
+
/** @type {Map<string, Set<() => void>>} */
|
|
397
|
+
#observers = new Map();
|
|
398
|
+
|
|
399
|
+
hasCachedDomains() {
|
|
400
|
+
return this.#cache.size > 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
clear() {
|
|
404
|
+
this.#cache.clear();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @param {string} domainKey
|
|
409
|
+
* @param {() => import("../utils/domainArray.js").DomainArray} build
|
|
410
|
+
* @returns {import("../utils/domainArray.js").DomainArray}
|
|
411
|
+
*/
|
|
412
|
+
getDomain(domainKey, build) {
|
|
413
|
+
const cached = this.#cache.get(domainKey);
|
|
414
|
+
if (cached) {
|
|
415
|
+
return cached;
|
|
416
|
+
} else {
|
|
417
|
+
const domain = build();
|
|
418
|
+
this.#cache.set(domainKey, domain);
|
|
419
|
+
return domain;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* @param {string} domainKey
|
|
425
|
+
* @param {() => void} listener
|
|
426
|
+
* @returns {() => void}
|
|
427
|
+
*/
|
|
428
|
+
subscribe(domainKey, listener) {
|
|
429
|
+
let listeners = this.#observers.get(domainKey);
|
|
430
|
+
if (!listeners) {
|
|
431
|
+
listeners = new Set();
|
|
432
|
+
this.#observers.set(domainKey, listeners);
|
|
433
|
+
}
|
|
434
|
+
listeners.add(listener);
|
|
435
|
+
|
|
436
|
+
return () => {
|
|
437
|
+
const entry = this.#observers.get(domainKey);
|
|
438
|
+
if (!entry) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
entry.delete(listener);
|
|
442
|
+
if (entry.size === 0) {
|
|
443
|
+
this.#observers.delete(domainKey);
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
notify() {
|
|
449
|
+
if (this.#observers.size === 0) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/** @type {Set<() => void>} */
|
|
454
|
+
const listeners = new Set();
|
|
455
|
+
for (const observers of this.#observers.values()) {
|
|
456
|
+
for (const observer of observers) {
|
|
457
|
+
listeners.add(observer);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
for (const listener of listeners) {
|
|
462
|
+
listener();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
317
465
|
}
|
|
318
466
|
|
|
319
467
|
/**
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
* DataFlow holds data sources and collectors for optimization and initialization.
|
|
3
3
|
*/
|
|
4
4
|
export default class DataFlow {
|
|
5
|
+
/**
|
|
6
|
+
* Registry for per-view loading status. The host may replace this.
|
|
7
|
+
*
|
|
8
|
+
* @type {import("../genomeSpy/loadingStatusRegistry.js").default}
|
|
9
|
+
*/
|
|
10
|
+
loadingStatusRegistry: import("../genomeSpy/loadingStatusRegistry.js").default;
|
|
5
11
|
get dataSources(): DataSource[];
|
|
6
12
|
get collectors(): import("./collector.js").default[];
|
|
7
13
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataFlow.d.ts","sourceRoot":"","sources":["../../../src/data/dataFlow.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dataFlow.d.ts","sourceRoot":"","sources":["../../../src/data/dataFlow.js"],"names":[],"mappings":"AAIA;;GAEG;AACH;IAOI;;;;OAIG;IACH,uBAFU,OAAO,uCAAuC,EAAE,OAAO,CAE3C;IAYtB,gCAEC;IAED,qDAEC;IAED;;OAEG;IACH,gCAFW,QAAQ,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,QAI7D;IAED;;OAEG;IACH,0BAFW,OAAO,yBAAyB,EAAE,OAAO,QAInD;IAED;;OAEG;IACH,6BAFW,OAAO,yBAAyB,EAAE,OAAO,QAInD;IAED;;OAEG;IACH,wBAFW,OAAO,gBAAgB,EAAE,OAAO,QAI1C;IAED;;OAEG;IACH,2BAFW,OAAO,gBAAgB,EAAE,OAAO,QAK1C;IAED;;;;OAIG;IACH,gCAFW,OAAO,gBAAgB,EAAE,OAAO,QAiB1C;IAED;;OAEG;IACH,0BAFW,MAAM;;MA2BhB;;CAGJ;uBA/HsB,yBAAyB;wBACxB,0BAA0B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import LoadingStatusRegistry from "../genomeSpy/loadingStatusRegistry.js";
|
|
1
2
|
import DataSource from "./sources/dataSource.js";
|
|
2
3
|
import NamedSource from "./sources/namedSource.js";
|
|
3
4
|
|
|
@@ -11,12 +12,21 @@ export default class DataFlow {
|
|
|
11
12
|
/** @type {Set<import("./collector.js").default>} */
|
|
12
13
|
#collectors;
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Registry for per-view loading status. The host may replace this.
|
|
17
|
+
*
|
|
18
|
+
* @type {import("../genomeSpy/loadingStatusRegistry.js").default}
|
|
19
|
+
*/
|
|
20
|
+
loadingStatusRegistry;
|
|
21
|
+
|
|
14
22
|
constructor() {
|
|
15
23
|
/** @type {Set<import("./sources/dataSource.js").default>} */
|
|
16
24
|
this.#dataSources = new Set();
|
|
17
25
|
|
|
18
26
|
/** @type {Set<import("./collector.js").default>} */
|
|
19
27
|
this.#collectors = new Set();
|
|
28
|
+
|
|
29
|
+
this.loadingStatusRegistry = new LoadingStatusRegistry();
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
get dataSources() {
|
|
@@ -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
|
|
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"}
|
|
@@ -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
|
|
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":"
|
|
1
|
+
{"version":3,"file":"flowInit.d.ts","sourceRoot":"","sources":["../../../src/data/flowInit.js"],"names":[],"mappings":"AAwDA;;;;;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,CA6FH;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,CAsB3B;qBA3SoB,qBAAqB"}
|
|
@@ -2,10 +2,11 @@ import UnitView from "../view/unitView.js";
|
|
|
2
2
|
import { buildDataFlow } from "../view/flowBuilder.js";
|
|
3
3
|
import { optimizeDataFlow } from "./flowOptimizer.js";
|
|
4
4
|
import { VISIT_SKIP } from "../view/view.js";
|
|
5
|
-
import { reconfigureScaleDomains } from "../scales/scaleResolution.js";
|
|
6
5
|
|
|
7
6
|
/** @type {WeakMap<import("./sources/dataSource.js").default, Promise<void>>} */
|
|
8
7
|
const inFlightLoads = new WeakMap();
|
|
8
|
+
/** @type {WeakMap<import("./sources/dataSource.js").default, Promise<void>>} */
|
|
9
|
+
const queuedReloads = new WeakMap();
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Deduplicate concurrent loads for shared sources without changing propagation.
|
|
@@ -16,12 +17,31 @@ const inFlightLoads = new WeakMap();
|
|
|
16
17
|
* promise settles, the source may be loaded again later as usual.
|
|
17
18
|
*
|
|
18
19
|
* @param {import("./sources/dataSource.js").default} dataSource
|
|
20
|
+
* @param {{ queueReload?: boolean }} [options]
|
|
19
21
|
* @returns {Promise<void>}
|
|
20
22
|
*/
|
|
21
|
-
function loadDataSourceOnce(dataSource) {
|
|
23
|
+
function loadDataSourceOnce(dataSource, options) {
|
|
22
24
|
const existing = inFlightLoads.get(dataSource);
|
|
23
25
|
if (existing) {
|
|
24
|
-
|
|
26
|
+
if (!options?.queueReload) {
|
|
27
|
+
return existing;
|
|
28
|
+
}
|
|
29
|
+
const queued = queuedReloads.get(dataSource);
|
|
30
|
+
if (queued) {
|
|
31
|
+
return queued;
|
|
32
|
+
}
|
|
33
|
+
const reload = existing
|
|
34
|
+
.catch(
|
|
35
|
+
/** @returns {void} */ () => {
|
|
36
|
+
// Nop: ensure a queued reload can proceed after a failure.
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
.then(() => loadDataSourceOnce(dataSource))
|
|
40
|
+
.finally(() => {
|
|
41
|
+
queuedReloads.delete(dataSource);
|
|
42
|
+
});
|
|
43
|
+
queuedReloads.set(dataSource, reload);
|
|
44
|
+
return reload;
|
|
25
45
|
}
|
|
26
46
|
|
|
27
47
|
const loadPromise = Promise.resolve()
|
|
@@ -92,6 +112,8 @@ export function syncFlowHandles(root, canonicalBySource) {
|
|
|
92
112
|
*
|
|
93
113
|
* @param {import("../view/view.js").default} subtreeRoot
|
|
94
114
|
* @param {import("./dataFlow.js").default} flow
|
|
115
|
+
* @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
|
|
116
|
+
* @param {(view: import("../view/view.js").default) => boolean} [viewInitializationPredicate]
|
|
95
117
|
* @returns {{
|
|
96
118
|
* dataFlow: import("./dataFlow.js").default,
|
|
97
119
|
* unitViews: UnitView[],
|
|
@@ -99,20 +121,54 @@ export function syncFlowHandles(root, canonicalBySource) {
|
|
|
99
121
|
* graphicsPromises: Promise<import("../marks/mark.js").default>[]
|
|
100
122
|
* }}
|
|
101
123
|
*/
|
|
102
|
-
export function initializeViewSubtree(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
124
|
+
export function initializeViewSubtree(
|
|
125
|
+
subtreeRoot,
|
|
126
|
+
flow,
|
|
127
|
+
viewFilter,
|
|
128
|
+
viewInitializationPredicate
|
|
129
|
+
) {
|
|
130
|
+
const shouldInitializeView = viewInitializationPredicate ?? (() => true);
|
|
131
|
+
const subtreeViews = collectSubtreeViews(subtreeRoot, viewFilter);
|
|
132
|
+
const viewsToInitialize = subtreeViews.filter(shouldInitializeView);
|
|
133
|
+
if (viewsToInitialize.length === 0) {
|
|
134
|
+
return {
|
|
135
|
+
dataFlow: flow,
|
|
136
|
+
unitViews: [],
|
|
137
|
+
dataSources: new Set(),
|
|
138
|
+
graphicsPromises: [],
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const viewsToInitializeSet = new Set(viewsToInitialize);
|
|
143
|
+
for (const view of viewsToInitialize) {
|
|
144
|
+
view._setDataInitializationState("pending");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let dataFlow;
|
|
148
|
+
try {
|
|
149
|
+
dataFlow = buildDataFlow(subtreeRoot, flow, viewFilter, (view) =>
|
|
150
|
+
viewsToInitializeSet.has(view)
|
|
151
|
+
);
|
|
152
|
+
const canonicalBySource = optimizeDataFlow(dataFlow);
|
|
153
|
+
syncFlowHandles(subtreeRoot, canonicalBySource);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
for (const view of viewsToInitialize) {
|
|
156
|
+
view._setDataInitializationState("none");
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const dataSources = collectViewSubtreeDataSources(viewsToInitialize);
|
|
108
162
|
|
|
109
163
|
// Initialize flow nodes for the sources that belong to this subtree.
|
|
110
164
|
for (const dataSource of dataSources) {
|
|
111
|
-
dataSource.visit((node) => node.
|
|
165
|
+
dataSource.visit((node) => node.initializeOnce());
|
|
112
166
|
}
|
|
113
167
|
|
|
114
168
|
/** @type {UnitView[]} */
|
|
115
|
-
const unitViews =
|
|
169
|
+
const unitViews = viewsToInitialize.filter(
|
|
170
|
+
(view) => view instanceof UnitView
|
|
171
|
+
);
|
|
116
172
|
|
|
117
173
|
/** @type {Promise<import("../marks/mark.js").default>[]} */
|
|
118
174
|
const graphicsPromises = [];
|
|
@@ -123,6 +179,7 @@ export function initializeViewSubtree(subtreeRoot, flow) {
|
|
|
123
179
|
const mark = view.mark;
|
|
124
180
|
// Encoders can be initialized immediately; graphics need a GL context.
|
|
125
181
|
mark.initializeEncoders();
|
|
182
|
+
view.registerDomainSubscriptions();
|
|
126
183
|
if (canInitializeGraphics) {
|
|
127
184
|
graphicsPromises.push(mark.initializeGraphics().then(() => mark));
|
|
128
185
|
}
|
|
@@ -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
|
|
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,52 @@ 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
|
|
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);
|
|
219
297
|
broadcastSubtreeDataReady(subtreeRoot);
|
|
220
298
|
return results;
|
|
221
299
|
});
|
|
222
300
|
}
|
|
223
301
|
|
|
302
|
+
/**
|
|
303
|
+
* @param {import("../view/view.js").default} subtreeRoot
|
|
304
|
+
* @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
|
|
305
|
+
* @returns {import("../view/view.js").default[]}
|
|
306
|
+
*/
|
|
307
|
+
function collectSubtreeViews(subtreeRoot, viewFilter) {
|
|
308
|
+
/** @type {import("../view/view.js").default[]} */
|
|
309
|
+
const views = [];
|
|
310
|
+
if (!viewFilter) {
|
|
311
|
+
return subtreeRoot.getDescendants();
|
|
312
|
+
}
|
|
313
|
+
subtreeRoot.visit((view) => {
|
|
314
|
+
if (!viewFilter(view)) {
|
|
315
|
+
return VISIT_SKIP;
|
|
316
|
+
}
|
|
317
|
+
views.push(view);
|
|
318
|
+
});
|
|
319
|
+
return views;
|
|
320
|
+
}
|
|
321
|
+
|
|
224
322
|
/**
|
|
225
323
|
* Broadcasts a subtree-scoped data-ready event to views within the subtree.
|
|
226
324
|
*
|
|
@@ -69,8 +69,16 @@ export default class FlowNode {
|
|
|
69
69
|
/**
|
|
70
70
|
* Allows for doing final initialization after the flow structure has been
|
|
71
71
|
* built and optimized. Must be called before any data are to be propagated.
|
|
72
|
+
* Note: Some transforms call initialize() from reset() to rebuild internal
|
|
73
|
+
* fast paths per batch. Use initializeOnce() for graph-level init to avoid
|
|
74
|
+
* double-initialization issues.
|
|
72
75
|
*/
|
|
73
76
|
initialize(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Calls initialize() once per node instance. Intended for graph-level init
|
|
79
|
+
* passes that should not rerun when reusing existing branches.
|
|
80
|
+
*/
|
|
81
|
+
initializeOnce(): void;
|
|
74
82
|
/**
|
|
75
83
|
* @param {Datum} datum
|
|
76
84
|
* @protected
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flowNode.d.ts","sourceRoot":"","sources":["../../../src/data/flowNode.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"flowNode.d.ts","sourceRoot":"","sources":["../../../src/data/flowNode.js"],"names":[],"mappings":"AAyVA;;;GAGG;AACH,uCAHW,OAAO,uBAAuB,EAAE,SAAS,GACvC,SAAS,IAAI,OAAO,uBAAuB,EAAE,SAAS,CAIlE;AAED;;;GAGG;AACH,wCAHW,OAAO,uBAAuB,EAAE,SAAS,GACvC,SAAS,IAAI,OAAO,uBAAuB,EAAE,UAAU,CAInE;AArWD;;;GAGG;AACH,qCAAsC;AAEtC;;;GAGG;AACH,uCAAwC;AAExC;;;GAGG;AACH,uCAAwC;AAExC;;GAEG;AAEH;;;;;GAKG;AACH;IA8BI;;OAEG;IACH,oCAFW,qBAAqB,EAa/B;IA3CD;;QAEI,oBAAoB;eAAT,KAAK;MAElB;IAKF;;;;OAIG;IACH,uBAFU,qBAAqB,CAEF;IAE7B,uBAEC;IAED;;;;OAIG;IACH,aAFa,MAAM,CAIlB;IAQG,yBAAyB;IACzB,UADW,QAAQ,EAAE,CACH;IAElB,uBAAuB;IACvB,QADW,QAAQ,CACI;IAEvB,2CAA2C;IAC3C,mBAAsB;IAG1B;;;OAGG;IACH,cASC;IAED;;;;;;OAMG;IACH,mBAEC;IAED;;;OAGG;IACH,uBAMC;IAgOD;;;OAGG;IACH,4BAHW,KAAK,QAKf;IA7MD;;;OAGG;IACH,kBAFW,QAAQ,QAIlB;IAED;;;OAGG;IACH,gBAFW,QAAQ,QAUlB;IAED;;OAEG;IACH,YAFW,QAAQ,QAQlB;IAED;;OAEG;IACH,6BAFW,QAAQ,QAMlB;IAED;;OAEG;IACH,0BAFW,QAAQ,QAalB;IAED;;;OAGG;IACH,mBAFW,QAAQ,QAWlB;IAED;;OAEG;IACH,eAiBC;IAED,kBAEC;IAED,uBAEC;IAED,sBAEC;IAED;;;;OAIG;IACH,eAFW,CAAC,CAAS,IAAQ,EAAR,QAAQ,KAAE,IAAI,CAAC,GAAG;QAAE,aAAa,CAAC,EAAE,CAAS,IAAQ,EAAR,QAAQ,KAAE,IAAI,CAAA;KAAC,QAchF;IAED;;;OAGG;IACH,wBAHW,MAAM,GACJ,MAAM,CAWlB;IAED;;;OAGG;IACH,cAFW,KAAK,QAKf;IAED,iBAMC;IAED;;;;OAIG;IACH,sBAFW,OAAO,uBAAuB,EAAE,SAAS,QAMnD;IAED;;;OAGG;IACH,+BAHa,OAAO,0BAA0B,EAAE,OAAO,CAYtD;IAED;;;;OAIG;IACH,8BAQC;;CASJ;oCAlUY;IAAC,aAAa,EAAE,OAAO,0BAA0B,EAAE,OAAO,CAAA;CAAC;;;;oBAM3D,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;;;;mBACnB,KAAK,EAAE"}
|