@genome-spy/core 0.65.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 (232) hide show
  1. package/dist/bundle/browser-BRemItdO.js +138 -0
  2. package/dist/bundle/{index-CD7FLu9x.js → index-BatuyGAI.js} +23 -21
  3. package/dist/bundle/{index-C0llXMqm.js → index-ByuE8dvu.js} +140 -88
  4. package/dist/bundle/index-Cq3QFUxX.js +1781 -0
  5. package/dist/bundle/index-D28m8tSW.js +1607 -0
  6. package/dist/bundle/index-DbJ0oeYM.js +631 -0
  7. package/dist/bundle/index.es.js +17587 -16593
  8. package/dist/bundle/index.js +214 -212
  9. package/dist/bundle/{inflate-DRgHi_KK.js → inflate-GtwLkvSP.js} +222 -224
  10. package/dist/bundle/unzip-NywezaRR.js +1492 -0
  11. package/dist/schema.json +13 -3
  12. package/dist/src/config/scaleDefaults.d.ts +8 -0
  13. package/dist/src/config/scaleDefaults.d.ts.map +1 -0
  14. package/dist/src/config/scaleDefaults.js +45 -0
  15. package/dist/src/data/flowInit.js +2 -2
  16. package/dist/src/data/sources/lazy/axisTickSource.js +1 -1
  17. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +1 -1
  18. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  19. package/dist/src/data/sources/lazy/singleAxisLazySource.js +10 -3
  20. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  21. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +5 -1
  22. package/dist/src/data/transforms/filterScoredLabels.d.ts +1 -1
  23. package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
  24. package/dist/src/data/transforms/filterScoredLabels.js +1 -1
  25. package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts.map +1 -1
  26. package/dist/src/data/transforms/linearizeGenomicCoordinate.js +2 -1
  27. package/dist/src/encoder/encoder.d.ts +1 -1
  28. package/dist/src/encoder/encoder.d.ts.map +1 -1
  29. package/dist/src/encoder/encoder.js +1 -1
  30. package/dist/src/genome/scaleLocus.d.ts +39 -0
  31. package/dist/src/genome/scaleLocus.d.ts.map +1 -1
  32. package/dist/src/genome/scaleLocus.js +76 -0
  33. package/dist/src/genomeSpy/canvasExport.d.ts +19 -0
  34. package/dist/src/genomeSpy/canvasExport.d.ts.map +1 -0
  35. package/dist/src/genomeSpy/canvasExport.js +66 -0
  36. package/dist/src/genomeSpy/containerUi.d.ts +17 -0
  37. package/dist/src/genomeSpy/containerUi.d.ts.map +1 -0
  38. package/dist/src/genomeSpy/containerUi.js +78 -0
  39. package/dist/src/genomeSpy/eventListenerRegistry.d.ts +19 -0
  40. package/dist/src/genomeSpy/eventListenerRegistry.d.ts.map +1 -0
  41. package/dist/src/genomeSpy/eventListenerRegistry.js +38 -0
  42. package/dist/src/genomeSpy/inputBindingManager.d.ts +14 -0
  43. package/dist/src/genomeSpy/inputBindingManager.d.ts.map +1 -0
  44. package/dist/src/genomeSpy/inputBindingManager.js +63 -0
  45. package/dist/src/genomeSpy/interactionController.d.ts +40 -0
  46. package/dist/src/genomeSpy/interactionController.d.ts.map +1 -0
  47. package/dist/src/genomeSpy/interactionController.js +371 -0
  48. package/dist/src/genomeSpy/keyboardListenerManager.d.ts +10 -0
  49. package/dist/src/genomeSpy/keyboardListenerManager.d.ts.map +1 -0
  50. package/dist/src/genomeSpy/keyboardListenerManager.js +31 -0
  51. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +15 -0
  52. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -0
  53. package/dist/src/genomeSpy/loadingIndicatorManager.js +92 -0
  54. package/dist/src/genomeSpy/renderCoordinator.d.ts +22 -0
  55. package/dist/src/genomeSpy/renderCoordinator.d.ts.map +1 -0
  56. package/dist/src/genomeSpy/renderCoordinator.js +118 -0
  57. package/dist/src/genomeSpy/viewContextFactory.d.ts +18 -0
  58. package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -0
  59. package/dist/src/genomeSpy/viewContextFactory.js +79 -0
  60. package/dist/src/genomeSpy/viewDataInit.d.ts +12 -0
  61. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -0
  62. package/dist/src/genomeSpy/viewDataInit.js +41 -0
  63. package/dist/src/genomeSpy/viewHierarchyConfig.d.ts +14 -0
  64. package/dist/src/genomeSpy/viewHierarchyConfig.d.ts.map +1 -0
  65. package/dist/src/genomeSpy/viewHierarchyConfig.js +24 -0
  66. package/dist/src/genomeSpy/viewHighlight.d.ts +5 -0
  67. package/dist/src/genomeSpy/viewHighlight.d.ts.map +1 -0
  68. package/dist/src/genomeSpy/viewHighlight.js +30 -0
  69. package/dist/src/genomeSpy.d.ts +16 -71
  70. package/dist/src/genomeSpy.d.ts.map +1 -1
  71. package/dist/src/genomeSpy.js +179 -745
  72. package/dist/src/gl/glslScaleGenerator.d.ts +1 -1
  73. package/dist/src/gl/webGLHelper.d.ts +2 -2
  74. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  75. package/dist/src/gl/webGLHelper.js +4 -4
  76. package/dist/src/index.d.ts.map +1 -1
  77. package/dist/src/index.js +2 -12
  78. package/dist/src/marks/mark.d.ts.map +1 -1
  79. package/dist/src/marks/mark.js +4 -2
  80. package/dist/src/{view → scales}/axisResolution.d.ts +9 -16
  81. package/dist/src/scales/axisResolution.d.ts.map +1 -0
  82. package/dist/src/{view → scales}/axisResolution.js +29 -18
  83. package/dist/src/scales/axisResolution.test.d.ts.map +1 -0
  84. package/dist/src/scales/scaleDomainAggregator.d.ts +57 -0
  85. package/dist/src/scales/scaleDomainAggregator.d.ts.map +1 -0
  86. package/dist/src/scales/scaleDomainAggregator.js +162 -0
  87. package/dist/src/scales/scaleDomainAggregator.test.d.ts +2 -0
  88. package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +1 -0
  89. package/dist/src/scales/scaleInstanceManager.d.ts +40 -0
  90. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -0
  91. package/dist/src/scales/scaleInstanceManager.js +313 -0
  92. package/dist/src/scales/scaleInstanceManager.test.d.ts +2 -0
  93. package/dist/src/scales/scaleInstanceManager.test.d.ts.map +1 -0
  94. package/dist/src/scales/scaleInteractionController.d.ts +73 -0
  95. package/dist/src/scales/scaleInteractionController.d.ts.map +1 -0
  96. package/dist/src/scales/scaleInteractionController.js +336 -0
  97. package/dist/src/scales/scaleInteractionController.test.d.ts +2 -0
  98. package/dist/src/scales/scaleInteractionController.test.d.ts.map +1 -0
  99. package/dist/src/scales/scalePropsResolver.d.ts +23 -0
  100. package/dist/src/scales/scalePropsResolver.d.ts.map +1 -0
  101. package/dist/src/scales/scalePropsResolver.js +74 -0
  102. package/dist/src/{view → scales}/scaleResolution.d.ts +52 -35
  103. package/dist/src/scales/scaleResolution.d.ts.map +1 -0
  104. package/dist/src/scales/scaleResolution.js +658 -0
  105. package/dist/src/scales/scaleResolution.test.d.ts.map +1 -0
  106. package/dist/src/scales/scaleResolutionConstants.d.ts +6 -0
  107. package/dist/src/scales/scaleResolutionConstants.d.ts.map +1 -0
  108. package/dist/src/scales/scaleResolutionConstants.js +5 -0
  109. package/dist/src/scales/scaleRules.d.ts +16 -0
  110. package/dist/src/scales/scaleRules.d.ts.map +1 -0
  111. package/dist/src/scales/scaleRules.js +103 -0
  112. package/dist/src/scales/scaleRules.test.d.ts +2 -0
  113. package/dist/src/scales/scaleRules.test.d.ts.map +1 -0
  114. package/dist/src/spec/channel.d.ts +13 -18
  115. package/dist/src/spec/scale.d.ts +6 -0
  116. package/dist/src/types/embedApi.d.ts +5 -0
  117. package/dist/src/types/scaleResolutionApi.d.ts +1 -1
  118. package/dist/src/view/concatView.d.ts +18 -0
  119. package/dist/src/view/concatView.d.ts.map +1 -1
  120. package/dist/src/view/concatView.js +73 -0
  121. package/dist/src/view/concatView.test.d.ts +2 -0
  122. package/dist/src/view/concatView.test.d.ts.map +1 -0
  123. package/dist/src/view/containerMutationHelper.d.ts +74 -0
  124. package/dist/src/view/containerMutationHelper.d.ts.map +1 -0
  125. package/dist/src/view/containerMutationHelper.js +114 -0
  126. package/dist/src/view/containerView.d.ts +0 -7
  127. package/dist/src/view/containerView.d.ts.map +1 -1
  128. package/dist/src/view/containerView.js +0 -10
  129. package/dist/src/view/facetView.d.ts.map +1 -1
  130. package/dist/src/view/facetView.js +0 -15
  131. package/dist/src/view/gridView/gridChild.d.ts +11 -0
  132. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  133. package/dist/src/view/gridView/gridChild.js +32 -6
  134. package/dist/src/view/gridView/gridView.d.ts +39 -1
  135. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  136. package/dist/src/view/gridView/gridView.js +106 -48
  137. package/dist/src/view/gridView/gridView.test.d.ts +2 -0
  138. package/dist/src/view/gridView/gridView.test.d.ts.map +1 -0
  139. package/dist/src/view/gridView/scrollbar.d.ts +39 -8
  140. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
  141. package/dist/src/view/gridView/scrollbar.js +184 -69
  142. package/dist/src/view/layerView.d.ts +14 -0
  143. package/dist/src/view/layerView.d.ts.map +1 -1
  144. package/dist/src/view/layerView.js +66 -0
  145. package/dist/src/view/layerView.test.d.ts +2 -0
  146. package/dist/src/view/layerView.test.d.ts.map +1 -0
  147. package/dist/src/view/testUtils.d.ts.map +1 -1
  148. package/dist/src/view/testUtils.js +2 -1
  149. package/dist/src/view/unitView.d.ts.map +1 -1
  150. package/dist/src/view/unitView.js +24 -34
  151. package/dist/src/view/view.d.ts +6 -6
  152. package/dist/src/view/view.d.ts.map +1 -1
  153. package/dist/src/view/view.js +4 -4
  154. package/package.json +2 -2
  155. package/dist/bundle/browser-txUcLy2H.js +0 -123
  156. package/dist/bundle/index-BQpbYrv4.js +0 -1712
  157. package/dist/bundle/index-BhtHKLUo.js +0 -73
  158. package/dist/bundle/index-CCe8rnZz.js +0 -716
  159. package/dist/bundle/index-DhcU-Gk-.js +0 -1487
  160. package/dist/src/data/collector.test.js +0 -138
  161. package/dist/src/data/dataFlow.test.js +0 -38
  162. package/dist/src/data/flow.test.js +0 -81
  163. package/dist/src/data/flowInit.test.js +0 -413
  164. package/dist/src/data/flowNode.test.js +0 -50
  165. package/dist/src/data/flowOptimizer.test.js +0 -209
  166. package/dist/src/data/formats/fasta.test.js +0 -27
  167. package/dist/src/data/sources/inlineSource.test.js +0 -63
  168. package/dist/src/data/sources/sequenceSource.test.js +0 -81
  169. package/dist/src/data/transforms/aggregate.test.js +0 -134
  170. package/dist/src/data/transforms/clone.test.js +0 -11
  171. package/dist/src/data/transforms/coverage.test.js +0 -238
  172. package/dist/src/data/transforms/filter.test.js +0 -20
  173. package/dist/src/data/transforms/flatten.test.js +0 -96
  174. package/dist/src/data/transforms/flattenDelimited.test.js +0 -90
  175. package/dist/src/data/transforms/flattenSequence.test.js +0 -34
  176. package/dist/src/data/transforms/formula.test.js +0 -25
  177. package/dist/src/data/transforms/identifier.test.js +0 -92
  178. package/dist/src/data/transforms/pileup.test.js +0 -70
  179. package/dist/src/data/transforms/project.test.js +0 -32
  180. package/dist/src/data/transforms/regexExtract.test.js +0 -70
  181. package/dist/src/data/transforms/regexFold.test.js +0 -201
  182. package/dist/src/data/transforms/sample.test.js +0 -38
  183. package/dist/src/data/transforms/stack.test.js +0 -91
  184. package/dist/src/encoder/accessor.test.js +0 -162
  185. package/dist/src/encoder/encoder.test.js +0 -105
  186. package/dist/src/genome/genome.test.js +0 -268
  187. package/dist/src/genome/genomes.test.js +0 -8
  188. package/dist/src/genome/scaleIndex.test.js +0 -78
  189. package/dist/src/genome/scaleLocus.test.js +0 -4
  190. package/dist/src/scale/scale.test.js +0 -326
  191. package/dist/src/scale/ticks.test.js +0 -46
  192. package/dist/src/selection/selection.test.js +0 -14
  193. package/dist/src/utils/addBaseUrl.test.js +0 -30
  194. package/dist/src/utils/binnedIndex.test.js +0 -201
  195. package/dist/src/utils/cloner.test.js +0 -35
  196. package/dist/src/utils/coalesce.test.js +0 -16
  197. package/dist/src/utils/concatIterables.test.js +0 -8
  198. package/dist/src/utils/domainArray.test.js +0 -130
  199. package/dist/src/utils/indexer.test.js +0 -49
  200. package/dist/src/utils/interactionEvent.test.js +0 -35
  201. package/dist/src/utils/iterateNestedMaps.test.js +0 -33
  202. package/dist/src/utils/kWayMerge.test.js +0 -30
  203. package/dist/src/utils/mergeObjects.test.js +0 -42
  204. package/dist/src/utils/numberExtractor.test.js +0 -6
  205. package/dist/src/utils/propertyCacher.test.js +0 -89
  206. package/dist/src/utils/propertyCoalescer.test.js +0 -25
  207. package/dist/src/utils/radixSort.test.js +0 -51
  208. package/dist/src/utils/reservationMap.test.js +0 -20
  209. package/dist/src/utils/ringBuffer.test.js +0 -39
  210. package/dist/src/utils/topK.test.js +0 -54
  211. package/dist/src/utils/trees.test.js +0 -135
  212. package/dist/src/utils/url.test.js +0 -28
  213. package/dist/src/utils/variableTools.test.js +0 -13
  214. package/dist/src/view/axisResolution.d.ts.map +0 -1
  215. package/dist/src/view/axisResolution.test.d.ts.map +0 -1
  216. package/dist/src/view/axisResolution.test.js +0 -206
  217. package/dist/src/view/flowBuilder.test.js +0 -125
  218. package/dist/src/view/gridView/selectionRect.test.js +0 -87
  219. package/dist/src/view/layout/flexLayout.test.js +0 -323
  220. package/dist/src/view/layout/grid.test.js +0 -71
  221. package/dist/src/view/layout/rectangle.test.js +0 -192
  222. package/dist/src/view/paramMediator.test.js +0 -282
  223. package/dist/src/view/scaleResolution.d.ts.map +0 -1
  224. package/dist/src/view/scaleResolution.js +0 -1059
  225. package/dist/src/view/scaleResolution.test.d.ts.map +0 -1
  226. package/dist/src/view/scaleResolution.test.js +0 -645
  227. package/dist/src/view/view.test.js +0 -245
  228. package/dist/src/view/viewDispose.test.js +0 -110
  229. package/dist/src/view/viewFactory.test.js +0 -25
  230. package/dist/src/view/viewUtils.test.js +0 -87
  231. /package/dist/src/{view → scales}/axisResolution.test.d.ts +0 -0
  232. /package/dist/src/{view → scales}/scaleResolution.test.d.ts +0 -0
@@ -0,0 +1,38 @@
1
+ export default class EventListenerRegistry {
2
+ /** @type {Map<string, Set<(event: any) => void>>} */
3
+ #listeners;
4
+
5
+ constructor() {
6
+ this.#listeners = new Map();
7
+ }
8
+
9
+ /**
10
+ * @param {string} type
11
+ * @param {(event: any) => void} listener
12
+ */
13
+ add(type, listener) {
14
+ let listeners = this.#listeners.get(type);
15
+ if (!listeners) {
16
+ listeners = new Set();
17
+ this.#listeners.set(type, listeners);
18
+ }
19
+
20
+ listeners.add(listener);
21
+ }
22
+
23
+ /**
24
+ * @param {string} type
25
+ * @param {(event: any) => void} listener
26
+ */
27
+ remove(type, listener) {
28
+ this.#listeners.get(type)?.delete(listener);
29
+ }
30
+
31
+ /**
32
+ * @param {string} type
33
+ * @param {any} event
34
+ */
35
+ emit(type, event) {
36
+ this.#listeners.get(type)?.forEach((listener) => listener(event));
37
+ }
38
+ }
@@ -0,0 +1,14 @@
1
+ export default class InputBindingManager {
2
+ /**
3
+ * @param {HTMLElement} container
4
+ * @param {import("../types/embedApi.js").EmbedOptions} options
5
+ */
6
+ constructor(container: HTMLElement, options: import("../types/embedApi.js").EmbedOptions);
7
+ /**
8
+ * @param {import("../view/view.js").default} viewRoot
9
+ */
10
+ initialize(viewRoot: import("../view/view.js").default): void;
11
+ remove(): void;
12
+ #private;
13
+ }
14
+ //# sourceMappingURL=inputBindingManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputBindingManager.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/inputBindingManager.js"],"names":[],"mappings":"AAIA;IAQI;;;OAGG;IACH,uBAHW,WAAW,WACX,OAAO,sBAAsB,EAAE,YAAY,EAOrD;IAED;;OAEG;IACH,qBAFW,OAAO,iBAAiB,EAAE,OAAO,QAiC3C;IAED,eAEC;;CACJ"}
@@ -0,0 +1,63 @@
1
+ import { html, render } from "lit";
2
+
3
+ import createBindingInputs from "../utils/inputBinding.js";
4
+
5
+ export default class InputBindingManager {
6
+ /** @type {HTMLElement} */
7
+ #container;
8
+ /** @type {import("../types/embedApi.js").EmbedOptions} */
9
+ #options;
10
+ /** @type {HTMLElement} */
11
+ #inputBindingContainer;
12
+
13
+ /**
14
+ * @param {HTMLElement} container
15
+ * @param {import("../types/embedApi.js").EmbedOptions} options
16
+ */
17
+ constructor(container, options) {
18
+ this.#container = container;
19
+ this.#options = options;
20
+
21
+ this.#inputBindingContainer = undefined;
22
+ }
23
+
24
+ /**
25
+ * @param {import("../view/view.js").default} viewRoot
26
+ */
27
+ initialize(viewRoot) {
28
+ /** @type {import("lit").TemplateResult[]} */
29
+ const inputs = [];
30
+
31
+ viewRoot.visit((view) => {
32
+ const mediator = view.paramMediator;
33
+ inputs.push(...createBindingInputs(mediator));
34
+ });
35
+ const ibc = this.#options.inputBindingContainer;
36
+
37
+ if (!ibc || ibc == "none" || !inputs.length) {
38
+ return;
39
+ }
40
+
41
+ this.#inputBindingContainer = document.createElement("div");
42
+ this.#inputBindingContainer.className = "gs-input-bindings";
43
+
44
+ if (ibc == "default") {
45
+ this.#container.appendChild(this.#inputBindingContainer);
46
+ } else if (ibc instanceof HTMLElement) {
47
+ ibc.appendChild(this.#inputBindingContainer);
48
+ } else {
49
+ throw new Error("Invalid inputBindingContainer");
50
+ }
51
+
52
+ if (inputs.length) {
53
+ render(
54
+ html`<div class="gs-input-binding">${inputs}</div>`,
55
+ this.#inputBindingContainer
56
+ );
57
+ }
58
+ }
59
+
60
+ remove() {
61
+ this.#inputBindingContainer?.remove();
62
+ }
63
+ }
@@ -0,0 +1,40 @@
1
+ export default class InteractionController {
2
+ /**
3
+ * @param {object} options
4
+ * @param {import("../view/view.js").default} options.viewRoot
5
+ * @param {import("../gl/webGLHelper.js").default} options.glHelper
6
+ * @param {import("../utils/ui/tooltip.js").default} options.tooltip
7
+ * @param {import("../utils/animator.js").default} options.animator
8
+ * @param {(type: string, event: any) => void} options.emitEvent
9
+ * @param {Record<string, import("../tooltip/tooltipHandler.js").TooltipHandler>} options.tooltipHandlers
10
+ * @param {() => void} options.renderPickingFramebuffer
11
+ * @param {() => number} options.getDevicePixelRatio
12
+ */
13
+ constructor({ viewRoot, glHelper, tooltip, animator, emitEvent, tooltipHandlers, renderPickingFramebuffer, getDevicePixelRatio, }: {
14
+ viewRoot: import("../view/view.js").default;
15
+ glHelper: import("../gl/webGLHelper.js").default;
16
+ tooltip: import("../utils/ui/tooltip.js").default;
17
+ animator: import("../utils/animator.js").default;
18
+ emitEvent: (type: string, event: any) => void;
19
+ tooltipHandlers: Record<string, import("../tooltip/tooltipHandler.js").TooltipHandler>;
20
+ renderPickingFramebuffer: () => void;
21
+ getDevicePixelRatio: () => number;
22
+ });
23
+ getCurrentHover(): {
24
+ mark: import("../marks/mark.js").default;
25
+ datum: import("../data/flowNode.js").Datum;
26
+ uniqueId: number;
27
+ };
28
+ registerMouseEvents(): void;
29
+ /**
30
+ * This method should be called in a mouseMove handler. If not called, the
31
+ * tooltip will be hidden.
32
+ *
33
+ * @param {T} datum
34
+ * @param {function(T):Promise<string | HTMLElement | import("lit").TemplateResult>} [converter]
35
+ * @template T
36
+ */
37
+ updateTooltip<T>(datum: T, converter?: (arg0: T) => Promise<string | HTMLElement | import("lit").TemplateResult>): void;
38
+ #private;
39
+ }
40
+ //# sourceMappingURL=interactionController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactionController.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/interactionController.js"],"names":[],"mappings":"AAQA;IA2BI;;;;;;;;;;OAUG;IACH,mIATG;QAAmD,QAAQ,EAAnD,OAAO,iBAAiB,EAAE,OAAO;QACe,QAAQ,EAAxD,OAAO,sBAAsB,EAAE,OAAO;QACY,OAAO,EAAzD,OAAO,wBAAwB,EAAE,OAAO;QACQ,QAAQ,EAAxD,OAAO,sBAAsB,EAAE,OAAO;QACM,SAAS,EAArD,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI;QAC6C,eAAe,EAA9F,MAAM,CAAC,MAAM,EAAE,OAAO,8BAA8B,EAAE,cAAc,CAAC;QACjD,wBAAwB,EAA5C,MAAM,IAAI;QACY,mBAAmB,EAAzC,MAAM,MAAM;KACtB,EAgCA;IAED;cArDkB,OAAO,kBAAkB,EAAE,OAAO;eAAS,OAAO,qBAAqB,EAAE,KAAK;kBAAY,MAAM;MAuDjH;IAED,4BAgMC;IA6ED;;;;;;;OAOG;IACH,cAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAYlF;;CACJ"}
@@ -0,0 +1,371 @@
1
+ import UnitView from "../view/unitView.js";
2
+ import { VISIT_STOP } from "../view/view.js";
3
+ import { readPickingPixel } from "../gl/webGLHelper.js";
4
+ import InteractionEvent from "../utils/interactionEvent.js";
5
+ import Inertia, { makeEventTemplate } from "../utils/inertia.js";
6
+ import Point from "../view/layout/point.js";
7
+ import { isStillZooming } from "../view/zoom.js";
8
+
9
+ export default class InteractionController {
10
+ /** @type {import("../view/view.js").default} */
11
+ #viewRoot;
12
+ /** @type {import("../gl/webGLHelper.js").default} */
13
+ #glHelper;
14
+ /** @type {import("../utils/ui/tooltip.js").default} */
15
+ #tooltip;
16
+ /** @type {import("../utils/animator.js").default} */
17
+ #animator;
18
+ /** @type {(type: string, event: any) => void} */
19
+ #emitEvent;
20
+ /** @type {Record<string, import("../tooltip/tooltipHandler.js").TooltipHandler>} */
21
+ #tooltipHandlers;
22
+ /** @type {() => void} */
23
+ #renderPickingFramebuffer;
24
+ /** @type {() => number} */
25
+ #getDevicePixelRatio;
26
+ /**
27
+ * @type {{ mark: import("../marks/mark.js").default, datum: import("../data/flowNode.js").Datum, uniqueId: number }}
28
+ */
29
+ #currentHover;
30
+ /** @type {Inertia} */
31
+ #wheelInertia;
32
+ /** @type {Point} */
33
+ #mouseDownCoords;
34
+ /** @type {boolean} */
35
+ #tooltipUpdateRequested;
36
+ /**
37
+ * @param {object} options
38
+ * @param {import("../view/view.js").default} options.viewRoot
39
+ * @param {import("../gl/webGLHelper.js").default} options.glHelper
40
+ * @param {import("../utils/ui/tooltip.js").default} options.tooltip
41
+ * @param {import("../utils/animator.js").default} options.animator
42
+ * @param {(type: string, event: any) => void} options.emitEvent
43
+ * @param {Record<string, import("../tooltip/tooltipHandler.js").TooltipHandler>} options.tooltipHandlers
44
+ * @param {() => void} options.renderPickingFramebuffer
45
+ * @param {() => number} options.getDevicePixelRatio
46
+ */
47
+ constructor({
48
+ viewRoot,
49
+ glHelper,
50
+ tooltip,
51
+ animator,
52
+ emitEvent,
53
+ tooltipHandlers,
54
+ renderPickingFramebuffer,
55
+ getDevicePixelRatio,
56
+ }) {
57
+ this.#viewRoot = viewRoot;
58
+ this.#glHelper = glHelper;
59
+ this.#tooltip = tooltip;
60
+ this.#animator = animator;
61
+ this.#emitEvent = emitEvent;
62
+ this.#tooltipHandlers = tooltipHandlers;
63
+ this.#renderPickingFramebuffer = renderPickingFramebuffer;
64
+ this.#getDevicePixelRatio = getDevicePixelRatio;
65
+
66
+ /**
67
+ * Currently hovered mark and datum
68
+ * @type {{ mark: import("../marks/mark.js").default, datum: import("../data/flowNode.js").Datum, uniqueId: number }}
69
+ */
70
+ this.#currentHover = undefined;
71
+
72
+ this.#wheelInertia = new Inertia(this.#animator);
73
+
74
+ /** @type {Point} */
75
+ this.#mouseDownCoords = undefined;
76
+
77
+ this.#tooltipUpdateRequested = false;
78
+ }
79
+
80
+ getCurrentHover() {
81
+ return this.#currentHover;
82
+ }
83
+
84
+ registerMouseEvents() {
85
+ const canvas = this.#glHelper.canvas;
86
+
87
+ let lastWheelEvent = performance.now();
88
+ let longPressTriggered = false;
89
+
90
+ /** @param {Event} event */
91
+ const listener = (event) => {
92
+ const now = performance.now();
93
+ const wheeling = now - lastWheelEvent < 200;
94
+
95
+ if (event instanceof MouseEvent) {
96
+ const rect = canvas.getBoundingClientRect();
97
+ const point = new Point(
98
+ event.clientX - rect.left - canvas.clientLeft,
99
+ event.clientY - rect.top - canvas.clientTop
100
+ );
101
+
102
+ if (event.type == "mousemove" && !wheeling) {
103
+ this.#tooltip.handleMouseMove(event);
104
+ this.#tooltipUpdateRequested = false;
105
+
106
+ // Disable picking during dragging. Also postpone picking until
107
+ // the user has stopped zooming as reading pixels from the
108
+ // picking buffer is slow and ruins smooth animations.
109
+ if (event.buttons == 0 && !isStillZooming()) {
110
+ this.#renderPickingFramebuffer();
111
+ this.#handlePicking(point.x, point.y);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * @param {MouseEvent} dispatchedEvent
117
+ */
118
+ const dispatchEvent = (dispatchedEvent) => {
119
+ this.#viewRoot.propagateInteractionEvent(
120
+ new InteractionEvent(point, dispatchedEvent)
121
+ );
122
+
123
+ if (!this.#tooltipUpdateRequested) {
124
+ this.#tooltip.clear();
125
+ }
126
+ };
127
+
128
+ if (event.type != "wheel") {
129
+ this.#wheelInertia.cancel();
130
+ }
131
+
132
+ if (
133
+ (event.type == "mousedown" || event.type == "mouseup") &&
134
+ !isStillZooming()
135
+ ) {
136
+ // Actually, only needed when clicking on a mark
137
+ this.#renderPickingFramebuffer();
138
+ } else if (event.type == "wheel") {
139
+ lastWheelEvent = now;
140
+ this.#tooltipUpdateRequested = false;
141
+
142
+ const wheelEvent = /** @type {WheelEvent} */ (event);
143
+
144
+ if (
145
+ Math.abs(wheelEvent.deltaX) >
146
+ Math.abs(wheelEvent.deltaY)
147
+ ) {
148
+ // If the viewport is panned (horizontally) using the wheel (touchpad),
149
+ // the picking buffer becomes stale and needs redrawing. However, we
150
+ // optimize by just clearing the currently hovered item so that snapping
151
+ // doesn't work incorrectly when zooming in/out.
152
+
153
+ // TODO: More robust solution (handle at higher level such as ScaleResolution's zoom method)
154
+ this.#currentHover = null;
155
+
156
+ this.#wheelInertia.cancel();
157
+ } else {
158
+ // Vertical wheeling zooms.
159
+ // We use inertia to generate fake wheel events for smoother zooming
160
+
161
+ const template = makeEventTemplate(wheelEvent);
162
+
163
+ this.#wheelInertia.setMomentum(
164
+ wheelEvent.deltaY * (wheelEvent.deltaMode ? 80 : 1),
165
+ (delta) => {
166
+ const e = new WheelEvent("wheel", {
167
+ ...template,
168
+ deltaMode: 0,
169
+ deltaX: 0,
170
+ deltaY: delta,
171
+ });
172
+ dispatchEvent(e);
173
+ }
174
+ );
175
+
176
+ wheelEvent.preventDefault();
177
+ return;
178
+ }
179
+ }
180
+
181
+ // TODO: Should be handled at the view level, not globally
182
+ if (event.type == "click") {
183
+ if (longPressTriggered) {
184
+ return;
185
+ }
186
+
187
+ const e = this.#currentHover
188
+ ? {
189
+ type: event.type,
190
+ viewPath: this.#currentHover.mark.unitView
191
+ .getLayoutAncestors()
192
+ .map(
193
+ /** @param {import("../view/view.js").default} view */
194
+ (view) => view.name
195
+ )
196
+ .reverse(),
197
+ datum: this.#currentHover.datum,
198
+ }
199
+ : {
200
+ type: event.type,
201
+ viewPath: null,
202
+ datum: null,
203
+ };
204
+
205
+ this.#emitEvent("click", e);
206
+ }
207
+
208
+ if (
209
+ event.type != "click" ||
210
+ // Suppress click events if the mouse has been dragged
211
+ this.#mouseDownCoords?.subtract(Point.fromMouseEvent(event))
212
+ .length < 3
213
+ ) {
214
+ dispatchEvent(event);
215
+ }
216
+ }
217
+ };
218
+
219
+ [
220
+ "mousedown",
221
+ "mouseup",
222
+ "wheel",
223
+ "click",
224
+ "mousemove",
225
+ "gesturechange",
226
+ "contextmenu",
227
+ "dblclick",
228
+ ].forEach((type) => canvas.addEventListener(type, listener));
229
+
230
+ canvas.addEventListener("mousedown", (/** @type {MouseEvent} */ e) => {
231
+ this.#mouseDownCoords = Point.fromMouseEvent(e);
232
+ if (this.#tooltip.sticky) {
233
+ this.#tooltip.sticky = false;
234
+ this.#tooltip.clear();
235
+ // A hack to prevent selection if the tooltip is sticky.
236
+ // Let the tooltip be destickified first.
237
+ longPressTriggered = true;
238
+ } else {
239
+ longPressTriggered = false;
240
+ }
241
+
242
+ const disableTooltip = () => {
243
+ document.addEventListener(
244
+ "mouseup",
245
+ () => this.#tooltip.popEnabledState(),
246
+ { once: true }
247
+ );
248
+ this.#tooltip.pushEnabledState(false);
249
+ };
250
+
251
+ // Opening context menu or using modifier keys disables the tooltip
252
+ if (e.button == 2 || e.shiftKey || e.ctrlKey || e.metaKey) {
253
+ disableTooltip();
254
+ } else if (this.#tooltip.visible) {
255
+ // Make tooltip sticky if the user long-presses
256
+ const timeout = setTimeout(() => {
257
+ longPressTriggered = true;
258
+ this.#tooltip.sticky = true;
259
+ }, 400);
260
+
261
+ const clear = () => clearTimeout(timeout);
262
+ document.addEventListener("mouseup", clear, { once: true });
263
+ document.addEventListener("mousemove", clear, { once: true });
264
+ }
265
+ });
266
+
267
+ // Prevent text selections etc while dragging
268
+ canvas.addEventListener("dragstart", (event) =>
269
+ event.stopPropagation()
270
+ );
271
+
272
+ canvas.addEventListener("mouseout", () => {
273
+ this.#tooltip.clear();
274
+ this.#currentHover = null;
275
+ });
276
+ }
277
+
278
+ /**
279
+ * @param {number} x
280
+ * @param {number} y
281
+ */
282
+ #handlePicking(x, y) {
283
+ const dpr = this.#getDevicePixelRatio();
284
+ const pp = readPickingPixel(
285
+ this.#glHelper.gl,
286
+ this.#glHelper._pickingBufferInfo,
287
+ x * dpr,
288
+ y * dpr
289
+ );
290
+
291
+ const uniqueId = pp[0] | (pp[1] << 8) | (pp[2] << 16) | (pp[3] << 24);
292
+
293
+ if (uniqueId == 0) {
294
+ this.#currentHover = null;
295
+ return;
296
+ }
297
+
298
+ if (uniqueId !== this.#currentHover?.uniqueId) {
299
+ this.#currentHover = null;
300
+ }
301
+
302
+ if (!this.#currentHover) {
303
+ this.#viewRoot.visit((view) => {
304
+ if (view instanceof UnitView) {
305
+ if (
306
+ view.mark.isPickingParticipant() &&
307
+ [...view.facetCoords.values()].some((coords) =>
308
+ coords.containsPoint(x, y)
309
+ )
310
+ ) {
311
+ const datum = view
312
+ .getCollector()
313
+ .findDatumByUniqueId(uniqueId);
314
+ if (datum) {
315
+ this.#currentHover = {
316
+ mark: view.mark,
317
+ datum,
318
+ uniqueId,
319
+ };
320
+ }
321
+ }
322
+ if (this.#currentHover) {
323
+ return VISIT_STOP;
324
+ }
325
+ }
326
+ });
327
+ }
328
+
329
+ if (this.#currentHover) {
330
+ const mark = this.#currentHover.mark;
331
+ this.updateTooltip(this.#currentHover.datum, async (datum) => {
332
+ if (!mark.isPickingParticipant()) {
333
+ return;
334
+ }
335
+
336
+ const tooltipProps = mark.properties.tooltip;
337
+
338
+ if (tooltipProps !== null) {
339
+ const handlerName = tooltipProps?.handler ?? "default";
340
+ const handler = this.#tooltipHandlers[handlerName];
341
+ if (!handler) {
342
+ throw new Error(
343
+ "No such tooltip handler: " + handlerName
344
+ );
345
+ }
346
+
347
+ return handler(datum, mark, tooltipProps?.params);
348
+ }
349
+ });
350
+ }
351
+ }
352
+
353
+ /**
354
+ * This method should be called in a mouseMove handler. If not called, the
355
+ * tooltip will be hidden.
356
+ *
357
+ * @param {T} datum
358
+ * @param {function(T):Promise<string | HTMLElement | import("lit").TemplateResult>} [converter]
359
+ * @template T
360
+ */
361
+ updateTooltip(datum, converter) {
362
+ if (!this.#tooltipUpdateRequested || !datum) {
363
+ this.#tooltip.updateWithDatum(datum, converter);
364
+ this.#tooltipUpdateRequested = true;
365
+ } else {
366
+ throw new Error(
367
+ "Tooltip has already been updated! Duplicate event handler?"
368
+ );
369
+ }
370
+ }
371
+ }
@@ -0,0 +1,10 @@
1
+ export default class KeyboardListenerManager {
2
+ /**
3
+ * @param {"keydown" | "keyup"} type
4
+ * @param {(event: KeyboardEvent) => void} listener
5
+ */
6
+ add(type: "keydown" | "keyup", listener: (event: KeyboardEvent) => void): void;
7
+ removeAll(): void;
8
+ #private;
9
+ }
10
+ //# sourceMappingURL=keyboardListenerManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboardListenerManager.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/keyboardListenerManager.js"],"names":[],"mappings":"AAAA;IAQI;;;OAGG;IACH,UAHW,SAAS,GAAG,OAAO,YACnB,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,QAUxC;IAED,kBAOC;;CACJ"}
@@ -0,0 +1,31 @@
1
+ export default class KeyboardListenerManager {
2
+ /** @type {Map<string, (function(KeyboardEvent):void)[]>} */
3
+ #listeners;
4
+
5
+ constructor() {
6
+ this.#listeners = new Map();
7
+ }
8
+
9
+ /**
10
+ * @param {"keydown" | "keyup"} type
11
+ * @param {(event: KeyboardEvent) => void} listener
12
+ */
13
+ add(type, listener) {
14
+ document.addEventListener(type, listener);
15
+ let listeners = this.#listeners.get(type);
16
+ if (!listeners) {
17
+ listeners = [];
18
+ this.#listeners.set(type, listeners);
19
+ }
20
+ listeners.push(listener);
21
+ }
22
+
23
+ removeAll() {
24
+ for (const [type, listeners] of this.#listeners) {
25
+ for (const listener of listeners) {
26
+ document.removeEventListener(type, listener);
27
+ }
28
+ }
29
+ this.#listeners.clear();
30
+ }
31
+ }
@@ -0,0 +1,15 @@
1
+ export default class LoadingIndicatorManager {
2
+ /**
3
+ * @param {HTMLElement} loadingIndicatorsElement
4
+ */
5
+ constructor(loadingIndicatorsElement: HTMLElement);
6
+ /**
7
+ * @param {import("../view/view.js").default} view
8
+ * @param {import("../types/viewContext.js").DataLoadingStatus} status
9
+ * @param {string} [detail]
10
+ */
11
+ setDataLoadingStatus(view: import("../view/view.js").default, status: import("../types/viewContext.js").DataLoadingStatus, detail?: string): void;
12
+ updateLayout(): void;
13
+ #private;
14
+ }
15
+ //# sourceMappingURL=loadingIndicatorManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadingIndicatorManager.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/loadingIndicatorManager.js"],"names":[],"mappings":"AAIA;IAQI;;OAEG;IACH,sCAFW,WAAW,EASrB;IAED;;;;OAIG;IACH,2BAJW,OAAO,iBAAiB,EAAE,OAAO,UACjC,OAAO,yBAAyB,EAAE,iBAAiB,WACnD,MAAM,QAKhB;IAED,qBAwDC;;CACJ"}