@genome-spy/core 0.78.0 → 0.79.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 (292) hide show
  1. package/dist/bundle/{browser-KWU9rWZT.js → browser-CETrb2cm.js} +53 -33
  2. package/dist/bundle/esm-BdLYkz-m.js +248 -0
  3. package/dist/bundle/esm-BwiDsqSb.js +1367 -0
  4. package/dist/bundle/esm-CDFd1cjk.js +441 -0
  5. package/dist/bundle/{esm-DVOHLB1e.js → esm-CTUHLDbv.js} +30 -30
  6. package/dist/bundle/{esm-NIYEaYkc.js → esm-Cx-EbkOj.js} +13 -13
  7. package/dist/bundle/esm-DlYGqi79.js +128 -0
  8. package/dist/bundle/{esm-BygJiwh0.js → esm-k9p3oHkt.js} +133 -158
  9. package/dist/bundle/{esm-CT3ygiMq.js → esm-zAZJQO6D.js} +226 -212
  10. package/dist/bundle/index.es.js +14879 -11656
  11. package/dist/bundle/index.js +119 -108
  12. package/dist/bundle/{parquetRead-DG_-F5j5.js → parquetRead-Cad1SOVV.js} +473 -399
  13. package/dist/schema.json +18940 -6914
  14. package/dist/src/config/axisConfig.d.ts +2 -2
  15. package/dist/src/config/axisConfig.d.ts.map +1 -1
  16. package/dist/src/config/axisConfig.js +28 -44
  17. package/dist/src/config/configLayers.d.ts +45 -0
  18. package/dist/src/config/configLayers.d.ts.map +1 -0
  19. package/dist/src/config/configLayers.js +110 -0
  20. package/dist/src/config/defaultConfig.d.ts.map +1 -1
  21. package/dist/src/config/defaultConfig.js +8 -1
  22. package/dist/src/config/defaults/legendDefaults.d.ts +14 -0
  23. package/dist/src/config/defaults/legendDefaults.d.ts.map +1 -0
  24. package/dist/src/config/defaults/legendDefaults.js +46 -0
  25. package/dist/src/config/defaults/titleDefaults.d.ts.map +1 -1
  26. package/dist/src/config/defaults/titleDefaults.js +26 -18
  27. package/dist/src/config/legendConfig.d.ts +11 -0
  28. package/dist/src/config/legendConfig.d.ts.map +1 -0
  29. package/dist/src/config/legendConfig.js +63 -0
  30. package/dist/src/config/styleUtils.d.ts +8 -2
  31. package/dist/src/config/styleUtils.d.ts.map +1 -1
  32. package/dist/src/config/styleUtils.js +25 -1
  33. package/dist/src/config/themes.d.ts.map +1 -1
  34. package/dist/src/config/themes.js +21 -2
  35. package/dist/src/config/titleConfig.d.ts.map +1 -1
  36. package/dist/src/config/titleConfig.js +2 -18
  37. package/dist/src/data/collector.d.ts.map +1 -1
  38. package/dist/src/data/collector.js +40 -18
  39. package/dist/src/data/flowInit.d.ts +6 -0
  40. package/dist/src/data/flowInit.d.ts.map +1 -1
  41. package/dist/src/data/flowInit.js +1 -1
  42. package/dist/src/data/flowNode.d.ts +32 -0
  43. package/dist/src/data/flowNode.d.ts.map +1 -1
  44. package/dist/src/data/flowNode.js +59 -0
  45. package/dist/src/data/sources/lazy/bamSource.d.ts +0 -1
  46. package/dist/src/data/sources/lazy/bamSource.d.ts.map +1 -1
  47. package/dist/src/data/sources/lazy/bamSource.js +39 -30
  48. package/dist/src/data/sources/lazy/bigBedSource.d.ts +0 -10
  49. package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
  50. package/dist/src/data/sources/lazy/bigBedSource.js +127 -62
  51. package/dist/src/data/sources/lazy/bigWigSource.d.ts +2 -2
  52. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  53. package/dist/src/data/sources/lazy/bigWigSource.js +234 -81
  54. package/dist/src/data/sources/lazy/gff3Source.d.ts +7 -3
  55. package/dist/src/data/sources/lazy/gff3Source.d.ts.map +1 -1
  56. package/dist/src/data/sources/lazy/gff3Source.js +7 -8
  57. package/dist/src/data/sources/lazy/indexedFastaSource.d.ts +1 -1
  58. package/dist/src/data/sources/lazy/indexedFastaSource.d.ts.map +1 -1
  59. package/dist/src/data/sources/lazy/indexedFastaSource.js +28 -19
  60. package/dist/src/data/sources/lazy/legendEntriesSource.d.ts +24 -0
  61. package/dist/src/data/sources/lazy/legendEntriesSource.d.ts.map +1 -0
  62. package/dist/src/data/sources/lazy/legendEntriesSource.js +218 -0
  63. package/dist/src/data/sources/lazy/legendGradientSource.d.ts +30 -0
  64. package/dist/src/data/sources/lazy/legendGradientSource.d.ts.map +1 -0
  65. package/dist/src/data/sources/lazy/legendGradientSource.js +388 -0
  66. package/dist/src/data/sources/lazy/mockLazySource.d.ts +4 -1
  67. package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -1
  68. package/dist/src/data/sources/lazy/mockLazySource.js +49 -4
  69. package/dist/src/data/sources/lazy/registerCoreLazySources.js +2 -0
  70. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  71. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +3 -4
  72. package/dist/src/data/sources/lazy/tabixSource.d.ts +9 -4
  73. package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
  74. package/dist/src/data/sources/lazy/tabixSource.js +201 -70
  75. package/dist/src/data/sources/lazy/tabixTsvSource.d.ts +2 -3
  76. package/dist/src/data/sources/lazy/tabixTsvSource.d.ts.map +1 -1
  77. package/dist/src/data/sources/lazy/tabixTsvSource.js +14 -12
  78. package/dist/src/data/sources/lazy/vcfSource.d.ts +7 -3
  79. package/dist/src/data/sources/lazy/vcfSource.d.ts.map +1 -1
  80. package/dist/src/data/sources/lazy/vcfSource.js +7 -8
  81. package/dist/src/data/sources/urlDescriptor.d.ts +165 -0
  82. package/dist/src/data/sources/urlDescriptor.d.ts.map +1 -0
  83. package/dist/src/data/sources/urlDescriptor.js +473 -0
  84. package/dist/src/data/sources/urlDescriptorController.d.ts +25 -0
  85. package/dist/src/data/sources/urlDescriptorController.d.ts.map +1 -0
  86. package/dist/src/data/sources/urlDescriptorController.js +72 -0
  87. package/dist/src/data/sources/urlDescriptorState.d.ts +47 -0
  88. package/dist/src/data/sources/urlDescriptorState.d.ts.map +1 -0
  89. package/dist/src/data/sources/urlDescriptorState.js +129 -0
  90. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  91. package/dist/src/data/sources/urlSource.js +101 -61
  92. package/dist/src/data/transforms/packLegendLabels.d.ts +21 -0
  93. package/dist/src/data/transforms/packLegendLabels.d.ts.map +1 -0
  94. package/dist/src/data/transforms/packLegendLabels.js +189 -0
  95. package/dist/src/data/transforms/transformFactory.d.ts.map +1 -1
  96. package/dist/src/data/transforms/transformFactory.js +4 -0
  97. package/dist/src/data/transforms/truncateText.d.ts +27 -0
  98. package/dist/src/data/transforms/truncateText.d.ts.map +1 -0
  99. package/dist/src/data/transforms/truncateText.js +94 -0
  100. package/dist/src/debug/dataflowDebugSnapshot.d.ts +58 -0
  101. package/dist/src/debug/dataflowDebugSnapshot.d.ts.map +1 -0
  102. package/dist/src/debug/dataflowDebugSnapshot.js +159 -0
  103. package/dist/src/debug/markDebugSnapshot.d.ts +54 -0
  104. package/dist/src/debug/markDebugSnapshot.d.ts.map +1 -0
  105. package/dist/src/debug/markDebugSnapshot.js +100 -0
  106. package/dist/src/debug/paramDebugSnapshot.d.ts +53 -0
  107. package/dist/src/debug/paramDebugSnapshot.d.ts.map +1 -0
  108. package/dist/src/debug/paramDebugSnapshot.js +86 -0
  109. package/dist/src/debug/resolutionDebugSnapshot.d.ts +155 -0
  110. package/dist/src/debug/resolutionDebugSnapshot.d.ts.map +1 -0
  111. package/dist/src/debug/resolutionDebugSnapshot.js +291 -0
  112. package/dist/src/debug/valuePreview.d.ts +9 -0
  113. package/dist/src/debug/valuePreview.d.ts.map +1 -0
  114. package/dist/src/debug/valuePreview.js +57 -0
  115. package/dist/src/debug/viewDebugSnapshot.d.ts +131 -0
  116. package/dist/src/debug/viewDebugSnapshot.d.ts.map +1 -0
  117. package/dist/src/debug/viewDebugSnapshot.js +390 -0
  118. package/dist/src/embedFactory.d.ts.map +1 -1
  119. package/dist/src/embedFactory.js +6 -1
  120. package/dist/src/encoder/encoder.d.ts +2 -2
  121. package/dist/src/encoder/encoder.d.ts.map +1 -1
  122. package/dist/src/encoder/encoder.js +5 -4
  123. package/dist/src/fonts/bmFontManager.d.ts +1 -1
  124. package/dist/src/fonts/bmFontManager.d.ts.map +1 -1
  125. package/dist/src/fonts/bmFontManager.js +45 -10
  126. package/dist/src/fonts/textMetrics.d.ts +69 -0
  127. package/dist/src/fonts/textMetrics.d.ts.map +1 -0
  128. package/dist/src/fonts/textMetrics.js +73 -0
  129. package/dist/src/genomeSpy/headlessBootstrap.d.ts.map +1 -1
  130. package/dist/src/genomeSpy/headlessBootstrap.js +6 -0
  131. package/dist/src/genomeSpy/renderCoordinator.d.ts.map +1 -1
  132. package/dist/src/genomeSpy/renderCoordinator.js +25 -3
  133. package/dist/src/genomeSpy/viewDataInit.d.ts +14 -0
  134. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
  135. package/dist/src/genomeSpy/viewDataInit.js +45 -8
  136. package/dist/src/genomeSpyBase.d.ts +6 -0
  137. package/dist/src/genomeSpyBase.d.ts.map +1 -1
  138. package/dist/src/genomeSpyBase.js +20 -3
  139. package/dist/src/gl/glslScaleGenerator.d.ts +17 -0
  140. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
  141. package/dist/src/gl/glslScaleGenerator.js +39 -2
  142. package/dist/src/gl/includes/common.glsl.js +1 -1
  143. package/dist/src/gl/vertexRangeIndex.d.ts.map +1 -1
  144. package/dist/src/gl/vertexRangeIndex.js +4 -2
  145. package/dist/src/gl/webGLHelper.d.ts +1 -1
  146. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  147. package/dist/src/gl/webGLHelper.js +13 -8
  148. package/dist/src/marks/__snapshots__/shaderSnapshot.test.js.snap +140 -3
  149. package/dist/src/marks/mark.d.ts +47 -4
  150. package/dist/src/marks/mark.d.ts.map +1 -1
  151. package/dist/src/marks/mark.js +158 -54
  152. package/dist/src/marks/point.d.ts.map +1 -1
  153. package/dist/src/marks/point.js +4 -0
  154. package/dist/src/marks/point.vertex.glsl.js +1 -1
  155. package/dist/src/marks/text.d.ts +1 -1
  156. package/dist/src/marks/text.d.ts.map +1 -1
  157. package/dist/src/marks/text.js +2 -7
  158. package/dist/src/marks/text.vertex.glsl.js +1 -1
  159. package/dist/src/paramRuntime/paramUtils.d.ts +43 -9
  160. package/dist/src/paramRuntime/paramUtils.d.ts.map +1 -1
  161. package/dist/src/paramRuntime/paramUtils.js +61 -1
  162. package/dist/src/paramRuntime/viewParamRuntime.d.ts +32 -0
  163. package/dist/src/paramRuntime/viewParamRuntime.d.ts.map +1 -1
  164. package/dist/src/paramRuntime/viewParamRuntime.js +63 -0
  165. package/dist/src/scales/axisResolution.d.ts +35 -0
  166. package/dist/src/scales/axisResolution.d.ts.map +1 -1
  167. package/dist/src/scales/axisResolution.js +115 -7
  168. package/dist/src/scales/legendResolution.d.ts +83 -0
  169. package/dist/src/scales/legendResolution.d.ts.map +1 -0
  170. package/dist/src/scales/legendResolution.js +461 -0
  171. package/dist/src/scales/scaleResolution.d.ts +36 -0
  172. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  173. package/dist/src/scales/scaleResolution.js +59 -0
  174. package/dist/src/scales/viewLevelGuideConfig.d.ts +53 -0
  175. package/dist/src/scales/viewLevelGuideConfig.d.ts.map +1 -0
  176. package/dist/src/scales/viewLevelGuideConfig.js +224 -0
  177. package/dist/src/scales/viewLevelScaleConfig.d.ts.map +1 -1
  178. package/dist/src/scales/viewLevelScaleConfig.js +13 -2
  179. package/dist/src/spec/axis.d.ts +109 -3
  180. package/dist/src/spec/channel.d.ts +23 -4
  181. package/dist/src/spec/config.d.ts +59 -4
  182. package/dist/src/spec/data.d.ts +177 -17
  183. package/dist/src/spec/legend.d.ts +246 -0
  184. package/dist/src/spec/mark.d.ts +16 -4
  185. package/dist/src/spec/title.d.ts +58 -1
  186. package/dist/src/spec/transform.d.ts +149 -0
  187. package/dist/src/spec/view.d.ts +39 -6
  188. package/dist/src/types/embedApi.d.ts +262 -6
  189. package/dist/src/types/rendering.d.ts +19 -3
  190. package/dist/src/types/viewContext.d.ts +18 -2
  191. package/dist/src/utils/arrayUtils.d.ts +11 -0
  192. package/dist/src/utils/arrayUtils.d.ts.map +1 -1
  193. package/dist/src/utils/arrayUtils.js +23 -0
  194. package/dist/src/utils/suspension.d.ts +17 -0
  195. package/dist/src/utils/suspension.d.ts.map +1 -0
  196. package/dist/src/utils/suspension.js +41 -0
  197. package/dist/src/view/axisGridView.d.ts.map +1 -1
  198. package/dist/src/view/axisGridView.js +1 -4
  199. package/dist/src/view/axisView.d.ts +18 -2
  200. package/dist/src/view/axisView.d.ts.map +1 -1
  201. package/dist/src/view/axisView.js +180 -75
  202. package/dist/src/view/concatView.d.ts +10 -2
  203. package/dist/src/view/concatView.d.ts.map +1 -1
  204. package/dist/src/view/concatView.js +46 -9
  205. package/dist/src/view/containerMutationHelper.d.ts +20 -1
  206. package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
  207. package/dist/src/view/containerMutationHelper.js +196 -33
  208. package/dist/src/view/facetView.d.ts +1 -1
  209. package/dist/src/view/gridView/gridChild.d.ts +54 -4
  210. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  211. package/dist/src/view/gridView/gridChild.js +301 -120
  212. package/dist/src/view/gridView/gridChildLegends.d.ts +57 -0
  213. package/dist/src/view/gridView/gridChildLegends.d.ts.map +1 -0
  214. package/dist/src/view/gridView/gridChildLegends.js +503 -0
  215. package/dist/src/view/gridView/gridView.d.ts +25 -0
  216. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  217. package/dist/src/view/gridView/gridView.js +490 -78
  218. package/dist/src/view/gridView/legendLayout.d.ts +30 -0
  219. package/dist/src/view/gridView/legendLayout.d.ts.map +1 -0
  220. package/dist/src/view/gridView/legendLayout.js +115 -0
  221. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
  222. package/dist/src/view/gridView/scrollbar.js +1 -4
  223. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  224. package/dist/src/view/gridView/selectionRect.js +1 -4
  225. package/dist/src/view/gridView/separatorView.d.ts.map +1 -1
  226. package/dist/src/view/gridView/separatorView.js +1 -4
  227. package/dist/src/view/layerView.d.ts +9 -2
  228. package/dist/src/view/layerView.d.ts.map +1 -1
  229. package/dist/src/view/layerView.js +18 -1
  230. package/dist/src/view/layout/flexLayout.d.ts +20 -4
  231. package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
  232. package/dist/src/view/layout/flexLayout.js +331 -31
  233. package/dist/src/view/layout/rectangle.d.ts +14 -0
  234. package/dist/src/view/layout/rectangle.d.ts.map +1 -1
  235. package/dist/src/view/layout/rectangle.js +40 -0
  236. package/dist/src/view/legend/legendEntries.d.ts +20 -0
  237. package/dist/src/view/legend/legendEntries.d.ts.map +1 -0
  238. package/dist/src/view/legend/legendEntries.js +21 -0
  239. package/dist/src/view/legendView.d.ts +137 -0
  240. package/dist/src/view/legendView.d.ts.map +1 -0
  241. package/dist/src/view/legendView.js +1654 -0
  242. package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts.map +1 -1
  243. package/dist/src/view/renderingContext/bufferedViewRenderingContext.js +26 -4
  244. package/dist/src/view/renderingContext/clipOptions.d.ts +44 -0
  245. package/dist/src/view/renderingContext/clipOptions.d.ts.map +1 -0
  246. package/dist/src/view/renderingContext/clipOptions.js +140 -0
  247. package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts.map +1 -1
  248. package/dist/src/view/renderingContext/simpleViewRenderingContext.js +12 -1
  249. package/dist/src/view/resolutionPlanner.d.ts +2 -1
  250. package/dist/src/view/resolutionPlanner.d.ts.map +1 -1
  251. package/dist/src/view/resolutionPlanner.js +89 -25
  252. package/dist/src/view/testUtils.d.ts +4 -2
  253. package/dist/src/view/testUtils.d.ts.map +1 -1
  254. package/dist/src/view/testUtils.js +60 -7
  255. package/dist/src/view/titleView.d.ts +37 -0
  256. package/dist/src/view/titleView.d.ts.map +1 -0
  257. package/dist/src/view/titleView.js +584 -0
  258. package/dist/src/view/unitView.d.ts +3 -3
  259. package/dist/src/view/unitView.d.ts.map +1 -1
  260. package/dist/src/view/unitView.js +3 -2
  261. package/dist/src/view/view.d.ts +25 -24
  262. package/dist/src/view/view.d.ts.map +1 -1
  263. package/dist/src/view/view.js +126 -16
  264. package/dist/src/view/viewChrome.d.ts +33 -0
  265. package/dist/src/view/viewChrome.d.ts.map +1 -0
  266. package/dist/src/view/viewChrome.js +64 -0
  267. package/dist/src/view/viewFactory.d.ts +2 -5
  268. package/dist/src/view/viewFactory.d.ts.map +1 -1
  269. package/dist/src/view/viewFactory.js +1 -2
  270. package/dist/src/view/viewIdentityRegistry.d.ts +37 -0
  271. package/dist/src/view/viewIdentityRegistry.d.ts.map +1 -0
  272. package/dist/src/view/viewIdentityRegistry.js +71 -0
  273. package/dist/src/view/viewMutationAcidTestUtils.d.ts +112 -0
  274. package/dist/src/view/viewMutationAcidTestUtils.d.ts.map +1 -0
  275. package/dist/src/view/viewMutationAcidTestUtils.js +234 -0
  276. package/dist/src/view/viewMutationApi.d.ts +42 -0
  277. package/dist/src/view/viewMutationApi.d.ts.map +1 -0
  278. package/dist/src/view/viewMutationApi.js +811 -0
  279. package/dist/src/view/viewSelectors.d.ts +11 -9
  280. package/dist/src/view/viewSelectors.d.ts.map +1 -1
  281. package/dist/src/view/viewSelectors.js +28 -17
  282. package/package.json +4 -4
  283. package/dist/bundle/esm-CuMSzCHy.js +0 -298
  284. package/dist/bundle/esm-DAnOffpD.js +0 -1426
  285. package/dist/bundle/esm-DMXpJXM4.js +0 -369
  286. package/dist/bundle/esm-DNtC3H80.js +0 -121
  287. package/dist/src/view/title.d.ts +0 -13
  288. package/dist/src/view/title.d.ts.map +0 -1
  289. package/dist/src/view/title.js +0 -154
  290. /package/dist/bundle/{AbortablePromiseCache-3gHJdF3E.js → AbortablePromiseCache-BTmAcN-t.js} +0 -0
  291. /package/dist/bundle/{esm-CuVa5T98.js → esm-VvpZ9hsq.js} +0 -0
  292. /package/dist/bundle/{chunk-DmhlhrBa.js → rolldown-runtime-Dy4uBu1J.js} +0 -0
@@ -2,19 +2,28 @@ import {
2
2
  activateExprRefProps,
3
3
  withoutExprRef,
4
4
  } from "../../../paramRuntime/paramUtils.js";
5
- import addBaseUrl from "../../../utils/addBaseUrl.js";
5
+ import { createDescriptorFieldAttacher } from "../urlDescriptor.js";
6
+ import UrlDescriptorController from "../urlDescriptorController.js";
7
+ import UrlDescriptorState, {
8
+ updateUrlDescriptorState,
9
+ } from "../urlDescriptorState.js";
6
10
  import { registerBuiltInLazyDataSource } from "./lazyDataSourceRegistry.js";
7
11
  import SingleAxisWindowedSource from "./singleAxisWindowedSource.js";
8
12
 
9
13
  export default class BigBedSource extends SingleAxisWindowedSource {
10
- /** @type {import("@gmod/bed").default} */
11
- parser;
14
+ /**
15
+ * @typedef {object} BigBedHandle
16
+ * @prop {(datum: Record<string, any>) => Record<string, any>} attachFields
17
+ * @prop {import("@gmod/bbi").BigBed} bbi
18
+ * @prop {(chrom: string, fields: { start: number, end: number, rest?: string }) => Record<string, any>} parseLine
19
+ * @prop {string} url
20
+ */
12
21
 
13
- /** @type {import("@gmod/bbi").BigBed} */
14
- bbi;
22
+ /** @type {UrlDescriptorState<BigBedHandle>} */
23
+ #descriptorState = new UrlDescriptorState();
15
24
 
16
- /** @type {(chrom: string, fields: { start: number, end: number, rest?: string }) => Record<string, any>} */
17
- parseLine;
25
+ /** @type {UrlDescriptorController} */
26
+ #urlDescriptors;
18
27
 
19
28
  /**
20
29
  * @param {import("../../../spec/data.js").BigBedData} params
@@ -38,7 +47,7 @@ export default class BigBedSource extends SingleAxisWindowedSource {
38
47
  paramsWithDefaults,
39
48
  (props) => {
40
49
  if (props.has("url")) {
41
- this.#initialize().then(() => this.reloadLastDomain());
50
+ this.#reloadIfCurrentDomainNeedsData();
42
51
  } else if (props.has("windowSize")) {
43
52
  this.reloadLastDomain();
44
53
  }
@@ -47,6 +56,11 @@ export default class BigBedSource extends SingleAxisWindowedSource {
47
56
  { batchMode: "whenPropagated" }
48
57
  );
49
58
 
59
+ this.#urlDescriptors = new UrlDescriptorController(this, {
60
+ getUrl: () => this.params.url,
61
+ onChange: () => this.#reloadIfCurrentDomainNeedsData(),
62
+ });
63
+
50
64
  if (!this.params.url) {
51
65
  throw new Error("No URL provided for BigBedSource");
52
66
  }
@@ -61,78 +75,120 @@ export default class BigBedSource extends SingleAxisWindowedSource {
61
75
  }
62
76
 
63
77
  #initialize() {
64
- this.initializedPromise = new Promise((resolve, reject) => {
65
- Promise.all([
66
- import("@gmod/bed"),
67
- import("@gmod/bbi"),
68
- import("generic-filehandle2"),
69
- ]).then(([bed, { BigBed }, { RemoteFile }]) => {
70
- const BED = bed.default;
71
-
72
- this.bbi = new BigBed({
73
- filehandle: new RemoteFile(
74
- addBaseUrl(
75
- withoutExprRef(this.params.url),
76
- this.view.getBaseUrl()
77
- )
78
- ),
79
- });
80
-
81
- this.setLoadingStatus("loading");
82
- this.bbi
83
- .getHeader()
84
- .then(async (header) => {
85
- // @ts-ignore TODO: Fix
86
- this.parser = new BED({ autoSql: header.autoSql });
87
- try {
88
- const fastParser = makeFastParser(this.parser);
89
- this.parseLine = (chrom, f) =>
90
- fastParser(chrom, f.start, f.end, f.rest);
91
- } catch {
92
- this.parseLine = (chrom, f) =>
93
- this.parser.parseLine(
94
- `${chrom}\t${f.start}\t${f.end}\t${f.rest}`
95
- );
96
- }
97
-
98
- this.setLoadingStatus("complete");
99
- resolve();
100
- })
101
- .catch((e) => {
102
- // Load empty data
103
- this.load();
104
- this.setLoadingStatus(
105
- "error",
106
- `${withoutExprRef(this.params.url)}: ${e.message}`
107
- );
108
- reject(e);
109
- });
110
- });
78
+ const initializePromise = this.#doInitialize();
79
+ this.initializedPromise = initializePromise;
80
+ return initializePromise;
81
+ }
82
+
83
+ /**
84
+ * Refreshes active descriptors and reloads the current domain only if the
85
+ * current loaded data does not cover the new active descriptor set.
86
+ */
87
+ async #reloadIfCurrentDomainNeedsData() {
88
+ try {
89
+ await this.#initialize();
90
+
91
+ if (
92
+ !this.isDataReadyForDomain({
93
+ [this.channel]: this.scaleResolution.getDomain(),
94
+ })
95
+ ) {
96
+ this.reloadLastDomain();
97
+ }
98
+ } catch {
99
+ // Initialization has already updated the loading status.
100
+ }
101
+ }
102
+
103
+ async #doInitialize() {
104
+ await updateUrlDescriptorState({
105
+ controller: this.#urlDescriptors,
106
+ state: this.#descriptorState,
107
+ clearData: () => this.load(),
108
+ setLoadingStatus: (status, detail) =>
109
+ this.setLoadingStatus(status, detail),
110
+ loadModules: loadBigBedModules,
111
+ createHandle: (descriptor, { BigBed, RemoteFile, BED }) =>
112
+ this.#createHandle(descriptor, BigBed, RemoteFile, BED),
113
+ });
114
+ }
115
+
116
+ /**
117
+ * @param {import("../urlDescriptor.js").UrlDescriptor} descriptor
118
+ * @param {typeof import("@gmod/bbi").BigBed} BigBed
119
+ * @param {typeof import("generic-filehandle2").RemoteFile} RemoteFile
120
+ * @param {typeof import("@gmod/bed").default} BED
121
+ * @returns {Promise<BigBedHandle>}
122
+ */
123
+ async #createHandle(descriptor, BigBed, RemoteFile, BED) {
124
+ const bbi = new BigBed({
125
+ filehandle: new RemoteFile(descriptor.url),
111
126
  });
127
+ const header = await bbi.getHeader();
128
+
129
+ // @ts-ignore TODO: Fix
130
+ const parser = new BED({ autoSql: header.autoSql });
131
+ /** @type {BigBedHandle["parseLine"]} */
132
+ let parseLine;
133
+ try {
134
+ const fastParser = makeFastParser(parser);
135
+ parseLine = (chrom, f) => fastParser(chrom, f.start, f.end, f.rest);
136
+ } catch {
137
+ parseLine = (chrom, f) =>
138
+ parser.parseLine(`${chrom}\t${f.start}\t${f.end}\t${f.rest}`);
139
+ }
112
140
 
113
- return this.initializedPromise;
141
+ return {
142
+ attachFields: createDescriptorFieldAttacher(descriptor.fields),
143
+ bbi,
144
+ parseLine,
145
+ url: descriptor.url,
146
+ };
114
147
  }
115
148
 
116
149
  /**
117
150
  * @param {number[]} interval linearized domain
118
151
  */
119
152
  async loadInterval(interval) {
153
+ const handles = this.#descriptorState.handles;
120
154
  const features = await this.discretizeAndLoad(
121
155
  interval,
122
156
  async (d, signal) =>
123
- this.bbi
124
- .getFeatures(d.chrom, d.startPos, d.endPos, {
125
- signal,
126
- })
127
- .then((features) =>
128
- features.map((f) => this.parseLine(d.chrom, f))
157
+ (
158
+ await Promise.all(
159
+ handles.map((handle) =>
160
+ handle.bbi
161
+ .getFeatures(d.chrom, d.startPos, d.endPos, {
162
+ signal,
163
+ })
164
+ .then((features) =>
165
+ features.map((f) =>
166
+ handle.attachFields(
167
+ handle.parseLine(d.chrom, f)
168
+ )
169
+ )
170
+ )
171
+ )
129
172
  )
173
+ ).flat()
130
174
  );
131
175
 
132
176
  if (features) {
133
177
  this.publishData(features);
178
+ this.#descriptorState.markLoaded();
134
179
  }
135
180
  }
181
+
182
+ /**
183
+ * @param {import("./singleAxisLazySource.js").DataReadinessRequest} request
184
+ * @returns {boolean}
185
+ */
186
+ isDataReadyForDomain(request) {
187
+ return (
188
+ this.#descriptorState.activeSetLoaded &&
189
+ super.isDataReadyForDomain(request)
190
+ );
191
+ }
136
192
  }
137
193
 
138
194
  /**
@@ -310,6 +366,15 @@ function isBigBedSource(params) {
310
366
 
311
367
  registerBuiltInLazyDataSource(isBigBedSource, BigBedSource);
312
368
 
369
+ async function loadBigBedModules() {
370
+ const [bed, { BigBed }, { RemoteFile }] = await Promise.all([
371
+ import("@gmod/bed"),
372
+ import("@gmod/bbi"),
373
+ import("generic-filehandle2"),
374
+ ]);
375
+ return { BigBed, RemoteFile, BED: bed.default };
376
+ }
377
+
313
378
  /**
314
379
  * @param {T[]} arr
315
380
  * @param {number} size
@@ -16,9 +16,9 @@ export default class BigWigSource extends SingleAxisWindowedSource {
16
16
  onDomainChanged(domain: number[]): Promise<void>;
17
17
  /**
18
18
  * @param {number[]} interval linearized domain
19
- * @param {number} reductionLevel
19
+ * @param {number[]} selectedReductionLevels
20
20
  */
21
- loadInterval(interval: number[], reductionLevel: number): Promise<void>;
21
+ loadInterval(interval: number[], selectedReductionLevels: number[]): Promise<void>;
22
22
  #private;
23
23
  }
24
24
  import SingleAxisWindowedSource from "./singleAxisWindowedSource.js";
@@ -1 +1 @@
1
- {"version":3,"file":"bigWigSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/bigWigSource.js"],"names":[],"mappings":"AAQA;;GAEG;AACH;IAOI;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,UAAU,QAC1C,OAAO,uBAAuB,EAAE,OAAO,EAoCjD;IArBG,mDAYC;IA+DL;;;;OAIG;IACH,wBAFW,MAAM,EAAE,iBAqBlB;IAED;;;OAGG;IAEH,uBAJW,MAAM,EAAE,kBACR,MAAM,iBAkChB;;CACJ;qCAvKoC,+BAA+B"}
1
+ {"version":3,"file":"bigWigSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/bigWigSource.js"],"names":[],"mappings":"AAYA;;GAEG;AACH;IAeI;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,UAAU,QAC1C,OAAO,uBAAuB,EAAE,OAAO,EAyCjD;IA1BG,mDAYC;IA+FL;;;;OAIG;IACH,wBAFW,MAAM,EAAE,iBA+BlB;IAED;;;OAGG;IAEH,uBAJW,MAAM,EAAE,2BACR,MAAM,EAAE,iBAqBlB;;CA8FJ;qCA9SoC,+BAA+B"}
@@ -2,19 +2,31 @@ import {
2
2
  activateExprRefProps,
3
3
  withoutExprRef,
4
4
  } from "../../../paramRuntime/paramUtils.js";
5
- import addBaseUrl from "../../../utils/addBaseUrl.js";
6
5
  import { registerBuiltInLazyDataSource } from "./lazyDataSourceRegistry.js";
7
6
  import SingleAxisWindowedSource from "./singleAxisWindowedSource.js";
7
+ import { createDescriptorFieldAttacher } from "../urlDescriptor.js";
8
+ import UrlDescriptorController from "../urlDescriptorController.js";
9
+ import UrlDescriptorState, {
10
+ updateUrlDescriptorState,
11
+ } from "../urlDescriptorState.js";
8
12
 
9
13
  /**
10
14
  *
11
15
  */
12
16
  export default class BigWigSource extends SingleAxisWindowedSource {
13
- /** @type {number[]} */
14
- #reductionLevels = [];
17
+ /**
18
+ * @typedef {object} BigWigHandle
19
+ * @prop {import("@gmod/bbi").BigWig} bbi
20
+ * @prop {(datum: Record<string, any>) => Record<string, any>} attachFields
21
+ * @prop {number[]} reductionLevels
22
+ * @prop {string} url
23
+ */
24
+
25
+ /** @type {UrlDescriptorState<BigWigHandle>} */
26
+ #descriptorState = new UrlDescriptorState();
15
27
 
16
- /** @type {import("@gmod/bbi").BigWig} */
17
- #bbi;
28
+ /** @type {UrlDescriptorController} */
29
+ #urlDescriptors;
18
30
 
19
31
  /**
20
32
  * @param {import("../../../spec/data.js").BigWigData} params
@@ -38,7 +50,7 @@ export default class BigWigSource extends SingleAxisWindowedSource {
38
50
  paramsWithDefaults,
39
51
  (props) => {
40
52
  if (props.has("url")) {
41
- this.#initialize().then(() => this.reloadLastDomain());
53
+ this.#reloadIfCurrentDomainNeedsData();
42
54
  } else if (props.has("pixelsPerBin")) {
43
55
  this.reloadLastDomain();
44
56
  }
@@ -47,6 +59,11 @@ export default class BigWigSource extends SingleAxisWindowedSource {
47
59
  { batchMode: "whenPropagated" }
48
60
  );
49
61
 
62
+ this.#urlDescriptors = new UrlDescriptorController(this, {
63
+ getUrl: () => this.params.url,
64
+ onChange: () => this.#reloadIfCurrentDomainNeedsData(),
65
+ });
66
+
50
67
  if (!this.params.url) {
51
68
  throw new Error("No URL provided for BigWigSource");
52
69
  }
@@ -60,52 +77,79 @@ export default class BigWigSource extends SingleAxisWindowedSource {
60
77
  return "bigWigSource";
61
78
  }
62
79
 
80
+ /**
81
+ * @returns {Promise<void>}
82
+ */
63
83
  #initialize() {
64
- this.initializedPromise = new Promise((resolve, reject) => {
65
- Promise.all([
66
- import("@gmod/bbi"),
67
- import("generic-filehandle2"),
68
- ]).then(([{ BigWig }, { RemoteFile }]) => {
69
- this.#bbi = new BigWig({
70
- filehandle: new RemoteFile(
71
- addBaseUrl(
72
- withoutExprRef(this.params.url),
73
- this.view.getBaseUrl()
74
- )
75
- ),
76
- });
77
-
78
- this.setLoadingStatus("loading");
79
- this.#bbi
80
- .getHeader()
81
- .then((header) => {
82
- this.#reductionLevels =
83
- /** @type {{reductionLevel: number}[]} */ (
84
- header.zoomLevels
85
- )
86
- .map((z) => z.reductionLevel)
87
- .reverse();
88
-
89
- // Add the non-reduced level. Not sure if this is the best way to do it.
90
- // Afaik, the non-reduced bin size is not available in the header.
91
- this.#reductionLevels.push(1);
92
-
93
- this.setLoadingStatus("complete");
94
- resolve();
95
- })
96
- .catch((e) => {
97
- // Load empty data
98
- this.load();
99
- this.setLoadingStatus(
100
- "error",
101
- `${withoutExprRef(this.params.url)}: ${e.message}`
102
- );
103
- reject(e);
104
- });
105
- });
84
+ const initializePromise = this.#doInitialize();
85
+ this.initializedPromise = initializePromise;
86
+ return initializePromise;
87
+ }
88
+
89
+ /**
90
+ * Refreshes active descriptors and reloads the current domain only if the
91
+ * current loaded data does not cover the new active descriptor set.
92
+ */
93
+ async #reloadIfCurrentDomainNeedsData() {
94
+ try {
95
+ await this.#initialize();
96
+
97
+ if (
98
+ !this.isDataReadyForDomain({
99
+ [this.channel]: this.scaleResolution.getDomain(),
100
+ })
101
+ ) {
102
+ this.reloadLastDomain();
103
+ }
104
+ } catch {
105
+ // Initialization has already updated the loading status.
106
+ }
107
+ }
108
+
109
+ /**
110
+ * @returns {Promise<void>}
111
+ */
112
+ async #doInitialize() {
113
+ await updateUrlDescriptorState({
114
+ controller: this.#urlDescriptors,
115
+ state: this.#descriptorState,
116
+ clearData: () => this.load(),
117
+ setLoadingStatus: (status, detail) =>
118
+ this.setLoadingStatus(status, detail),
119
+ loadModules: loadBigWigModules,
120
+ createHandle: (descriptor, { BigWig, RemoteFile }) =>
121
+ this.#createHandle(descriptor, BigWig, RemoteFile),
106
122
  });
123
+ }
107
124
 
108
- return this.initializedPromise;
125
+ /**
126
+ * @param {import("../urlDescriptor.js").UrlDescriptor} descriptor
127
+ * @param {typeof import("@gmod/bbi").BigWig} BigWig
128
+ * @param {typeof import("generic-filehandle2").RemoteFile} RemoteFile
129
+ * @returns {Promise<BigWigHandle>}
130
+ */
131
+ async #createHandle(descriptor, BigWig, RemoteFile) {
132
+ const bbi = new BigWig({
133
+ filehandle: new RemoteFile(descriptor.url),
134
+ });
135
+ const header = await bbi.getHeader();
136
+ const reductionLevels = /** @type {{reductionLevel: number}[]} */ (
137
+ header.zoomLevels
138
+ )
139
+ .map((z) => z.reductionLevel)
140
+ .reverse();
141
+
142
+ // Add the non-reduced level. Not sure if this is the best way to do it.
143
+ // Afaik, the non-reduced bin size is not available in the header.
144
+ reductionLevels.push(1);
145
+
146
+ const handle = {
147
+ bbi,
148
+ attachFields: createDescriptorFieldAttacher(descriptor.fields),
149
+ reductionLevels,
150
+ url: descriptor.url,
151
+ };
152
+ return handle;
109
153
  }
110
154
 
111
155
  /**
@@ -116,42 +160,116 @@ export default class BigWigSource extends SingleAxisWindowedSource {
116
160
  async onDomainChanged(domain) {
117
161
  await this.initializedPromise;
118
162
 
163
+ const handles = this.#descriptorState.handles;
164
+ if (!handles.length) {
165
+ this.publishData([]);
166
+ this.#descriptorState.markLoaded();
167
+ return;
168
+ }
169
+
119
170
  // TODO: Postpone the initial load until layout is computed and remove 700.
120
171
  const length = this.scaleResolution.getAxisLength() || 700;
121
172
 
122
- const reductionLevel = findReductionLevel(
123
- domain,
124
- length,
125
- this.#reductionLevels
173
+ const selectedReductionLevels = handles.map((handle) =>
174
+ findReductionLevel(domain, length, handle.reductionLevels)
126
175
  );
127
176
 
128
177
  // The sensible minimum window size actually depends on the non-reduced data density...
129
178
  // Using 5000 as a default to avoid too many requests.
130
- const windowSize = Math.max(reductionLevel * length, 5000);
179
+ const windowSize = Math.max(
180
+ ...selectedReductionLevels.map(
181
+ (reductionLevel) => reductionLevel * length
182
+ ),
183
+ 5000
184
+ );
131
185
 
132
186
  this.callIfWindowsChanged(domain, windowSize, (quantizedInterval) =>
133
- this.loadInterval(quantizedInterval, reductionLevel)
187
+ this.loadInterval(quantizedInterval, selectedReductionLevels)
134
188
  );
135
189
  }
136
190
 
137
191
  /**
138
192
  * @param {number[]} interval linearized domain
139
- * @param {number} reductionLevel
193
+ * @param {number[]} selectedReductionLevels
140
194
  */
141
195
  // @ts-expect-error
142
- async loadInterval(interval, reductionLevel) {
143
- const scale =
144
- 1 / 2 / reductionLevel / withoutExprRef(this.params.pixelsPerBin);
196
+ async loadInterval(interval, selectedReductionLevels) {
197
+ const handles = this.#descriptorState.handles;
145
198
  const featureChunks = await this.discretizeAndLoad(interval, {
146
199
  load: (d, signal) =>
147
- this.#bbi
148
- .getFeatures(d.chrom, d.startPos, d.endPos, {
149
- scale,
150
- signal,
151
- })
152
- .then((features) => mapFeatures(d.chrom, features)),
200
+ this.#loadFeatures(d, handles, selectedReductionLevels, signal),
153
201
  loadBatch: (intervals, signal) =>
154
- this.#bbi
202
+ this.#loadFeatureBatches(
203
+ intervals,
204
+ handles,
205
+ selectedReductionLevels,
206
+ signal
207
+ ),
208
+ });
209
+
210
+ if (featureChunks) {
211
+ this.publishData(featureChunks);
212
+ this.#descriptorState.markLoaded();
213
+ }
214
+ }
215
+
216
+ /**
217
+ * @param {import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval} interval
218
+ * @param {BigWigHandle[]} handles
219
+ * @param {number[]} selectedReductionLevels
220
+ * @param {AbortSignal} signal
221
+ */
222
+ async #loadFeatures(interval, handles, selectedReductionLevels, signal) {
223
+ const featuresByHandle = await Promise.all(
224
+ handles.map((handle, i) => {
225
+ const scale = bigWigScale(
226
+ selectedReductionLevels[i],
227
+ withoutExprRef(this.params.pixelsPerBin)
228
+ );
229
+
230
+ return handle.bbi
231
+ .getFeatures(
232
+ interval.chrom,
233
+ interval.startPos,
234
+ interval.endPos,
235
+ {
236
+ scale,
237
+ signal,
238
+ }
239
+ )
240
+ .then((features) =>
241
+ mapFeatures(
242
+ interval.chrom,
243
+ features,
244
+ handle.attachFields
245
+ )
246
+ );
247
+ })
248
+ );
249
+
250
+ return featuresByHandle.flat();
251
+ }
252
+
253
+ /**
254
+ * @param {import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval[]} intervals
255
+ * @param {BigWigHandle[]} handles
256
+ * @param {number[]} selectedReductionLevels
257
+ * @param {AbortSignal} signal
258
+ */
259
+ async #loadFeatureBatches(
260
+ intervals,
261
+ handles,
262
+ selectedReductionLevels,
263
+ signal
264
+ ) {
265
+ const chunksByHandle = await Promise.all(
266
+ handles.map((handle, handleIndex) => {
267
+ const scale = bigWigScale(
268
+ selectedReductionLevels[handleIndex],
269
+ withoutExprRef(this.params.pixelsPerBin)
270
+ );
271
+
272
+ return handle.bbi
155
273
  .getFeaturesMulti(
156
274
  intervals.map((d) => ({
157
275
  refName: d.chrom,
@@ -160,16 +278,32 @@ export default class BigWigSource extends SingleAxisWindowedSource {
160
278
  })),
161
279
  { scale, signal }
162
280
  )
163
- .then((featureChunks) =>
164
- featureChunks.map((features, i) =>
165
- mapFeatures(intervals[i].chrom, features)
281
+ .then((chunks) =>
282
+ chunks.map((features, intervalIndex) =>
283
+ mapFeatures(
284
+ intervals[intervalIndex].chrom,
285
+ features,
286
+ handle.attachFields
287
+ )
166
288
  )
167
- ),
168
- });
289
+ );
290
+ })
291
+ );
169
292
 
170
- if (featureChunks) {
171
- this.publishData(featureChunks);
172
- }
293
+ return intervals.map((_, intervalIndex) =>
294
+ chunksByHandle.flatMap((chunks) => chunks[intervalIndex])
295
+ );
296
+ }
297
+
298
+ /**
299
+ * @param {import("./singleAxisLazySource.js").DataReadinessRequest} request
300
+ * @returns {boolean}
301
+ */
302
+ isDataReadyForDomain(request) {
303
+ return (
304
+ this.#descriptorState.activeSetLoaded &&
305
+ super.isDataReadyForDomain(request)
306
+ );
173
307
  }
174
308
  }
175
309
 
@@ -183,17 +317,28 @@ function isBigWigSource(params) {
183
317
 
184
318
  registerBuiltInLazyDataSource(isBigWigSource, BigWigSource);
185
319
 
320
+ async function loadBigWigModules() {
321
+ const [{ BigWig }, { RemoteFile }] = await Promise.all([
322
+ import("@gmod/bbi"),
323
+ import("generic-filehandle2"),
324
+ ]);
325
+ return { BigWig, RemoteFile };
326
+ }
327
+
186
328
  /**
187
329
  * @param {string} chrom
188
330
  * @param {import("@gmod/bbi").Feature[]} features
331
+ * @param {(datum: Record<string, any>) => Record<string, any>} attachFields
189
332
  */
190
- function mapFeatures(chrom, features) {
191
- return features.map((f) => ({
192
- chrom,
193
- start: f.start,
194
- end: f.end,
195
- score: f.score,
196
- }));
333
+ function mapFeatures(chrom, features, attachFields) {
334
+ return features.map((f) =>
335
+ attachFields({
336
+ chrom,
337
+ start: f.start,
338
+ end: f.end,
339
+ score: f.score,
340
+ })
341
+ );
197
342
  }
198
343
 
199
344
  /**
@@ -207,3 +352,11 @@ function findReductionLevel(domain, widthInPixels, reductionLevels) {
207
352
  reductionLevels.find((r) => r < bpPerPixel) ?? reductionLevels.at(-1)
208
353
  );
209
354
  }
355
+
356
+ /**
357
+ * @param {number} reductionLevel
358
+ * @param {number} pixelsPerBin
359
+ */
360
+ function bigWigScale(reductionLevel, pixelsPerBin) {
361
+ return 1 / 2 / reductionLevel / pixelsPerBin;
362
+ }