@genome-spy/core 0.66.1 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/dist/bundle/index.es.js +7669 -6115
  2. package/dist/bundle/index.js +114 -133
  3. package/dist/schema.json +534 -132
  4. package/dist/src/data/collector.d.ts +20 -0
  5. package/dist/src/data/collector.d.ts.map +1 -1
  6. package/dist/src/data/collector.js +148 -0
  7. package/dist/src/data/dataFlow.d.ts +6 -0
  8. package/dist/src/data/dataFlow.d.ts.map +1 -1
  9. package/dist/src/data/dataFlow.js +10 -0
  10. package/dist/src/data/flowHandle.d.ts +2 -0
  11. package/dist/src/data/flowHandle.d.ts.map +1 -1
  12. package/dist/src/data/flowHandle.js +1 -0
  13. package/dist/src/data/flowInit.d.ts +12 -4
  14. package/dist/src/data/flowInit.d.ts.map +1 -1
  15. package/dist/src/data/flowInit.js +115 -17
  16. package/dist/src/data/flowNode.d.ts +8 -0
  17. package/dist/src/data/flowNode.d.ts.map +1 -1
  18. package/dist/src/data/flowNode.js +18 -0
  19. package/dist/src/data/keyIndex.d.ts +18 -0
  20. package/dist/src/data/keyIndex.d.ts.map +1 -0
  21. package/dist/src/data/keyIndex.js +241 -0
  22. package/dist/src/data/keyIndex.test.d.ts +2 -0
  23. package/dist/src/data/keyIndex.test.d.ts.map +1 -0
  24. package/dist/src/data/sources/dataSource.d.ts.map +1 -1
  25. package/dist/src/data/sources/dataSource.js +5 -1
  26. package/dist/src/data/sources/dataSourceFactory.d.ts +14 -12
  27. package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -1
  28. package/dist/src/data/sources/dataSourceFactory.js +52 -16
  29. package/dist/src/data/sources/lazy/mockLazySource.d.ts +29 -0
  30. package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -0
  31. package/dist/src/data/sources/lazy/mockLazySource.js +44 -0
  32. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +22 -1
  33. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  34. package/dist/src/data/sources/lazy/singleAxisLazySource.js +34 -2
  35. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  36. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +15 -0
  37. package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
  38. package/dist/src/data/sources/lazy/tabixSource.js +15 -5
  39. package/dist/src/data/transforms/stack.d.ts.map +1 -1
  40. package/dist/src/data/transforms/stack.js +1 -0
  41. package/dist/src/encoder/accessor.d.ts +43 -0
  42. package/dist/src/encoder/accessor.d.ts.map +1 -1
  43. package/dist/src/encoder/accessor.js +164 -0
  44. package/dist/src/encoder/encoder.d.ts +11 -2
  45. package/dist/src/encoder/encoder.d.ts.map +1 -1
  46. package/dist/src/encoder/encoder.js +24 -4
  47. package/dist/src/encoder/metadataChannels.d.ts +15 -0
  48. package/dist/src/encoder/metadataChannels.d.ts.map +1 -0
  49. package/dist/src/encoder/metadataChannels.js +65 -0
  50. package/dist/src/encoder/metadataChannels.test.d.ts +2 -0
  51. package/dist/src/encoder/metadataChannels.test.d.ts.map +1 -0
  52. package/dist/src/genome/scaleLocus.d.ts.map +1 -1
  53. package/dist/src/genome/scaleLocus.js +14 -1
  54. package/dist/src/genomeSpy/containerUi.d.ts +0 -1
  55. package/dist/src/genomeSpy/containerUi.d.ts.map +1 -1
  56. package/dist/src/genomeSpy/containerUi.js +0 -14
  57. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +3 -7
  58. package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -1
  59. package/dist/src/genomeSpy/loadingIndicatorManager.js +68 -20
  60. package/dist/src/genomeSpy/loadingStatusRegistry.d.ts +52 -0
  61. package/dist/src/genomeSpy/loadingStatusRegistry.d.ts.map +1 -0
  62. package/dist/src/genomeSpy/loadingStatusRegistry.js +86 -0
  63. package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -1
  64. package/dist/src/genomeSpy/viewContextFactory.js +0 -1
  65. package/dist/src/genomeSpy/viewDataInit.d.ts +10 -0
  66. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
  67. package/dist/src/genomeSpy/viewDataInit.js +166 -2
  68. package/dist/src/genomeSpy/viewDataInit.test.d.ts +2 -0
  69. package/dist/src/genomeSpy/viewDataInit.test.d.ts.map +1 -0
  70. package/dist/src/genomeSpy.d.ts +1 -2
  71. package/dist/src/genomeSpy.d.ts.map +1 -1
  72. package/dist/src/genomeSpy.js +69 -27
  73. package/dist/src/gl/dataToVertices.d.ts.map +1 -1
  74. package/dist/src/gl/dataToVertices.js +16 -4
  75. package/dist/src/marks/mark.d.ts.map +1 -1
  76. package/dist/src/marks/mark.js +18 -11
  77. package/dist/src/marks/markUtils.js +1 -1
  78. package/dist/src/scale/scale.d.ts +6 -1
  79. package/dist/src/scale/scale.d.ts.map +1 -1
  80. package/dist/src/scale/scale.js +83 -23
  81. package/dist/src/scales/axisResolution.d.ts.map +1 -1
  82. package/dist/src/scales/axisResolution.js +10 -0
  83. package/dist/src/scales/{scaleDomainAggregator.d.ts → domainPlanner.d.ts} +8 -5
  84. package/dist/src/scales/domainPlanner.d.ts.map +1 -0
  85. package/dist/src/scales/domainPlanner.js +285 -0
  86. package/dist/src/scales/domainPlanner.test.d.ts +2 -0
  87. package/dist/src/scales/domainPlanner.test.d.ts.map +1 -0
  88. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
  89. package/dist/src/scales/scaleInstanceManager.js +8 -4
  90. package/dist/src/scales/scaleInteractionController.d.ts +6 -0
  91. package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
  92. package/dist/src/scales/scaleInteractionController.js +41 -3
  93. package/dist/src/scales/scaleResolution.d.ts +19 -16
  94. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  95. package/dist/src/scales/scaleResolution.js +255 -70
  96. package/dist/src/scales/scaleResolution.test.d.ts.map +1 -1
  97. package/dist/src/selection/selection.d.ts +21 -0
  98. package/dist/src/selection/selection.d.ts.map +1 -1
  99. package/dist/src/selection/selection.js +82 -0
  100. package/dist/src/spec/channel.d.ts +52 -15
  101. package/dist/src/spec/data.d.ts +4 -0
  102. package/dist/src/spec/parameter.d.ts +16 -11
  103. package/dist/src/spec/testing.d.ts +12 -0
  104. package/dist/src/spec/testing.d.ts.map +1 -0
  105. package/dist/src/spec/testing.js +20 -0
  106. package/dist/src/spec/view.d.ts +45 -10
  107. package/dist/src/styles/genome-spy.css +3 -31
  108. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  109. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  110. package/dist/src/styles/genome-spy.css.js +0 -29
  111. package/dist/src/types/encoder.d.ts +37 -2
  112. package/dist/src/types/rendering.d.ts +4 -3
  113. package/dist/src/types/viewContext.d.ts +0 -14
  114. package/dist/src/utils/domainArray.d.ts.map +1 -1
  115. package/dist/src/utils/domainArray.js +3 -0
  116. package/dist/src/utils/indexer.d.ts +3 -0
  117. package/dist/src/utils/indexer.d.ts.map +1 -1
  118. package/dist/src/utils/indexer.js +3 -0
  119. package/dist/src/utils/throttle.d.ts +4 -1
  120. package/dist/src/utils/throttle.d.ts.map +1 -1
  121. package/dist/src/utils/throttle.js +54 -23
  122. package/dist/src/utils/throttle.test.d.ts +2 -0
  123. package/dist/src/utils/throttle.test.d.ts.map +1 -0
  124. package/dist/src/utils/transition.d.ts +21 -0
  125. package/dist/src/utils/transition.d.ts.map +1 -1
  126. package/dist/src/utils/transition.js +28 -0
  127. package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
  128. package/dist/src/utils/ui/tooltip.js +7 -1
  129. package/dist/src/utils/ui/tooltip.test.d.ts +2 -0
  130. package/dist/src/utils/ui/tooltip.test.d.ts.map +1 -0
  131. package/dist/src/view/axisGridView.d.ts.map +1 -1
  132. package/dist/src/view/axisGridView.js +22 -5
  133. package/dist/src/view/axisView.d.ts.map +1 -1
  134. package/dist/src/view/axisView.js +20 -5
  135. package/dist/src/view/concatView.js +3 -3
  136. package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
  137. package/dist/src/view/containerMutationHelper.js +6 -2
  138. package/dist/src/view/containerView.d.ts +9 -5
  139. package/dist/src/view/containerView.d.ts.map +1 -1
  140. package/dist/src/view/containerView.js +34 -9
  141. package/dist/src/view/dataReadiness.d.ts +46 -0
  142. package/dist/src/view/dataReadiness.d.ts.map +1 -0
  143. package/dist/src/view/dataReadiness.js +267 -0
  144. package/dist/src/view/dataReadiness.test.d.ts +2 -0
  145. package/dist/src/view/dataReadiness.test.d.ts.map +1 -0
  146. package/dist/src/view/facetView.d.ts.map +1 -1
  147. package/dist/src/view/facetView.js +7 -5
  148. package/dist/src/view/flowBuilder.d.ts +5 -3
  149. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  150. package/dist/src/view/flowBuilder.js +74 -7
  151. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  152. package/dist/src/view/gridView/gridChild.js +8 -0
  153. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  154. package/dist/src/view/gridView/gridView.js +119 -2
  155. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
  156. package/dist/src/view/gridView/scrollbar.js +3 -0
  157. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  158. package/dist/src/view/gridView/selectionRect.js +20 -5
  159. package/dist/src/view/gridView/separatorView.d.ts +51 -0
  160. package/dist/src/view/gridView/separatorView.d.ts.map +1 -0
  161. package/dist/src/view/gridView/separatorView.js +275 -0
  162. package/dist/src/view/layerView.js +3 -3
  163. package/dist/src/view/layout/flexLayout.d.ts +0 -30
  164. package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
  165. package/dist/src/view/layout/flexLayout.js +0 -86
  166. package/dist/src/view/paramMediator.d.ts +19 -0
  167. package/dist/src/view/paramMediator.d.ts.map +1 -1
  168. package/dist/src/view/paramMediator.js +86 -19
  169. package/dist/src/view/testUtils.d.ts.map +1 -1
  170. package/dist/src/view/testUtils.js +11 -1
  171. package/dist/src/view/unitView.d.ts +8 -13
  172. package/dist/src/view/unitView.d.ts.map +1 -1
  173. package/dist/src/view/unitView.js +127 -43
  174. package/dist/src/view/view.d.ts +34 -14
  175. package/dist/src/view/view.d.ts.map +1 -1
  176. package/dist/src/view/view.js +119 -9
  177. package/dist/src/view/viewFactory.d.ts.map +1 -1
  178. package/dist/src/view/viewFactory.js +20 -1
  179. package/dist/src/view/viewSelectors.d.ts +148 -0
  180. package/dist/src/view/viewSelectors.d.ts.map +1 -0
  181. package/dist/src/view/viewSelectors.js +773 -0
  182. package/dist/src/view/viewSelectors.test.d.ts +2 -0
  183. package/dist/src/view/viewSelectors.test.d.ts.map +1 -0
  184. package/dist/src/view/viewUtils.d.ts +0 -8
  185. package/dist/src/view/viewUtils.d.ts.map +1 -1
  186. package/dist/src/view/viewUtils.js +1 -21
  187. package/package.json +3 -3
  188. package/dist/src/scales/scaleDomainAggregator.d.ts.map +0 -1
  189. package/dist/src/scales/scaleDomainAggregator.js +0 -162
  190. package/dist/src/scales/scaleDomainAggregator.test.d.ts +0 -2
  191. package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +0 -1
@@ -0,0 +1,285 @@
1
+ import { span } from "vega-util";
2
+ import { isContinuous } from "vega-scale";
3
+
4
+ import { LOCUS } from "./scaleResolutionConstants.js";
5
+ import createDomain from "../utils/domainArray.js";
6
+ import { getAccessorDomainKey, isScaleAccessor } from "../encoder/accessor.js";
7
+
8
+ /**
9
+ * @typedef {import("../utils/domainArray.js").DomainArray} DomainArray
10
+ * @typedef {import("../spec/scale.js").ComplexDomain} ComplexDomain
11
+ * @typedef {import("../spec/scale.js").ScalarDomain} ScalarDomain
12
+ * @typedef {import("./scaleResolution.js").ScaleResolutionMember} ScaleResolutionMember
13
+ */
14
+
15
+ export default class DomainPlanner {
16
+ /** @type {() => Set<ScaleResolutionMember>} */
17
+ #getMembers;
18
+
19
+ /** @type {() => Set<ScaleResolutionMember>} */
20
+ #getDataMembers;
21
+
22
+ /** @type {() => import("../spec/channel.js").Type} */
23
+ #getType;
24
+
25
+ /** @type {() => number[]} */
26
+ #getLocusExtent;
27
+
28
+ /** @type {(interval: ScalarDomain | ComplexDomain) => number[]} */
29
+ #fromComplexInterval;
30
+
31
+ /** @type {any[]} */
32
+ #initialDomain;
33
+
34
+ /** @type {DomainArray | undefined} */
35
+ #configuredDomain;
36
+
37
+ #configuredDomainDirty = true;
38
+
39
+ /** @type {WeakMap<ScaleResolutionMember, import("../types/encoder.js").ScaleAccessor[]>} */
40
+ #accessorsByMember = new WeakMap();
41
+
42
+ /**
43
+ * @param {object} options
44
+ * @param {() => Set<ScaleResolutionMember>} options.getMembers
45
+ * @param {() => Set<ScaleResolutionMember>} [options.getDataMembers]
46
+ * @param {() => import("../spec/channel.js").Type} options.getType
47
+ * @param {() => number[]} options.getLocusExtent
48
+ * @param {(interval: ScalarDomain | ComplexDomain) => number[]} options.fromComplexInterval
49
+ */
50
+ constructor({
51
+ getMembers,
52
+ getDataMembers,
53
+ getType,
54
+ getLocusExtent,
55
+ fromComplexInterval,
56
+ }) {
57
+ this.#getMembers = getMembers;
58
+ this.#getDataMembers = getDataMembers ?? getMembers;
59
+ this.#getType = getType;
60
+ this.#getLocusExtent = getLocusExtent;
61
+ this.#fromComplexInterval = fromComplexInterval;
62
+ }
63
+
64
+ /**
65
+ * @returns {any[]}
66
+ */
67
+ get initialDomainSnapshot() {
68
+ return this.#initialDomain;
69
+ }
70
+
71
+ hasConfiguredDomain() {
72
+ return !!this.getConfiguredDomain();
73
+ }
74
+
75
+ invalidateConfiguredDomain() {
76
+ this.#configuredDomainDirty = true;
77
+ }
78
+
79
+ /**
80
+ * Returns the configured domain or a data-derived/default domain.
81
+ *
82
+ * @param {boolean} [extractDataDomain]
83
+ * @returns {any[]}
84
+ */
85
+ getConfiguredOrDefaultDomain(extractDataDomain = false) {
86
+ // TODO: intersect the domain with zoom extent (if it's defined)
87
+ return (
88
+ this.getConfiguredDomain() ??
89
+ resolveDefaultDomain(
90
+ this.#getType(),
91
+ this.#getLocusExtent,
92
+ extractDataDomain ? this.getDataDomain() : undefined
93
+ )
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Unions the configured domains of all participating views.
99
+ *
100
+ * @return {DomainArray}
101
+ */
102
+ getConfiguredDomain() {
103
+ if (!this.#configuredDomainDirty) {
104
+ return this.#configuredDomain;
105
+ }
106
+
107
+ const domain = resolveConfiguredDomain(
108
+ this.#getMembers(),
109
+ this.#fromComplexInterval
110
+ );
111
+ this.#configuredDomain = domain;
112
+ this.#configuredDomainDirty = false;
113
+ return domain;
114
+ }
115
+
116
+ /**
117
+ * Extracts and unions the data domains of all participating views.
118
+ *
119
+ * @return {DomainArray | undefined}
120
+ */
121
+ getDataDomain() {
122
+ return resolveDataDomain(
123
+ this.#getDataMembers(),
124
+ this.#getType,
125
+ (member) => this.#getMemberAccessors(member)
126
+ );
127
+ }
128
+
129
+ /**
130
+ * @param {import("../types/encoder.js").VegaScale} scale
131
+ * @param {boolean} domainWasInitialized
132
+ * @returns {boolean} true if listeners should be notified immediately
133
+ */
134
+ captureInitialDomain(scale, domainWasInitialized) {
135
+ if (!this.#initialDomain && isContinuous(scale.type)) {
136
+ const domain = scale.domain();
137
+ if (span(domain) > 0) {
138
+ this.#initialDomain = domain;
139
+ }
140
+ }
141
+
142
+ if (!domainWasInitialized) {
143
+ this.#initialDomain = scale.domain();
144
+ return true;
145
+ }
146
+
147
+ return false;
148
+ }
149
+
150
+ /**
151
+ * @param {ScaleResolutionMember} member
152
+ * @returns {import("../types/encoder.js").ScaleAccessor[]}
153
+ */
154
+ #getMemberAccessors(member) {
155
+ const cached = this.#accessorsByMember.get(member);
156
+ if (cached) {
157
+ return cached;
158
+ }
159
+
160
+ const encoders = member.view.mark.encoders;
161
+ if (!encoders) {
162
+ return [];
163
+ }
164
+
165
+ const encoder = encoders[member.channel];
166
+ if (!encoder) {
167
+ return [];
168
+ }
169
+
170
+ const accessors = encoder.accessors ?? [];
171
+ if (accessors.length === 0) {
172
+ return [];
173
+ }
174
+
175
+ const scaleAccessors = accessors
176
+ .filter(isScaleAccessor)
177
+ .filter((accessor) => !accessor.channelDef.domainInert);
178
+
179
+ this.#accessorsByMember.set(member, scaleAccessors);
180
+ return scaleAccessors;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * @param {Set<ScaleResolutionMember>} members
186
+ * @param {(interval: ScalarDomain | ComplexDomain) => number[]} fromComplexInterval
187
+ * @returns {DomainArray | undefined}
188
+ */
189
+ function resolveConfiguredDomain(members, fromComplexInterval) {
190
+ const domains = Array.from(members)
191
+ .filter((member) => member.contributesToDomain)
192
+ .map((member) => member.channelDef)
193
+ .filter((channelDef) => channelDef.scale?.domain)
194
+ .map((channelDef) =>
195
+ // TODO: Handle ExprRefs and Param in domain
196
+ createDomain(
197
+ channelDef.type,
198
+ // Chrom/pos must be linearized first
199
+ fromComplexInterval(channelDef.scale.domain)
200
+ )
201
+ );
202
+
203
+ if (domains.length > 0) {
204
+ return domains.reduce((acc, curr) => acc.extendAll(curr));
205
+ }
206
+ }
207
+
208
+ /**
209
+ * @param {Set<ScaleResolutionMember>} members
210
+ * @param {() => import("../spec/channel.js").Type} getType
211
+ * @param {(member: ScaleResolutionMember) => import("../types/encoder.js").ScaleAccessor[]} getAccessorsForMember
212
+ * @returns {DomainArray | undefined}
213
+ */
214
+ function resolveDataDomain(members, getType, getAccessorsForMember) {
215
+ const type = getType();
216
+
217
+ /** @type {Map<import("../data/collector.js").default | null, Map<string, DomainArray>>} */
218
+ const domainsByCollector = new Map();
219
+
220
+ for (const member of members) {
221
+ if (!member.contributesToDomain) {
222
+ continue;
223
+ }
224
+
225
+ const accessors = getAccessorsForMember(member);
226
+ if (accessors.length === 0) {
227
+ continue;
228
+ }
229
+
230
+ const collector = member.view.getCollector();
231
+
232
+ for (const accessor of accessors) {
233
+ const domainKey = getAccessorDomainKey(accessor, type);
234
+
235
+ const collectorKey = collector ?? null;
236
+ let domainsForCollector = domainsByCollector.get(collectorKey);
237
+ if (!domainsForCollector) {
238
+ domainsForCollector = new Map();
239
+ domainsByCollector.set(collectorKey, domainsForCollector);
240
+ }
241
+
242
+ if (domainsForCollector.has(domainKey)) {
243
+ continue;
244
+ }
245
+
246
+ let domain;
247
+ if (collector) {
248
+ domain = collector.getDomain(domainKey, type, accessor);
249
+ } else if (accessor.constant) {
250
+ domain = createDomain(type);
251
+ domain.extend(accessor({}));
252
+ } else {
253
+ continue;
254
+ }
255
+
256
+ domainsForCollector.set(domainKey, domain);
257
+ }
258
+ }
259
+
260
+ if (domainsByCollector.size === 0) {
261
+ return undefined;
262
+ }
263
+
264
+ const domain = createDomain(type);
265
+ for (const domainsForCollector of domainsByCollector.values()) {
266
+ for (const memberDomain of domainsForCollector.values()) {
267
+ domain.extendAll(memberDomain);
268
+ }
269
+ }
270
+
271
+ return domain;
272
+ }
273
+
274
+ /**
275
+ * @param {import("../spec/channel.js").Type} type
276
+ * @param {() => number[]} getLocusExtent
277
+ * @param {DomainArray | undefined} dataDomain
278
+ * @returns {any[]}
279
+ */
280
+ function resolveDefaultDomain(type, getLocusExtent, dataDomain) {
281
+ if (type == LOCUS) {
282
+ return getLocusExtent();
283
+ }
284
+ return dataDomain ?? [];
285
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=domainPlanner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domainPlanner.test.d.ts","sourceRoot":"","sources":["../../../src/scales/domainPlanner.test.js"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"scaleInstanceManager.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInstanceManager.js"],"names":[],"mappings":"AAMA;IA0BI;;;;;;OAMG;IACH,kFALG;QAAkE,gBAAgB,EAA1E,MAAM,OAAO,0BAA0B,EAAE,OAAO;QAC5B,aAAa,EAAjC,MAAM,IAAI;QACW,cAAc,GAAnC,MAAM,IAAI;QAC6D,cAAc,GAArF,MAAM,OAAO,0BAA0B,EAAE,OAAO,GAAG,SAAS;KAA0B,EAYhG;IAED;eA1CkC,OAAO,kBAAkB,EAAE,KAAK;MA4CjE;IAED;;OAEG;IACH,kBAFa,OAAO,qBAAqB,EAAE,OAAO,CASjD;IAED;;;OAGG;IACH,mBAHW,OAAO,kBAAkB,EAAE,KAAK;eA3DT,OAAO,kBAAkB,EAAE,KAAK;MAgFjE;IAoBD;;OAEG;IACH,wBAFW,OAAO,kBAAkB,EAAE,KAAK,QAc1C;IAED;;;OAGG;IACH,4CAHW,MAAM,IAAI,GACR,IAAI,CAShB;;CA6EJ"}
1
+ {"version":3,"file":"scaleInstanceManager.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInstanceManager.js"],"names":[],"mappings":"AAMA;IA0BI;;;;;;OAMG;IACH,kFALG;QAAkE,gBAAgB,EAA1E,MAAM,OAAO,0BAA0B,EAAE,OAAO;QAC5B,aAAa,EAAjC,MAAM,IAAI;QACW,cAAc,GAAnC,MAAM,IAAI;QAC6D,cAAc,GAArF,MAAM,OAAO,0BAA0B,EAAE,OAAO,GAAG,SAAS;KAA0B,EAYhG;IAED;eA1CkC,OAAO,kBAAkB,EAAE,KAAK;MA4CjE;IAED;;OAEG;IACH,kBAFa,OAAO,qBAAqB,EAAE,OAAO,CASjD;IAED;;;OAGG;IACH,mBAHW,OAAO,kBAAkB,EAAE,KAAK;eA3DT,OAAO,kBAAkB,EAAE,KAAK;MAgFjE;IAoBD;;OAEG;IACH,wBAFW,OAAO,kBAAkB,EAAE,KAAK,QAc1C;IAED;;;OAGG;IACH,4CAHW,MAAM,IAAI,GACR,IAAI,CAShB;;CAiFJ"}
@@ -142,12 +142,16 @@ export default class ScaleInstanceManager {
142
142
  * @returns {import("../spec/scale.js").Scale}
143
143
  */
144
144
  #stripNonScaleProps(props) {
145
- if (!("assembly" in props)) {
146
- return props;
147
- }
148
145
  // Avoid sending non-scale properties into vega-scale.
149
- const { assembly: _assembly, ...rest } = props;
146
+ // Strip internal runtime-only props before passing into vega-scale.
147
+ const propsAny = /** @type {any} */ (props);
148
+ const {
149
+ assembly: _assembly,
150
+ domainIndexer: _domainIndexer,
151
+ ...rest
152
+ } = propsAny;
150
153
  void _assembly;
154
+ void _domainIndexer;
151
155
  return rest;
152
156
  }
153
157
 
@@ -27,6 +27,12 @@ export default class ScaleInteractionController {
27
27
  getZoomExtent(): number[];
28
28
  isZoomable(): boolean;
29
29
  isZoomingSupported(): boolean;
30
+ /**
31
+ * @param {number[]} previousDomain
32
+ * @param {number[]} newDomain
33
+ * @returns {"restore" | "animate" | "notify" | "none"}
34
+ */
35
+ getDomainChangeAction(previousDomain: number[], newDomain: number[]): "restore" | "animate" | "notify" | "none";
30
36
  /**
31
37
  * Return true if the scale is zoomable and the current domain differs from the initial domain.
32
38
  *
@@ -1 +1 @@
1
- {"version":3,"file":"scaleInteractionController.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInteractionController.js"],"names":[],"mappings":"AAmBA;;;;;;;GAOG;AAEH;IAmBI;;;;;;;;OAQG;IACH,wHAPG;QAAsC,QAAQ,EAAtC,MAAM,cAAc;QACkC,WAAW,EAAjE,MAAM,OAAO,sBAAsB,EAAE,OAAO;QACpB,wBAAwB,EAAhD,MAAM,MAAM,EAAE;QACU,cAAc,EAAtC,MAAM,MAAM,EAAE;QAC8C,mBAAmB,EAA/E,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,KAAK,MAAM,EAAE;QAC1B,eAAe,EAAvC,MAAM,MAAM,EAAE;KACxB,EAeA;IAED,0BAUC;IAED,sBAEC;IAED,8BAEC;IAED;;;;OAIG;IACH,oBAQC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CA2BnB;IAED;;;;;;OAMG;IACH,eAJW,aAAa,GAAG,aAAa,aAC7B,OAAO,GAAG,MAAM,iBAuD1B;IAED;;;;OAIG;IACH,qBAcC;IAED;;OAEG;IACH,uBAOC;;CACJ;4BAvNY,OAAO,kBAAkB,EAAE,aAAa;2BACxC,OAAO,kBAAkB,EAAE,YAAY;4BACvC,OAAO,kBAAkB,EAAE,aAAa;yBACxC,OAAO,kBAAkB,EAAE,UAAU;wBACrC,OAAO,qBAAqB,EAAE,SAAS;6BACvC,SAAS,GAAG;IAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;CAAE"}
1
+ {"version":3,"file":"scaleInteractionController.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInteractionController.js"],"names":[],"mappings":"AAoBA;;;;;;;GAOG;AAEH;IAsBI;;;;;;;;OAQG;IACH,wHAPG;QAAsC,QAAQ,EAAtC,MAAM,cAAc;QACkC,WAAW,EAAjE,MAAM,OAAO,sBAAsB,EAAE,OAAO;QACpB,wBAAwB,EAAhD,MAAM,MAAM,EAAE;QACU,cAAc,EAAtC,MAAM,MAAM,EAAE;QAC8C,mBAAmB,EAA/E,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,KAAK,MAAM,EAAE;QAC1B,eAAe,EAAvC,MAAM,MAAM,EAAE;KACxB,EAeA;IAED,0BAUC;IAED,sBAEC;IAED,8BAGC;IAED;;;;OAIG;IACH,sCAJW,MAAM,EAAE,aACR,MAAM,EAAE,GACN,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAarD;IAED;;;;OAIG;IACH,oBAQC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CA2BnB;IAED;;;;;;OAMG;IACH,eAJW,aAAa,GAAG,aAAa,aAC7B,OAAO,GAAG,MAAM,iBA+D1B;IASD;;;;OAIG;IACH,qBAcC;IAED;;OAEG;IACH,uBAOC;;CACJ;4BA5PY,OAAO,kBAAkB,EAAE,aAAa;2BACxC,OAAO,kBAAkB,EAAE,YAAY;4BACvC,OAAO,kBAAkB,EAAE,aAAa;yBACxC,OAAO,kBAAkB,EAAE,UAAU;wBACrC,OAAO,qBAAqB,EAAE,SAAS;6BACvC,SAAS,GAAG;IAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;CAAE"}
@@ -11,11 +11,12 @@ import {
11
11
  zoomLog,
12
12
  zoomPow,
13
13
  } from "vega-util";
14
- import { isContinuous } from "vega-scale";
14
+ import { isContinuous, isDiscrete } from "vega-scale";
15
15
  import { easeCubicInOut } from "d3-ease";
16
16
 
17
17
  import eerp from "../utils/eerp.js";
18
18
  import { shallowArrayEquals } from "../utils/arrayUtils.js";
19
+ import { createCancelToken } from "../utils/transition.js";
19
20
 
20
21
  /**
21
22
  * @typedef {import("../spec/scale.js").NumericDomain} NumericDomain
@@ -45,6 +46,9 @@ export default class ScaleInteractionController {
45
46
  /** @type {() => number[]} */
46
47
  #getGenomeExtent;
47
48
 
49
+ /** @type {{ canceled: boolean } | null} */
50
+ #zoomTransitionToken = null;
51
+
48
52
  /**
49
53
  * @param {object} options
50
54
  * @param {() => ScaleWithProps} options.getScale
@@ -87,7 +91,26 @@ export default class ScaleInteractionController {
87
91
  }
88
92
 
89
93
  isZoomingSupported() {
90
- return isContinuous(this.#getScale().type);
94
+ const type = this.#getScale().type;
95
+ return isContinuous(type) && !isDiscrete(type);
96
+ }
97
+
98
+ /**
99
+ * @param {number[]} previousDomain
100
+ * @param {number[]} newDomain
101
+ * @returns {"restore" | "animate" | "notify" | "none"}
102
+ */
103
+ getDomainChangeAction(previousDomain, newDomain) {
104
+ if (shallowArrayEquals(newDomain, previousDomain)) {
105
+ return "none";
106
+ }
107
+ if (this.isZoomable()) {
108
+ return "restore";
109
+ }
110
+ if (this.isZoomingSupported()) {
111
+ return "animate";
112
+ }
113
+ return "notify";
91
114
  }
92
115
 
93
116
  /**
@@ -178,10 +201,14 @@ export default class ScaleInteractionController {
178
201
  const ac = from[0] == to[0];
179
202
  const bc = from[1] == to[1];
180
203
 
181
- // TODO: Abort possible previous transition
204
+ this.#cancelZoomTransition();
205
+ const cancelToken = createCancelToken();
206
+ this.#zoomTransitionToken = cancelToken;
207
+
182
208
  await animator.transition({
183
209
  duration,
184
210
  easingFunction: easeCubicInOut,
211
+ cancelToken,
185
212
  onUpdate: (t) => {
186
213
  const w = eerp(fw, tw, t);
187
214
  const wt = fw == tw ? t : (fw - w) / (fw - tw);
@@ -194,13 +221,24 @@ export default class ScaleInteractionController {
194
221
  },
195
222
  });
196
223
 
224
+ if (this.#zoomTransitionToken === cancelToken) {
225
+ this.#zoomTransitionToken = null;
226
+ }
197
227
  scale.domain(to);
198
228
  } else {
229
+ this.#cancelZoomTransition();
199
230
  scale.domain(to);
200
231
  animator?.requestRender();
201
232
  }
202
233
  }
203
234
 
235
+ #cancelZoomTransition() {
236
+ if (this.#zoomTransitionToken) {
237
+ this.#zoomTransitionToken.canceled = true;
238
+ this.#zoomTransitionToken = null;
239
+ }
240
+ }
241
+
204
242
  /**
205
243
  * Resets the current domain to the initial one
206
244
  *
@@ -1,17 +1,3 @@
1
- /**
2
- * Reconfigures scale domains, starting from the given view.
3
- *
4
- * Use this for data-driven updates where only domains need refreshing.
5
- *
6
- * TODO: This should be made unnecessary. Collectors should trigger the reconfiguration
7
- * for those views that get their data from the collector.
8
- *
9
- * TODO: This may reconfigure channels that are not affected by the change.
10
- * Causes performance issues with domains that are extracted from data.
11
- *
12
- * @param {import("../view/view.js").default | import("../view/view.js").default[]} fromViews
13
- */
14
- export function reconfigureScaleDomains(fromViews: import("../view/view.js").default | import("../view/view.js").default[]): void;
15
1
  /**
16
2
  * @template {ChannelWithScale}[T=ChannelWithScale]
17
3
  *
@@ -19,7 +5,7 @@ export function reconfigureScaleDomains(fromViews: import("../view/view.js").def
19
5
  * @prop {import("../view/unitView.js").default} view TODO: Get rid of the view reference
20
6
  * @prop {T} channel
21
7
  * @prop {import("../spec/channel.js").ChannelDefWithScale} channelDef
22
- * @prop {(channel: ChannelWithScale, type: import("../spec/channel.js").Type) => DomainArray} dataDomainSource
8
+ * @prop {boolean} contributesToDomain
23
9
  */
24
10
  /**
25
11
  * Resolves a shared scale for a channel by merging scale properties and domains
@@ -28,6 +14,16 @@ export function reconfigureScaleDomains(fromViews: import("../view/view.js").def
28
14
  * notifications, while delegating domain aggregation, scale instance setup, and
29
15
  * interaction logic to focused helpers.
30
16
  *
17
+ * Documentation overview of current concerns this class (and its helpers) deal with:
18
+ * - Resolution membership and rules (shared/independent/forced/excluded, visibility, registration).
19
+ * - Scale property aggregation (merge props, channel overrides, unique scale names).
20
+ * - Domain computation and caching (configured/data unions, defaults, indexer stability, subscriptions).
21
+ * - Scale instance lifecycle (create, reconfigure props, apply domains, notify changes).
22
+ * - Interaction and zoom (zoom/pan/reset coordination, snapshots, zoom extents).
23
+ * - Rendering integration (range textures, axis sizing/positioning).
24
+ * - Locus-specific conversions (complex intervals, genome extent bindings).
25
+ * - Diagnostics and edge cases (ordinal unknown, nice/zero/padding, log warnings).
26
+ *
31
27
  * @implements {ScaleResolutionApi}
32
28
  */
33
29
  export default class ScaleResolution implements ScaleResolutionApi {
@@ -60,6 +56,12 @@ export default class ScaleResolution implements ScaleResolutionApi {
60
56
  * @returns {() => boolean}
61
57
  */
62
58
  registerMember(member: ScaleResolutionMember): () => boolean;
59
+ /**
60
+ * @param {import("../data/collector.js").default} collector
61
+ * @param {Iterable<import("../types/encoder.js").ScaleAccessor>} accessors
62
+ * @returns {() => void}
63
+ */
64
+ registerCollectorSubscriptions(collector: import("../data/collector.js").default, accessors: Iterable<import("../types/encoder.js").ScaleAccessor>): () => void;
63
65
  /**
64
66
  * Reconfigures the scale: updates domain and other settings.
65
67
  *
@@ -71,6 +73,7 @@ export default class ScaleResolution implements ScaleResolutionApi {
71
73
  * Reconfigures only the effective domain (configured + data-derived).
72
74
  *
73
75
  * Use this when data changes but the scale membership and properties are stable.
76
+ *
74
77
  */
75
78
  reconfigureDomain(): void;
76
79
  /**
@@ -187,7 +190,7 @@ export type ScaleResolutionMember<T extends import("../spec/channel.js").Channel
187
190
  view: import("../view/unitView.js").default;
188
191
  channel: T;
189
192
  channelDef: import("../spec/channel.js").ChannelDefWithScale;
190
- dataDomainSource: (channel: import("../spec/channel.js").ChannelWithScale, type: import("../spec/channel.js").Type) => import("../utils/domainArray.js").DomainArray;
193
+ contributesToDomain: boolean;
191
194
  };
192
195
  import { INDEX } from "./scaleResolutionConstants.js";
193
196
  import { LOCUS } from "./scaleResolutionConstants.js";
@@ -1 +1 @@
1
- {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleResolution.js"],"names":[],"mappings":"AA0mBA;;;;;;;;;;;;GAYG;AACH,mDAFW,OAAO,iBAAiB,EAAE,OAAO,GAAG,OAAO,iBAAiB,EAAE,OAAO,EAAE,QA4BjF;AA5mBD;;;;;;;;GAQG;AACH;;;;;;;;GAQG;AACH;IAsCI;;OAEG;IACH,2DAgCC;IA/BG,8CAAsB;IACtB,0FAA0F;IAC1F,MADW,OAAO,oBAAoB,EAAE,IAAI,CAC5B;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IA2CzB,2BASC;IAqBD;;;;;;;OAOG;IACH,4KAEC;IAED;;;OAGG;IACH,+KAEC;IAyED;;;OAGG;IACH,uBAHW,qBAAqB,GACnB,MAAM,OAAO,CAQzB;IA8ED;;;;;OAKG;IACH,oBAGC;IAED;;;;OAIG;IACH,0BAKC;IAkDD;;OAEG;IACH;eAtWkC,OAAO,kBAAkB,EAAE,KAAK;MA6WjE;IAED;;;;;;OAMG;IACH;eAtXkC,OAAO,kBAAkB,EAAE,KAAK;MAwXjE;IAED;;;;OAIG;IACH;eA/XkC,OAAO,kBAAkB,EAAE,KAAK;MAwYjE;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;kCAlkB+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;;sBArBtF,+BAA+B;sBAA/B,+BAA+B;wBAA/B,+BAA+B;wBAA/B,+BAA+B;6BAA/B,+BAA+B"}
1
+ {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleResolution.js"],"names":[],"mappings":"AAuCA;;;;;;;;GAQG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH;IA8CI;;OAEG;IACH,2DAkCC;IAjCG,8CAAsB;IACtB,0FAA0F;IAC1F,MADW,OAAO,oBAAoB,EAAE,IAAI,CAC5B;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IAoEzB,2BASC;IAqBD;;;;;;;OAOG;IACH,4KAEC;IAED;;;OAGG;IACH,+KAEC;IA6ED;;;OAGG;IACH,uBAHW,qBAAqB,GACnB,MAAM,OAAO,CAYzB;IAWD;;;;OAIG;IACH,0CAJW,OAAO,sBAAsB,EAAE,OAAO,aACtC,QAAQ,CAAC,OAAO,qBAAqB,EAAE,aAAa,CAAC,GACnD,MAAM,IAAI,CAkCtB;IA4HD;;;;;OAKG;IACH,oBAUC;IAED;;;;;OAKG;IACH,0BAuBC;IAuGD;;OAEG;IACH;eA5jBkC,OAAO,kBAAkB,EAAE,KAAK;MAmkBjE;IAED;;;;;;OAMG;IACH;eA5kBkC,OAAO,kBAAkB,EAAE,KAAK;MA8kBjE;IAED;;;;OAIG;IACH;eArlBkC,OAAO,kBAAkB,EAAE,KAAK;MA8lBjE;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;kCAlyB+B,CAAC,SAApB,6CAAkB;;;;UAGrB,OAAO,qBAAqB,EAAE,OAAO;aACrC,CAAC;gBACD,OAAO,oBAAoB,EAAE,mBAAmB;yBAChD,OAAO;;sBAvBV,+BAA+B;sBAA/B,+BAA+B;wBAA/B,+BAA+B;wBAA/B,+BAA+B;6BAA/B,+BAA+B"}