@genome-spy/core 0.64.0 → 0.66.1

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 (285) hide show
  1. package/dist/bundle/{index-CCJIjehY.js → AbortablePromiseCache-CcuMrnn7.js} +22 -91
  2. package/dist/bundle/browser-BRemItdO.js +138 -0
  3. package/dist/bundle/index-BatuyGAI.js +271 -0
  4. package/dist/bundle/index-ByuE8dvu.js +332 -0
  5. package/dist/bundle/index-Cq3QFUxX.js +1781 -0
  6. package/dist/bundle/{index-C08YCM2T.js → index-D-w7Mmt9.js} +246 -126
  7. package/dist/bundle/index-D28m8tSW.js +1607 -0
  8. package/dist/bundle/index-D74H8TTz.js +508 -0
  9. package/dist/bundle/index-DbJ0oeYM.js +631 -0
  10. package/dist/bundle/index.es.js +15034 -13842
  11. package/dist/bundle/index.js +223 -237
  12. package/dist/bundle/inflate-GtwLkvSP.js +1048 -0
  13. package/dist/bundle/unzip-NywezaRR.js +1492 -0
  14. package/dist/schema.json +22 -4
  15. package/dist/src/config/scaleDefaults.d.ts +8 -0
  16. package/dist/src/config/scaleDefaults.d.ts.map +1 -0
  17. package/dist/src/config/scaleDefaults.js +45 -0
  18. package/dist/src/data/collector.d.ts +7 -2
  19. package/dist/src/data/collector.d.ts.map +1 -1
  20. package/dist/src/data/collector.js +13 -2
  21. package/dist/src/data/dataFlow.d.ts +20 -42
  22. package/dist/src/data/dataFlow.d.ts.map +1 -1
  23. package/dist/src/data/dataFlow.js +57 -80
  24. package/dist/src/data/flowHandle.d.ts +15 -0
  25. package/dist/src/data/flowHandle.d.ts.map +1 -0
  26. package/dist/src/data/flowHandle.js +13 -0
  27. package/dist/src/data/flowInit.d.ts +85 -0
  28. package/dist/src/data/flowInit.d.ts.map +1 -0
  29. package/dist/src/data/flowInit.js +238 -0
  30. package/dist/src/data/flowInit.test.d.ts +2 -0
  31. package/dist/src/data/flowInit.test.d.ts.map +1 -0
  32. package/dist/src/data/flowOptimizer.d.ts +6 -4
  33. package/dist/src/data/flowOptimizer.d.ts.map +1 -1
  34. package/dist/src/data/flowOptimizer.js +29 -14
  35. package/dist/src/data/sources/lazy/axisTickSource.js +1 -1
  36. package/dist/src/data/sources/lazy/bamSource.js +1 -1
  37. package/dist/src/data/sources/lazy/bigBedSource.js +1 -1
  38. package/dist/src/data/sources/lazy/bigWigSource.js +1 -1
  39. package/dist/src/data/sources/lazy/gff3Source.d.ts +2 -6
  40. package/dist/src/data/sources/lazy/gff3Source.d.ts.map +1 -1
  41. package/dist/src/data/sources/lazy/gff3Source.js +4 -8
  42. package/dist/src/data/sources/lazy/indexedFastaSource.d.ts.map +1 -1
  43. package/dist/src/data/sources/lazy/indexedFastaSource.js +17 -17
  44. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +1 -1
  45. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  46. package/dist/src/data/sources/lazy/singleAxisLazySource.js +10 -3
  47. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  48. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +5 -1
  49. package/dist/src/data/sources/lazy/tabixSource.js +1 -1
  50. package/dist/src/data/transforms/filterScoredLabels.d.ts +1 -1
  51. package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
  52. package/dist/src/data/transforms/filterScoredLabels.js +1 -1
  53. package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts.map +1 -1
  54. package/dist/src/data/transforms/linearizeGenomicCoordinate.js +2 -1
  55. package/dist/src/encoder/encoder.d.ts +1 -1
  56. package/dist/src/encoder/encoder.d.ts.map +1 -1
  57. package/dist/src/encoder/encoder.js +1 -1
  58. package/dist/src/genome/scaleLocus.d.ts +39 -0
  59. package/dist/src/genome/scaleLocus.d.ts.map +1 -1
  60. package/dist/src/genome/scaleLocus.js +76 -0
  61. package/dist/src/genomeSpy/canvasExport.d.ts +19 -0
  62. package/dist/src/genomeSpy/canvasExport.d.ts.map +1 -0
  63. package/dist/src/genomeSpy/canvasExport.js +66 -0
  64. package/dist/src/genomeSpy/containerUi.d.ts +17 -0
  65. package/dist/src/genomeSpy/containerUi.d.ts.map +1 -0
  66. package/dist/src/genomeSpy/containerUi.js +78 -0
  67. package/dist/src/genomeSpy/eventListenerRegistry.d.ts +19 -0
  68. package/dist/src/genomeSpy/eventListenerRegistry.d.ts.map +1 -0
  69. package/dist/src/genomeSpy/eventListenerRegistry.js +38 -0
  70. package/dist/src/genomeSpy/inputBindingManager.d.ts +14 -0
  71. package/dist/src/genomeSpy/inputBindingManager.d.ts.map +1 -0
  72. package/dist/src/genomeSpy/inputBindingManager.js +63 -0
  73. package/dist/src/genomeSpy/interactionController.d.ts +40 -0
  74. package/dist/src/genomeSpy/interactionController.d.ts.map +1 -0
  75. package/dist/src/genomeSpy/interactionController.js +371 -0
  76. package/dist/src/genomeSpy/keyboardListenerManager.d.ts +10 -0
  77. package/dist/src/genomeSpy/keyboardListenerManager.d.ts.map +1 -0
  78. package/dist/src/genomeSpy/keyboardListenerManager.js +31 -0
  79. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +15 -0
  80. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -0
  81. package/dist/src/genomeSpy/loadingIndicatorManager.js +92 -0
  82. package/dist/src/genomeSpy/renderCoordinator.d.ts +22 -0
  83. package/dist/src/genomeSpy/renderCoordinator.d.ts.map +1 -0
  84. package/dist/src/genomeSpy/renderCoordinator.js +118 -0
  85. package/dist/src/genomeSpy/viewContextFactory.d.ts +18 -0
  86. package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -0
  87. package/dist/src/genomeSpy/viewContextFactory.js +79 -0
  88. package/dist/src/genomeSpy/viewDataInit.d.ts +12 -0
  89. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -0
  90. package/dist/src/genomeSpy/viewDataInit.js +41 -0
  91. package/dist/src/genomeSpy/viewHierarchyConfig.d.ts +14 -0
  92. package/dist/src/genomeSpy/viewHierarchyConfig.d.ts.map +1 -0
  93. package/dist/src/genomeSpy/viewHierarchyConfig.js +24 -0
  94. package/dist/src/genomeSpy/viewHighlight.d.ts +5 -0
  95. package/dist/src/genomeSpy/viewHighlight.d.ts.map +1 -0
  96. package/dist/src/genomeSpy/viewHighlight.js +30 -0
  97. package/dist/src/genomeSpy.d.ts +17 -72
  98. package/dist/src/genomeSpy.d.ts.map +1 -1
  99. package/dist/src/genomeSpy.js +180 -789
  100. package/dist/src/gl/glslScaleGenerator.d.ts +1 -1
  101. package/dist/src/gl/webGLHelper.d.ts +2 -2
  102. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  103. package/dist/src/gl/webGLHelper.js +4 -4
  104. package/dist/src/index.d.ts.map +1 -1
  105. package/dist/src/index.js +2 -12
  106. package/dist/src/marks/mark.d.ts +1 -0
  107. package/dist/src/marks/mark.d.ts.map +1 -1
  108. package/dist/src/marks/mark.js +26 -3
  109. package/dist/src/{view → scales}/axisResolution.d.ts +12 -14
  110. package/dist/src/scales/axisResolution.d.ts.map +1 -0
  111. package/dist/src/{view → scales}/axisResolution.js +38 -12
  112. package/dist/src/scales/axisResolution.test.d.ts.map +1 -0
  113. package/dist/src/scales/scaleDomainAggregator.d.ts +57 -0
  114. package/dist/src/scales/scaleDomainAggregator.d.ts.map +1 -0
  115. package/dist/src/scales/scaleDomainAggregator.js +162 -0
  116. package/dist/src/scales/scaleDomainAggregator.test.d.ts +2 -0
  117. package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +1 -0
  118. package/dist/src/scales/scaleInstanceManager.d.ts +40 -0
  119. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -0
  120. package/dist/src/scales/scaleInstanceManager.js +313 -0
  121. package/dist/src/scales/scaleInstanceManager.test.d.ts +2 -0
  122. package/dist/src/scales/scaleInstanceManager.test.d.ts.map +1 -0
  123. package/dist/src/scales/scaleInteractionController.d.ts +73 -0
  124. package/dist/src/scales/scaleInteractionController.d.ts.map +1 -0
  125. package/dist/src/scales/scaleInteractionController.js +336 -0
  126. package/dist/src/scales/scaleInteractionController.test.d.ts +2 -0
  127. package/dist/src/scales/scaleInteractionController.test.d.ts.map +1 -0
  128. package/dist/src/scales/scalePropsResolver.d.ts +23 -0
  129. package/dist/src/scales/scalePropsResolver.d.ts.map +1 -0
  130. package/dist/src/scales/scalePropsResolver.js +74 -0
  131. package/dist/src/{view → scales}/scaleResolution.d.ts +53 -31
  132. package/dist/src/scales/scaleResolution.d.ts.map +1 -0
  133. package/dist/src/scales/scaleResolution.js +658 -0
  134. package/dist/src/scales/scaleResolution.test.d.ts.map +1 -0
  135. package/dist/src/scales/scaleResolutionConstants.d.ts +6 -0
  136. package/dist/src/scales/scaleResolutionConstants.d.ts.map +1 -0
  137. package/dist/src/scales/scaleResolutionConstants.js +5 -0
  138. package/dist/src/scales/scaleRules.d.ts +16 -0
  139. package/dist/src/scales/scaleRules.d.ts.map +1 -0
  140. package/dist/src/scales/scaleRules.js +103 -0
  141. package/dist/src/scales/scaleRules.test.d.ts +2 -0
  142. package/dist/src/scales/scaleRules.test.d.ts.map +1 -0
  143. package/dist/src/spec/channel.d.ts +13 -18
  144. package/dist/src/spec/sampleView.d.ts +3 -2
  145. package/dist/src/spec/scale.d.ts +6 -0
  146. package/dist/src/types/embedApi.d.ts +5 -0
  147. package/dist/src/types/scaleResolutionApi.d.ts +1 -1
  148. package/dist/src/types/viewContext.d.ts +1 -1
  149. package/dist/src/view/concatView.d.ts +18 -0
  150. package/dist/src/view/concatView.d.ts.map +1 -1
  151. package/dist/src/view/concatView.js +73 -0
  152. package/dist/src/view/concatView.test.d.ts +2 -0
  153. package/dist/src/view/concatView.test.d.ts.map +1 -0
  154. package/dist/src/view/containerMutationHelper.d.ts +74 -0
  155. package/dist/src/view/containerMutationHelper.d.ts.map +1 -0
  156. package/dist/src/view/containerMutationHelper.js +114 -0
  157. package/dist/src/view/containerView.d.ts +0 -7
  158. package/dist/src/view/containerView.d.ts.map +1 -1
  159. package/dist/src/view/containerView.js +0 -10
  160. package/dist/src/view/facetView.d.ts.map +1 -1
  161. package/dist/src/view/facetView.js +0 -14
  162. package/dist/src/view/flowBuilder.d.ts +2 -2
  163. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  164. package/dist/src/view/flowBuilder.js +21 -4
  165. package/dist/src/view/gridView/gridChild.d.ts +11 -0
  166. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  167. package/dist/src/view/gridView/gridChild.js +32 -6
  168. package/dist/src/view/gridView/gridView.d.ts +39 -1
  169. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  170. package/dist/src/view/gridView/gridView.js +113 -42
  171. package/dist/src/view/gridView/gridView.test.d.ts +2 -0
  172. package/dist/src/view/gridView/gridView.test.d.ts.map +1 -0
  173. package/dist/src/view/gridView/scrollbar.d.ts +39 -8
  174. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
  175. package/dist/src/view/gridView/scrollbar.js +184 -69
  176. package/dist/src/view/gridView/selectionRect.d.ts +8 -4
  177. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  178. package/dist/src/view/gridView/selectionRect.js +28 -3
  179. package/dist/src/view/gridView/selectionRect.test.d.ts +2 -0
  180. package/dist/src/view/gridView/selectionRect.test.d.ts.map +1 -0
  181. package/dist/src/view/layerView.d.ts +14 -0
  182. package/dist/src/view/layerView.d.ts.map +1 -1
  183. package/dist/src/view/layerView.js +66 -0
  184. package/dist/src/view/layerView.test.d.ts +2 -0
  185. package/dist/src/view/layerView.test.d.ts.map +1 -0
  186. package/dist/src/view/paramMediator.d.ts +2 -1
  187. package/dist/src/view/paramMediator.d.ts.map +1 -1
  188. package/dist/src/view/paramMediator.js +13 -1
  189. package/dist/src/view/testUtils.d.ts.map +1 -1
  190. package/dist/src/view/testUtils.js +18 -5
  191. package/dist/src/view/unitView.d.ts.map +1 -1
  192. package/dist/src/view/unitView.js +52 -12
  193. package/dist/src/view/view.d.ts +23 -7
  194. package/dist/src/view/view.d.ts.map +1 -1
  195. package/dist/src/view/view.js +61 -5
  196. package/dist/src/view/viewDispose.test.d.ts +2 -0
  197. package/dist/src/view/viewDispose.test.d.ts.map +1 -0
  198. package/dist/src/view/viewUtils.d.ts +4 -4
  199. package/dist/src/view/viewUtils.d.ts.map +1 -1
  200. package/dist/src/view/viewUtils.js +19 -15
  201. package/dist/src/view/viewUtils.test.d.ts +2 -0
  202. package/dist/src/view/viewUtils.test.d.ts.map +1 -0
  203. package/package.json +10 -10
  204. package/dist/bundle/__vite-browser-external-C--ziKoh.js +0 -8
  205. package/dist/bundle/_commonjsHelpers-DjF3Plf2.js +0 -26
  206. package/dist/bundle/index-5ajWdKly.js +0 -1319
  207. package/dist/bundle/index-B03-Om4z.js +0 -274
  208. package/dist/bundle/index-BftNdA0O.js +0 -27
  209. package/dist/bundle/index-Bg7C4Xat.js +0 -2750
  210. package/dist/bundle/index-C3QR8Lv6.js +0 -2131
  211. package/dist/bundle/index-DTcHjAHp.js +0 -505
  212. package/dist/bundle/index-DnIkxb0L.js +0 -1025
  213. package/dist/bundle/index-Ww3TAo6_.js +0 -71
  214. package/dist/bundle/index-g8iXgW0W.js +0 -651
  215. package/dist/bundle/long-B-FASCSo.js +0 -2387
  216. package/dist/bundle/remoteFile-BuaqFGWk.js +0 -94
  217. package/dist/src/data/collector.test.js +0 -138
  218. package/dist/src/data/dataFlow.test.js +0 -5
  219. package/dist/src/data/flow.test.js +0 -81
  220. package/dist/src/data/flowNode.test.js +0 -50
  221. package/dist/src/data/flowOptimizer.test.js +0 -204
  222. package/dist/src/data/formats/fasta.test.js +0 -27
  223. package/dist/src/data/sources/inlineSource.test.js +0 -63
  224. package/dist/src/data/sources/sequenceSource.test.js +0 -81
  225. package/dist/src/data/transforms/aggregate.test.js +0 -134
  226. package/dist/src/data/transforms/clone.test.js +0 -11
  227. package/dist/src/data/transforms/coverage.test.js +0 -238
  228. package/dist/src/data/transforms/filter.test.js +0 -20
  229. package/dist/src/data/transforms/flatten.test.js +0 -96
  230. package/dist/src/data/transforms/flattenDelimited.test.js +0 -90
  231. package/dist/src/data/transforms/flattenSequence.test.js +0 -34
  232. package/dist/src/data/transforms/formula.test.js +0 -25
  233. package/dist/src/data/transforms/identifier.test.js +0 -92
  234. package/dist/src/data/transforms/pileup.test.js +0 -70
  235. package/dist/src/data/transforms/project.test.js +0 -32
  236. package/dist/src/data/transforms/regexExtract.test.js +0 -70
  237. package/dist/src/data/transforms/regexFold.test.js +0 -201
  238. package/dist/src/data/transforms/sample.test.js +0 -38
  239. package/dist/src/data/transforms/stack.test.js +0 -91
  240. package/dist/src/encoder/accessor.test.js +0 -162
  241. package/dist/src/encoder/encoder.test.js +0 -105
  242. package/dist/src/genome/genome.test.js +0 -268
  243. package/dist/src/genome/genomes.test.js +0 -8
  244. package/dist/src/genome/scaleIndex.test.js +0 -78
  245. package/dist/src/genome/scaleLocus.test.js +0 -4
  246. package/dist/src/scale/scale.test.js +0 -326
  247. package/dist/src/scale/ticks.test.js +0 -46
  248. package/dist/src/selection/selection.test.js +0 -14
  249. package/dist/src/utils/addBaseUrl.test.js +0 -30
  250. package/dist/src/utils/binnedIndex.test.js +0 -201
  251. package/dist/src/utils/cloner.test.js +0 -35
  252. package/dist/src/utils/coalesce.test.js +0 -16
  253. package/dist/src/utils/concatIterables.test.js +0 -8
  254. package/dist/src/utils/domainArray.test.js +0 -130
  255. package/dist/src/utils/indexer.test.js +0 -49
  256. package/dist/src/utils/interactionEvent.test.js +0 -35
  257. package/dist/src/utils/iterateNestedMaps.test.js +0 -33
  258. package/dist/src/utils/kWayMerge.test.js +0 -30
  259. package/dist/src/utils/mergeObjects.test.js +0 -42
  260. package/dist/src/utils/numberExtractor.test.js +0 -6
  261. package/dist/src/utils/propertyCacher.test.js +0 -89
  262. package/dist/src/utils/propertyCoalescer.test.js +0 -25
  263. package/dist/src/utils/radixSort.test.js +0 -51
  264. package/dist/src/utils/reservationMap.test.js +0 -20
  265. package/dist/src/utils/ringBuffer.test.js +0 -39
  266. package/dist/src/utils/topK.test.js +0 -54
  267. package/dist/src/utils/trees.test.js +0 -135
  268. package/dist/src/utils/url.test.js +0 -28
  269. package/dist/src/utils/variableTools.test.js +0 -13
  270. package/dist/src/view/axisResolution.d.ts.map +0 -1
  271. package/dist/src/view/axisResolution.test.d.ts.map +0 -1
  272. package/dist/src/view/axisResolution.test.js +0 -206
  273. package/dist/src/view/flowBuilder.test.js +0 -125
  274. package/dist/src/view/layout/flexLayout.test.js +0 -323
  275. package/dist/src/view/layout/grid.test.js +0 -71
  276. package/dist/src/view/layout/rectangle.test.js +0 -192
  277. package/dist/src/view/paramMediator.test.js +0 -260
  278. package/dist/src/view/scaleResolution.d.ts.map +0 -1
  279. package/dist/src/view/scaleResolution.js +0 -1049
  280. package/dist/src/view/scaleResolution.test.d.ts.map +0 -1
  281. package/dist/src/view/scaleResolution.test.js +0 -645
  282. package/dist/src/view/view.test.js +0 -245
  283. package/dist/src/view/viewFactory.test.js +0 -25
  284. /package/dist/src/{view → scales}/axisResolution.test.d.ts +0 -0
  285. /package/dist/src/{view → scales}/scaleResolution.test.d.ts +0 -0
@@ -4,37 +4,57 @@ import Rectangle from "../layout/rectangle.js";
4
4
  import UnitView from "../unitView.js";
5
5
 
6
6
  /**
7
+ * This class represents a scrollbar thumb that can be used within a grid view
8
+ * to provide scrolling functionality for overflowing content.
9
+ *
7
10
  * @typedef {"horizontal" | "vertical"} ScrollDirection
8
11
  */
9
12
  export default class Scrollbar extends UnitView {
10
13
  /** @type {ScrollDirection} */
11
14
  #scrollDirection;
12
15
 
16
+ // NOTE: Keep this Rectangle instance stable. Buffered rendering caches
17
+ // a reference to coords; replacing it breaks dynamic updates.
13
18
  #scrollbarCoords = Rectangle.ZERO;
14
19
 
15
- #maxScrollOffset = 0;
20
+ #viewportCoords = Rectangle.ZERO;
16
21
 
17
- #maxViewportOffset = 0;
22
+ #contentCoords = Rectangle.ZERO;
18
23
 
19
- // This is the actual state of the scrollbar. It's better to keep track of
20
- // the viewport offset rather than the scrollbar offset because the former
21
- // is more stable when the viewport size changes.
24
+ /**
25
+ * The actual state of the scrollbar.
26
+ *
27
+ * It's better to keep track of the viewport offset rather than the
28
+ * scrollbar offset because the former is more stable when the
29
+ * viewport size changes.
30
+ */
22
31
  viewportOffset = 0;
23
32
 
33
+ /** @type {(offset: number) => void} */
34
+ #onViewportOffsetChange;
35
+
24
36
  /**
25
37
  * @param {import("./gridChild.js").default} gridChild
26
38
  * @param {ScrollDirection} scrollDirection
39
+ * @param {{ onViewportOffsetChange?: (offset: number) => void }} [options]
27
40
  */
28
- constructor(gridChild, scrollDirection) {
29
- // TODO: Configurable
41
+ constructor(gridChild, scrollDirection, options = {}) {
42
+ // TODO: Configurable per view
30
43
  const config = {
31
44
  scrollbarSize: 8,
32
45
  scrollbarPadding: 2,
33
- // TODO: inside/outside view
46
+ scrollbarMinLength: 20,
34
47
  };
35
48
 
36
49
  super(
37
50
  {
51
+ params: [
52
+ {
53
+ name: "scrollbarOpacity",
54
+ value: 1,
55
+ },
56
+ ],
57
+ opacity: { expr: "scrollbarOpacity" },
38
58
  data: { values: [{}] },
39
59
  mark: {
40
60
  type: "rect",
@@ -59,22 +79,41 @@ export default class Scrollbar extends UnitView {
59
79
 
60
80
  this.config = config;
61
81
  this.#scrollDirection = scrollDirection;
82
+ this.#onViewportOffsetChange = options.onViewportOffsetChange;
62
83
 
63
- // Make it smooth!
64
- this.interpolateViewportOffset = makeLerpSmoother(
65
- this.context.animator,
66
- (value) => {
67
- this.viewportOffset = value.x;
68
- },
69
- 50,
70
- 0.4,
71
- { x: this.viewportOffset }
72
- );
84
+ const sPad = this.config.scrollbarPadding;
85
+ const sSize = this.config.scrollbarSize;
86
+
87
+ this.#scrollbarCoords =
88
+ this.#scrollDirection == "vertical"
89
+ ? new Rectangle(
90
+ () =>
91
+ this.#viewportCoords.x +
92
+ this.#viewportCoords.width -
93
+ sSize -
94
+ sPad,
95
+ () => this.#viewportCoords.y + sPad + this.scrollOffset,
96
+ () => sSize,
97
+ () => this.#getScrollLength()
98
+ )
99
+ : new Rectangle(
100
+ () => this.#viewportCoords.x + sPad + this.scrollOffset,
101
+ () =>
102
+ this.#viewportCoords.y +
103
+ this.#viewportCoords.height -
104
+ sSize -
105
+ sPad,
106
+ () => this.#getScrollLength(),
107
+ () => sSize
108
+ );
109
+
110
+ // Smooth viewport offset updates
111
+ this.#initViewportOffsetSmoother(this.viewportOffset);
73
112
 
74
113
  this.addInteractionEventListener("mousedown", (coords, event) => {
75
114
  event.stopPropagation();
76
115
 
77
- if (this.#maxScrollOffset <= 0) {
116
+ if (this.#getMaxScrollOffset() <= 0) {
78
117
  return;
79
118
  }
80
119
 
@@ -91,18 +130,21 @@ export default class Scrollbar extends UnitView {
91
130
  const onMousemove = /** @param {MouseEvent} moveEvent */ (
92
131
  moveEvent
93
132
  ) => {
133
+ const maxScrollOffset = this.#getMaxScrollOffset();
134
+ if (maxScrollOffset <= 0) {
135
+ return;
136
+ }
137
+
94
138
  const scrollOffset = clamp(
95
139
  getMouseOffset(moveEvent) -
96
140
  initialOffset +
97
141
  initialScrollOffset,
98
142
  0,
99
- this.#maxScrollOffset
143
+ maxScrollOffset
100
144
  );
101
145
 
102
146
  this.interpolateViewportOffset({
103
- x:
104
- (scrollOffset / this.#maxScrollOffset) *
105
- this.#maxViewportOffset,
147
+ x: this.#getViewportOffsetFromScrollOffset(scrollOffset),
106
148
  });
107
149
  };
108
150
 
@@ -117,9 +159,95 @@ export default class Scrollbar extends UnitView {
117
159
  }
118
160
 
119
161
  get scrollOffset() {
120
- return (
121
- (this.viewportOffset / this.#maxViewportOffset) *
122
- this.#maxScrollOffset
162
+ return this.#getScrollOffsetFromViewportOffset(this.viewportOffset);
163
+ }
164
+
165
+ /**
166
+ * @param {number} value
167
+ * @param {{ notify?: boolean, syncSmoother?: boolean }} [options]
168
+ */
169
+ setViewportOffset(value, { notify = true, syncSmoother = false } = {}) {
170
+ this.viewportOffset = clamp(value, 0, this.#getMaxViewportOffset());
171
+
172
+ if (syncSmoother) {
173
+ this.#initViewportOffsetSmoother(this.viewportOffset);
174
+ }
175
+
176
+ if (notify && this.#onViewportOffsetChange) {
177
+ this.#onViewportOffsetChange(this.viewportOffset);
178
+ }
179
+ }
180
+
181
+ #getVisibleFraction() {
182
+ const dimension =
183
+ this.#scrollDirection == "horizontal" ? "width" : "height";
184
+
185
+ const viewportSize = this.#viewportCoords[dimension];
186
+ const contentSize = this.#contentCoords[dimension];
187
+
188
+ return contentSize > 0 ? Math.min(1, viewportSize / contentSize) : 1;
189
+ }
190
+
191
+ #getMaxScrollLength() {
192
+ const dimension =
193
+ this.#scrollDirection == "horizontal" ? "width" : "height";
194
+
195
+ return Math.max(
196
+ 0,
197
+ this.#viewportCoords[dimension] - 2 * this.config.scrollbarPadding
198
+ );
199
+ }
200
+
201
+ #getScrollLength() {
202
+ const maxScrollLength = this.#getMaxScrollLength();
203
+ const scrollLength = this.#getVisibleFraction() * maxScrollLength;
204
+ const minLength = this.config.scrollbarMinLength;
205
+
206
+ return Math.min(maxScrollLength, Math.max(minLength, scrollLength));
207
+ }
208
+
209
+ #getMaxScrollOffset() {
210
+ return Math.max(
211
+ 0,
212
+ this.#getMaxScrollLength() - this.#getScrollLength()
213
+ );
214
+ }
215
+
216
+ /**
217
+ * @param {number} viewportOffset
218
+ */
219
+ #getScrollOffsetFromViewportOffset(viewportOffset) {
220
+ const maxViewportOffset = this.#getMaxViewportOffset();
221
+ const maxScrollOffset = this.#getMaxScrollOffset();
222
+
223
+ if (maxViewportOffset <= 0 || maxScrollOffset <= 0) {
224
+ return 0;
225
+ }
226
+
227
+ return (viewportOffset / maxViewportOffset) * maxScrollOffset;
228
+ }
229
+
230
+ /**
231
+ * @param {number} scrollOffset
232
+ */
233
+ #getViewportOffsetFromScrollOffset(scrollOffset) {
234
+ const maxViewportOffset = this.#getMaxViewportOffset();
235
+ const maxScrollOffset = this.#getMaxScrollOffset();
236
+
237
+ if (maxViewportOffset <= 0 || maxScrollOffset <= 0) {
238
+ return 0;
239
+ }
240
+
241
+ return (scrollOffset / maxScrollOffset) * maxViewportOffset;
242
+ }
243
+
244
+ #getMaxViewportOffset() {
245
+ const dimension =
246
+ this.#scrollDirection == "horizontal" ? "width" : "height";
247
+
248
+ return Math.max(
249
+ 0,
250
+ this.#contentCoords[dimension] - this.#viewportCoords[dimension]
123
251
  );
124
252
  }
125
253
 
@@ -129,57 +257,44 @@ export default class Scrollbar extends UnitView {
129
257
  * @param {import("../../types/rendering.js").RenderingOptions} [options]
130
258
  */
131
259
  render(context, coords, options) {
260
+ // NOTE: This only records layout coordinates for buffered rendering.
132
261
  super.render(context, this.#scrollbarCoords, options);
133
262
  }
134
263
 
135
264
  /**
265
+ * Updates the scrollbar with the latest viewport and content rectangles.
266
+ *
267
+ * Viewport coords are flattened to stay stable between layout passes, while
268
+ * content coords may be dynamic (e.g., peek transitions) and are evaluated
269
+ * on demand via accessors.
136
270
  *
137
271
  * @param {Rectangle} viewportCoords
138
- * @param {Rectangle} coords
272
+ * @param {Rectangle} contentCoords
139
273
  */
140
- updateScrollbar(viewportCoords, coords) {
141
- const sPad = this.config.scrollbarPadding;
142
- const sSize = this.config.scrollbarSize;
143
-
144
- const dimension =
145
- this.#scrollDirection == "horizontal" ? "width" : "height";
146
-
147
- const visibleFraction = Math.min(
148
- 1,
149
- viewportCoords[dimension] / coords[dimension]
150
- );
151
- const maxScrollLength = viewportCoords[dimension] - 2 * sPad;
152
- const scrollLength = visibleFraction * maxScrollLength;
274
+ updateScrollbar(viewportCoords, contentCoords) {
275
+ this.#viewportCoords = viewportCoords.flatten();
276
+ this.#contentCoords = contentCoords;
277
+ this.setViewportOffset(this.viewportOffset, {
278
+ notify: false,
279
+ syncSmoother: true,
280
+ });
281
+ }
153
282
 
154
- this.#maxScrollOffset = maxScrollLength - scrollLength;
155
- this.#maxViewportOffset = coords[dimension] - viewportCoords[dimension];
156
- this.viewportOffset = clamp(
157
- this.viewportOffset,
158
- 0,
159
- this.#maxViewportOffset
283
+ /**
284
+ * @param {number} value
285
+ */
286
+ #initViewportOffsetSmoother(value) {
287
+ this.interpolateViewportOffset = makeLerpSmoother(
288
+ this.context.animator,
289
+ (current) => {
290
+ this.setViewportOffset(current.x, {
291
+ notify: true,
292
+ syncSmoother: false,
293
+ });
294
+ },
295
+ 35,
296
+ 0.4,
297
+ { x: value }
160
298
  );
161
-
162
- this.#scrollbarCoords =
163
- this.#scrollDirection == "vertical"
164
- ? new Rectangle(
165
- () =>
166
- viewportCoords.x +
167
- viewportCoords.width -
168
- sSize -
169
- sPad,
170
- () => viewportCoords.y + sPad + this.scrollOffset,
171
- () => sSize,
172
- () => scrollLength
173
- )
174
- : new Rectangle(
175
- () => viewportCoords.x + sPad + this.scrollOffset,
176
- () =>
177
- viewportCoords.y +
178
- viewportCoords.height -
179
- sSize -
180
- sPad,
181
- () => scrollLength,
182
- () => sSize
183
- );
184
299
  }
185
300
  }
@@ -1,14 +1,18 @@
1
1
  export default class SelectionRect extends LayerView {
2
- /**
3
- * @typedef {import("../../spec/channel.js").PrimaryPositionalChannel} PrimaryPositionalChannel
4
- * @typedef {import("../../types/selectionTypes.js").IntervalSelection} IntervalSelection
5
- */
6
2
  /**
7
3
  * @param {import("./gridChild.js").default} gridChild
8
4
  * @param {import("../paramMediator.js").ExprRefFunction} selectionExpr
9
5
  * @param {import("../../spec/parameter.js").BrushConfig} [brushConfig]
10
6
  */
11
7
  constructor(gridChild: import("./gridChild.js").default, selectionExpr: import("../paramMediator.js").ExprRefFunction, brushConfig?: import("../../spec/parameter.js").BrushConfig);
8
+ /**
9
+ * @typedef {import("../../spec/channel.js").PrimaryPositionalChannel} PrimaryPositionalChannel
10
+ * @typedef {import("../../types/selectionTypes.js").IntervalSelection} IntervalSelection
11
+ */
12
+ /** @type {import("../paramMediator.js").ExprRefFunction} */
13
+ _selectionExpr: import("../paramMediator.js").ExprRefFunction;
14
+ /** @type {() => void} */
15
+ _selectionListener: () => void;
12
16
  }
13
17
  import LayerView from "../layerView.js";
14
18
  //# sourceMappingURL=selectionRect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"selectionRect.d.ts","sourceRoot":"","sources":["../../../../src/view/gridView/selectionRect.js"],"names":[],"mappings":"AAGA;IACI;;;OAGG;IAEH;;;;OAIG;IACH,uBAJW,OAAO,gBAAgB,EAAE,OAAO,iBAChC,OAAO,qBAAqB,EAAE,eAAe,gBAC7C,OAAO,yBAAyB,EAAE,WAAW,EA0IvD;CACJ;sBAtJqB,iBAAiB"}
1
+ {"version":3,"file":"selectionRect.d.ts","sourceRoot":"","sources":["../../../../src/view/gridView/selectionRect.js"],"names":[],"mappings":"AAGA;IAYI;;;;OAIG;IACH,uBAJW,OAAO,gBAAgB,EAAE,OAAO,iBAChC,OAAO,qBAAqB,EAAE,eAAe,gBAC7C,OAAO,yBAAyB,EAAE,WAAW,EAqJvD;IAnKD;;;OAGG;IAEH,4DAA4D;IAC5D,gBADW,OAAO,qBAAqB,EAAE,eAAe,CACzC;IAEf,yBAAyB;IACzB,oBADW,MAAM,IAAI,CACF;CAmKtB;sBA/KqB,iBAAiB"}
@@ -7,6 +7,12 @@ export default class SelectionRect extends LayerView {
7
7
  * @typedef {import("../../types/selectionTypes.js").IntervalSelection} IntervalSelection
8
8
  */
9
9
 
10
+ /** @type {import("../paramMediator.js").ExprRefFunction} */
11
+ _selectionExpr;
12
+
13
+ /** @type {() => void} */
14
+ _selectionListener;
15
+
10
16
  /**
11
17
  * @param {import("./gridChild.js").default} gridChild
12
18
  * @param {import("../paramMediator.js").ExprRefFunction} selectionExpr
@@ -135,7 +141,10 @@ export default class SelectionRect extends LayerView {
135
141
  }
136
142
  );
137
143
 
138
- selectionExpr.addListener(() => {
144
+ /** @type {import("../paramMediator.js").ExprRefFunction} */
145
+ this._selectionExpr = selectionExpr;
146
+
147
+ this._selectionListener = () => {
139
148
  const selection =
140
149
  /** @type {import("../../types/selectionTypes.js").IntervalSelection} */ (
141
150
  selectionExpr()
@@ -143,11 +152,27 @@ export default class SelectionRect extends LayerView {
143
152
 
144
153
  const datasource =
145
154
  /** @type {import("../../data/sources/inlineSource.js").default} */ (
146
- this.context.dataFlow.findDataSourceByKey(this)
155
+ this.flowHandle?.dataSource
147
156
  );
148
157
 
158
+ if (!datasource) {
159
+ throw new Error(
160
+ "Cannot find selection rect data source handle!"
161
+ );
162
+ }
163
+
149
164
  datasource.updateDynamicData(selectionToData(selection));
150
- });
165
+ };
166
+
167
+ selectionExpr.addListener(this._selectionListener);
168
+ }
169
+
170
+ /**
171
+ * @override
172
+ */
173
+ dispose() {
174
+ this._selectionExpr.removeListener(this._selectionListener);
175
+ super.dispose();
151
176
  }
152
177
  }
153
178
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=selectionRect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectionRect.test.d.ts","sourceRoot":"","sources":["../../../../src/view/gridView/selectionRect.test.js"],"names":[],"mappings":""}
@@ -10,6 +10,20 @@ export default class LayerView extends ContainerView {
10
10
  */
11
11
  constructor(spec: import("../spec/view.js").LayerSpec, context: import("../types/viewContext.js").default, layoutParent: ContainerView, dataParent: import("./view.js").default, name: string, options?: import("./view.js").ViewOptions);
12
12
  spec: import("../spec/view.js").LayerSpec;
13
+ /**
14
+ * Adds a child spec dynamically. Intended for post-initialization updates.
15
+ *
16
+ * @param {import("../spec/view.js").LayerSpec | import("../spec/view.js").UnitSpec | import("../spec/view.js").ImportSpec} childSpec
17
+ * @param {number} [index]
18
+ * @returns {Promise<LayerView | import("./unitView.js").default>}
19
+ */
20
+ addChildSpec(childSpec: import("../spec/view.js").LayerSpec | import("../spec/view.js").UnitSpec | import("../spec/view.js").ImportSpec, index?: number): Promise<LayerView | import("./unitView.js").default>;
21
+ /**
22
+ * Removes a child by index. Intended for post-initialization updates.
23
+ *
24
+ * @param {number} index
25
+ */
26
+ removeChildAt(index: number): Promise<void>;
13
27
  get children(): (import("./unitView.js").default | LayerView)[];
14
28
  #private;
15
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"layerView.d.ts","sourceRoot":"","sources":["../../../src/view/layerView.js"],"names":[],"mappings":"AAIA;IAQI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,SAAS,WACnC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,cACb,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAWzC;IAHG,0CAAgB;IAoCpB,gEAEC;;CA6CJ;0BA7GyB,oBAAoB"}
1
+ {"version":3,"file":"layerView.d.ts","sourceRoot":"","sources":["../../../src/view/layerView.js"],"names":[],"mappings":"AAKA;IAQI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,SAAS,WACnC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,cACb,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAWzC;IAHG,0CAAgB;IAoCpB;;;;;;OAMG;IACH,wBAJW,OAAO,iBAAiB,EAAE,SAAS,GAAG,OAAO,iBAAiB,EAAE,QAAQ,GAAG,OAAO,iBAAiB,EAAE,UAAU,UAC/G,MAAM,GACJ,OAAO,CAAC,SAAS,GAAG,OAAO,eAAe,EAAE,OAAO,CAAC,CAMhE;IAED;;;;OAIG;IACH,qBAFW,MAAM,iBAIhB;IA6CD,gEAEC;;CA6CJ;0BA/KyB,oBAAoB"}
@@ -1,6 +1,7 @@
1
1
  import { isLayerSpec, isUnitSpec } from "./viewFactory.js";
2
2
  import ContainerView from "./containerView.js";
3
3
  import ViewError from "./viewError.js";
4
+ import ContainerMutationHelper from "./containerMutationHelper.js";
4
5
 
5
6
  export default class LayerView extends ContainerView {
6
7
  /**
@@ -61,6 +62,71 @@ export default class LayerView extends ContainerView {
61
62
  );
62
63
  }
63
64
 
65
+ /**
66
+ * Adds a child spec dynamically. Intended for post-initialization updates.
67
+ *
68
+ * @param {import("../spec/view.js").LayerSpec | import("../spec/view.js").UnitSpec | import("../spec/view.js").ImportSpec} childSpec
69
+ * @param {number} [index]
70
+ * @returns {Promise<LayerView | import("./unitView.js").default>}
71
+ */
72
+ async addChildSpec(childSpec, index) {
73
+ return /** @type {Promise<LayerView | import("./unitView.js").default>} */ (
74
+ this.#getMutationHelper().addChildSpec(childSpec, index)
75
+ );
76
+ }
77
+
78
+ /**
79
+ * Removes a child by index. Intended for post-initialization updates.
80
+ *
81
+ * @param {number} index
82
+ */
83
+ async removeChildAt(index) {
84
+ await this.#getMutationHelper().removeChildAt(index);
85
+ }
86
+
87
+ /**
88
+ * @returns {ContainerMutationHelper}
89
+ */
90
+ #getMutationHelper() {
91
+ return new ContainerMutationHelper(this, {
92
+ getChildSpecs: () => ({
93
+ specs: this.spec.layer,
94
+ insertAt: (index, spec) => {
95
+ this.spec.layer.splice(
96
+ index,
97
+ 0,
98
+ /** @type {import("../spec/view.js").LayerSpec | import("../spec/view.js").UnitSpec | import("../spec/view.js").ImportSpec} */ (
99
+ spec
100
+ )
101
+ );
102
+ },
103
+ removeAt: (index) => {
104
+ this.spec.layer.splice(index, 1);
105
+ },
106
+ }),
107
+ insertView: (view, index) => {
108
+ view.layoutParent ??= this;
109
+ this.#children.splice(
110
+ index,
111
+ 0,
112
+ /** @type {LayerView | import("./unitView.js").default} */ (
113
+ view
114
+ )
115
+ );
116
+ return view;
117
+ },
118
+ removeView: (index) => {
119
+ const view = this.#children[index];
120
+ if (!view) {
121
+ throw new Error("Child index out of range!");
122
+ }
123
+ view.disposeSubtree();
124
+ this.#children.splice(index, 1);
125
+ },
126
+ defaultName: (index) => "layer" + index,
127
+ });
128
+ }
129
+
64
130
  get children() {
65
131
  return this.#children.slice();
66
132
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=layerView.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layerView.test.d.ts","sourceRoot":"","sources":["../../../src/view/layerView.test.js"],"names":[],"mappings":""}
@@ -58,7 +58,7 @@ export function makeConstantExprRef(value: any): ExprRefFunction;
58
58
  * TODO: The proposed JavaScript signals may provide a better way to implement this.
59
59
  * https://github.com/proposal-signals/proposal-signals
60
60
  *
61
- * @typedef {import("../utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, invalidate: () => void, identifier: () => string}} ExprRefFunction
61
+ * @typedef {import("../utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, removeListener: (listener: () => void) => void, invalidate: () => void, identifier: () => string}} ExprRefFunction
62
62
  */
63
63
  export default class ParamMediator {
64
64
  /**
@@ -142,6 +142,7 @@ export default class ParamMediator {
142
142
  */
143
143
  export type ExprRefFunction = import("../utils/expression.js").ExpressionFunction & {
144
144
  addListener: (listener: () => void) => void;
145
+ removeListener: (listener: () => void) => void;
145
146
  invalidate: () => void;
146
147
  identifier: () => string;
147
148
  };
@@ -1 +1 @@
1
- {"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"AAmVA;;;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,CAW3B;AAtcD;;;;;;;;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,mBA4EhB;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAKhB;IAED;;;;;OAKG;IACH,sBAFa,OAAO,CAiBnB;;CACJ;;;;;;;;8BA/TY,OAAO,wBAAwB,EAAE,kBAAkB,GAAG;IAAE,WAAW,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":"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"}
@@ -16,7 +16,7 @@ import {
16
16
  * TODO: The proposed JavaScript signals may provide a better way to implement this.
17
17
  * https://github.com/proposal-signals/proposal-signals
18
18
  *
19
- * @typedef {import("../utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, invalidate: () => void, identifier: () => string}} ExprRefFunction
19
+ * @typedef {import("../utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, removeListener: (listener: () => void) => void, invalidate: () => void, identifier: () => string}} ExprRefFunction
20
20
  */
21
21
  export default class ParamMediator {
22
22
  /**
@@ -280,6 +280,16 @@ export default class ParamMediator {
280
280
  }
281
281
  };
282
282
 
283
+ /**
284
+ * @param {() => void} listener
285
+ */
286
+ fn.removeListener = (listener) => {
287
+ for (const [param, mediator] of mediatorsForParams) {
288
+ mediator.paramListeners.get(param)?.delete(listener);
289
+ }
290
+ myListeners.delete(listener);
291
+ };
292
+
283
293
  /**
284
294
  * Detach listeners. This must be called if the expression is no longer used.
285
295
  * TODO: What if the expression is used in multiple places?
@@ -290,6 +300,7 @@ export default class ParamMediator {
290
300
  mediator.paramListeners.get(param)?.delete(listener);
291
301
  }
292
302
  }
303
+ myListeners.clear();
293
304
  };
294
305
 
295
306
  // TODO: This should contain unique identifier for each parameter.
@@ -457,6 +468,7 @@ export function validateParameterName(name) {
457
468
  export function makeConstantExprRef(value) {
458
469
  return Object.assign(() => value, {
459
470
  addListener: () => /** @type {void} */ (undefined),
471
+ removeListener: () => /** @type {void} */ (undefined),
460
472
  invalidate: () => /** @type {void} */ (undefined),
461
473
  identifier: () => "constant",
462
474
  fields: [],
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../../src/view/testUtils.js"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,2DAHW,OAAO,kBAAkB,EAAE,kBAAkB,6CA+CvD;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;;;;;uBAhFpL,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,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"}
@@ -6,12 +6,15 @@
6
6
  * @typedef {import("../types/viewContext.js").default} ViewContext
7
7
  */
8
8
 
9
- import { checkForDuplicateScaleNames, initializeData } from "./viewUtils.js";
9
+ import { checkForDuplicateScaleNames } from "./viewUtils.js";
10
+ import {
11
+ initializeViewSubtree,
12
+ loadViewSubtreeData,
13
+ } from "../data/flowInit.js";
10
14
  import DataFlow from "../data/dataFlow.js";
11
15
  import { VIEW_ROOT_NAME, ViewFactory } from "./viewFactory.js";
12
16
  import GenomeStore from "../genome/genomeStore.js";
13
17
  import BmFontManager from "../fonts/bmFontManager.js";
14
- import { reconfigureScales } from "./scaleResolution.js";
15
18
  import UnitView from "./unitView.js";
16
19
  import ContainerView from "./containerView.js";
17
20
 
@@ -56,6 +59,17 @@ export function createTestViewContext(viewFactoryOptions = {}) {
56
59
  genomeStore,
57
60
 
58
61
  fontManager: new BmFontManager(),
62
+ animator: /** @type {import("../utils/animator.js").default} */ (
63
+ /** @type {any} */ ({
64
+ requestRender: /** @type {() => void} */ (() => undefined),
65
+ requestTransition:
66
+ /** @type {(callback: () => void) => void} */ (
67
+ (callback) => callback()
68
+ ),
69
+ })
70
+ ),
71
+
72
+ requestLayoutReflow: () => undefined,
59
73
 
60
74
  isViewConfiguredVisible: () => true,
61
75
 
@@ -88,7 +102,6 @@ export async function createAndInitialize(spec, viewClass) {
88
102
  const view = await create(spec, viewClass);
89
103
 
90
104
  checkForDuplicateScaleNames(view);
91
-
92
105
  if (view instanceof UnitView) {
93
106
  view.mark.initializeEncoders();
94
107
  } else if (view instanceof ContainerView) {
@@ -99,7 +112,7 @@ export async function createAndInitialize(spec, viewClass) {
99
112
  });
100
113
  }
101
114
 
102
- await initializeData(view, view.context.dataFlow);
103
- reconfigureScales(view);
115
+ const { dataSources } = initializeViewSubtree(view, view.context.dataFlow);
116
+ await loadViewSubtreeData(view, dataSources);
104
117
  return view;
105
118
  }