@genome-spy/core 0.14.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 (226) hide show
  1. package/dist/index.js +224 -0
  2. package/dist/style.css +1 -0
  3. package/package.json +54 -0
  4. package/src/data/collector.js +178 -0
  5. package/src/data/collector.test.js +82 -0
  6. package/src/data/dataFlow.js +109 -0
  7. package/src/data/dataFlow.test.js +3 -0
  8. package/src/data/facetNode.js +17 -0
  9. package/src/data/flow.test.js +71 -0
  10. package/src/data/flowBatch.d.ts +40 -0
  11. package/src/data/flowNode.js +283 -0
  12. package/src/data/flowNode.test.js +49 -0
  13. package/src/data/flowOptimizer.js +117 -0
  14. package/src/data/flowOptimizer.test.js +192 -0
  15. package/src/data/flowTestUtils.js +63 -0
  16. package/src/data/formats/fasta.js +32 -0
  17. package/src/data/formats/fasta.test.js +26 -0
  18. package/src/data/sources/dataSource.js +22 -0
  19. package/src/data/sources/dataSourceFactory.js +24 -0
  20. package/src/data/sources/dataUtils.js +31 -0
  21. package/src/data/sources/dynamicCallbackSource.js +56 -0
  22. package/src/data/sources/dynamicSource.js +36 -0
  23. package/src/data/sources/inlineSource.js +69 -0
  24. package/src/data/sources/inlineSource.test.js +55 -0
  25. package/src/data/sources/namedSource.js +74 -0
  26. package/src/data/sources/sequenceSource.js +46 -0
  27. package/src/data/sources/sequenceSource.test.js +45 -0
  28. package/src/data/sources/urlSource.js +74 -0
  29. package/src/data/transforms/aggregate.js +69 -0
  30. package/src/data/transforms/clone.js +40 -0
  31. package/src/data/transforms/clone.test.js +10 -0
  32. package/src/data/transforms/coverage.js +187 -0
  33. package/src/data/transforms/coverage.test.js +122 -0
  34. package/src/data/transforms/filter.js +37 -0
  35. package/src/data/transforms/filter.test.js +17 -0
  36. package/src/data/transforms/filterScoredLabels.js +134 -0
  37. package/src/data/transforms/flattenCompressedExons.js +57 -0
  38. package/src/data/transforms/flattenDelimited.js +68 -0
  39. package/src/data/transforms/flattenDelimited.test.js +86 -0
  40. package/src/data/transforms/flattenSequence.js +39 -0
  41. package/src/data/transforms/flattenSequence.test.js +33 -0
  42. package/src/data/transforms/formula.js +39 -0
  43. package/src/data/transforms/formula.test.js +18 -0
  44. package/src/data/transforms/identifier.js +108 -0
  45. package/src/data/transforms/identifier.test.js +82 -0
  46. package/src/data/transforms/linearizeGenomicCoordinate.js +101 -0
  47. package/src/data/transforms/measureText.js +44 -0
  48. package/src/data/transforms/pileup.js +128 -0
  49. package/src/data/transforms/pileup.test.js +69 -0
  50. package/src/data/transforms/project.js +41 -0
  51. package/src/data/transforms/project.test.js +31 -0
  52. package/src/data/transforms/regexExtract.js +61 -0
  53. package/src/data/transforms/regexExtract.test.js +66 -0
  54. package/src/data/transforms/regexFold.js +141 -0
  55. package/src/data/transforms/regexFold.test.js +159 -0
  56. package/src/data/transforms/sample.js +101 -0
  57. package/src/data/transforms/sample.test.js +37 -0
  58. package/src/data/transforms/stack.js +137 -0
  59. package/src/data/transforms/stack.test.js +90 -0
  60. package/src/data/transforms/transformFactory.js +60 -0
  61. package/src/encoder/accessor.js +82 -0
  62. package/src/encoder/accessor.test.js +46 -0
  63. package/src/encoder/encoder.js +369 -0
  64. package/src/encoder/encoder.test.js +97 -0
  65. package/src/fonts/Lato-Regular.json +1267 -0
  66. package/src/fonts/Lato-Regular.png +0 -0
  67. package/src/fonts/OFL.txt +93 -0
  68. package/src/fonts/README.md +3 -0
  69. package/src/fonts/bmFont.d.ts +58 -0
  70. package/src/fonts/bmFontManager.js +357 -0
  71. package/src/fonts/bmFontMetrics.js +108 -0
  72. package/src/genome/genome.js +305 -0
  73. package/src/genome/genome.test.js +152 -0
  74. package/src/genome/genomeStore.js +54 -0
  75. package/src/genome/locusFormat.js +31 -0
  76. package/src/genome/scaleIndex.js +199 -0
  77. package/src/genome/scaleIndex.test.js +61 -0
  78. package/src/genome/scaleLocus.js +112 -0
  79. package/src/genome/scaleLocus.test.js +3 -0
  80. package/src/genomeSpy.js +753 -0
  81. package/src/gl/arrayBuilder.js +199 -0
  82. package/src/gl/dataToVertices.js +621 -0
  83. package/src/gl/includes/common.glsl +63 -0
  84. package/src/gl/includes/fp64-arithmetic.glsl +187 -0
  85. package/src/gl/includes/fp64-utils.js +132 -0
  86. package/src/gl/includes/picking.fragment.glsl +3 -0
  87. package/src/gl/includes/picking.vertex.glsl +29 -0
  88. package/src/gl/includes/sampleFacet.glsl +107 -0
  89. package/src/gl/includes/scales.glsl +79 -0
  90. package/src/gl/includes/scales_fp64.glsl +30 -0
  91. package/src/gl/link.fragment.glsl +18 -0
  92. package/src/gl/link.vertex.glsl +111 -0
  93. package/src/gl/point.fragment.glsl +123 -0
  94. package/src/gl/point.vertex.glsl +128 -0
  95. package/src/gl/rect.fragment.glsl +51 -0
  96. package/src/gl/rect.vertex.glsl +114 -0
  97. package/src/gl/rule.fragment.glsl +52 -0
  98. package/src/gl/rule.vertex.glsl +89 -0
  99. package/src/gl/text.fragment.glsl +31 -0
  100. package/src/gl/text.vertex.glsl +246 -0
  101. package/src/gl/webGLHelper.js +490 -0
  102. package/src/img/bowtie.svg +1 -0
  103. package/src/img/genomespy-favicon.svg +34 -0
  104. package/src/index.html +11 -0
  105. package/src/index.js +151 -0
  106. package/src/marks/link.js +189 -0
  107. package/src/marks/mark.js +867 -0
  108. package/src/marks/markUtils.js +109 -0
  109. package/src/marks/pointMark.js +279 -0
  110. package/src/marks/rectMark.js +236 -0
  111. package/src/marks/rule.js +231 -0
  112. package/src/marks/text.js +274 -0
  113. package/src/options.d.ts +9 -0
  114. package/src/scale/colorUtils.js +184 -0
  115. package/src/scale/glslScaleGenerator.js +462 -0
  116. package/src/scale/scale.js +441 -0
  117. package/src/scale/scale.test.js +323 -0
  118. package/src/scale/ticks.js +198 -0
  119. package/src/scale/ticks.test.js +39 -0
  120. package/src/singlePageApp.js +13 -0
  121. package/src/spec/axis.d.ts +296 -0
  122. package/src/spec/channel.d.ts +127 -0
  123. package/src/spec/data.d.ts +185 -0
  124. package/src/spec/font.d.ts +15 -0
  125. package/src/spec/genome.d.ts +35 -0
  126. package/src/spec/mark.d.ts +432 -0
  127. package/src/spec/root.d.ts +22 -0
  128. package/src/spec/scale.d.ts +265 -0
  129. package/src/spec/tooltip.d.ts +9 -0
  130. package/src/spec/transform.d.ts +479 -0
  131. package/src/spec/view.d.ts +215 -0
  132. package/src/styles/genome-spy.scss +153 -0
  133. package/src/tooltip/dataTooltipHandler.js +59 -0
  134. package/src/tooltip/refseqGeneTooltipHandler.js +77 -0
  135. package/src/tooltip/tooltipHandler.ts +12 -0
  136. package/src/types/filetypes.d.ts +4 -0
  137. package/src/types/flatqueue.d.ts +53 -0
  138. package/src/types/glsl.d.ts +4 -0
  139. package/src/types/object.d.ts +21 -0
  140. package/src/types/vega-scale.d.ts +60 -0
  141. package/src/utils/animator.js +83 -0
  142. package/src/utils/arrayUtils.js +55 -0
  143. package/src/utils/binnedRangeIndex.js +83 -0
  144. package/src/utils/clamp.js +8 -0
  145. package/src/utils/cloner.js +32 -0
  146. package/src/utils/cloner.test.js +23 -0
  147. package/src/utils/coalesce.js +11 -0
  148. package/src/utils/coalesce.test.js +15 -0
  149. package/src/utils/concatIterables.js +26 -0
  150. package/src/utils/concatIterables.test.js +7 -0
  151. package/src/utils/debounce.js +37 -0
  152. package/src/utils/domainArray.js +224 -0
  153. package/src/utils/domainArray.test.js +129 -0
  154. package/src/utils/eerp.js +13 -0
  155. package/src/utils/expression.js +32 -0
  156. package/src/utils/field.js +28 -0
  157. package/src/utils/fisheye.js +60 -0
  158. package/src/utils/formatObject.js +31 -0
  159. package/src/utils/html.js +23 -0
  160. package/src/utils/html.test.js +13 -0
  161. package/src/utils/indexer.js +43 -0
  162. package/src/utils/indexer.test.js +46 -0
  163. package/src/utils/inertia.js +124 -0
  164. package/src/utils/interactionEvent.js +33 -0
  165. package/src/utils/iterateNestedMaps.js +21 -0
  166. package/src/utils/iterateNestedMaps.test.js +32 -0
  167. package/src/utils/kWayMerge.js +42 -0
  168. package/src/utils/kWayMerge.test.js +25 -0
  169. package/src/utils/layout/flexLayout.js +336 -0
  170. package/src/utils/layout/flexLayout.test.js +296 -0
  171. package/src/utils/layout/padding.js +107 -0
  172. package/src/utils/layout/point.js +23 -0
  173. package/src/utils/layout/rectangle.js +282 -0
  174. package/src/utils/layout/rectangle.test.js +171 -0
  175. package/src/utils/mergeObjects.js +99 -0
  176. package/src/utils/mergeObjects.test.js +41 -0
  177. package/src/utils/numberExtractor.js +24 -0
  178. package/src/utils/numberExtractor.test.js +5 -0
  179. package/src/utils/point.js +14 -0
  180. package/src/utils/propertyCacher.js +70 -0
  181. package/src/utils/propertyCacher.test.js +84 -0
  182. package/src/utils/propertyCoalescer.js +37 -0
  183. package/src/utils/propertyCoalescer.test.js +21 -0
  184. package/src/utils/reservationMap.js +103 -0
  185. package/src/utils/reservationMap.test.js +19 -0
  186. package/src/utils/scaleNull.js +19 -0
  187. package/src/utils/setOperations.js +75 -0
  188. package/src/utils/smoothstep.js +10 -0
  189. package/src/utils/throttle.js +34 -0
  190. package/src/utils/topK.js +76 -0
  191. package/src/utils/topK.test.js +63 -0
  192. package/src/utils/transition.js +74 -0
  193. package/src/utils/ui/tooltip.js +189 -0
  194. package/src/utils/url.js +22 -0
  195. package/src/utils/variableTools.js +24 -0
  196. package/src/utils/variableTools.test.js +12 -0
  197. package/src/view/axisResolution.js +135 -0
  198. package/src/view/axisResolution.test.js +200 -0
  199. package/src/view/axisView.js +746 -0
  200. package/src/view/channel.js +5 -0
  201. package/src/view/concatView.js +296 -0
  202. package/src/view/containerView.js +141 -0
  203. package/src/view/decoratorView.js +510 -0
  204. package/src/view/facetView.js +488 -0
  205. package/src/view/flowBuilder.js +362 -0
  206. package/src/view/flowBuilder.test.js +124 -0
  207. package/src/view/importView.js +19 -0
  208. package/src/view/layerView.js +60 -0
  209. package/src/view/rendering.d.ts +44 -0
  210. package/src/view/renderingContext/compositeViewRenderingContext.js +51 -0
  211. package/src/view/renderingContext/deferredViewRenderingContext.js +174 -0
  212. package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +128 -0
  213. package/src/view/renderingContext/simpleViewRenderingContext.js +62 -0
  214. package/src/view/renderingContext/svgViewRenderingContext.js +121 -0
  215. package/src/view/renderingContext/viewRenderingContext.js +41 -0
  216. package/src/view/scaleResolution.js +756 -0
  217. package/src/view/scaleResolution.test.js +571 -0
  218. package/src/view/scaleResolutionApi.d.ts +40 -0
  219. package/src/view/testUtils.js +48 -0
  220. package/src/view/unitView.js +368 -0
  221. package/src/view/view.js +589 -0
  222. package/src/view/view.test.js +213 -0
  223. package/src/view/viewContext.d.ts +57 -0
  224. package/src/view/viewFactory.js +179 -0
  225. package/src/view/viewFactory.test.js +16 -0
  226. package/src/view/viewUtils.js +420 -0
@@ -0,0 +1,368 @@
1
+ import RectMark from "../marks/rectMark";
2
+ import PointMark from "../marks/pointMark";
3
+ import RuleMark from "../marks/rule";
4
+ import LinkMark from "../marks/link";
5
+ import TextMark from "../marks/text";
6
+
7
+ import ContainerView from "./containerView";
8
+ import ScaleResolution from "./scaleResolution";
9
+ import {
10
+ isSecondaryChannel,
11
+ secondaryChannels,
12
+ isPositionalChannel,
13
+ isChannelDefWithScale,
14
+ primaryPositionalChannels,
15
+ getPrimaryChannel,
16
+ } from "../encoder/encoder";
17
+ import createDomain from "../utils/domainArray";
18
+ import AxisResolution from "./axisResolution";
19
+ import { isAggregateSamplesSpec } from "./viewFactory";
20
+
21
+ /**
22
+ *
23
+ * @type {Object.<string, typeof import("../marks/mark").default>}
24
+ * TODO: Find a proper place, make extendible
25
+ */
26
+ export const markTypes = {
27
+ point: PointMark,
28
+ rect: RectMark,
29
+ rule: RuleMark,
30
+ link: LinkMark,
31
+ text: TextMark,
32
+ };
33
+
34
+ /**
35
+ * @typedef {import("../spec/channel").Channel} Channel
36
+ * @typedef {import("./view").default} View
37
+ * @typedef {import("./layerView").default} LayerView
38
+ * @typedef {import("../utils/domainArray").DomainArray} DomainArray
39
+ * @typedef {import("../encoder/accessor").Accessor} Accessor
40
+ * @typedef {import("../utils/layout/flexLayout").SizeDef} SizeDef
41
+ * @typedef {import("../spec/view").ResolutionTarget} ResolutionTarget
42
+ * @typedef {import("./decoratorView").default} DecoratorView
43
+ *
44
+ */
45
+ export default class UnitView extends ContainerView {
46
+ /**
47
+ *
48
+ * @param {import("../spec/view").UnitSpec} spec
49
+ * @param {import("./viewUtils").ViewContext} context
50
+ * @param {import("./containerView").default} parent
51
+ * @param {string} name
52
+ */
53
+ constructor(spec, context, parent, name) {
54
+ super(spec, context, parent, name);
55
+
56
+ this.spec = spec; // Set here again to keep types happy
57
+
58
+ const Mark = markTypes[this.getMarkType()];
59
+ if (Mark) {
60
+ /** @type {import("../marks/mark").default} */
61
+ this.mark = new Mark(this);
62
+ } else {
63
+ throw new Error(`No such mark: ${this.getMarkType()}`);
64
+ }
65
+
66
+ /** @type {(UnitView | LayerView | DecoratorView)[]} */
67
+ this.sampleAggregateViews = [];
68
+ this._initializeAggregateViews();
69
+
70
+ /**
71
+ * Not nice! Inconsistent when faceting!
72
+ * TODO: Something. Perhaps a Map that has coords for each facet or something...
73
+ * @type {import("../utils/layout/rectangle").default}
74
+ */
75
+ this.coords = undefined;
76
+ }
77
+
78
+ /**
79
+ * @returns {IterableIterator<View>}
80
+ */
81
+ *[Symbol.iterator]() {
82
+ for (const child of this.sampleAggregateViews) {
83
+ yield child;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * @param {View} child
89
+ * @param {View} replacement
90
+ */
91
+ replaceChild(child, replacement) {
92
+ const i = this.sampleAggregateViews.indexOf(child);
93
+ if (i >= 0) {
94
+ this.sampleAggregateViews[i] = replacement;
95
+ } else {
96
+ throw new Error("Not my child view!");
97
+ }
98
+ }
99
+
100
+ /**
101
+ * @param {import("./renderingContext/viewRenderingContext").default} context
102
+ * @param {import("../utils/layout/rectangle").default} coords
103
+ * @param {import("./view").RenderingOptions} [options]
104
+ */
105
+ render(context, coords, options = {}) {
106
+ if (!this.isVisible()) {
107
+ return;
108
+ }
109
+
110
+ coords = coords.shrink(this.getPadding());
111
+
112
+ this.coords = coords;
113
+
114
+ context.pushView(this, coords);
115
+ context.renderMark(this.mark, options);
116
+ context.popView(this);
117
+ }
118
+
119
+ getMarkType() {
120
+ return typeof this.spec.mark == "object"
121
+ ? this.spec.mark.type
122
+ : this.spec.mark;
123
+ }
124
+
125
+ /**
126
+ * Pulls scales and axes up in the view hierarcy according to the resolution rules.
127
+ * TODO: legends
128
+ *
129
+ * @param {ResolutionTarget} type
130
+ */
131
+ resolve(type) {
132
+ // TODO: Complain about nonsensical configuration, e.g. shared parent has independent children.
133
+
134
+ const encoding = this.mark.encoding;
135
+
136
+ for (const [channel, channelDef] of Object.entries(encoding)) {
137
+ if (!isChannelDefWithScale(channelDef)) {
138
+ continue;
139
+ }
140
+
141
+ let targetChannel = getPrimaryChannel(
142
+ channelDef.resolutionChannel ?? channel
143
+ );
144
+
145
+ if (type == "axis" && !isPositionalChannel(targetChannel)) {
146
+ continue;
147
+ }
148
+
149
+ // eslint-disable-next-line consistent-this
150
+ let view = this;
151
+ while (
152
+ view.parent instanceof ContainerView &&
153
+ ["shared", "excluded"].includes(
154
+ view.parent.getConfiguredOrDefaultResolution(
155
+ targetChannel,
156
+ type
157
+ )
158
+ ) &&
159
+ view.getConfiguredOrDefaultResolution(targetChannel, type) !=
160
+ "excluded"
161
+ ) {
162
+ // @ts-ignore
163
+ view = view.parent;
164
+ }
165
+
166
+ if (!view.resolutions[type][targetChannel]) {
167
+ view.resolutions[type][targetChannel] =
168
+ type == "scale"
169
+ ? new ScaleResolution(targetChannel)
170
+ : new AxisResolution(targetChannel);
171
+ }
172
+
173
+ view.resolutions[type][targetChannel].pushUnitView(this, channel);
174
+ }
175
+ }
176
+
177
+ /**
178
+ *
179
+ * @param {import("./view").Channel} channel
180
+ */
181
+ getAccessor(channel) {
182
+ return this._cache("accessor/" + channel, () => {
183
+ const encoding = this.mark.encoding; // Mark provides encodings with defaults and possible modifications
184
+ if (encoding && encoding[channel]) {
185
+ return this.context.accessorFactory.createAccessor(
186
+ encoding[channel]
187
+ );
188
+ }
189
+ });
190
+ }
191
+
192
+ /**
193
+ * Returns an accessor that returns a (composite) key for partitioning the data
194
+ *
195
+ * @param {View} [whoIsAsking]
196
+ * @returns {function(object):any}
197
+ */
198
+ getFacetAccessor(whoIsAsking) {
199
+ // TODO: Rewrite, call getFacetFields
200
+ const sampleAccessor = this.getAccessor("sample");
201
+ if (sampleAccessor) {
202
+ return sampleAccessor;
203
+ }
204
+
205
+ return super.getFacetAccessor(this);
206
+ }
207
+
208
+ /**
209
+ * Returns a collector that is associated with this view.
210
+ */
211
+ getCollector() {
212
+ return this.context.dataFlow.findCollectorByKey(this);
213
+ }
214
+
215
+ /**
216
+ * @param {Channel} channel A primary channel
217
+ */
218
+ _validateDomainQuery(channel) {
219
+ if (isSecondaryChannel(channel)) {
220
+ throw new Error(
221
+ `getDomain(${channel}), must only be called for primary channels!`
222
+ );
223
+ }
224
+
225
+ const channelDef = this.mark.encoding[channel];
226
+ if (!isChannelDefWithScale(channelDef)) {
227
+ throw new Error("The channel has no scale, cannot get domain!");
228
+ }
229
+
230
+ const type = channelDef.type;
231
+ if (!type) {
232
+ throw new Error(`No data type for channel "${channel}"!`);
233
+ // TODO: Support defaults
234
+ }
235
+
236
+ return channelDef;
237
+ }
238
+
239
+ /**
240
+ * Returns the domain of the specified channel of this domain/mark.
241
+ *
242
+ * @param {Channel} channel A primary channel
243
+ * @returns {DomainArray}
244
+ */
245
+ getConfiguredDomain(channel) {
246
+ const channelDef = this._validateDomainQuery(channel);
247
+
248
+ const specDomain =
249
+ channelDef && channelDef.scale && channelDef.scale.domain;
250
+ if (specDomain) {
251
+ const scaleResolution = this.getScaleResolution(
252
+ channelDef.resolutionChannel ?? channel
253
+ );
254
+ return createDomain(
255
+ channelDef.type,
256
+ // Chrom/pos must be linearized first
257
+ scaleResolution.fromComplexInterval(specDomain)
258
+ );
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Extracts the domain from the data.
264
+ *
265
+ * TODO: Optimize! Now this performs redundant work if multiple views share the same collector.
266
+ * Also, all relevant fields should be processed in one iteration: https://jsbench.me/y5kkqy52jo/1
267
+ * In fact, domain extraction could be a responsibility of the collector: As it handles data items,
268
+ * it extracts domains for all fields (and data types) that need extracted domains.
269
+ * Alternatively, extractor nodes could be added to the data flow, just like Vega does
270
+ * (with aggregate and extent).
271
+ *
272
+ * @param {Channel} channel
273
+ * @returns {DomainArray}
274
+ */
275
+ extractDataDomain(channel) {
276
+ const channelDef = this._validateDomainQuery(channel);
277
+ const type = channelDef.type;
278
+
279
+ /** @param {Channel} channel */
280
+ const extract = (channel) => {
281
+ /** @type {DomainArray} */
282
+ let domain;
283
+
284
+ const encodingSpec = this.mark.encoding[channel];
285
+
286
+ if (encodingSpec) {
287
+ const accessor =
288
+ this.context.accessorFactory.createAccessor(encodingSpec);
289
+ if (accessor) {
290
+ domain = createDomain(type);
291
+
292
+ if (accessor.constant) {
293
+ domain.extend(accessor({}));
294
+ } else {
295
+ const collector = this.getCollector();
296
+ if (collector?.completed) {
297
+ collector.visitData((d) =>
298
+ domain.extend(accessor(d))
299
+ );
300
+ }
301
+ }
302
+ }
303
+ }
304
+ return domain;
305
+ };
306
+
307
+ let domain = extract(channel);
308
+
309
+ const secondaryChannel = secondaryChannels[channel];
310
+ if (secondaryChannel) {
311
+ const secondaryDomain = extract(secondaryChannel);
312
+ if (secondaryDomain) {
313
+ domain.extendAll(secondaryDomain);
314
+ }
315
+ }
316
+
317
+ return domain;
318
+ }
319
+
320
+ getZoomLevel() {
321
+ /** @param {Channel} channel */
322
+ const getZoomLevel = (channel) =>
323
+ this.getScaleResolution(channel)?.getZoomLevel() ?? 1.0;
324
+
325
+ return primaryPositionalChannels
326
+ .map(getZoomLevel)
327
+ .reduce((a, c) => a * c, 1);
328
+ }
329
+
330
+ _initializeAggregateViews() {
331
+ if (isAggregateSamplesSpec(this.spec)) {
332
+ // TODO: Support multiple
333
+ for (const sumSpec of this.spec.aggregateSamples) {
334
+ sumSpec.transform = [
335
+ ...(sumSpec.transform ?? []),
336
+ { type: "mergeFacets" },
337
+ ];
338
+
339
+ sumSpec.encoding = {
340
+ ...(sumSpec.encoding ?? {}),
341
+ sample: null,
342
+ };
343
+
344
+ const summaryView =
345
+ /** @type { UnitView | LayerView | DecoratorView } */ (
346
+ this.context.createView(sumSpec, this, "summaryView")
347
+ );
348
+
349
+ /**
350
+ * @param {View} [whoIsAsking]
351
+ */
352
+ summaryView.getFacetFields = (whoIsAsking) => undefined;
353
+
354
+ this.sampleAggregateViews.push(summaryView);
355
+ }
356
+ }
357
+ }
358
+
359
+ /**
360
+ * @param {string} channel
361
+ * @param {import("./containerView").ResolutionTarget} resolutionType
362
+ * @returns {import("../spec/view").ResolutionBehavior}
363
+ */
364
+ getDefaultResolution(channel, resolutionType) {
365
+ // This affects the sample aggregate views.
366
+ return channel == "x" ? "shared" : "independent";
367
+ }
368
+ }