@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.
Files changed (191) hide show
  1. package/dist/bundle/index.es.js +7669 -6115
  2. package/dist/bundle/index.js +114 -133
  3. package/dist/schema.json +534 -132
  4. package/dist/src/data/collector.d.ts +20 -0
  5. package/dist/src/data/collector.d.ts.map +1 -1
  6. package/dist/src/data/collector.js +148 -0
  7. package/dist/src/data/dataFlow.d.ts +6 -0
  8. package/dist/src/data/dataFlow.d.ts.map +1 -1
  9. package/dist/src/data/dataFlow.js +10 -0
  10. package/dist/src/data/flowHandle.d.ts +2 -0
  11. package/dist/src/data/flowHandle.d.ts.map +1 -1
  12. package/dist/src/data/flowHandle.js +1 -0
  13. package/dist/src/data/flowInit.d.ts +12 -4
  14. package/dist/src/data/flowInit.d.ts.map +1 -1
  15. package/dist/src/data/flowInit.js +115 -17
  16. package/dist/src/data/flowNode.d.ts +8 -0
  17. package/dist/src/data/flowNode.d.ts.map +1 -1
  18. package/dist/src/data/flowNode.js +18 -0
  19. package/dist/src/data/keyIndex.d.ts +18 -0
  20. package/dist/src/data/keyIndex.d.ts.map +1 -0
  21. package/dist/src/data/keyIndex.js +241 -0
  22. package/dist/src/data/keyIndex.test.d.ts +2 -0
  23. package/dist/src/data/keyIndex.test.d.ts.map +1 -0
  24. package/dist/src/data/sources/dataSource.d.ts.map +1 -1
  25. package/dist/src/data/sources/dataSource.js +5 -1
  26. package/dist/src/data/sources/dataSourceFactory.d.ts +14 -12
  27. package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -1
  28. package/dist/src/data/sources/dataSourceFactory.js +52 -16
  29. package/dist/src/data/sources/lazy/mockLazySource.d.ts +29 -0
  30. package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -0
  31. package/dist/src/data/sources/lazy/mockLazySource.js +44 -0
  32. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +22 -1
  33. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  34. package/dist/src/data/sources/lazy/singleAxisLazySource.js +34 -2
  35. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  36. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +15 -0
  37. package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
  38. package/dist/src/data/sources/lazy/tabixSource.js +15 -5
  39. package/dist/src/data/transforms/stack.d.ts.map +1 -1
  40. package/dist/src/data/transforms/stack.js +1 -0
  41. package/dist/src/encoder/accessor.d.ts +43 -0
  42. package/dist/src/encoder/accessor.d.ts.map +1 -1
  43. package/dist/src/encoder/accessor.js +164 -0
  44. package/dist/src/encoder/encoder.d.ts +11 -2
  45. package/dist/src/encoder/encoder.d.ts.map +1 -1
  46. package/dist/src/encoder/encoder.js +24 -4
  47. package/dist/src/encoder/metadataChannels.d.ts +15 -0
  48. package/dist/src/encoder/metadataChannels.d.ts.map +1 -0
  49. package/dist/src/encoder/metadataChannels.js +65 -0
  50. package/dist/src/encoder/metadataChannels.test.d.ts +2 -0
  51. package/dist/src/encoder/metadataChannels.test.d.ts.map +1 -0
  52. package/dist/src/genome/scaleLocus.d.ts.map +1 -1
  53. package/dist/src/genome/scaleLocus.js +14 -1
  54. package/dist/src/genomeSpy/containerUi.d.ts +0 -1
  55. package/dist/src/genomeSpy/containerUi.d.ts.map +1 -1
  56. package/dist/src/genomeSpy/containerUi.js +0 -14
  57. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +3 -7
  58. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -1
  59. package/dist/src/genomeSpy/loadingIndicatorManager.js +68 -20
  60. package/dist/src/genomeSpy/loadingStatusRegistry.d.ts +52 -0
  61. package/dist/src/genomeSpy/loadingStatusRegistry.d.ts.map +1 -0
  62. package/dist/src/genomeSpy/loadingStatusRegistry.js +86 -0
  63. package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -1
  64. package/dist/src/genomeSpy/viewContextFactory.js +0 -1
  65. package/dist/src/genomeSpy/viewDataInit.d.ts +10 -0
  66. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
  67. package/dist/src/genomeSpy/viewDataInit.js +166 -2
  68. package/dist/src/genomeSpy/viewDataInit.test.d.ts +2 -0
  69. package/dist/src/genomeSpy/viewDataInit.test.d.ts.map +1 -0
  70. package/dist/src/genomeSpy.d.ts +1 -2
  71. package/dist/src/genomeSpy.d.ts.map +1 -1
  72. package/dist/src/genomeSpy.js +69 -27
  73. package/dist/src/gl/dataToVertices.d.ts.map +1 -1
  74. package/dist/src/gl/dataToVertices.js +16 -4
  75. package/dist/src/marks/mark.d.ts.map +1 -1
  76. package/dist/src/marks/mark.js +18 -11
  77. package/dist/src/marks/markUtils.js +1 -1
  78. package/dist/src/scale/scale.d.ts +6 -1
  79. package/dist/src/scale/scale.d.ts.map +1 -1
  80. package/dist/src/scale/scale.js +83 -23
  81. package/dist/src/scales/axisResolution.d.ts.map +1 -1
  82. package/dist/src/scales/axisResolution.js +10 -0
  83. package/dist/src/scales/{scaleDomainAggregator.d.ts → domainPlanner.d.ts} +8 -5
  84. package/dist/src/scales/domainPlanner.d.ts.map +1 -0
  85. package/dist/src/scales/domainPlanner.js +285 -0
  86. package/dist/src/scales/domainPlanner.test.d.ts +2 -0
  87. package/dist/src/scales/domainPlanner.test.d.ts.map +1 -0
  88. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
  89. package/dist/src/scales/scaleInstanceManager.js +8 -4
  90. package/dist/src/scales/scaleInteractionController.d.ts +6 -0
  91. package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
  92. package/dist/src/scales/scaleInteractionController.js +41 -3
  93. package/dist/src/scales/scaleResolution.d.ts +19 -16
  94. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  95. package/dist/src/scales/scaleResolution.js +255 -70
  96. package/dist/src/scales/scaleResolution.test.d.ts.map +1 -1
  97. package/dist/src/selection/selection.d.ts +21 -0
  98. package/dist/src/selection/selection.d.ts.map +1 -1
  99. package/dist/src/selection/selection.js +82 -0
  100. package/dist/src/spec/channel.d.ts +52 -15
  101. package/dist/src/spec/data.d.ts +4 -0
  102. package/dist/src/spec/parameter.d.ts +16 -11
  103. package/dist/src/spec/testing.d.ts +12 -0
  104. package/dist/src/spec/testing.d.ts.map +1 -0
  105. package/dist/src/spec/testing.js +20 -0
  106. package/dist/src/spec/view.d.ts +45 -10
  107. package/dist/src/styles/genome-spy.css +3 -31
  108. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  109. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  110. package/dist/src/styles/genome-spy.css.js +0 -29
  111. package/dist/src/types/encoder.d.ts +37 -2
  112. package/dist/src/types/rendering.d.ts +4 -3
  113. package/dist/src/types/viewContext.d.ts +0 -14
  114. package/dist/src/utils/domainArray.d.ts.map +1 -1
  115. package/dist/src/utils/domainArray.js +3 -0
  116. package/dist/src/utils/indexer.d.ts +3 -0
  117. package/dist/src/utils/indexer.d.ts.map +1 -1
  118. package/dist/src/utils/indexer.js +3 -0
  119. package/dist/src/utils/throttle.d.ts +4 -1
  120. package/dist/src/utils/throttle.d.ts.map +1 -1
  121. package/dist/src/utils/throttle.js +54 -23
  122. package/dist/src/utils/throttle.test.d.ts +2 -0
  123. package/dist/src/utils/throttle.test.d.ts.map +1 -0
  124. package/dist/src/utils/transition.d.ts +21 -0
  125. package/dist/src/utils/transition.d.ts.map +1 -1
  126. package/dist/src/utils/transition.js +28 -0
  127. package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
  128. package/dist/src/utils/ui/tooltip.js +7 -1
  129. package/dist/src/utils/ui/tooltip.test.d.ts +2 -0
  130. package/dist/src/utils/ui/tooltip.test.d.ts.map +1 -0
  131. package/dist/src/view/axisGridView.d.ts.map +1 -1
  132. package/dist/src/view/axisGridView.js +22 -5
  133. package/dist/src/view/axisView.d.ts.map +1 -1
  134. package/dist/src/view/axisView.js +20 -5
  135. package/dist/src/view/concatView.js +3 -3
  136. package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
  137. package/dist/src/view/containerMutationHelper.js +6 -2
  138. package/dist/src/view/containerView.d.ts +9 -5
  139. package/dist/src/view/containerView.d.ts.map +1 -1
  140. package/dist/src/view/containerView.js +34 -9
  141. package/dist/src/view/dataReadiness.d.ts +46 -0
  142. package/dist/src/view/dataReadiness.d.ts.map +1 -0
  143. package/dist/src/view/dataReadiness.js +267 -0
  144. package/dist/src/view/dataReadiness.test.d.ts +2 -0
  145. package/dist/src/view/dataReadiness.test.d.ts.map +1 -0
  146. package/dist/src/view/facetView.d.ts.map +1 -1
  147. package/dist/src/view/facetView.js +7 -5
  148. package/dist/src/view/flowBuilder.d.ts +5 -3
  149. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  150. package/dist/src/view/flowBuilder.js +74 -7
  151. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  152. package/dist/src/view/gridView/gridChild.js +8 -0
  153. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  154. package/dist/src/view/gridView/gridView.js +119 -2
  155. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
  156. package/dist/src/view/gridView/scrollbar.js +3 -0
  157. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  158. package/dist/src/view/gridView/selectionRect.js +20 -5
  159. package/dist/src/view/gridView/separatorView.d.ts +51 -0
  160. package/dist/src/view/gridView/separatorView.d.ts.map +1 -0
  161. package/dist/src/view/gridView/separatorView.js +275 -0
  162. package/dist/src/view/layerView.js +3 -3
  163. package/dist/src/view/layout/flexLayout.d.ts +0 -30
  164. package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
  165. package/dist/src/view/layout/flexLayout.js +0 -86
  166. package/dist/src/view/paramMediator.d.ts +19 -0
  167. package/dist/src/view/paramMediator.d.ts.map +1 -1
  168. package/dist/src/view/paramMediator.js +86 -19
  169. package/dist/src/view/testUtils.d.ts.map +1 -1
  170. package/dist/src/view/testUtils.js +11 -1
  171. package/dist/src/view/unitView.d.ts +8 -13
  172. package/dist/src/view/unitView.d.ts.map +1 -1
  173. package/dist/src/view/unitView.js +127 -43
  174. package/dist/src/view/view.d.ts +34 -14
  175. package/dist/src/view/view.d.ts.map +1 -1
  176. package/dist/src/view/view.js +119 -9
  177. package/dist/src/view/viewFactory.d.ts.map +1 -1
  178. package/dist/src/view/viewFactory.js +20 -1
  179. package/dist/src/view/viewSelectors.d.ts +148 -0
  180. package/dist/src/view/viewSelectors.d.ts.map +1 -0
  181. package/dist/src/view/viewSelectors.js +773 -0
  182. package/dist/src/view/viewSelectors.test.d.ts +2 -0
  183. package/dist/src/view/viewSelectors.test.d.ts.map +1 -0
  184. package/dist/src/view/viewUtils.d.ts +0 -8
  185. package/dist/src/view/viewUtils.d.ts.map +1 -1
  186. package/dist/src/view/viewUtils.js +1 -21
  187. package/package.json +3 -3
  188. package/dist/src/scales/scaleDomainAggregator.d.ts.map +0 -1
  189. package/dist/src/scales/scaleDomainAggregator.js +0 -162
  190. package/dist/src/scales/scaleDomainAggregator.test.d.ts +0 -2
  191. package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +0 -1
@@ -302,89 +302,3 @@ export function parseSizeDef(size) {
302
302
 
303
303
  throw new Error(`Invalid sizeDef: ${size}`);
304
304
  }
305
-
306
- // TODO: Find a better place for the following utilities: ////////////////////////////////////
307
-
308
- /**
309
- * Interpolates between two LocSizes
310
- *
311
- * @param {LocSize} from
312
- * @param {LocSize} to
313
- * @param {function():number} ratio
314
- * @returns {LocSize}
315
- */
316
- export function interpolateLocSizes(from, to, ratio) {
317
- return {
318
- get location() {
319
- const r = ratio();
320
- switch (r) {
321
- case 0:
322
- return from.location;
323
- case 1:
324
- return to.location;
325
- default:
326
- return r * to.location + (1 - r) * from.location;
327
- }
328
- },
329
-
330
- get size() {
331
- const r = ratio();
332
- switch (r) {
333
- case 0:
334
- return from.size;
335
- case 1:
336
- return to.size;
337
- default:
338
- return r * to.size + (1 - r) * from.size;
339
- }
340
- },
341
- };
342
- }
343
-
344
- /**
345
- * Wraps a LocSize and allows scrolling.
346
- *
347
- * @param {LocSize} locSize
348
- * @param {number | function():number} offset
349
- * @returns {LocSize}
350
- */
351
- export function translateLocSize(locSize, offset) {
352
- const fn = isNumber(offset) ? () => offset : offset;
353
- return {
354
- get location() {
355
- return locSize.location + fn();
356
- },
357
-
358
- get size() {
359
- return locSize.size;
360
- },
361
- };
362
- }
363
-
364
- /**
365
- * Wraps a LocSize and allows scaling.
366
- *
367
- * @param {LocSize} locSize
368
- * @param {number | function():number} factor
369
- * @returns {LocSize}
370
- */
371
- export function scaleLocSize(locSize, factor) {
372
- const fn = isNumber(factor) ? () => factor : factor;
373
- return {
374
- get location() {
375
- return locSize.location * fn();
376
- },
377
-
378
- get size() {
379
- return locSize.size * fn();
380
- },
381
- };
382
- }
383
-
384
- /**
385
- * @param {LocSize} locSize
386
- * @param {number} value
387
- */
388
- export function locSizeEncloses(locSize, value) {
389
- return value >= locSize.location && value < locSize.location + locSize.size;
390
- }
@@ -22,6 +22,15 @@ export function isVariableParameter(param: import("../spec/parameter.js").Parame
22
22
  * @returns {param is import("../spec/parameter.js").SelectionParameter}
23
23
  */
24
24
  export function isSelectionParameter(param: import("../spec/parameter.js").Parameter): param is import("../spec/parameter.js").SelectionParameter;
25
+ /**
26
+ * Computes the default value for a parameter specification.
27
+ *
28
+ * @param {Parameter} param
29
+ * @param {ParamMediator} [paramMediator]
30
+ * @param {ExprRefFunction} [exprFn]
31
+ * @returns {any}
32
+ */
33
+ export function getDefaultParamValue(param: import("../spec/parameter.js").Parameter, paramMediator?: ParamMediator, exprFn?: ExprRefFunction): any;
25
34
  /**
26
35
  * Takes a record of properties that may have ExprRefs as values. Converts the
27
36
  * ExprRefs to getters and setups a listener that is called when any of the
@@ -97,6 +106,16 @@ export default class ParamMediator {
97
106
  * @param {string} paramName
98
107
  */
99
108
  getValue(paramName: string): any;
109
+ /**
110
+ * Subscribe to changes of a parameter's value. The listener is called only
111
+ * when the stored value changes. For expression parameters, the listener is
112
+ * called when upstream changes re-evaluate to a different value.
113
+ *
114
+ * @param {string} paramName
115
+ * @param {() => void} listener
116
+ * @returns {() => void}
117
+ */
118
+ subscribe(paramName: string, listener: () => void): () => void;
100
119
  /**
101
120
  * Get the value of a parameter from this mediator or the ancestors.
102
121
  * @param {string} paramName
@@ -1 +1 @@
1
- {"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"AA8VA;;;GAGG;AACH,6BAHW,GAAG,GACD,CAAC,IAAI,OAAO,sBAAsB,EAAE,OAAO,CAIvD;AAED;;;;;;;GAOG;AACH,+BAHa,CAAC,KADH,CAAC,GAAG,OAAO,sBAAsB,EAAE,OAAO,GAExC,CAAC,CAWb;AAED;;;GAGG;AACH,sFAFa,KAAK,IAAI,OAAO,sBAAsB,EAAE,iBAAiB,CAIrE;AAED;;;GAGG;AACH,uFAFa,KAAK,IAAI,OAAO,sBAAsB,EAAE,kBAAkB,CAItE;AAED;;;;;;;;;;GAUG;AACH,qCAF4E,CAAC,SAA/D,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,sBAAsB,EAAE,OAAO,CAAE,iBAJhE,aAAa,SACb,CAAC,aACD,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,GAuCjB,CAAC,CACtB;AAED;;;;;;GAMG;AACH,4CAHW,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;GAOG;AACH,2CAHW,GAAG,GACD,eAAe,CAY3B;AAldD;;;;;;;;GAQG;AACH;IA2BI;;;;;OAKG;IACH,2BALW,MAAM,aAAa,EAU7B;IA7BD;;;OAGG;IACH,0BAHU,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAGvB;IA2Bf;;;OAGG;IACH,wEAzCqB,GAAG,KAAK,IAAI,CA2GhC;IAED;;;;;;;OAOG;IACH,eAFa,CAAC,aAJH,MAAM,gBACN,CAAC,YACD,OAAO,GACL,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAgC9B;IAED;;;OAGG;IACH,qBAFW,MAAM,WA1Ic,GAAG,KAAK,IAAI,CAkJ1C;IAED;;;OAGG;IACH,oBAFW,MAAM,OAIhB;IAED;;;OAGG;IACH,qBAFW,MAAM,OAKhB;IAED;;OAEG;IACH,oBACsB,WAAW,CAAC,MAAM,2CAAY,CAGnD;IAED;;;;OAIG;IACH,gCAHW,MAAM,GACJ,aAAa,CAQzB;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBAuFhB;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAKhB;IAED;;;;;OAKG;IACH,sBAFa,OAAO,CAiBnB;;CACJ;;;;;;;;8BA1UY,OAAO,wBAAwB,EAAE,kBAAkB,GAAG;IAAE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,MAAM,CAAA;CAAC"}
1
+ {"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"AAiXA;;;GAGG;AACH,6BAHW,GAAG,GACD,CAAC,IAAI,OAAO,sBAAsB,EAAE,OAAO,CAIvD;AAED;;;;;;;GAOG;AACH,+BAHa,CAAC,KADH,CAAC,GAAG,OAAO,sBAAsB,EAAE,OAAO,GAExC,CAAC,CAWb;AAED;;;GAGG;AACH,sFAFa,KAAK,IAAI,OAAO,sBAAsB,EAAE,iBAAiB,CAIrE;AAED;;;GAGG;AACH,uFAFa,KAAK,IAAI,OAAO,sBAAsB,EAAE,kBAAkB,CAItE;AAED;;;;;;;GAOG;AACH,sGAJW,aAAa,WACb,eAAe,GACb,GAAG,CAwCf;AAED;;;;;;;;;;GAUG;AACH,qCAF4E,CAAC,SAA/D,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,sBAAsB,EAAE,OAAO,CAAE,iBAJhE,aAAa,SACb,CAAC,aACD,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,GAuCjB,CAAC,CACtB;AAED;;;;;;GAMG;AACH,4CAHW,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;GAOG;AACH,2CAHW,GAAG,GACD,eAAe,CAY3B;AArhBD;;;;;;;;GAQG;AACH;IA2BI;;;;;OAKG;IACH,2BALW,MAAM,aAAa,EAU7B;IA7BD;;;OAGG;IACH,0BAHU,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAGvB;IA2Bf;;;OAGG;IACH,wEAzCqB,GAAG,KAAK,IAAI,CAkGhC;IAED;;;;;;;OAOG;IACH,eAFa,CAAC,aAJH,MAAM,gBACN,CAAC,YACD,OAAO,GACL,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAgC9B;IAED;;;OAGG;IACH,qBAFW,MAAM,WAjIc,GAAG,KAAK,IAAI,CAyI1C;IAED;;;OAGG;IACH,oBAFW,MAAM,OAIhB;IAED;;;;;;;;OAQG;IACH,qBAJW,MAAM,YACN,MAAM,IAAI,GACR,MAAM,IAAI,CAmBtB;IAED;;;OAGG;IACH,qBAFW,MAAM,OAKhB;IAED;;OAEG;IACH,oBACsB,WAAW,CAAC,MAAM,2CAAY,CAGnD;IAED;;;;OAIG;IACH,gCAHW,MAAM,GACJ,aAAa,CAQzB;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBAuFhB;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAKhB;IAED;;;;;OAKG;IACH,sBAFa,OAAO,CAiBnB;;CACJ;;;;;;;;8BA7VY,OAAO,wBAAwB,EAAE,kBAAkB,GAAG;IAAE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,MAAM,CAAA;CAAC"}
@@ -73,6 +73,7 @@ export default class ParamMediator {
73
73
 
74
74
  /** @type {ParameterSetter} */
75
75
  let setter;
76
+ let defaultValue;
76
77
 
77
78
  if (param.push == "outer") {
78
79
  const outerMediator = this.findMediatorForParam(name);
@@ -93,36 +94,26 @@ export default class ParamMediator {
93
94
  // support mutation (i.e. adding/removing children) in future.
94
95
  this.#allocatedSetters.set(name, setter);
95
96
  } else if ("value" in param) {
96
- setter = this.allocateSetter(name, param.value);
97
+ defaultValue = getDefaultParamValue(param, this);
98
+ setter = this.allocateSetter(name, defaultValue);
97
99
  } else if ("expr" in param) {
98
100
  const expr = this.createExpression(param.expr);
99
101
  // TODO: getSetter(param) should return a setter that throws if
100
102
  // modifying the value is attempted.
101
- const realSetter = this.allocateSetter(name, expr(null));
103
+ defaultValue = getDefaultParamValue(param, this, expr);
104
+ const realSetter = this.allocateSetter(name, defaultValue);
102
105
  expr.addListener(() => realSetter(expr(null)));
103
106
  // NOP
104
107
  setter = (_) => undefined;
105
108
  } else {
106
- setter = this.allocateSetter(name, null);
109
+ defaultValue = getDefaultParamValue(param, this);
110
+ setter = this.allocateSetter(name, defaultValue);
107
111
  }
108
112
 
109
113
  if ("select" in param) {
110
- const select = asSelectionConfig(param.select);
111
- if (isPointSelectionConfig(select)) {
112
- // Set initial value so that production rules in shaders can be generated, etc.
113
- setter(
114
- select.toggle
115
- ? createMultiPointSelection()
116
- : createSinglePointSelection(null)
117
- );
118
- } else if (isIntervalSelectionConfig(select)) {
119
- if (!select.encodings) {
120
- throw new Error(
121
- `Interval selection "${name}" must have encodings defined!`
122
- );
123
- }
124
- setter(createIntervalSelection(select.encodings));
125
- }
114
+ defaultValue ??= getDefaultParamValue(param, this);
115
+ // Set initial value so that production rules in shaders can be generated, etc.
116
+ setter(defaultValue);
126
117
  }
127
118
 
128
119
  this.#paramConfigs.set(name, param);
@@ -189,6 +180,34 @@ export default class ParamMediator {
189
180
  return this.#paramValues.get(paramName);
190
181
  }
191
182
 
183
+ /**
184
+ * Subscribe to changes of a parameter's value. The listener is called only
185
+ * when the stored value changes. For expression parameters, the listener is
186
+ * called when upstream changes re-evaluate to a different value.
187
+ *
188
+ * @param {string} paramName
189
+ * @param {() => void} listener
190
+ * @returns {() => void}
191
+ */
192
+ subscribe(paramName, listener) {
193
+ validateParameterName(paramName);
194
+ const mediator = this.findMediatorForParam(paramName);
195
+ if (!mediator) {
196
+ throw new Error("Parameter not found: " + paramName);
197
+ }
198
+
199
+ const listeners = mediator.paramListeners.get(paramName) ?? new Set();
200
+ mediator.paramListeners.set(paramName, listeners);
201
+ listeners.add(listener);
202
+
203
+ return () => {
204
+ listeners.delete(listener);
205
+ if (!listeners.size) {
206
+ mediator.paramListeners.delete(paramName);
207
+ }
208
+ };
209
+ }
210
+
192
211
  /**
193
212
  * Get the value of a parameter from this mediator or the ancestors.
194
213
  * @param {string} paramName
@@ -391,6 +410,54 @@ export function isSelectionParameter(param) {
391
410
  return !("expr" in param || "bind" in param) && "select" in param;
392
411
  }
393
412
 
413
+ /**
414
+ * Computes the default value for a parameter specification.
415
+ *
416
+ * @param {Parameter} param
417
+ * @param {ParamMediator} [paramMediator]
418
+ * @param {ExprRefFunction} [exprFn]
419
+ * @returns {any}
420
+ */
421
+ export function getDefaultParamValue(param, paramMediator, exprFn) {
422
+ if ("select" in param) {
423
+ const select = asSelectionConfig(param.select);
424
+ if (isPointSelectionConfig(select)) {
425
+ return select.toggle
426
+ ? createMultiPointSelection()
427
+ : createSinglePointSelection(null);
428
+ }
429
+ if (isIntervalSelectionConfig(select)) {
430
+ if (!select.encodings) {
431
+ throw new Error(
432
+ `Interval selection "${param.name}" must have encodings defined!`
433
+ );
434
+ }
435
+ return createIntervalSelection(select.encodings);
436
+ }
437
+ throw new Error(
438
+ `Unknown selection config for parameter "${param.name}".`
439
+ );
440
+ }
441
+
442
+ if ("expr" in param) {
443
+ const expr =
444
+ exprFn ??
445
+ paramMediator?.createExpression(/** @type {string} */ (param.expr));
446
+ if (!expr) {
447
+ throw new Error(
448
+ `Cannot evaluate expression for parameter "${param.name}".`
449
+ );
450
+ }
451
+ return expr(null);
452
+ }
453
+
454
+ if ("value" in param) {
455
+ return param.value;
456
+ }
457
+
458
+ return null;
459
+ }
460
+
394
461
  /**
395
462
  * Takes a record of properties that may have ExprRefs as values. Converts the
396
463
  * ExprRefs to getters and setups a listener that is called when any of the
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../../src/view/testUtils.js"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,2DAHW,OAAO,kBAAkB,EAAE,kBAAkB,6CA0DvD;AAGS,uBAAC,CAAC,SAAS,OAAO,WAAW,EAAE,OAAO,QAAQ,QAAQ,aAAa;IAAE,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,uBAAuB,OAAO,kBAAkB,EAAE,kBAAkB,GAAK,OAAO,CAAC,CAAC,CAAC,CAAA;AAgBhL,oCAAC,CAAC,SAAS,OAAO,WAAW,EAAE,OAAO,QAAQ,QAAQ,aAAa;IAAE,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,YAAY,WAAW,YAAY;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAC,GAAK,OAAO,CAAC,CAAC,CAAC,CAAA;;;;;uBA9FpL,OAAO,iBAAiB,EAAE,QAAQ;;;;;0BAClC,OAAO,yBAAyB,EAAE,OAAO"}
1
+ {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../../src/view/testUtils.js"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,2DAHW,OAAO,kBAAkB,EAAE,kBAAkB,6CAoEvD;AAGS,uBAAC,CAAC,SAAS,OAAO,WAAW,EAAE,OAAO,QAAQ,QAAQ,aAAa;IAAE,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,uBAAuB,OAAO,kBAAkB,EAAE,kBAAkB,GAAK,OAAO,CAAC,CAAC,CAAC,CAAA;AAgBhL,oCAAC,CAAC,SAAS,OAAO,WAAW,EAAE,OAAO,QAAQ,QAAQ,aAAa;IAAE,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,YAAY,WAAW,YAAY;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAC,GAAK,OAAO,CAAC,CAAC,CAAC,CAAA;;;;;uBAxGpL,OAAO,iBAAiB,EAAE,QAAQ;;;;;0BAClC,OAAO,yBAAyB,EAAE,OAAO"}
@@ -38,6 +38,8 @@ export function createTestViewContext(viewFactoryOptions = {}) {
38
38
  ],
39
39
  });
40
40
 
41
+ const dataFlow = new DataFlow();
42
+
41
43
  // @ts-expect-error
42
44
  const c = /** @type {ViewContext} */ ({
43
45
  createOrImportView: async function (
@@ -55,7 +57,7 @@ export function createTestViewContext(viewFactoryOptions = {}) {
55
57
  );
56
58
  },
57
59
 
58
- dataFlow: new DataFlow(),
60
+ dataFlow,
59
61
  genomeStore,
60
62
 
61
63
  fontManager: new BmFontManager(),
@@ -66,6 +68,11 @@ export function createTestViewContext(viewFactoryOptions = {}) {
66
68
  /** @type {(callback: () => void) => void} */ (
67
69
  (callback) => callback()
68
70
  ),
71
+ transition: (/** @type {any} */ options) => {
72
+ const to = typeof options.to === "number" ? options.to : 1;
73
+ options.onUpdate(to);
74
+ return Promise.resolve();
75
+ },
69
76
  })
70
77
  ),
71
78
 
@@ -73,6 +80,9 @@ export function createTestViewContext(viewFactoryOptions = {}) {
73
80
 
74
81
  isViewConfiguredVisible: () => true,
75
82
 
83
+ addBroadcastListener: () => undefined,
84
+ removeBroadcastListener: () => undefined,
85
+
76
86
  //...partialContext,
77
87
  });
78
88
 
@@ -33,25 +33,20 @@ export default class UnitView extends View {
33
33
  * @param {Channel} channel
34
34
  */
35
35
  getDataAccessor(channel: import("../spec/channel.js").Channel): import("../types/encoder.js").Accessor<import("../spec/channel.js").Scalar>;
36
+ /**
37
+ * Returns data accessors configured for the `search` channel.
38
+ *
39
+ * @returns {import("vega-util").AccessorFn[]}
40
+ */
41
+ getSearchAccessors(): import("vega-util").AccessorFn[];
36
42
  /**
37
43
  * Returns a collector that is associated with this view.
38
44
  */
39
45
  getCollector(): import("../data/collector.js").default;
40
46
  /**
41
- * Extracts the domain from the data.
42
- *
43
- * TODO: Optimize! Now this performs redundant work if multiple views share the same collector.
44
- * Also, all relevant fields should be processed in one iteration: https://jsbench.me/y5kkqy52jo/1
45
- * In fact, domain extraction could be a responsibility of the collector: As it handles data items,
46
- * it extracts domains for all fields (and data types) that need extracted domains.
47
- * Alternatively, extractor nodes could be added to the data flow, just like Vega does
48
- * (with aggregate and extent).
49
- *
50
- * @param {Channel} channel
51
- * @param {import("../spec/channel.js").Type} type
52
- * @returns {DomainArray}
47
+ * Registers collector subscriptions that keep scale domains up to date.
53
48
  */
54
- extractDataDomain(channel: import("../spec/channel.js").Channel, type: import("../spec/channel.js").Type): import("../utils/domainArray.js").DomainArray;
49
+ registerDomainSubscriptions(): void;
55
50
  getZoomLevel(): number;
56
51
  /**
57
52
  * @param {string} channel
@@ -1 +1 @@
1
- {"version":3,"file":"unitView.d.ts","sourceRoot":"","sources":["../../../src/view/unitView.js"],"names":[],"mappings":"AA6BA;;;;GAIG;AACH,wBAHU,MAAM,CAAC,OAAO,iBAAiB,EAAE,QAAQ,EAAE,cAAc,kBAAkB,EAAE,OAAO,CAAC,CAc7F;AAEF;IAeI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,QAAQ,WAClC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAyCzC;IApCG,yCAAgB;IAIZ,iDAAiD;IACjD,MADW,OAAO,kBAAkB,EAAE,OAAO,CACnB;IAoKlC,2DAIC;IAgBD;;;;;OAKG;IAEH,iEA0IC;IAUD;;;;;OAKG;IACH,4IAMC;IAkBD;;OAEG;IACH,uDAEC;IAED;;;;;;;;;;;;;OAaG;IACH,uEAHW,OAAO,oBAAoB,EAAE,IAAI,iDAqB3C;IAED,uBAQC;IAgBD;;;;OAIG;IACH,8BAJW,MAAM,+DAEJ,OAAO,iBAAiB,EAAE,kBAAkB,CAKxD;;CACJ;iBAxfgB,WAAW"}
1
+ {"version":3,"file":"unitView.d.ts","sourceRoot":"","sources":["../../../src/view/unitView.js"],"names":[],"mappings":"AA+BA;;;;GAIG;AACH,wBAHU,MAAM,CAAC,OAAO,iBAAiB,EAAE,QAAQ,EAAE,cAAc,kBAAkB,EAAE,OAAO,CAAC,CAc7F;AAEF;IAwBI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,QAAQ,WAClC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAyCzC;IApCG,yCAAgB;IAIZ,iDAAiD;IACjD,MADW,OAAO,kBAAkB,EAAE,OAAO,CACnB;IAoKlC,2DAIC;IAoBD;;;;;OAKG;IAEH,iEAoJC;IAUD;;;;;OAKG;IACH,4IAMC;IAED;;;;OAIG;IACH,sBAFa,OAAO,WAAW,EAAE,UAAU,EAAE,CAS5C;IAkBD;;OAEG;IACH,uDAEC;IAED;;OAEG;IACH,oCA0EC;IAED,uBAQC;IAgBD;;;;OAIG;IACH,8BAJW,MAAM,+DAEJ,OAAO,iBAAiB,EAAE,kBAAkB,CAKxD;;CACJ;iBA5kBgB,WAAW"}
@@ -14,7 +14,7 @@ import {
14
14
  isPrimaryPositionalChannel,
15
15
  isValueDefWithCondition,
16
16
  } from "../encoder/encoder.js";
17
- import createDomain from "../utils/domainArray.js";
17
+ import { isScaleAccessor } from "../encoder/accessor.js";
18
18
  import AxisResolution from "../scales/axisResolution.js";
19
19
  import View from "./view.js";
20
20
  import {
@@ -24,8 +24,10 @@ import {
24
24
  isPointSelectionConfig,
25
25
  updateMultiPointSelection,
26
26
  } from "../selection/selection.js";
27
+ import { getEncodingSearchFields } from "../encoder/metadataChannels.js";
27
28
  import { UNIQUE_ID_KEY } from "../data/transforms/identifier.js";
28
29
  import { createEventFilterFunction } from "../utils/expression.js";
30
+ import { field } from "../utils/field.js";
29
31
 
30
32
  /**
31
33
  *
@@ -48,7 +50,6 @@ export const markTypes = {
48
50
  export default class UnitView extends View {
49
51
  /**
50
52
  * @typedef {import("../spec/channel.js").Channel} Channel
51
- * @typedef {import("../utils/domainArray.js").DomainArray} DomainArray
52
53
  * @typedef {import("../spec/view.js").ResolutionTarget} ResolutionTarget
53
54
  * @typedef {((datum: import("../data/flowNode.js").Datum) => import("../spec/channel.js").Scalar) & { fieldDef: import("../spec/channel.js").FieldDef}} FieldAccessor
54
55
  *
@@ -60,6 +61,16 @@ export default class UnitView extends View {
60
61
  */
61
62
  #zoomLevelSetter;
62
63
 
64
+ /**
65
+ * @type {boolean}
66
+ */
67
+ #domainSubscriptionsRegistered = false;
68
+
69
+ /**
70
+ * @type {import("vega-util").AccessorFn[] | null}
71
+ */
72
+ #searchAccessors = null;
73
+
63
74
  /**
64
75
  *
65
76
  * @param {import("../spec/view.js").UnitSpec} spec
@@ -253,6 +264,10 @@ export default class UnitView extends View {
253
264
  const encoding = super.getEncoding();
254
265
  const supportedChannels = this.mark.getSupportedChannels();
255
266
  for (const channel of Object.keys(encoding)) {
267
+ if (channel === "key") {
268
+ continue;
269
+ }
270
+
256
271
  if (!supportedChannels.includes(channel)) {
257
272
  delete encoding[channel];
258
273
  }
@@ -284,6 +299,10 @@ export default class UnitView extends View {
284
299
  continue;
285
300
  }
286
301
 
302
+ if (Array.isArray(channelDef)) {
303
+ continue;
304
+ }
305
+
287
306
  /** @type {import("../spec/channel.js").ChannelDefWithScale} */
288
307
  let channelDefWithScale;
289
308
 
@@ -368,32 +387,38 @@ export default class UnitView extends View {
368
387
  const resolution = new ScaleResolution(targetChannel);
369
388
  view.resolutions[type][targetChannel] = resolution;
370
389
 
371
- resolution.addEventListener("range", (event) => {
372
- // Create if WebGLHelper is available, i.e., if not running in headless mode
390
+ const updateRangeTexture = (
391
+ /** @type {import("../types/scaleResolutionApi.js").ScaleResolutionEvent} */ event
392
+ ) => {
393
+ // Create if WebGLHelper is available, i.e., if not running in headless mode.
394
+ // Domain changes can alter discrete texture sizes as well.
373
395
  this.context.glHelper?.createRangeTexture(
374
396
  event.scaleResolution,
375
397
  true
376
398
  );
399
+ };
400
+ resolution.addEventListener("range", updateRangeTexture);
401
+ resolution.addEventListener("domain", updateRangeTexture);
402
+ this.registerDisposer(() => {
403
+ resolution.removeEventListener(
404
+ "range",
405
+ updateRangeTexture
406
+ );
407
+ resolution.removeEventListener(
408
+ "domain",
409
+ updateRangeTexture
410
+ );
377
411
  });
378
412
  }
379
413
 
380
- const dataDomainSource =
381
- this.getLayoutAncestors()
382
- // TODO: Should check until the resolved scale resolution
383
- .some(
384
- (view) => !view.options.contributesToScaleDomain
385
- ) ||
386
- (isChannelDefWithScale(channelDefWithScale) &&
387
- channelDefWithScale.contributesToScaleDomain === false)
388
- ? undefined
389
- : this.extractDataDomain.bind(this);
414
+ const contributesToDomain = !this.isDomainInert();
390
415
 
391
416
  const resolution = view.resolutions[type][targetChannel];
392
417
  const unregister = resolution.registerMember({
393
418
  view: this,
394
419
  channel,
395
420
  channelDef: channelDefWithScale,
396
- dataDomainSource,
421
+ contributesToDomain,
397
422
  });
398
423
  this.registerDisposer(() => {
399
424
  // Unregister returns true when it removed the last member.
@@ -430,6 +455,20 @@ export default class UnitView extends View {
430
455
  return encoders[channel]?.dataAccessor;
431
456
  }
432
457
 
458
+ /**
459
+ * Returns data accessors configured for the `search` channel.
460
+ *
461
+ * @returns {import("vega-util").AccessorFn[]}
462
+ */
463
+ getSearchAccessors() {
464
+ if (!this.#searchAccessors) {
465
+ const fields = getEncodingSearchFields(this.getEncoding()) ?? [];
466
+ this.#searchAccessors = fields.map((fieldName) => field(fieldName));
467
+ }
468
+
469
+ return this.#searchAccessors;
470
+ }
471
+
433
472
  /**
434
473
  * Returns an accessor that returns a (composite) key for partitioning the data
435
474
  *
@@ -454,37 +493,82 @@ export default class UnitView extends View {
454
493
  }
455
494
 
456
495
  /**
457
- * Extracts the domain from the data.
458
- *
459
- * TODO: Optimize! Now this performs redundant work if multiple views share the same collector.
460
- * Also, all relevant fields should be processed in one iteration: https://jsbench.me/y5kkqy52jo/1
461
- * In fact, domain extraction could be a responsibility of the collector: As it handles data items,
462
- * it extracts domains for all fields (and data types) that need extracted domains.
463
- * Alternatively, extractor nodes could be added to the data flow, just like Vega does
464
- * (with aggregate and extent).
465
- *
466
- * @param {Channel} channel
467
- * @param {import("../spec/channel.js").Type} type
468
- * @returns {DomainArray}
496
+ * Registers collector subscriptions that keep scale domains up to date.
469
497
  */
470
- extractDataDomain(channel, type) {
471
- /** @type {DomainArray} */
472
- let domain = createDomain(type);
473
-
474
- (this.mark.encoders[channel]?.accessors ?? [])
475
- .filter((a) => a.scaleChannel)
476
- .forEach((accessor) => {
477
- if (accessor.constant) {
478
- domain.extend(accessor({}));
479
- } else {
480
- const collector = this.getCollector();
481
- if (collector?.completed) {
482
- collector.visitData((d) => domain.extend(accessor(d)));
483
- }
498
+ registerDomainSubscriptions() {
499
+ if (this.#domainSubscriptionsRegistered) {
500
+ return;
501
+ }
502
+
503
+ if (this.isDomainInert()) {
504
+ return;
505
+ }
506
+
507
+ const collector = this.getCollector();
508
+ if (!collector) {
509
+ return;
510
+ }
511
+
512
+ const encoders = this.mark.encoders;
513
+ if (!encoders) {
514
+ throw new Error("Encoders are not initialized!");
515
+ }
516
+
517
+ this.#domainSubscriptionsRegistered = true;
518
+
519
+ /** @type {Map<import("../scales/scaleResolution.js").default, Set<import("../types/encoder.js").ScaleAccessor>>} */
520
+ const accessorsByResolution = new Map();
521
+
522
+ for (const encoder of Object.values(encoders)) {
523
+ if (!encoder) {
524
+ continue;
525
+ }
526
+
527
+ const accessors = encoder.accessors ?? [];
528
+ if (accessors.length === 0) {
529
+ continue;
530
+ }
531
+
532
+ for (const accessor of accessors) {
533
+ if (!isScaleAccessor(accessor)) {
534
+ continue;
535
+ }
536
+ if (accessor.channelDef.domainInert) {
537
+ continue;
538
+ }
539
+ const resolution = this.getScaleResolution(
540
+ accessor.scaleChannel
541
+ );
542
+ if (!resolution) {
543
+ throw new Error(
544
+ "Missing scale resolution for channel: " +
545
+ accessor.scaleChannel
546
+ );
547
+ }
548
+
549
+ let accessorsForResolution =
550
+ accessorsByResolution.get(resolution);
551
+ if (!accessorsForResolution) {
552
+ accessorsForResolution = new Set();
553
+ accessorsByResolution.set(
554
+ resolution,
555
+ accessorsForResolution
556
+ );
484
557
  }
485
- });
558
+ accessorsForResolution.add(accessor);
559
+ }
560
+ }
486
561
 
487
- return domain;
562
+ for (const [resolution, accessors] of accessorsByResolution) {
563
+ if (accessors.size === 0) {
564
+ continue;
565
+ }
566
+ const unregister = resolution.registerCollectorSubscriptions(
567
+ collector,
568
+ accessors
569
+ );
570
+ this.registerDisposer(unregister);
571
+ }
488
572
  }
489
573
 
490
574
  getZoomLevel() {