@genome-spy/core 0.64.0 → 0.65.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 (104) hide show
  1. package/dist/bundle/{index-CCJIjehY.js → AbortablePromiseCache-CcuMrnn7.js} +22 -91
  2. package/dist/bundle/browser-txUcLy2H.js +123 -0
  3. package/dist/bundle/index-BQpbYrv4.js +1712 -0
  4. package/dist/bundle/index-BhtHKLUo.js +73 -0
  5. package/dist/bundle/index-C0llXMqm.js +280 -0
  6. package/dist/bundle/index-CCe8rnZz.js +716 -0
  7. package/dist/bundle/index-CD7FLu9x.js +269 -0
  8. package/dist/bundle/{index-C08YCM2T.js → index-D-w7Mmt9.js} +246 -126
  9. package/dist/bundle/index-D74H8TTz.js +508 -0
  10. package/dist/bundle/index-DhcU-Gk-.js +1487 -0
  11. package/dist/bundle/index.es.js +4878 -4680
  12. package/dist/bundle/index.js +151 -167
  13. package/dist/bundle/inflate-DRgHi_KK.js +1050 -0
  14. package/dist/schema.json +9 -1
  15. package/dist/src/data/collector.d.ts +7 -2
  16. package/dist/src/data/collector.d.ts.map +1 -1
  17. package/dist/src/data/collector.js +13 -2
  18. package/dist/src/data/dataFlow.d.ts +20 -42
  19. package/dist/src/data/dataFlow.d.ts.map +1 -1
  20. package/dist/src/data/dataFlow.js +57 -80
  21. package/dist/src/data/dataFlow.test.js +35 -2
  22. package/dist/src/data/flowHandle.d.ts +15 -0
  23. package/dist/src/data/flowHandle.d.ts.map +1 -0
  24. package/dist/src/data/flowHandle.js +13 -0
  25. package/dist/src/data/flowInit.d.ts +85 -0
  26. package/dist/src/data/flowInit.d.ts.map +1 -0
  27. package/dist/src/data/flowInit.js +238 -0
  28. package/dist/src/data/flowInit.test.d.ts +2 -0
  29. package/dist/src/data/flowInit.test.d.ts.map +1 -0
  30. package/dist/src/data/flowInit.test.js +413 -0
  31. package/dist/src/data/flowOptimizer.d.ts +6 -4
  32. package/dist/src/data/flowOptimizer.d.ts.map +1 -1
  33. package/dist/src/data/flowOptimizer.js +29 -14
  34. package/dist/src/data/flowOptimizer.test.js +20 -15
  35. package/dist/src/data/sources/lazy/bamSource.js +1 -1
  36. package/dist/src/data/sources/lazy/bigBedSource.js +1 -1
  37. package/dist/src/data/sources/lazy/bigWigSource.js +1 -1
  38. package/dist/src/data/sources/lazy/gff3Source.d.ts +2 -6
  39. package/dist/src/data/sources/lazy/gff3Source.d.ts.map +1 -1
  40. package/dist/src/data/sources/lazy/gff3Source.js +4 -8
  41. package/dist/src/data/sources/lazy/indexedFastaSource.d.ts.map +1 -1
  42. package/dist/src/data/sources/lazy/indexedFastaSource.js +17 -17
  43. package/dist/src/data/sources/lazy/tabixSource.js +1 -1
  44. package/dist/src/genomeSpy.d.ts +1 -1
  45. package/dist/src/genomeSpy.d.ts.map +1 -1
  46. package/dist/src/genomeSpy.js +18 -61
  47. package/dist/src/marks/mark.d.ts +1 -0
  48. package/dist/src/marks/mark.d.ts.map +1 -1
  49. package/dist/src/marks/mark.js +22 -1
  50. package/dist/src/spec/sampleView.d.ts +3 -2
  51. package/dist/src/types/viewContext.d.ts +1 -1
  52. package/dist/src/view/axisResolution.d.ts +5 -0
  53. package/dist/src/view/axisResolution.d.ts.map +1 -1
  54. package/dist/src/view/axisResolution.js +16 -1
  55. package/dist/src/view/facetView.d.ts.map +1 -1
  56. package/dist/src/view/facetView.js +1 -0
  57. package/dist/src/view/flowBuilder.d.ts +2 -2
  58. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  59. package/dist/src/view/flowBuilder.js +21 -4
  60. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  61. package/dist/src/view/gridView/gridView.js +13 -0
  62. package/dist/src/view/gridView/selectionRect.d.ts +8 -4
  63. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  64. package/dist/src/view/gridView/selectionRect.js +28 -3
  65. package/dist/src/view/gridView/selectionRect.test.d.ts +2 -0
  66. package/dist/src/view/gridView/selectionRect.test.d.ts.map +1 -0
  67. package/dist/src/view/gridView/selectionRect.test.js +87 -0
  68. package/dist/src/view/paramMediator.d.ts +2 -1
  69. package/dist/src/view/paramMediator.d.ts.map +1 -1
  70. package/dist/src/view/paramMediator.js +13 -1
  71. package/dist/src/view/paramMediator.test.js +22 -0
  72. package/dist/src/view/scaleResolution.d.ts +5 -0
  73. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  74. package/dist/src/view/scaleResolution.js +10 -0
  75. package/dist/src/view/testUtils.d.ts.map +1 -1
  76. package/dist/src/view/testUtils.js +16 -4
  77. package/dist/src/view/unitView.d.ts.map +1 -1
  78. package/dist/src/view/unitView.js +58 -8
  79. package/dist/src/view/view.d.ts +17 -1
  80. package/dist/src/view/view.d.ts.map +1 -1
  81. package/dist/src/view/view.js +57 -1
  82. package/dist/src/view/viewDispose.test.d.ts +2 -0
  83. package/dist/src/view/viewDispose.test.d.ts.map +1 -0
  84. package/dist/src/view/viewDispose.test.js +110 -0
  85. package/dist/src/view/viewUtils.d.ts +4 -4
  86. package/dist/src/view/viewUtils.d.ts.map +1 -1
  87. package/dist/src/view/viewUtils.js +19 -15
  88. package/dist/src/view/viewUtils.test.d.ts +2 -0
  89. package/dist/src/view/viewUtils.test.d.ts.map +1 -0
  90. package/dist/src/view/viewUtils.test.js +87 -0
  91. package/package.json +10 -10
  92. package/dist/bundle/__vite-browser-external-C--ziKoh.js +0 -8
  93. package/dist/bundle/_commonjsHelpers-DjF3Plf2.js +0 -26
  94. package/dist/bundle/index-5ajWdKly.js +0 -1319
  95. package/dist/bundle/index-B03-Om4z.js +0 -274
  96. package/dist/bundle/index-BftNdA0O.js +0 -27
  97. package/dist/bundle/index-Bg7C4Xat.js +0 -2750
  98. package/dist/bundle/index-C3QR8Lv6.js +0 -2131
  99. package/dist/bundle/index-DTcHjAHp.js +0 -505
  100. package/dist/bundle/index-DnIkxb0L.js +0 -1025
  101. package/dist/bundle/index-Ww3TAo6_.js +0 -71
  102. package/dist/bundle/index-g8iXgW0W.js +0 -651
  103. package/dist/bundle/long-B-FASCSo.js +0 -2387
  104. package/dist/bundle/remoteFile-BuaqFGWk.js +0 -94
package/dist/schema.json CHANGED
@@ -8183,7 +8183,7 @@
8183
8183
  "type": "string"
8184
8184
  },
8185
8185
  "type": {
8186
- "$ref": "#/definitions/Type",
8186
+ "$ref": "#/definitions/SampleAttributeType",
8187
8187
  "description": "The attribute type. One of `\"nominal\"`, `\"ordinal\"`, or `\"quantitative\"`."
8188
8188
  },
8189
8189
  "visible": {
@@ -8197,6 +8197,14 @@
8197
8197
  },
8198
8198
  "type": "object"
8199
8199
  },
8200
+ "SampleAttributeType": {
8201
+ "enum": [
8202
+ "nominal",
8203
+ "ordinal",
8204
+ "quantitative"
8205
+ ],
8206
+ "type": "string"
8207
+ },
8200
8208
  "SampleDef": {
8201
8209
  "additionalProperties": false,
8202
8210
  "properties": {
@@ -10,10 +10,15 @@ export default class Collector extends FlowNode {
10
10
  */
11
11
  constructor(params?: import("../spec/transform.js").CollectParams);
12
12
  params: import("../spec/transform.js").CollectParams;
13
- /** @type {(function(Collector):void)[]} */
14
- observers: ((arg0: Collector) => void)[];
13
+ /** @type {Set<function(Collector):void>} */
14
+ observers: Set<(arg0: Collector) => void>;
15
15
  /** @type {Map<import("../spec/channel.js").Scalar[], Data>} TODO: proper type for key */
16
16
  facetBatches: Map<import("../spec/channel.js").Scalar[], import("./flowNode.js").Data>;
17
+ /**
18
+ * @param {function(Collector):void} listener
19
+ * @returns {() => void}
20
+ */
21
+ observe(listener: (arg0: Collector) => void): () => void;
17
22
  /**
18
23
  * @returns {Iterable<Datum>}
19
24
  */
@@ -1 +1 @@
1
- {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../../src/data/collector.js"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH;IAuCI;;OAEG;IACH,qBAFW,OAAO,sBAAsB,EAAE,aAAa,EAiBtD;IAZG,qDAA2C;IAE3C,2CAA2C;IAC3C,WADW,CAAC,CAAS,IAAS,EAAT,SAAS,KAAE,IAAI,CAAC,EAAE,CACpB;IAGnB,yFAAyF;IACzF,cADW,GAAG,CAAC,OAAO,oBAAoB,EAAE,MAAM,EAAE,+BAAO,CACN;IAgHzD;;OAEG;IACH,WAFa,QAAQ,+BAAO,CAqB3B;IAED;;;OAGG;IACH,mBAFW,CAAC,KAAK,+BAAO,KAAK,IAAI,QAUhC;IAED;;OAEG;IACH,uBAMC;IA8CD;;;;OAIG;IACH,8BAFW,MAAM,iCA4BhB;;CACJ;qBA7SyD,eAAe"}
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../../src/data/collector.js"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH;IAuCI;;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;IAmFzD;;;OAGG;IACH,kBAHW,CAAS,IAAS,EAAT,SAAS,KAAE,IAAI,GACtB,MAAM,IAAI,CAOtB;IA+BD;;OAEG;IACH,WAFa,QAAQ,+BAAO,CAqB3B;IAED;;;OAGG;IACH,mBAFW,CAAC,KAAK,+BAAO,KAAK,IAAI,QAUhC;IAED;;OAEG;IACH,uBAMC;IA8CD;;;;OAIG;IACH,8BAFW,MAAM,iCA4BhB;;CACJ;qBAxTyD,eAAe"}
@@ -61,8 +61,8 @@ export default class Collector extends FlowNode {
61
61
 
62
62
  this.params = params ?? { type: "collect" };
63
63
 
64
- /** @type {(function(Collector):void)[]} */
65
- this.observers = [];
64
+ /** @type {Set<function(Collector):void>} */
65
+ this.observers = new Set();
66
66
 
67
67
  // TODO: Consider nested maps instead of InternMap
68
68
  /** @type {Map<import("../spec/channel.js").Scalar[], Data>} TODO: proper type for key */
@@ -149,6 +149,17 @@ export default class Collector extends FlowNode {
149
149
  }
150
150
  }
151
151
 
152
+ /**
153
+ * @param {function(Collector):void} listener
154
+ * @returns {() => void}
155
+ */
156
+ observe(listener) {
157
+ this.observers.add(listener);
158
+ return () => {
159
+ this.observers.delete(listener);
160
+ };
161
+ }
162
+
152
163
  #propagateToChildren() {
153
164
  if (this.children.length) {
154
165
  for (const [facetId, data] of this.facetBatches.entries()) {
@@ -1,65 +1,43 @@
1
1
  /**
2
- * @template H A key (string, object, whatever) that is used to retrieve
3
- * data sources and collectors.
2
+ * DataFlow holds data sources and collectors for optimization and initialization.
4
3
  */
5
- export default class DataFlow<H> {
6
- /** @type {Map<H, import("./sources/dataSource.js").default>} */
7
- _dataSourcesByHost: Map<H, import("./sources/dataSource.js").default>;
8
- /** @type {Map<H, import("./collector.js").default>} */
9
- _collectorsByHost: Map<H, import("./collector.js").default>;
10
- /** @type {Map<H, (function(import("./collector.js").default):void)[]>} */
11
- _observers: Map<H, ((arg0: import("./collector.js").default) => void)[]>;
12
- get dataSources(): import("./sources/dataSource.js").default[];
4
+ export default class DataFlow {
5
+ get dataSources(): DataSource[];
13
6
  get collectors(): import("./collector.js").default[];
14
7
  /**
15
- * Adds a callback function that will be called when a collector has completed.
16
- *
17
- * @param {function(import("./collector.js").default):void} callback
18
- * @param {H} key
19
- */
20
- addObserver(callback: (arg0: import("./collector.js").default) => void, key: H): void;
21
- /**
22
- *
23
- * @param {import("./collector.js").default} collector
24
- * @param {H} key
8
+ * @param {Iterable<import("./sources/dataSource.js").default>} dataSources
25
9
  */
26
- _relayObserverCallback(collector: import("./collector.js").default, key: H): void;
10
+ replaceDataSources(dataSources: Iterable<import("./sources/dataSource.js").default>): void;
27
11
  /**
28
- *
29
12
  * @param {import("./sources/dataSource.js").default} dataSource
30
- * @param {H} key
31
13
  */
32
- addDataSource(dataSource: import("./sources/dataSource.js").default, key: H): void;
14
+ addDataSource(dataSource: import("./sources/dataSource.js").default): void;
33
15
  /**
34
- *
35
- * @param {H} key
16
+ * @param {import("./sources/dataSource.js").default} dataSource
36
17
  */
37
- findDataSourceByKey(key: H): import("./sources/dataSource.js").default;
18
+ removeDataSource(dataSource: import("./sources/dataSource.js").default): void;
38
19
  /**
39
- *
40
- * @param {string} name
20
+ * @param {import("./collector.js").default} collector
41
21
  */
42
- findNamedDataSource(name: string): {
43
- dataSource: NamedSource;
44
- hosts: H[];
45
- };
22
+ addCollector(collector: import("./collector.js").default): void;
46
23
  /**
47
- *
48
24
  * @param {import("./collector.js").default} collector
49
- * @param {H} key
50
25
  */
51
- addCollector(collector: import("./collector.js").default, key: H): void;
26
+ removeCollector(collector: import("./collector.js").default): void;
52
27
  /**
28
+ * Prune a collector branch from the flow graph, removing empty ancestors.
53
29
  *
54
- * @param {H} key
30
+ * @param {import("./collector.js").default} collector
55
31
  */
56
- findCollectorByKey(key: H): import("./collector.js").default;
32
+ pruneCollectorBranch(collector: import("./collector.js").default): void;
57
33
  /**
58
- * Allows the flow nodes to perform final initialization after the flow
59
- * structure has been built and optimized.
60
- * Must be called before any data are to be propagated.
34
+ * @param {string} name
61
35
  */
62
- initialize(): void;
36
+ findNamedDataSource(name: string): {
37
+ dataSource: NamedSource;
38
+ };
39
+ #private;
63
40
  }
41
+ import DataSource from "./sources/dataSource.js";
64
42
  import NamedSource from "./sources/namedSource.js";
65
43
  //# sourceMappingURL=dataFlow.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataFlow.d.ts","sourceRoot":"","sources":["../../../src/data/dataFlow.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,8BAHa,CAAC;IAKN,gEAAgE;IAChE,oBADW,GAAG,CAAC,CAAC,EAAE,OAAO,yBAAyB,EAAE,OAAO,CAAC,CACzB;IAEnC,uDAAuD;IACvD,mBADW,GAAG,CAAC,CAAC,EAAE,OAAO,gBAAgB,EAAE,OAAO,CAAC,CACjB;IAElC,0EAA0E;IAC1E,YADW,GAAG,CAAC,CAAC,EAAE,CAAC,CAAS,IAAgC,EAAhC,OAAO,gBAAgB,EAAE,OAAO,KAAE,IAAI,CAAC,EAAE,CAAC,CAC3C;IAG/B,+DAEC;IAED,qDAEC;IAED;;;;;OAKG;IACH,sBAHW,CAAS,IAAgC,EAAhC,OAAO,gBAAgB,EAAE,OAAO,KAAE,IAAI,OAC/C,CAAC,QAUX;IAED;;;;OAIG;IACH,kCAHW,OAAO,gBAAgB,EAAE,OAAO,OAChC,CAAC,QAUX;IAED;;;;OAIG;IACH,0BAHW,OAAO,yBAAyB,EAAE,OAAO,OACzC,CAAC,QAIX;IAED;;;OAGG;IACH,yBAFW,CAAC,6CAIX;IAED;;;OAGG;IACH,0BAFW,MAAM;;;MAiChB;IAED;;;;OAIG;IACH,wBAHW,OAAO,gBAAgB,EAAE,OAAO,OAChC,CAAC,QAOX;IAED;;;OAGG;IACH,wBAFW,CAAC,oCAIX;IAED;;;;OAIG;IACH,mBAIC;CACJ;wBA7IuB,0BAA0B"}
1
+ {"version":3,"file":"dataFlow.d.ts","sourceRoot":"","sources":["../../../src/data/dataFlow.js"],"names":[],"mappings":"AAGA;;GAEG;AACH;IAeI,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;uBAtHsB,yBAAyB;wBACxB,0BAA0B"}
@@ -1,92 +1,100 @@
1
+ import DataSource from "./sources/dataSource.js";
1
2
  import NamedSource from "./sources/namedSource.js";
2
3
 
3
4
  /**
4
- * @template H A key (string, object, whatever) that is used to retrieve
5
- * data sources and collectors.
5
+ * DataFlow holds data sources and collectors for optimization and initialization.
6
6
  */
7
7
  export default class DataFlow {
8
- constructor() {
9
- /** @type {Map<H, import("./sources/dataSource.js").default>} */
10
- this._dataSourcesByHost = new Map();
8
+ /** @type {Set<import("./sources/dataSource.js").default>} */
9
+ #dataSources;
10
+
11
+ /** @type {Set<import("./collector.js").default>} */
12
+ #collectors;
11
13
 
12
- /** @type {Map<H, import("./collector.js").default>} */
13
- this._collectorsByHost = new Map();
14
+ constructor() {
15
+ /** @type {Set<import("./sources/dataSource.js").default>} */
16
+ this.#dataSources = new Set();
14
17
 
15
- /** @type {Map<H, (function(import("./collector.js").default):void)[]>} */
16
- this._observers = new Map();
18
+ /** @type {Set<import("./collector.js").default>} */
19
+ this.#collectors = new Set();
17
20
  }
18
21
 
19
22
  get dataSources() {
20
- return [...new Set(this._dataSourcesByHost.values()).values()];
23
+ return [...this.#dataSources];
21
24
  }
22
25
 
23
26
  get collectors() {
24
- return [...this._collectorsByHost.values()];
27
+ return [...this.#collectors];
25
28
  }
26
29
 
27
30
  /**
28
- * Adds a callback function that will be called when a collector has completed.
29
- *
30
- * @param {function(import("./collector.js").default):void} callback
31
- * @param {H} key
31
+ * @param {Iterable<import("./sources/dataSource.js").default>} dataSources
32
32
  */
33
- addObserver(callback, key) {
34
- let arr = this._observers.get(key);
35
- if (!arr) {
36
- arr = [];
37
- this._observers.set(key, arr);
38
- }
33
+ replaceDataSources(dataSources) {
34
+ this.#dataSources = new Set(dataSources);
35
+ }
39
36
 
40
- arr.push(callback);
37
+ /**
38
+ * @param {import("./sources/dataSource.js").default} dataSource
39
+ */
40
+ addDataSource(dataSource) {
41
+ this.#dataSources.add(dataSource);
42
+ }
43
+
44
+ /**
45
+ * @param {import("./sources/dataSource.js").default} dataSource
46
+ */
47
+ removeDataSource(dataSource) {
48
+ this.#dataSources.delete(dataSource);
41
49
  }
42
50
 
43
51
  /**
44
- *
45
52
  * @param {import("./collector.js").default} collector
46
- * @param {H} key
47
53
  */
48
- _relayObserverCallback(collector, key) {
49
- const arr = this._observers.get(key);
50
- if (arr) {
51
- for (const callback of arr) {
52
- // eslint-disable-next-line callback-return
53
- callback(collector);
54
- }
55
- }
54
+ addCollector(collector) {
55
+ this.#collectors.add(collector);
56
56
  }
57
57
 
58
58
  /**
59
- *
60
- * @param {import("./sources/dataSource.js").default} dataSource
61
- * @param {H} key
59
+ * @param {import("./collector.js").default} collector
62
60
  */
63
- addDataSource(dataSource, key) {
64
- this._dataSourcesByHost.set(key, dataSource);
61
+ removeCollector(collector) {
62
+ collector.observers.clear();
63
+ this.#collectors.delete(collector);
65
64
  }
66
65
 
67
66
  /**
67
+ * Prune a collector branch from the flow graph, removing empty ancestors.
68
68
  *
69
- * @param {H} key
69
+ * @param {import("./collector.js").default} collector
70
70
  */
71
- findDataSourceByKey(key) {
72
- return this._dataSourcesByHost.get(key);
71
+ pruneCollectorBranch(collector) {
72
+ let parent = collector.parent;
73
+ if (parent) {
74
+ parent.removeChild(collector);
75
+ }
76
+
77
+ while (parent && parent.children.length === 0) {
78
+ const current = parent;
79
+ parent = current.parent;
80
+ if (parent) {
81
+ parent.removeChild(current);
82
+ } else if (current instanceof DataSource) {
83
+ this.removeDataSource(current);
84
+ }
85
+ }
73
86
  }
74
87
 
75
88
  /**
76
- *
77
89
  * @param {string} name
78
90
  */
79
91
  findNamedDataSource(name) {
80
92
  /** @type {NamedSource} */
81
93
  let namedSource;
82
- /** @type {H[]} */
83
- let hosts = [];
84
-
85
- // Note: If a named sources with the same name are present at multiple locations in the
86
- // view hierarchy, the should actually be exactly the same instance. It's arranged that
87
- // way in the data flow optimization phase.
88
94
 
89
- for (const [host, dataSource] of this._dataSourcesByHost.entries()) {
95
+ // Note: If named sources with the same name are present at multiple locations in the
96
+ // view hierarchy, they should actually be exactly the same instance.
97
+ for (const dataSource of this.#dataSources.values()) {
90
98
  if (dataSource instanceof NamedSource) {
91
99
  if (name == dataSource.identifier) {
92
100
  if (namedSource && namedSource !== dataSource) {
@@ -96,7 +104,6 @@ export default class DataFlow {
96
104
  );
97
105
  }
98
106
  namedSource = dataSource;
99
- hosts.push(host);
100
107
  }
101
108
  }
102
109
  }
@@ -104,39 +111,9 @@ export default class DataFlow {
104
111
  if (namedSource) {
105
112
  return {
106
113
  dataSource: namedSource,
107
- hosts,
108
114
  };
109
115
  }
110
116
  }
111
117
 
112
- /**
113
- *
114
- * @param {import("./collector.js").default} collector
115
- * @param {H} key
116
- */
117
- addCollector(collector, key) {
118
- this._collectorsByHost.set(key, collector);
119
- collector.observers.push((collector) =>
120
- this._relayObserverCallback(collector, key)
121
- );
122
- }
123
-
124
- /**
125
- *
126
- * @param {H} key
127
- */
128
- findCollectorByKey(key) {
129
- return this._collectorsByHost.get(key);
130
- }
131
-
132
- /**
133
- * Allows the flow nodes to perform final initialization after the flow
134
- * structure has been built and optimized.
135
- * Must be called before any data are to be propagated.
136
- */
137
- initialize() {
138
- for (const ds of this.dataSources) {
139
- ds.visit((node) => node.initialize());
140
- }
141
- }
118
+ // Initialization is handled by subtree helpers to avoid global init order.
142
119
  }
@@ -1,5 +1,38 @@
1
- import { describe, test } from "vitest";
1
+ import { describe, expect, test } from "vitest";
2
+ import DataFlow from "./dataFlow.js";
3
+ import DataSource from "./sources/dataSource.js";
4
+ import Collector from "./collector.js";
2
5
 
3
6
  describe("DataFlow", () => {
4
- test.todo("TODO");
7
+ test("removes sources and collectors and clears observers", () => {
8
+ const flow = new DataFlow();
9
+
10
+ const sourceA = new DataSource(/** @type {any} */ ({}));
11
+ const sourceB = new DataSource(/** @type {any} */ ({}));
12
+
13
+ flow.addDataSource(sourceA);
14
+ flow.addDataSource(sourceB);
15
+
16
+ const collector = new Collector();
17
+ flow.addCollector(collector);
18
+
19
+ let called = false;
20
+ collector.observe(() => {
21
+ called = true;
22
+ });
23
+
24
+ expect(flow.dataSources).toContain(sourceA);
25
+ expect(flow.collectors).toContain(collector);
26
+ expect(collector.observers.size).toBe(1);
27
+
28
+ flow.removeDataSource(sourceA);
29
+ flow.removeCollector(collector);
30
+
31
+ expect(flow.dataSources).not.toContain(sourceA);
32
+ expect(flow.collectors).not.toContain(collector);
33
+
34
+ expect(collector.observers.size).toBe(0);
35
+ expect(called).toBe(false);
36
+ expect(flow.dataSources).toContain(sourceB);
37
+ });
5
38
  });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @typedef {object} FlowHandle
3
+ * @prop {import("./sources/dataSource.js").default} [dataSource]
4
+ * @prop {import("./collector.js").default} [collector]
5
+ */
6
+ /**
7
+ * @param {FlowHandle} [handle]
8
+ * @returns {FlowHandle}
9
+ */
10
+ export function createFlowHandle(handle?: FlowHandle): FlowHandle;
11
+ export type FlowHandle = {
12
+ dataSource?: import("./sources/dataSource.js").default;
13
+ collector?: import("./collector.js").default;
14
+ };
15
+ //# sourceMappingURL=flowHandle.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @typedef {object} FlowHandle
3
+ * @prop {import("./sources/dataSource.js").default} [dataSource]
4
+ * @prop {import("./collector.js").default} [collector]
5
+ */
6
+
7
+ /**
8
+ * @param {FlowHandle} [handle]
9
+ * @returns {FlowHandle}
10
+ */
11
+ export function createFlowHandle(handle = {}) {
12
+ return handle;
13
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Synchronize flow handles after data flow optimization.
3
+ *
4
+ * @param {import("../view/view.js").default} root
5
+ * @param {Map<import("./sources/dataSource.js").default, import("./sources/dataSource.js").default>} canonicalBySource
6
+ */
7
+ export function syncFlowHandles(root: import("../view/view.js").default, canonicalBySource: Map<import("./sources/dataSource.js").default, import("./sources/dataSource.js").default>): void;
8
+ /**
9
+ * Initializes data flow and mark wiring for a subtree without rebuilding the
10
+ * entire view hierarchy. This is the primary entry point for dynamic view
11
+ * insertion: build the subtree fully, call this, then attach the subtree to
12
+ * the live hierarchy.
13
+ *
14
+ * What it does:
15
+ * - builds/extends the dataflow graph for the subtree
16
+ * - runs flow optimization and syncs flow handles to canonical data sources
17
+ * - discovers the nearest data sources for views in the subtree
18
+ * - initializes dataflow nodes (initialize) for those sources
19
+ * - initializes mark encoders for unit views
20
+ * - queues graphics initialization (if a GL context exists)
21
+ * - wires collector observers so marks update on data arrival
22
+ *
23
+ * How to use it:
24
+ * - call after the subtree is fully constructed (post-order build)
25
+ * - do not attach the subtree to the live hierarchy until after this call
26
+ * - dispose the old subtree before replacing it to prevent observer leaks
27
+ * - follow up with finalizeSubtreeGraphics(...) once graphics promises resolve
28
+ * - reconfigure scales for the subtree when data loads complete
29
+ *
30
+ * Considerations:
31
+ * - this does not trigger data loading; callers decide when to load
32
+ * - data sources are derived by walking to the nearest ancestor source; nested
33
+ * sources should be treated as boundaries (do not walk past them)
34
+ * - only call updateGraphicsData when graphics are initialized or a GL context
35
+ * is available; headless/test contexts must avoid WebGL usage
36
+ * - loadViewSubtreeData emits a subtree-scoped "subtreeDataReady" broadcast
37
+ *
38
+ * TODO:
39
+ * - promote in-flight load caching to a persistent load-state per source
40
+ * - replace global dataLoaded usage with subtree-scoped readiness
41
+ * - integrate with async font readiness for text marks
42
+ * - unify observer wiring via a disposable registry across view types
43
+ *
44
+ * @param {import("../view/view.js").default} subtreeRoot
45
+ * @param {import("./dataFlow.js").default} flow
46
+ * @returns {{
47
+ * dataFlow: import("./dataFlow.js").default,
48
+ * unitViews: UnitView[],
49
+ * dataSources: Set<import("./sources/dataSource.js").default>,
50
+ * graphicsPromises: Promise<import("../marks/mark.js").default>[]
51
+ * }}
52
+ */
53
+ export function initializeViewSubtree(subtreeRoot: import("../view/view.js").default, flow: import("./dataFlow.js").default): {
54
+ dataFlow: import("./dataFlow.js").default;
55
+ unitViews: UnitView[];
56
+ dataSources: Set<import("./sources/dataSource.js").default>;
57
+ graphicsPromises: Promise<import("../marks/mark.js").default>[];
58
+ };
59
+ /**
60
+ * Collects data sources needed to initialize all views in the subtree.
61
+ * This includes sources that are overridden deeper in the hierarchy.
62
+ *
63
+ * @param {import("../view/view.js").default | import("../view/view.js").default[]} subtreeRoot
64
+ * @returns {Set<import("./sources/dataSource.js").default>}
65
+ */
66
+ export function collectViewSubtreeDataSources(subtreeRoot: import("../view/view.js").default | import("../view/view.js").default[]): Set<import("./sources/dataSource.js").default>;
67
+ /**
68
+ * Collects the nearest data sources under a subtree root.
69
+ * These sources define data-ready boundaries for subtree-level loading.
70
+ *
71
+ * @param {import("../view/view.js").default} subtreeRoot
72
+ * @returns {Set<import("./sources/dataSource.js").default>}
73
+ */
74
+ export function collectNearestViewSubtreeDataSources(subtreeRoot: import("../view/view.js").default): Set<import("./sources/dataSource.js").default>;
75
+ /**
76
+ * Loads the nearest data sources for a subtree.
77
+ * Use the returned promise as a subtree-level "data ready" signal.
78
+ *
79
+ * @param {import("../view/view.js").default} subtreeRoot
80
+ * @param {Set<import("./sources/dataSource.js").default>} [dataSources]
81
+ * @returns {Promise<void[]>}
82
+ */
83
+ export function loadViewSubtreeData(subtreeRoot: import("../view/view.js").default, dataSources?: Set<import("./sources/dataSource.js").default>): Promise<void[]>;
84
+ import UnitView from "../view/unitView.js";
85
+ //# sourceMappingURL=flowInit.d.ts.map
@@ -0,0 +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"}