@genome-spy/core 0.29.0 → 0.30.2
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.es.js +16373 -0
- package/dist/index.js +43 -43
- package/package.json +10 -7
- package/src/data/collector.js +0 -183
- package/src/data/collector.test.js +0 -84
- package/src/data/dataFlow.js +0 -148
- package/src/data/dataFlow.test.js +0 -5
- package/src/data/facetNode.js +0 -17
- package/src/data/flow.test.js +0 -72
- package/src/data/flowBatch.d.ts +0 -40
- package/src/data/flowNode.js +0 -283
- package/src/data/flowNode.test.js +0 -50
- package/src/data/flowOptimizer.js +0 -123
- package/src/data/flowOptimizer.test.js +0 -193
- package/src/data/flowTestUtils.js +0 -63
- package/src/data/formats/fasta.js +0 -32
- package/src/data/formats/fasta.test.js +0 -27
- package/src/data/sources/dataSource.js +0 -22
- package/src/data/sources/dataSourceFactory.js +0 -24
- package/src/data/sources/dataUtils.js +0 -78
- package/src/data/sources/dynamicCallbackSource.js +0 -57
- package/src/data/sources/dynamicSource.js +0 -37
- package/src/data/sources/inlineSource.js +0 -67
- package/src/data/sources/inlineSource.test.js +0 -56
- package/src/data/sources/namedSource.js +0 -79
- package/src/data/sources/sequenceSource.js +0 -46
- package/src/data/sources/sequenceSource.test.js +0 -46
- package/src/data/sources/urlSource.js +0 -74
- package/src/data/transforms/aggregate.js +0 -70
- package/src/data/transforms/clone.js +0 -40
- package/src/data/transforms/clone.test.js +0 -11
- package/src/data/transforms/coverage.js +0 -187
- package/src/data/transforms/coverage.test.js +0 -123
- package/src/data/transforms/filter.js +0 -37
- package/src/data/transforms/filter.test.js +0 -18
- package/src/data/transforms/filterScoredLabels.js +0 -134
- package/src/data/transforms/flattenCompressedExons.js +0 -57
- package/src/data/transforms/flattenDelimited.js +0 -74
- package/src/data/transforms/flattenDelimited.test.js +0 -87
- package/src/data/transforms/flattenSequence.js +0 -39
- package/src/data/transforms/flattenSequence.test.js +0 -34
- package/src/data/transforms/formula.js +0 -39
- package/src/data/transforms/formula.test.js +0 -19
- package/src/data/transforms/identifier.js +0 -108
- package/src/data/transforms/identifier.test.js +0 -83
- package/src/data/transforms/linearizeGenomicCoordinate.js +0 -101
- package/src/data/transforms/measureText.js +0 -44
- package/src/data/transforms/pileup.js +0 -128
- package/src/data/transforms/pileup.test.js +0 -70
- package/src/data/transforms/project.js +0 -41
- package/src/data/transforms/project.test.js +0 -32
- package/src/data/transforms/regexExtract.js +0 -61
- package/src/data/transforms/regexExtract.test.js +0 -67
- package/src/data/transforms/regexFold.js +0 -141
- package/src/data/transforms/regexFold.test.js +0 -160
- package/src/data/transforms/sample.js +0 -101
- package/src/data/transforms/sample.test.js +0 -38
- package/src/data/transforms/stack.js +0 -137
- package/src/data/transforms/stack.test.js +0 -91
- package/src/data/transforms/transformFactory.js +0 -60
- package/src/embedApi.d.ts +0 -67
- package/src/encoder/accessor.js +0 -82
- package/src/encoder/accessor.test.js +0 -47
- package/src/encoder/encoder.js +0 -394
- package/src/encoder/encoder.test.js +0 -98
- package/src/fonts/Lato-Regular.json +0 -1267
- package/src/fonts/Lato-Regular.png +0 -0
- package/src/fonts/OFL.txt +0 -93
- package/src/fonts/README.md +0 -3
- package/src/fonts/bmFont.d.ts +0 -58
- package/src/fonts/bmFontManager.js +0 -357
- package/src/fonts/bmFontMetrics.js +0 -108
- package/src/genome/genome.js +0 -317
- package/src/genome/genome.test.js +0 -188
- package/src/genome/genomeStore.js +0 -54
- package/src/genome/locusFormat.js +0 -31
- package/src/genome/scaleIndex.d.ts +0 -38
- package/src/genome/scaleIndex.js +0 -166
- package/src/genome/scaleIndex.test.js +0 -78
- package/src/genome/scaleLocus.d.ts +0 -11
- package/src/genome/scaleLocus.js +0 -108
- package/src/genome/scaleLocus.test.js +0 -4
- package/src/genomeSpy.js +0 -784
- package/src/gl/arrayBuilder.js +0 -199
- package/src/gl/dataToVertices.js +0 -636
- package/src/gl/includes/common.glsl +0 -63
- package/src/gl/includes/picking.fragment.glsl +0 -1
- package/src/gl/includes/picking.vertex.glsl +0 -27
- package/src/gl/includes/sampleFacet.glsl +0 -107
- package/src/gl/includes/scales.glsl +0 -112
- package/src/gl/link.fragment.glsl +0 -18
- package/src/gl/link.vertex.glsl +0 -111
- package/src/gl/point.fragment.glsl +0 -123
- package/src/gl/point.vertex.glsl +0 -129
- package/src/gl/rect.fragment.glsl +0 -51
- package/src/gl/rect.vertex.glsl +0 -114
- package/src/gl/rule.fragment.glsl +0 -52
- package/src/gl/rule.vertex.glsl +0 -89
- package/src/gl/text.fragment.glsl +0 -31
- package/src/gl/text.vertex.glsl +0 -246
- package/src/gl/webGLHelper.js +0 -489
- package/src/img/bowtie.svg +0 -1
- package/src/img/genomespy-favicon.svg +0 -34
- package/src/index.html +0 -11
- package/src/index.js +0 -128
- package/src/marks/link.js +0 -175
- package/src/marks/mark.js +0 -975
- package/src/marks/markUtils.js +0 -125
- package/src/marks/pointMark.js +0 -251
- package/src/marks/rectMark.js +0 -241
- package/src/marks/rule.js +0 -250
- package/src/marks/text.js +0 -278
- package/src/node_modules/.vitest/results.json +0 -1
- package/src/scale/colorUtils.js +0 -184
- package/src/scale/glslScaleGenerator.js +0 -488
- package/src/scale/scale.js +0 -451
- package/src/scale/scale.test.js +0 -324
- package/src/scale/ticks.js +0 -203
- package/src/scale/ticks.test.js +0 -40
- package/src/singlePageApp.js +0 -13
- package/src/spec/axis.d.ts +0 -296
- package/src/spec/channel.d.ts +0 -430
- package/src/spec/data.d.ts +0 -196
- package/src/spec/font.d.ts +0 -15
- package/src/spec/genome.d.ts +0 -35
- package/src/spec/mark.d.ts +0 -429
- package/src/spec/root.d.ts +0 -17
- package/src/spec/sampleView.d.ts +0 -180
- package/src/spec/scale.d.ts +0 -273
- package/src/spec/title.d.ts +0 -102
- package/src/spec/tooltip.d.ts +0 -9
- package/src/spec/transform.d.ts +0 -479
- package/src/spec/view.d.ts +0 -201
- package/src/styles/genome-spy.scss +0 -153
- package/src/tooltip/dataTooltipHandler.js +0 -64
- package/src/tooltip/refseqGeneTooltipHandler.js +0 -78
- package/src/tooltip/tooltipHandler.ts +0 -12
- package/src/types/filetypes.d.ts +0 -14
- package/src/types/flatqueue.d.ts +0 -53
- package/src/types/glsl.d.ts +0 -4
- package/src/types/internmap.d.ts +0 -22
- package/src/types/object.d.ts +0 -21
- package/src/types/vega-loader.d.ts +0 -1
- package/src/types/vega-scale.d.ts +0 -60
- package/src/utils/addBaseUrl.js +0 -19
- package/src/utils/addBaseUrl.test.js +0 -22
- package/src/utils/animator.js +0 -83
- package/src/utils/arrayUtils.js +0 -61
- package/src/utils/binnedIndex.js +0 -167
- package/src/utils/binnedIndex.test.js +0 -155
- package/src/utils/clamp.js +0 -8
- package/src/utils/cloner.js +0 -34
- package/src/utils/cloner.test.js +0 -24
- package/src/utils/coalesce.js +0 -11
- package/src/utils/coalesce.test.js +0 -16
- package/src/utils/concatIterables.js +0 -26
- package/src/utils/concatIterables.test.js +0 -8
- package/src/utils/debounce.js +0 -37
- package/src/utils/domainArray.js +0 -216
- package/src/utils/domainArray.test.js +0 -130
- package/src/utils/eerp.js +0 -13
- package/src/utils/expression.js +0 -32
- package/src/utils/field.js +0 -28
- package/src/utils/formatObject.js +0 -31
- package/src/utils/indexer.js +0 -43
- package/src/utils/indexer.test.js +0 -47
- package/src/utils/inertia.js +0 -124
- package/src/utils/interactionEvent.js +0 -33
- package/src/utils/iterateNestedMaps.js +0 -21
- package/src/utils/iterateNestedMaps.test.js +0 -33
- package/src/utils/kWayMerge.js +0 -42
- package/src/utils/kWayMerge.test.js +0 -26
- package/src/utils/layout/flexLayout.js +0 -368
- package/src/utils/layout/flexLayout.test.js +0 -311
- package/src/utils/layout/grid.js +0 -95
- package/src/utils/layout/grid.test.js +0 -71
- package/src/utils/layout/padding.js +0 -120
- package/src/utils/layout/point.js +0 -23
- package/src/utils/layout/rectangle.js +0 -288
- package/src/utils/layout/rectangle.test.js +0 -172
- package/src/utils/mergeObjects.js +0 -99
- package/src/utils/mergeObjects.test.js +0 -42
- package/src/utils/numberExtractor.js +0 -24
- package/src/utils/numberExtractor.test.js +0 -6
- package/src/utils/point.js +0 -14
- package/src/utils/propertyCacher.js +0 -70
- package/src/utils/propertyCacher.test.js +0 -85
- package/src/utils/propertyCoalescer.js +0 -42
- package/src/utils/propertyCoalescer.test.js +0 -22
- package/src/utils/reservationMap.js +0 -103
- package/src/utils/reservationMap.test.js +0 -20
- package/src/utils/scaleNull.js +0 -19
- package/src/utils/setOperations.js +0 -75
- package/src/utils/smoothstep.js +0 -10
- package/src/utils/throttle.js +0 -34
- package/src/utils/topK.js +0 -76
- package/src/utils/topK.test.js +0 -64
- package/src/utils/transition.js +0 -74
- package/src/utils/ui/tooltip.js +0 -189
- package/src/utils/url.js +0 -22
- package/src/utils/variableTools.js +0 -24
- package/src/utils/variableTools.test.js +0 -13
- package/src/view/axisResolution.js +0 -140
- package/src/view/axisResolution.test.js +0 -201
- package/src/view/axisView.js +0 -747
- package/src/view/concatView.js +0 -45
- package/src/view/containerView.js +0 -159
- package/src/view/facetView.js +0 -491
- package/src/view/flowBuilder.js +0 -367
- package/src/view/flowBuilder.test.js +0 -125
- package/src/view/gridView.js +0 -786
- package/src/view/implicitRootView.js +0 -14
- package/src/view/importView.js +0 -19
- package/src/view/layerView.js +0 -74
- package/src/view/rendering.d.ts +0 -44
- package/src/view/renderingContext/compositeViewRenderingContext.js +0 -51
- package/src/view/renderingContext/deferredViewRenderingContext.js +0 -176
- package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
- package/src/view/renderingContext/simpleViewRenderingContext.js +0 -64
- package/src/view/renderingContext/svgViewRenderingContext.js +0 -125
- package/src/view/renderingContext/viewRenderingContext.js +0 -41
- package/src/view/scaleResolution.js +0 -791
- package/src/view/scaleResolution.test.js +0 -572
- package/src/view/scaleResolutionApi.d.ts +0 -40
- package/src/view/testUtils.js +0 -51
- package/src/view/title.js +0 -165
- package/src/view/unitView.js +0 -382
- package/src/view/view.js +0 -612
- package/src/view/view.test.js +0 -214
- package/src/view/viewContext.d.ts +0 -62
- package/src/view/viewFactory.js +0 -181
- package/src/view/viewFactory.test.js +0 -17
- package/src/view/viewUtils.js +0 -327
- package/src/view/zoom.js +0 -89
package/src/view/view.js
DELETED
|
@@ -1,612 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
parseSizeDef,
|
|
3
|
-
FlexDimensions,
|
|
4
|
-
ZERO_FLEXDIMENSIONS,
|
|
5
|
-
} from "../utils/layout/flexLayout";
|
|
6
|
-
import Padding from "../utils/layout/padding";
|
|
7
|
-
import {
|
|
8
|
-
getCachedOrCall,
|
|
9
|
-
initPropertyCache,
|
|
10
|
-
invalidatePrefix,
|
|
11
|
-
} from "../utils/propertyCacher";
|
|
12
|
-
import { isNumber, isString, span } from "vega-util";
|
|
13
|
-
import { scaleLog } from "d3-scale";
|
|
14
|
-
import { isFieldDef, getPrimaryChannel } from "../encoder/encoder";
|
|
15
|
-
import { appendToBaseUrl } from "../utils/url";
|
|
16
|
-
import { isDiscrete, bandSpace } from "vega-scale";
|
|
17
|
-
import { peek } from "../utils/arrayUtils";
|
|
18
|
-
|
|
19
|
-
// TODO: View classes have too many responsibilities. Come up with a way
|
|
20
|
-
// to separate the concerns. However, most concerns are tightly tied to
|
|
21
|
-
// the hierarchy, which makes the separation quite tricky.
|
|
22
|
-
// Separation of concerns would also make the code more easily testable.
|
|
23
|
-
|
|
24
|
-
/** Skip children */
|
|
25
|
-
export const VISIT_SKIP = "VISIT_SKIP";
|
|
26
|
-
/** Stop further visits */
|
|
27
|
-
export const VISIT_STOP = "VISIT_STOP";
|
|
28
|
-
|
|
29
|
-
/** @type {function(number):number} */
|
|
30
|
-
const defaultOpacityFunction = (parentOpacity) => parentOpacity;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @typedef {import("../spec/channel").Channel} Channel
|
|
34
|
-
* @typedef {import("../spec/channel").ChannelDef} ChannelDef
|
|
35
|
-
* @typedef {import("../spec/view").ViewSpec} ViewSpec
|
|
36
|
-
* @typedef {import("./viewUtils").ViewContext} ViewContext
|
|
37
|
-
* @typedef {import("../utils/layout/flexLayout").SizeDef} SizeDef
|
|
38
|
-
* @typedef {import("../utils/layout/flexLayout").LocSize} LocSize
|
|
39
|
-
*
|
|
40
|
-
* @typedef {import("../spec/view").ResolutionTarget} ResolutionTarget
|
|
41
|
-
* @typedef {import("./scaleResolution").default} ScaleResolution
|
|
42
|
-
* @typedef {import("./axisResolution").default} AxisResolution
|
|
43
|
-
*
|
|
44
|
-
* @typedef {VISIT_SKIP|VISIT_STOP|void} VisitResult
|
|
45
|
-
*
|
|
46
|
-
* @callback VisitorCallback
|
|
47
|
-
* @param {View} view
|
|
48
|
-
* @returns {VisitResult}
|
|
49
|
-
*
|
|
50
|
-
* @typedef {VisitorCallback & {
|
|
51
|
-
* postOrder?: function(View):void,
|
|
52
|
-
* beforeChildren?: function(View):void,
|
|
53
|
-
* afterChildren?: function(View):void}
|
|
54
|
-
* } Visitor
|
|
55
|
-
*
|
|
56
|
-
* @typedef {object} BroadcastMessage
|
|
57
|
-
* @prop {string} type Broadcast type
|
|
58
|
-
* @prop {any} [payload] Anything
|
|
59
|
-
*
|
|
60
|
-
* @typedef {import("./rendering").RenderingOptions} RenderingOptions
|
|
61
|
-
*
|
|
62
|
-
* @callback InteractionEventListener
|
|
63
|
-
* @param {import("../utils/layout/rectangle").default} coords
|
|
64
|
-
* Coordinates of the view
|
|
65
|
-
* @param {import("../utils/interactionEvent").default} event
|
|
66
|
-
*/
|
|
67
|
-
export default class View {
|
|
68
|
-
/**
|
|
69
|
-
*
|
|
70
|
-
* @param {ViewSpec} spec
|
|
71
|
-
* @param {ViewContext} context
|
|
72
|
-
* @param {import("./containerView").default} parent
|
|
73
|
-
* @param {string} name
|
|
74
|
-
*/
|
|
75
|
-
constructor(spec, context, parent, name) {
|
|
76
|
-
this.context = context;
|
|
77
|
-
this.parent = parent;
|
|
78
|
-
this.name = spec.name || name;
|
|
79
|
-
this.spec = spec;
|
|
80
|
-
|
|
81
|
-
this.resolutions = {
|
|
82
|
-
/**
|
|
83
|
-
* Channel-specific scale resolutions
|
|
84
|
-
* @type {Partial<Record<Channel, import("./scaleResolution").default>>}
|
|
85
|
-
*/
|
|
86
|
-
scale: {},
|
|
87
|
-
/**
|
|
88
|
-
* Channel-specific axis resolutions
|
|
89
|
-
* @type {Partial<Record<import("../spec/channel").PrimaryPositionalChannel, import("./axisResolution").default>>}
|
|
90
|
-
*/
|
|
91
|
-
axis: {},
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/** @type {Record<string, (function(BroadcastMessage):void)[]>} */
|
|
95
|
-
this._broadcastHandlers = {};
|
|
96
|
-
|
|
97
|
-
/** @type {Record<string, InteractionEventListener[]>} */
|
|
98
|
-
this._capturingInteractionEventListeners = {};
|
|
99
|
-
/** @type {Record<string, InteractionEventListener[]>} */
|
|
100
|
-
this._nonCapturingInteractionEventListeners = {};
|
|
101
|
-
|
|
102
|
-
initPropertyCache(this);
|
|
103
|
-
|
|
104
|
-
/** @type {function(number):number} */
|
|
105
|
-
this.opacityFunction = defaultOpacityFunction;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Don't inherit encodings from parent.
|
|
109
|
-
* TODO: Make configurable through spec. Allow more fine-grained control.
|
|
110
|
-
*/
|
|
111
|
-
this.blockEncodingInheritance = false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
getPadding() {
|
|
115
|
-
return this._cache("size/padding", () =>
|
|
116
|
-
Padding.createFromConfig(this.spec.padding)
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Returns a padding that indicates how much axes and titles extend over the plot area.
|
|
122
|
-
*
|
|
123
|
-
* @returns {Padding}
|
|
124
|
-
*/
|
|
125
|
-
getOverhang() {
|
|
126
|
-
return Padding.zero();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Returns the configured size, if present. Otherwise a computed or default
|
|
131
|
-
* height is returned.
|
|
132
|
-
*
|
|
133
|
-
* @returns {FlexDimensions}
|
|
134
|
-
*/
|
|
135
|
-
getSize() {
|
|
136
|
-
return this._cache("size/size", () =>
|
|
137
|
-
this.isVisible()
|
|
138
|
-
? this.getSizeFromSpec().addPadding(this.getPadding())
|
|
139
|
-
: ZERO_FLEXDIMENSIONS
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @return {FlexDimensions}
|
|
145
|
-
*/
|
|
146
|
-
getSizeFromSpec() {
|
|
147
|
-
/**
|
|
148
|
-
* @param {"width" | "height"} dimension
|
|
149
|
-
* @return {SizeDef}
|
|
150
|
-
*/
|
|
151
|
-
const handleSize = (dimension) => {
|
|
152
|
-
let value = this.spec[dimension];
|
|
153
|
-
|
|
154
|
-
if (isStepSize(value)) {
|
|
155
|
-
const stepSize = value.step;
|
|
156
|
-
|
|
157
|
-
const scale = this.getScaleResolution(
|
|
158
|
-
dimension == "width" ? "x" : "y"
|
|
159
|
-
)?.getScale();
|
|
160
|
-
|
|
161
|
-
if (scale) {
|
|
162
|
-
// Note: this and all ancestral views need to be refreshed when the domain is changed.
|
|
163
|
-
let steps = 0;
|
|
164
|
-
if (isDiscrete(scale.type)) {
|
|
165
|
-
steps = scale.domain().length;
|
|
166
|
-
} else if (["locus", "index"].includes(scale.type)) {
|
|
167
|
-
const domain = scale.domain();
|
|
168
|
-
steps = peek(domain) - domain[0];
|
|
169
|
-
} else {
|
|
170
|
-
throw new Error(
|
|
171
|
-
`Cannot use step-based size with "${scale.type}" scale!`
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// TODO: Type guards maybe?
|
|
176
|
-
const _scale =
|
|
177
|
-
/** @type {import("d3-scale").ScaleBand<any> | import("../genome/scaleLocus").ScaleLocus | import("../genome/scaleIndex").ScaleIndex} */ (
|
|
178
|
-
scale
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
steps = bandSpace(
|
|
182
|
-
steps,
|
|
183
|
-
_scale.paddingInner(),
|
|
184
|
-
_scale.paddingOuter()
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
return { px: steps * stepSize, grow: 0 };
|
|
188
|
-
} else {
|
|
189
|
-
throw new Error(
|
|
190
|
-
"Cannot use 'step' size with missing scale!"
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
} else {
|
|
194
|
-
return (value && parseSizeDef(value)) ?? { px: 0, grow: 1 };
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
return this._cache(
|
|
199
|
-
"size/sizeFromSpec",
|
|
200
|
-
() => new FlexDimensions(handleSize("width"), handleSize("height"))
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
isVisible() {
|
|
205
|
-
return this.context.isViewVisible(this);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
isVisibleInSpec() {
|
|
209
|
-
return this.spec.visible ?? true;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Returns the effective opacity of this view, e.g., view's opacity multiplied
|
|
214
|
-
* by opacities of its ancestors.
|
|
215
|
-
*
|
|
216
|
-
* TODO: This methods makes sense only in Unit and Layer views.
|
|
217
|
-
*
|
|
218
|
-
* @returns {number}
|
|
219
|
-
*/
|
|
220
|
-
getEffectiveOpacity() {
|
|
221
|
-
return this.opacityFunction(this.parent?.getEffectiveOpacity() ?? 1.0);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
getPathString() {
|
|
225
|
-
return [...this.getAncestors()]
|
|
226
|
-
.map((v) => v.name)
|
|
227
|
-
.reverse()
|
|
228
|
-
.join("/");
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
*getAncestors() {
|
|
232
|
-
// eslint-disable-next-line consistent-this
|
|
233
|
-
let view = /** @type {View} */ (this);
|
|
234
|
-
do {
|
|
235
|
-
yield view;
|
|
236
|
-
view = view.parent;
|
|
237
|
-
} while (view);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Handles a broadcast message that is intended for the whole view hierarchy.
|
|
242
|
-
*
|
|
243
|
-
* @param {BroadcastMessage} message
|
|
244
|
-
*/
|
|
245
|
-
handleBroadcast(message) {
|
|
246
|
-
// TODO: message types should be constants
|
|
247
|
-
for (const handler of this._broadcastHandlers[message.type] || []) {
|
|
248
|
-
handler(message);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
*
|
|
254
|
-
* @param {string} type
|
|
255
|
-
* @param {function(BroadcastMessage):void} handler
|
|
256
|
-
*/
|
|
257
|
-
_addBroadcastHandler(type, handler) {
|
|
258
|
-
let handlers = this._broadcastHandlers[type];
|
|
259
|
-
if (!handlers) {
|
|
260
|
-
handlers = [];
|
|
261
|
-
this._broadcastHandlers[type] = handlers;
|
|
262
|
-
}
|
|
263
|
-
handlers.push(handler);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Handles an interactionEvent
|
|
268
|
-
*
|
|
269
|
-
* @param {import("../utils/layout/rectangle").default} coords
|
|
270
|
-
* Coordinates of the view
|
|
271
|
-
* @param {import("../utils/interactionEvent").default} event
|
|
272
|
-
* @param {boolean} capturing
|
|
273
|
-
*/
|
|
274
|
-
handleInteractionEvent(coords, event, capturing) {
|
|
275
|
-
const listenersByType = capturing
|
|
276
|
-
? this._capturingInteractionEventListeners
|
|
277
|
-
: this._nonCapturingInteractionEventListeners;
|
|
278
|
-
for (const listener of listenersByType[event.type] || []) {
|
|
279
|
-
listener(coords, event);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Add an "interaction" event listener that mimics DOM's event model inside
|
|
285
|
-
* the view hierarchy.
|
|
286
|
-
*
|
|
287
|
-
* This is intended for GenomeSpy's internal use. It allows the views to handle
|
|
288
|
-
* low level interactions such as dragging, wheeling, etc.
|
|
289
|
-
*
|
|
290
|
-
* @param {string} type
|
|
291
|
-
* @param {InteractionEventListener} listener
|
|
292
|
-
* @param {boolean} [useCapture]
|
|
293
|
-
*/
|
|
294
|
-
addInteractionEventListener(type, listener, useCapture) {
|
|
295
|
-
const listenersByType = useCapture
|
|
296
|
-
? this._capturingInteractionEventListeners
|
|
297
|
-
: this._nonCapturingInteractionEventListeners;
|
|
298
|
-
let listeners = listenersByType[type];
|
|
299
|
-
if (!listeners) {
|
|
300
|
-
listeners = [];
|
|
301
|
-
listenersByType[type] = listeners;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
listeners.push(listener);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Visits child views in depth-first order. Visitor's return value
|
|
309
|
-
* controls the traversal.
|
|
310
|
-
*
|
|
311
|
-
* @param {Visitor} visitor
|
|
312
|
-
* @returns {VisitResult}
|
|
313
|
-
*
|
|
314
|
-
*/
|
|
315
|
-
visit(visitor) {
|
|
316
|
-
try {
|
|
317
|
-
const result = visitor(this);
|
|
318
|
-
|
|
319
|
-
if (visitor.postOrder) {
|
|
320
|
-
visitor.postOrder(this);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
if (result !== VISIT_STOP) {
|
|
324
|
-
return result;
|
|
325
|
-
}
|
|
326
|
-
} catch (e) {
|
|
327
|
-
// Augment the exception with the view
|
|
328
|
-
e.view = this;
|
|
329
|
-
throw e;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Called after all scales in the view hierarchy have been resolved.
|
|
335
|
-
*/
|
|
336
|
-
onScalesResolved() {
|
|
337
|
-
// Only set the opacity function once. The idea is to allow custom functions
|
|
338
|
-
// and prevent accidental overwrites.
|
|
339
|
-
if (
|
|
340
|
-
!this.opacityFunction ||
|
|
341
|
-
this.opacityFunction === defaultOpacityFunction
|
|
342
|
-
) {
|
|
343
|
-
this.opacityFunction = createViewOpacityFunction(this);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* ViewRenderingContext calls this method once for each view during each rendering
|
|
349
|
-
* pass. The order is depth first, pre order.
|
|
350
|
-
*/
|
|
351
|
-
onBeforeRender() {
|
|
352
|
-
//
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Recursively traverses the view hierarchy, computes the view coordinates,
|
|
357
|
-
* and coordinates the mark rendering.
|
|
358
|
-
*
|
|
359
|
-
* @param {import("./renderingContext/viewRenderingContext").default} context
|
|
360
|
-
* @param {import("../utils/layout/rectangle").default} coords The coordinate rectangle that the parent computed
|
|
361
|
-
* for the child that is being visited.
|
|
362
|
-
* @param {RenderingOptions} [options]
|
|
363
|
-
*/
|
|
364
|
-
render(context, coords, options = {}) {
|
|
365
|
-
// override
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Returns the encodings specified in this view combined with the inherited
|
|
370
|
-
* encodings. However, this does not contain any defaults or inferred/adjusted/fixed
|
|
371
|
-
* encodings. Those are available in Mark's encoding property.
|
|
372
|
-
*
|
|
373
|
-
* @return {import("../spec/channel").Encoding}
|
|
374
|
-
*/
|
|
375
|
-
getEncoding() {
|
|
376
|
-
const pe =
|
|
377
|
-
this.parent && !this.blockEncodingInheritance
|
|
378
|
-
? this.parent.getEncoding()
|
|
379
|
-
: {};
|
|
380
|
-
const te = this.spec.encoding || {};
|
|
381
|
-
|
|
382
|
-
/** @type {import("../spec/channel").Encoding} */
|
|
383
|
-
const combined = {
|
|
384
|
-
...pe,
|
|
385
|
-
...te,
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
for (const [channel, channelDef] of Object.entries(combined)) {
|
|
389
|
-
if (channelDef === null) {
|
|
390
|
-
// Prevent propagation
|
|
391
|
-
delete combined[channel];
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return combined;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* @param {View} [whoIsAsking] Passed to the immediate parent. Allows for
|
|
400
|
-
* selectively breaking the inheritance.
|
|
401
|
-
* @return {function(object):any}
|
|
402
|
-
*/
|
|
403
|
-
getFacetAccessor(whoIsAsking) {
|
|
404
|
-
if (this.parent) {
|
|
405
|
-
return this.parent.getFacetAccessor(this);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Returns the fields that should be used for partitioning the data for facets.
|
|
411
|
-
*
|
|
412
|
-
* @param {View} [whoIsAsking]
|
|
413
|
-
* @returns {string[]}
|
|
414
|
-
*/
|
|
415
|
-
getFacetFields(whoIsAsking) {
|
|
416
|
-
const sampleFieldDef = this.getEncoding().sample;
|
|
417
|
-
if (isFieldDef(sampleFieldDef)) {
|
|
418
|
-
return [sampleFieldDef.field];
|
|
419
|
-
} else {
|
|
420
|
-
return this.parent?.getFacetFields(this);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Returns a texture that has a mapping for the sample locations. This is implemented
|
|
426
|
-
* only in the SampleView of GenomeSpy App.
|
|
427
|
-
*
|
|
428
|
-
* @returns {WebGLTexture}
|
|
429
|
-
*/
|
|
430
|
-
getSampleFacetTexture() {
|
|
431
|
-
return undefined;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
*
|
|
436
|
-
* @param {Channel} channel
|
|
437
|
-
* @param {ResolutionTarget} type
|
|
438
|
-
* @returns {ScaleResolution | AxisResolution}
|
|
439
|
-
*/
|
|
440
|
-
_getResolution(channel, type) {
|
|
441
|
-
channel = getPrimaryChannel(channel);
|
|
442
|
-
|
|
443
|
-
/** @type {import("./view").default } */
|
|
444
|
-
// eslint-disable-next-line consistent-this
|
|
445
|
-
let view = this;
|
|
446
|
-
do {
|
|
447
|
-
const resolution = view.resolutions[type][channel];
|
|
448
|
-
if (resolution) {
|
|
449
|
-
return resolution;
|
|
450
|
-
}
|
|
451
|
-
view = view.parent;
|
|
452
|
-
} while (view);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* @param {Channel} channel
|
|
457
|
-
*/
|
|
458
|
-
getScaleResolution(channel) {
|
|
459
|
-
return /** @type {ScaleResolution} */ (
|
|
460
|
-
this._getResolution(channel, "scale")
|
|
461
|
-
);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* @param {Channel} channel
|
|
466
|
-
*/
|
|
467
|
-
getAxisResolution(channel) {
|
|
468
|
-
return /** @type {AxisResolution} */ (
|
|
469
|
-
this._getResolution(channel, "axis")
|
|
470
|
-
);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* @returns {string}
|
|
475
|
-
*/
|
|
476
|
-
getBaseUrl() {
|
|
477
|
-
return appendToBaseUrl(
|
|
478
|
-
() => this.parent?.getBaseUrl(),
|
|
479
|
-
this.spec.baseUrl
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* @returns {import("../data/sources/dataSource").default}
|
|
485
|
-
*/
|
|
486
|
-
getDynamicDataSource() {
|
|
487
|
-
throw new Error("The view does not provide dynamic data!");
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Returns `true` if this view and its children supports picking.
|
|
492
|
-
*/
|
|
493
|
-
isPickingSupported() {
|
|
494
|
-
return true;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
getTitleText() {
|
|
498
|
-
const title = this.spec.title;
|
|
499
|
-
if (title) {
|
|
500
|
-
return isString(title) ? title : title.text;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* @param {any} key string
|
|
506
|
-
* @param {function(key?):T} callable A function that produces a value to be cached
|
|
507
|
-
* @returns {T}
|
|
508
|
-
* @template T
|
|
509
|
-
*/
|
|
510
|
-
_cache(key, callable) {
|
|
511
|
-
return getCachedOrCall(this, key, callable);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
*
|
|
516
|
-
* @param {string} key
|
|
517
|
-
* @param {"self" | "progeny" | "ancestors"} [direction]
|
|
518
|
-
*/
|
|
519
|
-
_invalidateCacheByPrefix(key, direction = "self") {
|
|
520
|
-
switch (direction) {
|
|
521
|
-
case "self":
|
|
522
|
-
invalidatePrefix(this, key);
|
|
523
|
-
break;
|
|
524
|
-
case "ancestors":
|
|
525
|
-
for (const view of this.getAncestors()) {
|
|
526
|
-
invalidatePrefix(view, key);
|
|
527
|
-
}
|
|
528
|
-
break;
|
|
529
|
-
case "progeny":
|
|
530
|
-
this.visit((view) => invalidatePrefix(view, key));
|
|
531
|
-
break;
|
|
532
|
-
default:
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
invalidateSizeCache() {
|
|
537
|
-
this._invalidateCacheByPrefix("size/", "ancestors");
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* Broadcasts a message to views that include the given (x, y) point.
|
|
542
|
-
* This is mainly intended for mouse events.
|
|
543
|
-
*
|
|
544
|
-
* @param {import("../utils/interactionEvent").default} event
|
|
545
|
-
*/
|
|
546
|
-
propagateInteractionEvent(event) {
|
|
547
|
-
// Subclasses must implement proper handling
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
/**
|
|
552
|
-
*
|
|
553
|
-
* @param {any} opacity
|
|
554
|
-
* @returns {opacity is import("../spec/view").DynamicOpacity}
|
|
555
|
-
*/
|
|
556
|
-
function isDynamicOpacity(opacity) {
|
|
557
|
-
return "unitsPerPixel" in opacity;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
/**
|
|
561
|
-
*
|
|
562
|
-
* @param {View} view
|
|
563
|
-
* @returns {function(number):number}
|
|
564
|
-
*/
|
|
565
|
-
function createViewOpacityFunction(view) {
|
|
566
|
-
const opacityDef = view.spec.opacity;
|
|
567
|
-
|
|
568
|
-
if (opacityDef !== undefined) {
|
|
569
|
-
if (isNumber(opacityDef)) {
|
|
570
|
-
return (parentOpacity) => parentOpacity * opacityDef;
|
|
571
|
-
} else if (isDynamicOpacity(opacityDef)) {
|
|
572
|
-
/** @type {function(Channel):any} */
|
|
573
|
-
const getScale = (channel) => {
|
|
574
|
-
const scale = view.getScaleResolution(channel)?.getScale();
|
|
575
|
-
// Only works on linear scales
|
|
576
|
-
if (["linear", "index", "locus"].includes(scale?.type)) {
|
|
577
|
-
return scale;
|
|
578
|
-
}
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
const scale = opacityDef.channel
|
|
582
|
-
? getScale(opacityDef.channel)
|
|
583
|
-
: getScale("x") || getScale("y");
|
|
584
|
-
|
|
585
|
-
if (!scale) {
|
|
586
|
-
throw new Error(
|
|
587
|
-
"Cannot find a resolved quantitative scale for dynamic opacity!"
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
const interpolate = scaleLog()
|
|
592
|
-
.domain(opacityDef.unitsPerPixel)
|
|
593
|
-
.range(opacityDef.values)
|
|
594
|
-
.clamp(true);
|
|
595
|
-
|
|
596
|
-
return (parentOpacity) => {
|
|
597
|
-
const rangeSpan = 1000; //TODO: span(scale.range());
|
|
598
|
-
const unitsPerPixel = span(scale.domain()) / rangeSpan;
|
|
599
|
-
|
|
600
|
-
return interpolate(unitsPerPixel) * parentOpacity;
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
return (parentOpacity) => parentOpacity;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
/**
|
|
608
|
-
*
|
|
609
|
-
* @param {any} size
|
|
610
|
-
* @return {size is import("../spec/view").Step}
|
|
611
|
-
*/
|
|
612
|
-
export const isStepSize = (size) => !!size?.step;
|