@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.
- package/dist/index.js +224 -0
- package/dist/style.css +1 -0
- package/package.json +54 -0
- package/src/data/collector.js +178 -0
- package/src/data/collector.test.js +82 -0
- package/src/data/dataFlow.js +109 -0
- package/src/data/dataFlow.test.js +3 -0
- package/src/data/facetNode.js +17 -0
- package/src/data/flow.test.js +71 -0
- package/src/data/flowBatch.d.ts +40 -0
- package/src/data/flowNode.js +283 -0
- package/src/data/flowNode.test.js +49 -0
- package/src/data/flowOptimizer.js +117 -0
- package/src/data/flowOptimizer.test.js +192 -0
- package/src/data/flowTestUtils.js +63 -0
- package/src/data/formats/fasta.js +32 -0
- package/src/data/formats/fasta.test.js +26 -0
- package/src/data/sources/dataSource.js +22 -0
- package/src/data/sources/dataSourceFactory.js +24 -0
- package/src/data/sources/dataUtils.js +31 -0
- package/src/data/sources/dynamicCallbackSource.js +56 -0
- package/src/data/sources/dynamicSource.js +36 -0
- package/src/data/sources/inlineSource.js +69 -0
- package/src/data/sources/inlineSource.test.js +55 -0
- package/src/data/sources/namedSource.js +74 -0
- package/src/data/sources/sequenceSource.js +46 -0
- package/src/data/sources/sequenceSource.test.js +45 -0
- package/src/data/sources/urlSource.js +74 -0
- package/src/data/transforms/aggregate.js +69 -0
- package/src/data/transforms/clone.js +40 -0
- package/src/data/transforms/clone.test.js +10 -0
- package/src/data/transforms/coverage.js +187 -0
- package/src/data/transforms/coverage.test.js +122 -0
- package/src/data/transforms/filter.js +37 -0
- package/src/data/transforms/filter.test.js +17 -0
- package/src/data/transforms/filterScoredLabels.js +134 -0
- package/src/data/transforms/flattenCompressedExons.js +57 -0
- package/src/data/transforms/flattenDelimited.js +68 -0
- package/src/data/transforms/flattenDelimited.test.js +86 -0
- package/src/data/transforms/flattenSequence.js +39 -0
- package/src/data/transforms/flattenSequence.test.js +33 -0
- package/src/data/transforms/formula.js +39 -0
- package/src/data/transforms/formula.test.js +18 -0
- package/src/data/transforms/identifier.js +108 -0
- package/src/data/transforms/identifier.test.js +82 -0
- package/src/data/transforms/linearizeGenomicCoordinate.js +101 -0
- package/src/data/transforms/measureText.js +44 -0
- package/src/data/transforms/pileup.js +128 -0
- package/src/data/transforms/pileup.test.js +69 -0
- package/src/data/transforms/project.js +41 -0
- package/src/data/transforms/project.test.js +31 -0
- package/src/data/transforms/regexExtract.js +61 -0
- package/src/data/transforms/regexExtract.test.js +66 -0
- package/src/data/transforms/regexFold.js +141 -0
- package/src/data/transforms/regexFold.test.js +159 -0
- package/src/data/transforms/sample.js +101 -0
- package/src/data/transforms/sample.test.js +37 -0
- package/src/data/transforms/stack.js +137 -0
- package/src/data/transforms/stack.test.js +90 -0
- package/src/data/transforms/transformFactory.js +60 -0
- package/src/encoder/accessor.js +82 -0
- package/src/encoder/accessor.test.js +46 -0
- package/src/encoder/encoder.js +369 -0
- package/src/encoder/encoder.test.js +97 -0
- package/src/fonts/Lato-Regular.json +1267 -0
- package/src/fonts/Lato-Regular.png +0 -0
- package/src/fonts/OFL.txt +93 -0
- package/src/fonts/README.md +3 -0
- package/src/fonts/bmFont.d.ts +58 -0
- package/src/fonts/bmFontManager.js +357 -0
- package/src/fonts/bmFontMetrics.js +108 -0
- package/src/genome/genome.js +305 -0
- package/src/genome/genome.test.js +152 -0
- package/src/genome/genomeStore.js +54 -0
- package/src/genome/locusFormat.js +31 -0
- package/src/genome/scaleIndex.js +199 -0
- package/src/genome/scaleIndex.test.js +61 -0
- package/src/genome/scaleLocus.js +112 -0
- package/src/genome/scaleLocus.test.js +3 -0
- package/src/genomeSpy.js +753 -0
- package/src/gl/arrayBuilder.js +199 -0
- package/src/gl/dataToVertices.js +621 -0
- package/src/gl/includes/common.glsl +63 -0
- package/src/gl/includes/fp64-arithmetic.glsl +187 -0
- package/src/gl/includes/fp64-utils.js +132 -0
- package/src/gl/includes/picking.fragment.glsl +3 -0
- package/src/gl/includes/picking.vertex.glsl +29 -0
- package/src/gl/includes/sampleFacet.glsl +107 -0
- package/src/gl/includes/scales.glsl +79 -0
- package/src/gl/includes/scales_fp64.glsl +30 -0
- package/src/gl/link.fragment.glsl +18 -0
- package/src/gl/link.vertex.glsl +111 -0
- package/src/gl/point.fragment.glsl +123 -0
- package/src/gl/point.vertex.glsl +128 -0
- package/src/gl/rect.fragment.glsl +51 -0
- package/src/gl/rect.vertex.glsl +114 -0
- package/src/gl/rule.fragment.glsl +52 -0
- package/src/gl/rule.vertex.glsl +89 -0
- package/src/gl/text.fragment.glsl +31 -0
- package/src/gl/text.vertex.glsl +246 -0
- package/src/gl/webGLHelper.js +490 -0
- package/src/img/bowtie.svg +1 -0
- package/src/img/genomespy-favicon.svg +34 -0
- package/src/index.html +11 -0
- package/src/index.js +151 -0
- package/src/marks/link.js +189 -0
- package/src/marks/mark.js +867 -0
- package/src/marks/markUtils.js +109 -0
- package/src/marks/pointMark.js +279 -0
- package/src/marks/rectMark.js +236 -0
- package/src/marks/rule.js +231 -0
- package/src/marks/text.js +274 -0
- package/src/options.d.ts +9 -0
- package/src/scale/colorUtils.js +184 -0
- package/src/scale/glslScaleGenerator.js +462 -0
- package/src/scale/scale.js +441 -0
- package/src/scale/scale.test.js +323 -0
- package/src/scale/ticks.js +198 -0
- package/src/scale/ticks.test.js +39 -0
- package/src/singlePageApp.js +13 -0
- package/src/spec/axis.d.ts +296 -0
- package/src/spec/channel.d.ts +127 -0
- package/src/spec/data.d.ts +185 -0
- package/src/spec/font.d.ts +15 -0
- package/src/spec/genome.d.ts +35 -0
- package/src/spec/mark.d.ts +432 -0
- package/src/spec/root.d.ts +22 -0
- package/src/spec/scale.d.ts +265 -0
- package/src/spec/tooltip.d.ts +9 -0
- package/src/spec/transform.d.ts +479 -0
- package/src/spec/view.d.ts +215 -0
- package/src/styles/genome-spy.scss +153 -0
- package/src/tooltip/dataTooltipHandler.js +59 -0
- package/src/tooltip/refseqGeneTooltipHandler.js +77 -0
- package/src/tooltip/tooltipHandler.ts +12 -0
- package/src/types/filetypes.d.ts +4 -0
- package/src/types/flatqueue.d.ts +53 -0
- package/src/types/glsl.d.ts +4 -0
- package/src/types/object.d.ts +21 -0
- package/src/types/vega-scale.d.ts +60 -0
- package/src/utils/animator.js +83 -0
- package/src/utils/arrayUtils.js +55 -0
- package/src/utils/binnedRangeIndex.js +83 -0
- package/src/utils/clamp.js +8 -0
- package/src/utils/cloner.js +32 -0
- package/src/utils/cloner.test.js +23 -0
- package/src/utils/coalesce.js +11 -0
- package/src/utils/coalesce.test.js +15 -0
- package/src/utils/concatIterables.js +26 -0
- package/src/utils/concatIterables.test.js +7 -0
- package/src/utils/debounce.js +37 -0
- package/src/utils/domainArray.js +224 -0
- package/src/utils/domainArray.test.js +129 -0
- package/src/utils/eerp.js +13 -0
- package/src/utils/expression.js +32 -0
- package/src/utils/field.js +28 -0
- package/src/utils/fisheye.js +60 -0
- package/src/utils/formatObject.js +31 -0
- package/src/utils/html.js +23 -0
- package/src/utils/html.test.js +13 -0
- package/src/utils/indexer.js +43 -0
- package/src/utils/indexer.test.js +46 -0
- package/src/utils/inertia.js +124 -0
- package/src/utils/interactionEvent.js +33 -0
- package/src/utils/iterateNestedMaps.js +21 -0
- package/src/utils/iterateNestedMaps.test.js +32 -0
- package/src/utils/kWayMerge.js +42 -0
- package/src/utils/kWayMerge.test.js +25 -0
- package/src/utils/layout/flexLayout.js +336 -0
- package/src/utils/layout/flexLayout.test.js +296 -0
- package/src/utils/layout/padding.js +107 -0
- package/src/utils/layout/point.js +23 -0
- package/src/utils/layout/rectangle.js +282 -0
- package/src/utils/layout/rectangle.test.js +171 -0
- package/src/utils/mergeObjects.js +99 -0
- package/src/utils/mergeObjects.test.js +41 -0
- package/src/utils/numberExtractor.js +24 -0
- package/src/utils/numberExtractor.test.js +5 -0
- package/src/utils/point.js +14 -0
- package/src/utils/propertyCacher.js +70 -0
- package/src/utils/propertyCacher.test.js +84 -0
- package/src/utils/propertyCoalescer.js +37 -0
- package/src/utils/propertyCoalescer.test.js +21 -0
- package/src/utils/reservationMap.js +103 -0
- package/src/utils/reservationMap.test.js +19 -0
- package/src/utils/scaleNull.js +19 -0
- package/src/utils/setOperations.js +75 -0
- package/src/utils/smoothstep.js +10 -0
- package/src/utils/throttle.js +34 -0
- package/src/utils/topK.js +76 -0
- package/src/utils/topK.test.js +63 -0
- package/src/utils/transition.js +74 -0
- package/src/utils/ui/tooltip.js +189 -0
- package/src/utils/url.js +22 -0
- package/src/utils/variableTools.js +24 -0
- package/src/utils/variableTools.test.js +12 -0
- package/src/view/axisResolution.js +135 -0
- package/src/view/axisResolution.test.js +200 -0
- package/src/view/axisView.js +746 -0
- package/src/view/channel.js +5 -0
- package/src/view/concatView.js +296 -0
- package/src/view/containerView.js +141 -0
- package/src/view/decoratorView.js +510 -0
- package/src/view/facetView.js +488 -0
- package/src/view/flowBuilder.js +362 -0
- package/src/view/flowBuilder.test.js +124 -0
- package/src/view/importView.js +19 -0
- package/src/view/layerView.js +60 -0
- package/src/view/rendering.d.ts +44 -0
- package/src/view/renderingContext/compositeViewRenderingContext.js +51 -0
- package/src/view/renderingContext/deferredViewRenderingContext.js +174 -0
- package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +128 -0
- package/src/view/renderingContext/simpleViewRenderingContext.js +62 -0
- package/src/view/renderingContext/svgViewRenderingContext.js +121 -0
- package/src/view/renderingContext/viewRenderingContext.js +41 -0
- package/src/view/scaleResolution.js +756 -0
- package/src/view/scaleResolution.test.js +571 -0
- package/src/view/scaleResolutionApi.d.ts +40 -0
- package/src/view/testUtils.js +48 -0
- package/src/view/unitView.js +368 -0
- package/src/view/view.js +589 -0
- package/src/view/view.test.js +213 -0
- package/src/view/viewContext.d.ts +57 -0
- package/src/view/viewFactory.js +179 -0
- package/src/view/viewFactory.test.js +16 -0
- 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
|
+
}
|