@genome-spy/core 0.65.0 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) 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 +15821 -14601
  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/flowHandle.d.ts +2 -0
  16. package/dist/src/data/flowHandle.d.ts.map +1 -1
  17. package/dist/src/data/flowHandle.js +1 -0
  18. package/dist/src/data/flowInit.d.ts +12 -4
  19. package/dist/src/data/flowInit.d.ts.map +1 -1
  20. package/dist/src/data/flowInit.js +115 -16
  21. package/dist/src/data/sources/lazy/axisTickSource.js +1 -1
  22. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +1 -1
  23. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  24. package/dist/src/data/sources/lazy/singleAxisLazySource.js +10 -3
  25. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  26. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +5 -1
  27. package/dist/src/data/transforms/filterScoredLabels.d.ts +1 -1
  28. package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
  29. package/dist/src/data/transforms/filterScoredLabels.js +1 -1
  30. package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts.map +1 -1
  31. package/dist/src/data/transforms/linearizeGenomicCoordinate.js +2 -1
  32. package/dist/src/encoder/encoder.d.ts +1 -1
  33. package/dist/src/encoder/encoder.d.ts.map +1 -1
  34. package/dist/src/encoder/encoder.js +1 -1
  35. package/dist/src/genome/scaleLocus.d.ts +39 -0
  36. package/dist/src/genome/scaleLocus.d.ts.map +1 -1
  37. package/dist/src/genome/scaleLocus.js +76 -0
  38. package/dist/src/genomeSpy/canvasExport.d.ts +19 -0
  39. package/dist/src/genomeSpy/canvasExport.d.ts.map +1 -0
  40. package/dist/src/genomeSpy/canvasExport.js +66 -0
  41. package/dist/src/genomeSpy/containerUi.d.ts +17 -0
  42. package/dist/src/genomeSpy/containerUi.d.ts.map +1 -0
  43. package/dist/src/genomeSpy/containerUi.js +78 -0
  44. package/dist/src/genomeSpy/eventListenerRegistry.d.ts +19 -0
  45. package/dist/src/genomeSpy/eventListenerRegistry.d.ts.map +1 -0
  46. package/dist/src/genomeSpy/eventListenerRegistry.js +38 -0
  47. package/dist/src/genomeSpy/inputBindingManager.d.ts +14 -0
  48. package/dist/src/genomeSpy/inputBindingManager.d.ts.map +1 -0
  49. package/dist/src/genomeSpy/inputBindingManager.js +63 -0
  50. package/dist/src/genomeSpy/interactionController.d.ts +40 -0
  51. package/dist/src/genomeSpy/interactionController.d.ts.map +1 -0
  52. package/dist/src/genomeSpy/interactionController.js +371 -0
  53. package/dist/src/genomeSpy/keyboardListenerManager.d.ts +10 -0
  54. package/dist/src/genomeSpy/keyboardListenerManager.d.ts.map +1 -0
  55. package/dist/src/genomeSpy/keyboardListenerManager.js +31 -0
  56. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +15 -0
  57. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -0
  58. package/dist/src/genomeSpy/loadingIndicatorManager.js +92 -0
  59. package/dist/src/genomeSpy/renderCoordinator.d.ts +22 -0
  60. package/dist/src/genomeSpy/renderCoordinator.d.ts.map +1 -0
  61. package/dist/src/genomeSpy/renderCoordinator.js +118 -0
  62. package/dist/src/genomeSpy/viewContextFactory.d.ts +18 -0
  63. package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -0
  64. package/dist/src/genomeSpy/viewContextFactory.js +79 -0
  65. package/dist/src/genomeSpy/viewDataInit.d.ts +22 -0
  66. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -0
  67. package/dist/src/genomeSpy/viewDataInit.js +160 -0
  68. package/dist/src/genomeSpy/viewDataInit.test.d.ts +2 -0
  69. package/dist/src/genomeSpy/viewDataInit.test.d.ts.map +1 -0
  70. package/dist/src/genomeSpy/viewHierarchyConfig.d.ts +14 -0
  71. package/dist/src/genomeSpy/viewHierarchyConfig.d.ts.map +1 -0
  72. package/dist/src/genomeSpy/viewHierarchyConfig.js +24 -0
  73. package/dist/src/genomeSpy/viewHighlight.d.ts +5 -0
  74. package/dist/src/genomeSpy/viewHighlight.d.ts.map +1 -0
  75. package/dist/src/genomeSpy/viewHighlight.js +30 -0
  76. package/dist/src/genomeSpy.d.ts +17 -71
  77. package/dist/src/genomeSpy.d.ts.map +1 -1
  78. package/dist/src/genomeSpy.js +197 -741
  79. package/dist/src/gl/dataToVertices.d.ts.map +1 -1
  80. package/dist/src/gl/dataToVertices.js +16 -4
  81. package/dist/src/gl/glslScaleGenerator.d.ts +1 -1
  82. package/dist/src/gl/webGLHelper.d.ts +2 -2
  83. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  84. package/dist/src/gl/webGLHelper.js +4 -4
  85. package/dist/src/index.d.ts.map +1 -1
  86. package/dist/src/index.js +2 -12
  87. package/dist/src/marks/mark.d.ts.map +1 -1
  88. package/dist/src/marks/mark.js +4 -2
  89. package/dist/src/{view → scales}/axisResolution.d.ts +9 -16
  90. package/dist/src/scales/axisResolution.d.ts.map +1 -0
  91. package/dist/src/{view → scales}/axisResolution.js +29 -18
  92. package/dist/src/scales/axisResolution.test.d.ts.map +1 -0
  93. package/dist/src/scales/scaleDomainAggregator.d.ts +57 -0
  94. package/dist/src/scales/scaleDomainAggregator.d.ts.map +1 -0
  95. package/dist/src/scales/scaleDomainAggregator.js +167 -0
  96. package/dist/src/scales/scaleDomainAggregator.test.d.ts +2 -0
  97. package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +1 -0
  98. package/dist/src/scales/scaleInstanceManager.d.ts +40 -0
  99. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -0
  100. package/dist/src/scales/scaleInstanceManager.js +317 -0
  101. package/dist/src/scales/scaleInstanceManager.test.d.ts +2 -0
  102. package/dist/src/scales/scaleInstanceManager.test.d.ts.map +1 -0
  103. package/dist/src/scales/scaleInteractionController.d.ts +73 -0
  104. package/dist/src/scales/scaleInteractionController.d.ts.map +1 -0
  105. package/dist/src/scales/scaleInteractionController.js +336 -0
  106. package/dist/src/scales/scaleInteractionController.test.d.ts +2 -0
  107. package/dist/src/scales/scaleInteractionController.test.d.ts.map +1 -0
  108. package/dist/src/scales/scalePropsResolver.d.ts +23 -0
  109. package/dist/src/scales/scalePropsResolver.d.ts.map +1 -0
  110. package/dist/src/scales/scalePropsResolver.js +74 -0
  111. package/dist/src/{view → scales}/scaleResolution.d.ts +53 -35
  112. package/dist/src/scales/scaleResolution.d.ts.map +1 -0
  113. package/dist/src/scales/scaleResolution.js +732 -0
  114. package/dist/src/scales/scaleResolution.test.d.ts.map +1 -0
  115. package/dist/src/scales/scaleResolutionConstants.d.ts +6 -0
  116. package/dist/src/scales/scaleResolutionConstants.d.ts.map +1 -0
  117. package/dist/src/scales/scaleResolutionConstants.js +5 -0
  118. package/dist/src/scales/scaleRules.d.ts +16 -0
  119. package/dist/src/scales/scaleRules.d.ts.map +1 -0
  120. package/dist/src/scales/scaleRules.js +103 -0
  121. package/dist/src/scales/scaleRules.test.d.ts +2 -0
  122. package/dist/src/scales/scaleRules.test.d.ts.map +1 -0
  123. package/dist/src/spec/channel.d.ts +13 -18
  124. package/dist/src/spec/scale.d.ts +6 -0
  125. package/dist/src/types/embedApi.d.ts +5 -0
  126. package/dist/src/types/scaleResolutionApi.d.ts +1 -1
  127. package/dist/src/utils/domainArray.d.ts.map +1 -1
  128. package/dist/src/utils/domainArray.js +3 -0
  129. package/dist/src/utils/indexer.d.ts +3 -0
  130. package/dist/src/utils/indexer.d.ts.map +1 -1
  131. package/dist/src/utils/indexer.js +3 -0
  132. package/dist/src/view/concatView.d.ts +18 -0
  133. package/dist/src/view/concatView.d.ts.map +1 -1
  134. package/dist/src/view/concatView.js +73 -0
  135. package/dist/src/view/concatView.test.d.ts +2 -0
  136. package/dist/src/view/concatView.test.d.ts.map +1 -0
  137. package/dist/src/view/containerMutationHelper.d.ts +74 -0
  138. package/dist/src/view/containerMutationHelper.d.ts.map +1 -0
  139. package/dist/src/view/containerMutationHelper.js +118 -0
  140. package/dist/src/view/containerView.d.ts +0 -7
  141. package/dist/src/view/containerView.d.ts.map +1 -1
  142. package/dist/src/view/containerView.js +0 -10
  143. package/dist/src/view/facetView.d.ts.map +1 -1
  144. package/dist/src/view/facetView.js +0 -15
  145. package/dist/src/view/flowBuilder.d.ts +5 -3
  146. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  147. package/dist/src/view/flowBuilder.js +69 -6
  148. package/dist/src/view/gridView/gridChild.d.ts +11 -0
  149. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  150. package/dist/src/view/gridView/gridChild.js +32 -6
  151. package/dist/src/view/gridView/gridView.d.ts +39 -1
  152. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  153. package/dist/src/view/gridView/gridView.js +106 -48
  154. package/dist/src/view/gridView/gridView.test.d.ts +2 -0
  155. package/dist/src/view/gridView/gridView.test.d.ts.map +1 -0
  156. package/dist/src/view/gridView/scrollbar.d.ts +39 -8
  157. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
  158. package/dist/src/view/gridView/scrollbar.js +184 -69
  159. package/dist/src/view/layerView.d.ts +14 -0
  160. package/dist/src/view/layerView.d.ts.map +1 -1
  161. package/dist/src/view/layerView.js +66 -0
  162. package/dist/src/view/layerView.test.d.ts +2 -0
  163. package/dist/src/view/layerView.test.d.ts.map +1 -0
  164. package/dist/src/view/testUtils.d.ts.map +1 -1
  165. package/dist/src/view/testUtils.js +7 -1
  166. package/dist/src/view/unitView.d.ts.map +1 -1
  167. package/dist/src/view/unitView.js +41 -36
  168. package/dist/src/view/view.d.ts +18 -6
  169. package/dist/src/view/view.d.ts.map +1 -1
  170. package/dist/src/view/view.js +30 -4
  171. package/package.json +2 -2
  172. package/dist/bundle/browser-txUcLy2H.js +0 -123
  173. package/dist/bundle/index-BQpbYrv4.js +0 -1712
  174. package/dist/bundle/index-BhtHKLUo.js +0 -73
  175. package/dist/bundle/index-CCe8rnZz.js +0 -716
  176. package/dist/bundle/index-DhcU-Gk-.js +0 -1487
  177. package/dist/src/data/collector.test.js +0 -138
  178. package/dist/src/data/dataFlow.test.js +0 -38
  179. package/dist/src/data/flow.test.js +0 -81
  180. package/dist/src/data/flowInit.test.js +0 -413
  181. package/dist/src/data/flowNode.test.js +0 -50
  182. package/dist/src/data/flowOptimizer.test.js +0 -209
  183. package/dist/src/data/formats/fasta.test.js +0 -27
  184. package/dist/src/data/sources/inlineSource.test.js +0 -63
  185. package/dist/src/data/sources/sequenceSource.test.js +0 -81
  186. package/dist/src/data/transforms/aggregate.test.js +0 -134
  187. package/dist/src/data/transforms/clone.test.js +0 -11
  188. package/dist/src/data/transforms/coverage.test.js +0 -238
  189. package/dist/src/data/transforms/filter.test.js +0 -20
  190. package/dist/src/data/transforms/flatten.test.js +0 -96
  191. package/dist/src/data/transforms/flattenDelimited.test.js +0 -90
  192. package/dist/src/data/transforms/flattenSequence.test.js +0 -34
  193. package/dist/src/data/transforms/formula.test.js +0 -25
  194. package/dist/src/data/transforms/identifier.test.js +0 -92
  195. package/dist/src/data/transforms/pileup.test.js +0 -70
  196. package/dist/src/data/transforms/project.test.js +0 -32
  197. package/dist/src/data/transforms/regexExtract.test.js +0 -70
  198. package/dist/src/data/transforms/regexFold.test.js +0 -201
  199. package/dist/src/data/transforms/sample.test.js +0 -38
  200. package/dist/src/data/transforms/stack.test.js +0 -91
  201. package/dist/src/encoder/accessor.test.js +0 -162
  202. package/dist/src/encoder/encoder.test.js +0 -105
  203. package/dist/src/genome/genome.test.js +0 -268
  204. package/dist/src/genome/genomes.test.js +0 -8
  205. package/dist/src/genome/scaleIndex.test.js +0 -78
  206. package/dist/src/genome/scaleLocus.test.js +0 -4
  207. package/dist/src/scale/scale.test.js +0 -326
  208. package/dist/src/scale/ticks.test.js +0 -46
  209. package/dist/src/selection/selection.test.js +0 -14
  210. package/dist/src/utils/addBaseUrl.test.js +0 -30
  211. package/dist/src/utils/binnedIndex.test.js +0 -201
  212. package/dist/src/utils/cloner.test.js +0 -35
  213. package/dist/src/utils/coalesce.test.js +0 -16
  214. package/dist/src/utils/concatIterables.test.js +0 -8
  215. package/dist/src/utils/domainArray.test.js +0 -130
  216. package/dist/src/utils/indexer.test.js +0 -49
  217. package/dist/src/utils/interactionEvent.test.js +0 -35
  218. package/dist/src/utils/iterateNestedMaps.test.js +0 -33
  219. package/dist/src/utils/kWayMerge.test.js +0 -30
  220. package/dist/src/utils/mergeObjects.test.js +0 -42
  221. package/dist/src/utils/numberExtractor.test.js +0 -6
  222. package/dist/src/utils/propertyCacher.test.js +0 -89
  223. package/dist/src/utils/propertyCoalescer.test.js +0 -25
  224. package/dist/src/utils/radixSort.test.js +0 -51
  225. package/dist/src/utils/reservationMap.test.js +0 -20
  226. package/dist/src/utils/ringBuffer.test.js +0 -39
  227. package/dist/src/utils/topK.test.js +0 -54
  228. package/dist/src/utils/trees.test.js +0 -135
  229. package/dist/src/utils/url.test.js +0 -28
  230. package/dist/src/utils/variableTools.test.js +0 -13
  231. package/dist/src/view/axisResolution.d.ts.map +0 -1
  232. package/dist/src/view/axisResolution.test.d.ts.map +0 -1
  233. package/dist/src/view/axisResolution.test.js +0 -206
  234. package/dist/src/view/flowBuilder.test.js +0 -125
  235. package/dist/src/view/gridView/selectionRect.test.js +0 -87
  236. package/dist/src/view/layout/flexLayout.test.js +0 -323
  237. package/dist/src/view/layout/grid.test.js +0 -71
  238. package/dist/src/view/layout/rectangle.test.js +0 -192
  239. package/dist/src/view/paramMediator.test.js +0 -282
  240. package/dist/src/view/scaleResolution.d.ts.map +0 -1
  241. package/dist/src/view/scaleResolution.js +0 -1059
  242. package/dist/src/view/scaleResolution.test.d.ts.map +0 -1
  243. package/dist/src/view/scaleResolution.test.js +0 -645
  244. package/dist/src/view/view.test.js +0 -245
  245. package/dist/src/view/viewDispose.test.js +0 -110
  246. package/dist/src/view/viewFactory.test.js +0 -25
  247. package/dist/src/view/viewUtils.test.js +0 -87
  248. /package/dist/src/{view → scales}/axisResolution.test.d.ts +0 -0
  249. /package/dist/src/{view → scales}/scaleResolution.test.d.ts +0 -0
@@ -0,0 +1,336 @@
1
+ import {
2
+ clampRange,
3
+ isArray,
4
+ isBoolean,
5
+ isObject,
6
+ panLinear,
7
+ panLog,
8
+ panPow,
9
+ span,
10
+ zoomLinear,
11
+ zoomLog,
12
+ zoomPow,
13
+ } from "vega-util";
14
+ import { isContinuous } from "vega-scale";
15
+ import { easeCubicInOut } from "d3-ease";
16
+
17
+ import eerp from "../utils/eerp.js";
18
+ import { shallowArrayEquals } from "../utils/arrayUtils.js";
19
+
20
+ /**
21
+ * @typedef {import("../spec/scale.js").NumericDomain} NumericDomain
22
+ * @typedef {import("../spec/scale.js").ScalarDomain} ScalarDomain
23
+ * @typedef {import("../spec/scale.js").ComplexDomain} ComplexDomain
24
+ * @typedef {import("../spec/scale.js").ZoomParams} ZoomParams
25
+ * @typedef {import("../types/encoder.js").VegaScale} VegaScale
26
+ * @typedef {VegaScale & { props: import("../spec/scale.js").Scale }} ScaleWithProps
27
+ */
28
+
29
+ export default class ScaleInteractionController {
30
+ /** @type {() => ScaleWithProps} */
31
+ #getScale;
32
+
33
+ /** @type {() => import("../utils/animator.js").default} */
34
+ #getAnimator;
35
+
36
+ /** @type {() => number[]} */
37
+ #getInitialDomainSnapshot;
38
+
39
+ /** @type {() => number[]} */
40
+ #getResetDomain;
41
+
42
+ /** @type {(domain: ScalarDomain | ComplexDomain) => number[]} */
43
+ #fromComplexInterval;
44
+
45
+ /** @type {() => number[]} */
46
+ #getGenomeExtent;
47
+
48
+ /**
49
+ * @param {object} options
50
+ * @param {() => ScaleWithProps} options.getScale
51
+ * @param {() => import("../utils/animator.js").default} options.getAnimator
52
+ * @param {() => number[]} options.getInitialDomainSnapshot
53
+ * @param {() => number[]} options.getResetDomain
54
+ * @param {(domain: ScalarDomain | ComplexDomain) => number[]} options.fromComplexInterval
55
+ * @param {() => number[]} options.getGenomeExtent
56
+ */
57
+ constructor({
58
+ getScale,
59
+ getAnimator,
60
+ getInitialDomainSnapshot,
61
+ getResetDomain,
62
+ fromComplexInterval,
63
+ getGenomeExtent,
64
+ }) {
65
+ this.#getScale = getScale;
66
+ this.#getAnimator = getAnimator;
67
+ this.#getInitialDomainSnapshot = getInitialDomainSnapshot;
68
+ this.#getResetDomain = getResetDomain;
69
+ this.#fromComplexInterval = fromComplexInterval;
70
+ this.#getGenomeExtent = getGenomeExtent;
71
+ }
72
+
73
+ getZoomExtent() {
74
+ const scale = this.#getScale();
75
+ const zoom = scale.props.zoom;
76
+ return resolveZoomExtent(
77
+ scale,
78
+ zoom,
79
+ this.#fromComplexInterval,
80
+ this.#getGenomeExtent,
81
+ this.#getInitialDomainSnapshot
82
+ );
83
+ }
84
+
85
+ isZoomable() {
86
+ return this.isZoomingSupported() && !!this.#getScale().props.zoom;
87
+ }
88
+
89
+ isZoomingSupported() {
90
+ return isContinuous(this.#getScale().type);
91
+ }
92
+
93
+ /**
94
+ * Return true if the scale is zoomable and the current domain differs from the initial domain.
95
+ *
96
+ * @returns true if zoomed
97
+ */
98
+ isZoomed() {
99
+ return (
100
+ this.isZoomingSupported() &&
101
+ shallowArrayEquals(
102
+ this.#getResetDomain(),
103
+ this.#getScale().domain()
104
+ )
105
+ );
106
+ }
107
+
108
+ /**
109
+ * Pans (translates) and zooms using a specified scale factor.
110
+ *
111
+ * @param {number} scaleFactor
112
+ * @param {number} scaleAnchor
113
+ * @param {number} pan
114
+ * @returns {boolean} true if the scale was zoomed
115
+ */
116
+ zoom(scaleFactor, scaleAnchor, pan) {
117
+ if (!this.isZoomingSupported()) {
118
+ return false;
119
+ }
120
+
121
+ const scale = this.#getScale();
122
+ const oldDomain = scale.domain();
123
+ let newDomain = applyZoomTransform(
124
+ scale,
125
+ oldDomain,
126
+ scaleFactor,
127
+ scaleAnchor,
128
+ pan
129
+ );
130
+
131
+ // TODO: Use the zoomTo method. Move clamping etc there.
132
+ const zoomExtent = this.getZoomExtent();
133
+ newDomain = clampRange(newDomain, zoomExtent[0], zoomExtent[1]);
134
+
135
+ if ([0, 1].some((i) => newDomain[i] != oldDomain[i])) {
136
+ scale.domain(newDomain);
137
+ return true;
138
+ }
139
+
140
+ return false;
141
+ }
142
+
143
+ /**
144
+ * Immediately zooms to the given interval.
145
+ *
146
+ * @param {NumericDomain | ComplexDomain} domain
147
+ * @param {boolean | number} [duration] an approximate duration for transition.
148
+ * Zero duration zooms immediately. Boolean `true` indicates a default duration.
149
+ */
150
+ async zoomTo(domain, duration = false) {
151
+ if (isBoolean(duration)) {
152
+ duration = duration ? 700 : 0;
153
+ }
154
+
155
+ if (!this.isZoomingSupported()) {
156
+ throw new Error("Not a zoomable scale!");
157
+ }
158
+
159
+ const to = this.#fromComplexInterval(domain);
160
+
161
+ // TODO: Intersect the domain with zoom extent
162
+
163
+ const animator = this.#getAnimator();
164
+
165
+ const scale = this.#getScale();
166
+ const from = /** @type {number[]} */ (scale.domain());
167
+
168
+ if (duration > 0 && from.length == 2) {
169
+ // Spans
170
+ const fw = from[1] - from[0];
171
+ const tw = to[1] - to[0];
172
+
173
+ // Centers
174
+ const fc = from[0] + fw / 2;
175
+ const tc = to[0] + tw / 2;
176
+
177
+ // Constant endpoints. Skip calculation to maintain precision.
178
+ const ac = from[0] == to[0];
179
+ const bc = from[1] == to[1];
180
+
181
+ // TODO: Abort possible previous transition
182
+ await animator.transition({
183
+ duration,
184
+ easingFunction: easeCubicInOut,
185
+ onUpdate: (t) => {
186
+ const w = eerp(fw, tw, t);
187
+ const wt = fw == tw ? t : (fw - w) / (fw - tw);
188
+ const c = wt * tc + (1 - wt) * fc;
189
+ const newDomain = [
190
+ ac ? from[0] : c - w / 2,
191
+ bc ? from[1] : c + w / 2,
192
+ ];
193
+ scale.domain(newDomain);
194
+ },
195
+ });
196
+
197
+ scale.domain(to);
198
+ } else {
199
+ scale.domain(to);
200
+ animator?.requestRender();
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Resets the current domain to the initial one
206
+ *
207
+ * @returns true if the domain was changed
208
+ */
209
+ resetZoom() {
210
+ if (!this.isZoomingSupported()) {
211
+ throw new Error("Not a zoomable scale!");
212
+ }
213
+
214
+ const scale = this.#getScale();
215
+ const oldDomain = scale.domain();
216
+ const newDomain = this.#getResetDomain();
217
+
218
+ if ([0, 1].some((i) => newDomain[i] != oldDomain[i])) {
219
+ scale.domain(newDomain);
220
+ return true;
221
+ }
222
+ return false;
223
+ }
224
+
225
+ /**
226
+ * Returns the zoom level with respect to the reference domain span (the original domain).
227
+ */
228
+ getZoomLevel() {
229
+ // Zoom level makes sense only for user-zoomable scales where zoom extent is defined
230
+ if (this.isZoomable()) {
231
+ return span(this.getZoomExtent()) / span(this.#getScale().domain());
232
+ }
233
+
234
+ return 1.0;
235
+ }
236
+ }
237
+
238
+ /**
239
+ * @param {ScaleWithProps} scale
240
+ * @param {ZoomParams | boolean | undefined} zoom
241
+ * @param {(interval: ScalarDomain | ComplexDomain) => number[]} fromComplexInterval
242
+ * @param {() => number[]} getGenomeExtent
243
+ * @param {() => number[]} getInitialDomainSnapshot
244
+ * @returns {number[]}
245
+ */
246
+ function resolveZoomExtent(
247
+ scale,
248
+ zoom,
249
+ fromComplexInterval,
250
+ getGenomeExtent,
251
+ getInitialDomainSnapshot
252
+ ) {
253
+ if (isZoomParams(zoom)) {
254
+ if (isArray(zoom.extent)) {
255
+ return fromComplexInterval(zoom.extent);
256
+ }
257
+ }
258
+
259
+ if (zoom && scale.props.type == "locus") {
260
+ return getGenomeExtent();
261
+ }
262
+
263
+ // TODO: Perhaps this should be "domain" for index scale and nothing for quantitative.
264
+ // Would behave similarly to Vega-Lite, which doesn't have constraints.
265
+ return getInitialDomainSnapshot();
266
+ }
267
+
268
+ /**
269
+ * @param {ScaleWithProps} scale
270
+ * @param {number[]} domain
271
+ * @param {number} scaleFactor
272
+ * @param {number} scaleAnchor
273
+ * @param {number} pan
274
+ * @returns {number[]}
275
+ */
276
+ function applyZoomTransform(scale, domain, scaleFactor, scaleAnchor, pan) {
277
+ let newDomain = [...domain];
278
+
279
+ /** @type {number} */
280
+ // @ts-ignore
281
+ let anchor = scale.invert(scaleAnchor);
282
+
283
+ if (scale.props.reverse) {
284
+ pan = -pan;
285
+ }
286
+
287
+ if ("align" in scale) {
288
+ anchor += scale.align();
289
+ }
290
+
291
+ // TODO: symlog
292
+ switch (scale.type) {
293
+ case "linear":
294
+ case "index":
295
+ case "locus":
296
+ newDomain = panLinear(newDomain, pan || 0);
297
+ newDomain = zoomLinear(newDomain, anchor, scaleFactor);
298
+ break;
299
+ case "log":
300
+ newDomain = panLog(newDomain, pan || 0);
301
+ newDomain = zoomLog(newDomain, anchor, scaleFactor);
302
+ break;
303
+ case "pow":
304
+ case "sqrt": {
305
+ const powScale =
306
+ /** @type {import("d3-scale").ScalePower<number, number>} */ (
307
+ scale
308
+ );
309
+ newDomain = panPow(newDomain, pan || 0, powScale.exponent());
310
+ newDomain = zoomPow(
311
+ newDomain,
312
+ anchor,
313
+ scaleFactor,
314
+ powScale.exponent()
315
+ );
316
+ break;
317
+ }
318
+ default:
319
+ throw new Error("Zooming is not implemented for: " + scale.type);
320
+ }
321
+
322
+ return newDomain;
323
+ }
324
+
325
+ /**
326
+ * @param {boolean | ZoomParams} zoom
327
+ * @returns {zoom is ZoomParams}
328
+ */
329
+ function isZoomParams(zoom) {
330
+ return isObject(zoom);
331
+ }
332
+
333
+ /**
334
+ * @param {any[]} a
335
+ * @param {any[]} b
336
+ */
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scaleInteractionController.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaleInteractionController.test.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInteractionController.test.js"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @typedef {import("../spec/channel.js").Channel} Channel
3
+ * @typedef {import("../spec/scale.js").Scale} Scale
4
+ * @typedef {import("./scaleResolution.js").ScaleResolutionMember} ScaleResolutionMember
5
+ */
6
+ /**
7
+ * @param {object} options
8
+ * @param {Channel} options.channel
9
+ * @param {import("../spec/channel.js").Type} options.dataType
10
+ * @param {Set<ScaleResolutionMember>} options.members
11
+ * @param {boolean} options.isExplicitDomain
12
+ * @returns {Scale}
13
+ */
14
+ export function resolveScalePropsBase({ channel, dataType, members, isExplicitDomain, }: {
15
+ channel: Channel;
16
+ dataType: import("../spec/channel.js").Type;
17
+ members: Set<ScaleResolutionMember>;
18
+ isExplicitDomain: boolean;
19
+ }): Scale;
20
+ export type Channel = import("../spec/channel.js").Channel;
21
+ export type Scale = import("../spec/scale.js").Scale;
22
+ export type ScaleResolutionMember = import("./scaleResolution.js").ScaleResolutionMember;
23
+ //# sourceMappingURL=scalePropsResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scalePropsResolver.d.ts","sourceRoot":"","sources":["../../../src/scales/scalePropsResolver.js"],"names":[],"mappings":"AAOA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,yFANG;IAAyB,OAAO,EAAxB,OAAO;IACoC,QAAQ,EAAnD,OAAO,oBAAoB,EAAE,IAAI;IACG,OAAO,EAA3C,GAAG,CAAC,qBAAqB,CAAC;IACT,gBAAgB,EAAjC,OAAO;CACf,GAAU,KAAK,CAiDjB;sBA5DY,OAAO,oBAAoB,EAAE,OAAO;oBACpC,OAAO,kBAAkB,EAAE,KAAK;oCAChC,OAAO,sBAAsB,EAAE,qBAAqB"}
@@ -0,0 +1,74 @@
1
+ import { isDiscrete } from "vega-scale";
2
+
3
+ import mergeObjects from "../utils/mergeObjects.js";
4
+ import { getDefaultScaleProperties } from "../config/scaleDefaults.js";
5
+ import { applyLockedProperties, getDefaultScaleType } from "./scaleRules.js";
6
+ import { INDEX, LOCUS } from "./scaleResolutionConstants.js";
7
+
8
+ /**
9
+ * @typedef {import("../spec/channel.js").Channel} Channel
10
+ * @typedef {import("../spec/scale.js").Scale} Scale
11
+ * @typedef {import("./scaleResolution.js").ScaleResolutionMember} ScaleResolutionMember
12
+ */
13
+
14
+ /**
15
+ * @param {object} options
16
+ * @param {Channel} options.channel
17
+ * @param {import("../spec/channel.js").Type} options.dataType
18
+ * @param {Set<ScaleResolutionMember>} options.members
19
+ * @param {boolean} options.isExplicitDomain
20
+ * @returns {Scale}
21
+ */
22
+ export function resolveScalePropsBase({
23
+ channel,
24
+ dataType,
25
+ members,
26
+ isExplicitDomain,
27
+ }) {
28
+ const propArray = Array.from(members)
29
+ .map((member) => member.channelDef.scale)
30
+ .filter((props) => props !== undefined);
31
+
32
+ // TODO: Disabled scale: https://vega.github.io/vega-lite/docs/scale.html#disable
33
+ const mergedProps = mergeObjects(propArray, "scale", ["domain"]);
34
+ if (mergedProps === null || mergedProps.type == "null") {
35
+ return /** @type {Scale} */ ({ type: "null" });
36
+ }
37
+
38
+ const props = {
39
+ ...getDefaultScaleProperties(channel, dataType, isExplicitDomain),
40
+ ...mergedProps,
41
+ };
42
+
43
+ if (!props.type) {
44
+ props.type = getDefaultScaleType(channel, dataType);
45
+ }
46
+
47
+ // Reverse discrete y axis
48
+ if (
49
+ channel == "y" &&
50
+ isDiscrete(props.type) &&
51
+ props.reverse == undefined
52
+ ) {
53
+ props.reverse = true;
54
+ }
55
+
56
+ if (props.range && props.scheme) {
57
+ delete props.scheme;
58
+ // TODO: Props should be set more intelligently
59
+ }
60
+
61
+ // By default, index and locus scales are zoomable, others are not
62
+ if (!("zoom" in props) && [INDEX, LOCUS].includes(props.type)) {
63
+ props.zoom = true;
64
+ }
65
+
66
+ applyLockedProperties(props, channel);
67
+
68
+ return props;
69
+ }
70
+
71
+ /**
72
+ * @param {Scale} props
73
+ * @param {Channel} channel
74
+ */
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Reconfigures scales, starting from the given view.
2
+ * Reconfigures scale domains for resolutions used by the given view(s).
3
+ *
4
+ * Use this for data-driven updates where only domains need refreshing.
3
5
  *
4
6
  * TODO: This should be made unnecessary. Collectors should trigger the reconfiguration
5
7
  * for those views that get their data from the collector.
@@ -7,28 +9,25 @@
7
9
  * TODO: This may reconfigure channels that are not affected by the change.
8
10
  * Causes performance issues with domains that are extracted from data.
9
11
  *
10
- * @param {import("./view.js").default | import("./view.js").default[]} fromViews
12
+ * @param {import("../view/view.js").default | import("../view/view.js").default[]} fromViews
13
+ * @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
11
14
  */
12
- export function reconfigureScales(fromViews: import("./view.js").default | import("./view.js").default[]): void;
13
- export const QUANTITATIVE: "quantitative";
14
- export const ORDINAL: "ordinal";
15
- export const NOMINAL: "nominal";
16
- export const LOCUS: "locus";
17
- export const INDEX: "index";
15
+ export function reconfigureScaleDomains(fromViews: import("../view/view.js").default | import("../view/view.js").default[], viewFilter?: (view: import("../view/view.js").default) => boolean): void;
18
16
  /**
19
17
  * @template {ChannelWithScale}[T=ChannelWithScale]
20
18
  *
21
19
  * @typedef {object} ScaleResolutionMember
22
- * @prop {import("./unitView.js").default} view TODO: Get rid of the view reference
20
+ * @prop {import("../view/unitView.js").default} view TODO: Get rid of the view reference
23
21
  * @prop {T} channel
24
22
  * @prop {import("../spec/channel.js").ChannelDefWithScale} channelDef
25
23
  * @prop {(channel: ChannelWithScale, type: import("../spec/channel.js").Type) => DomainArray} dataDomainSource
26
24
  */
27
25
  /**
28
- * Resolution takes care of merging domains and scales from multiple views.
29
- * This class also provides some utility methods for zooming the scales etc..
30
- *
31
- * TODO: This has grown a bit too fat. Consider splitting.
26
+ * Resolves a shared scale for a channel by merging scale properties and domains
27
+ * across participating views, then coordinating range updates and zoom/pan
28
+ * interactions. It is the central wiring point for scale-related state and
29
+ * notifications, while delegating domain aggregation, scale instance setup, and
30
+ * interaction logic to focused helpers.
32
31
  *
33
32
  * @implements {ScaleResolutionApi}
34
33
  */
@@ -38,8 +37,6 @@ export default class ScaleResolution implements ScaleResolutionApi {
38
37
  */
39
38
  constructor(channel: import("../spec/channel.js").Channel);
40
39
  channel: import("../spec/channel.js").Channel;
41
- /** @type {ScaleResolutionMember[]} The involved views */
42
- members: ScaleResolutionMember[];
43
40
  /** @type {import("../spec/channel.js").Type} Data type (quantitative, nominal, etc...) */
44
41
  type: import("../spec/channel.js").Type;
45
42
  /** @type {string} An optional unique identifier for the scale */
@@ -60,34 +57,54 @@ export default class ScaleResolution implements ScaleResolutionApi {
60
57
  */
61
58
  removeEventListener(type: import("../types/scaleResolutionApi.js").ScaleResolutionEventType, listener: import("../types/scaleResolutionApi.js").ScaleResolutionListener): void;
62
59
  /**
63
- * Add a view to this resolution.
64
- * N.B. This is expected to be called in depth-first order
65
- *
66
- * @param {ScaleResolutionMember} newMember
60
+ * @param {ScaleResolutionMember} member
61
+ * @returns {() => boolean}
67
62
  */
68
- addMember(newMember: ScaleResolutionMember): void;
63
+ registerMember(member: ScaleResolutionMember): () => boolean;
69
64
  /**
70
- * @param {UnitView} view
71
- * @returns {boolean}
65
+ * Reconfigures the scale: updates domain and other settings.
66
+ *
67
+ * Use this when the set of participating members changes (views added or removed),
68
+ * or when scale properties are otherwise re-resolved from the view hierarchy.
72
69
  */
73
- removeMembersByView(view: import("./unitView.js").default): boolean;
70
+ reconfigure(): void;
74
71
  /**
75
- * Extracts and unions the data domains of all participating views.
72
+ * Reconfigures only the effective domain (configured + data-derived).
76
73
  *
77
- * @return { DomainArray }
74
+ * Use this when data changes but the scale membership and properties are stable.
78
75
  */
79
- getDataDomain(): import("../utils/domainArray.js").DomainArray;
76
+ reconfigureDomain(): void;
80
77
  /**
81
- * Reconfigures the scale: updates domain and other settings
78
+ * @returns {ScaleWithProps}
82
79
  */
83
- reconfigure(): void;
80
+ get scale(): import("../types/encoder.js").VegaScale & {
81
+ props: import("../spec/scale.js").Scale;
82
+ };
84
83
  /**
84
+ * Returns the scale instance, creating it if needed.
85
+ *
86
+ * Use this from call sites that may run before explicit initialization.
87
+ *
85
88
  * @returns {ScaleWithProps}
86
89
  */
87
- get scale(): import("../types/encoder.js").VegaScale & {
90
+ getScale(): import("../types/encoder.js").VegaScale & {
91
+ props: import("../spec/scale.js").Scale;
92
+ };
93
+ /**
94
+ * Initializes the scale instance once resolution has stabilized.
95
+ *
96
+ * @returns {ScaleWithProps}
97
+ */
98
+ initializeScale(): import("../types/encoder.js").VegaScale & {
88
99
  props: import("../spec/scale.js").Scale;
89
100
  };
90
101
  getDomain(): any[];
102
+ /**
103
+ * Extracts and unions the data domains of all participating views.
104
+ *
105
+ * @return { DomainArray }
106
+ */
107
+ getDataDomain(): import("../utils/domainArray.js").DomainArray;
91
108
  /**
92
109
  * @returns {NumericDomain | ComplexDomain}
93
110
  */
@@ -141,11 +158,6 @@ export default class ScaleResolution implements ScaleResolutionApi {
141
158
  * be configured as pixels, but that is yet to be materialized.
142
159
  */
143
160
  getAxisLength(): number;
144
- /**
145
- *
146
- * @returns {import("../genome/genome.js").default}
147
- */
148
- getGenome(): import("../genome/genome.js").default;
149
161
  /**
150
162
  * Inverts a value in range to a value on domain. Returns an object in
151
163
  * case of locus scale.
@@ -173,9 +185,15 @@ export type ScaleResolutionMember<T extends import("../spec/channel.js").Channel
173
185
  /**
174
186
  * TODO: Get rid of the view reference
175
187
  */
176
- view: import("./unitView.js").default;
188
+ view: import("../view/unitView.js").default;
177
189
  channel: T;
178
190
  channelDef: import("../spec/channel.js").ChannelDefWithScale;
179
191
  dataDomainSource: (channel: import("../spec/channel.js").ChannelWithScale, type: import("../spec/channel.js").Type) => import("../utils/domainArray.js").DomainArray;
180
192
  };
193
+ import { INDEX } from "./scaleResolutionConstants.js";
194
+ import { LOCUS } from "./scaleResolutionConstants.js";
195
+ import { NOMINAL } from "./scaleResolutionConstants.js";
196
+ import { ORDINAL } from "./scaleResolutionConstants.js";
197
+ import { QUANTITATIVE } from "./scaleResolutionConstants.js";
198
+ export { INDEX, LOCUS, NOMINAL, ORDINAL, QUANTITATIVE };
181
199
  //# sourceMappingURL=scaleResolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleResolution.js"],"names":[],"mappings":"AAmrBA;;;;;;;;;;;;;GAaG;AACH,mDAHW,OAAO,iBAAiB,EAAE,OAAO,GAAG,OAAO,iBAAiB,EAAE,OAAO,EAAE,eACvE,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,KAAK,OAAO,QA4B9D;AAprBD;;;;;;;;GAQG;AACH;;;;;;;;GAQG;AACH;IA2CI;;OAEG;IACH,2DAgCC;IA/BG,8CAAsB;IACtB,0FAA0F;IAC1F,MADW,OAAO,oBAAoB,EAAE,IAAI,CAC5B;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IA+DzB,2BASC;IAqBD;;;;;;;OAOG;IACH,4KAEC;IAED;;;OAGG;IACH,+KAEC;IAyED;;;OAGG;IACH,uBAHW,qBAAqB,GACnB,MAAM,OAAO,CAQzB;IA4HD;;;;;OAKG;IACH,oBAGC;IAED;;;;OAIG;IACH,0BAKC;IAkDD;;OAEG;IACH;eA7akC,OAAO,kBAAkB,EAAE,KAAK;MAobjE;IAED;;;;;;OAMG;IACH;eA7bkC,OAAO,kBAAkB,EAAE,KAAK;MA+bjE;IAED;;;;OAIG;IACH;eAtckC,OAAO,kBAAkB,EAAE,KAAK;MA+cjE;IAED,mBAEC;IAED;;;;OAIG;IACH,+DAEC;IAED;;OAEG;IACH,oBAFa,mFAA6B,CAMzC;IAED;;;;OAIG;IACH,oBAEC;IAED;;OAEG;IACH,sBAGC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CAInB;IAED;;;;;;OAMG;IACH,eAJW,mFAA6B,aAC7B,OAAO,GAAG,MAAM,iBAK1B;IAED;;;;OAIG;IACH,qBAEC;IAED;;;;;OAKG;IACH,uBAEC;IAED;;;;;;;OAOG;IACH,wBAoBC;IAED;;;;;OAKG;IACH,uBAFW,MAAM,yDAUhB;IAED;;OAEG;IACH,iBAFW,MAAM,yDAIhB;IAED;;;OAGG;IACH,qBAHW,MAAM,+CAAmB,GACvB,MAAM,CAIlB;IAED;;;OAGG;IACH,8BAHW,kFAA4B,GAC1B,MAAM,EAAE,CAOpB;;CACJ;kCAzoB+B,CAAC,SAApB,6CAAkB;;;;UAGrB,OAAO,qBAAqB,EAAE,OAAO;aACrC,CAAC;gBACD,OAAO,oBAAoB,EAAE,mBAAmB;sBAChD,CAAC,OAAO,+CAAkB,EAAE,IAAI,EAAE,OAAO,oBAAoB,EAAE,IAAI,kDAAgB;;sBAvBtF,+BAA+B;sBAA/B,+BAA+B;wBAA/B,+BAA+B;wBAA/B,+BAA+B;6BAA/B,+BAA+B"}