@jbrowse/core 5.0.0-beta.4 → 5.0.0-beta.7
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/README.md +278 -250
- package/esm/PluginManager.js +1 -1
- package/esm/ReExports/publicUi.d.ts +1 -1
- package/esm/ReExports/publicUi.js +1 -1
- package/esm/ReExports/publicUtil.d.ts +1 -1
- package/esm/ReExports/publicUtil.js +1 -1
- package/esm/ReExports/workerNamespaceNames.js +3 -9
- package/esm/assemblyManager/assemblyConfigSchema.d.ts +2 -1
- package/esm/assemblyManager/assemblyConfigSchema.js +2 -1
- package/esm/assemblyManager/expandAssemblyConfigShorthand.d.ts +15 -15
- package/esm/assemblyManager/expandAssemblyConfigShorthand.js +34 -18
- package/esm/configuration/configurationSchema.d.ts +1 -2
- package/esm/configuration/configurationSchema.js +3 -8
- package/esm/configuration/configurationSlot.d.ts +0 -47
- package/esm/configuration/configurationSlot.js +4 -54
- package/esm/configuration/fillLocations.d.ts +14 -0
- package/esm/configuration/fillLocations.js +14 -0
- package/esm/configuration/fullConfSnapshot.d.ts +0 -15
- package/esm/configuration/fullConfSnapshot.js +0 -28
- package/esm/configuration/getConf.d.ts +4 -34
- package/esm/configuration/getConf.js +3 -38
- package/esm/configuration/index.d.ts +3 -4
- package/esm/configuration/index.js +3 -2
- package/esm/configuration/schemaRegistry.d.ts +1 -2
- package/esm/configuration/schemaRegistry.js +1 -2
- package/esm/configuration/slotFacade.d.ts +1 -16
- package/esm/configuration/slotFacade.js +1 -2
- package/esm/configuration/tabixShorthand.js +3 -3
- package/esm/configuration/types.d.ts +4 -16
- package/esm/data_adapters/CytobandAdapter/configSchema.js +3 -4
- package/esm/pluggableElementTypes/DisplayType.d.ts +5 -3
- package/esm/pluggableElementTypes/DisplayType.js +3 -1
- package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +30 -0
- package/esm/pluggableElementTypes/models/BaseTrackModel.js +45 -17
- package/esm/rpc/RpcRegistry.d.ts +7 -1
- package/esm/rpc/coreRpcMethods.d.ts +1 -0
- package/esm/rpc/coreRpcMethods.js +1 -0
- package/esm/rpc/methods/CoreEncodeFeatures.d.ts +15 -0
- package/esm/rpc/methods/CoreEncodeFeatures.js +62 -0
- package/esm/svg/svgId.d.ts +1 -1
- package/esm/svg/svgId.js +1 -1
- package/esm/ui/LegendSwatchGlyph.js +26 -21
- package/esm/ui/MenuTypes.d.ts +5 -52
- package/esm/ui/SizeSliderRow.d.ts +1 -3
- package/esm/ui/SizeSliderRow.js +4 -6
- package/esm/ui/SvgColorLegend.d.ts +9 -3
- package/esm/ui/SvgColorLegend.js +74 -33
- package/esm/ui/colorScale.d.ts +64 -0
- package/esm/ui/colorScale.js +41 -0
- package/esm/ui/colors.d.ts +11 -0
- package/esm/ui/colors.js +7 -0
- package/esm/ui/index.d.ts +5 -7
- package/esm/ui/index.js +3 -13
- package/esm/ui/legendMenuItem.d.ts +5 -16
- package/esm/ui/legendMenuItem.js +3 -14
- package/esm/ui/legendSpec.d.ts +11 -5
- package/esm/ui/legendSpec.js +8 -11
- package/esm/ui/makeSizeMenu.d.ts +0 -6
- package/esm/ui/makeSizeMenu.js +6 -30
- package/esm/ui/measureLegendText.js +1 -1
- package/esm/ui/menuItemAdornment.d.ts +9 -19
- package/esm/ui/menuItemAdornment.js +10 -31
- package/esm/ui/menuItems.d.ts +2 -6
- package/esm/ui/menuItems.js +0 -4
- package/esm/ui/palette.js +2 -1
- package/esm/ui/toggleMenuItems.d.ts +6 -13
- package/esm/ui/toggleMenuItems.js +13 -29
- package/esm/util/colorRamp.d.ts +3 -3
- package/esm/util/colorRamp.js +2 -2
- package/esm/util/featureTransforms.d.ts +15 -0
- package/esm/util/featureTransforms.js +342 -0
- package/esm/util/freezeDeep.d.ts +8 -10
- package/esm/util/freezeDeep.js +8 -10
- package/esm/util/glyphNames.d.ts +8 -0
- package/esm/util/glyphNames.js +12 -0
- package/esm/util/index.d.ts +0 -1
- package/esm/util/index.js +0 -1
- package/esm/util/markEncoding.d.ts +76 -0
- package/esm/util/markEncoding.js +436 -0
- package/esm/util/markEncodingTypes.d.ts +331 -0
- package/esm/util/markEncodingTypes.js +8 -0
- package/esm/util/renderToStaticMarkup.js +1 -1
- package/esm/util/starFusion.d.ts +26 -0
- package/esm/util/starFusion.js +37 -0
- package/esm/util/trackConfigDelta.d.ts +4 -8
- package/esm/util/trackConfigDelta.js +2 -4
- package/esm/util/tracks.d.ts +7 -1
- package/esm/util/tracks.js +72 -7
- package/esm/util/types/index.d.ts +12 -4
- package/esm/util/whenViewSettled.d.ts +9 -0
- package/esm/util/whenViewSettled.js +12 -4
- package/package.json +13 -3
- package/esm/configuration/promotableDefaults.d.ts +0 -234
- package/esm/configuration/promotableDefaults.js +0 -395
- package/esm/configuration/promotablePin.d.ts +0 -65
- package/esm/configuration/promotablePin.js +0 -1
- package/esm/configuration/promotableResolve.d.ts +0 -108
- package/esm/configuration/promotableResolve.js +0 -117
- package/esm/configuration/promotableSlots.d.ts +0 -12
- package/esm/configuration/promotableSlots.js +0 -45
- package/esm/configuration/slotShape.d.ts +0 -12
- package/esm/configuration/slotShape.js +0 -84
- package/esm/ui/PinAdornment.d.ts +0 -5
- package/esm/ui/PinAdornment.js +0 -67
- package/esm/ui/SvgGradientLegend.d.ts +0 -26
- package/esm/ui/SvgGradientLegend.js +0 -26
- package/esm/ui/promotablePinCoverage.d.ts +0 -58
- package/esm/ui/promotablePinCoverage.js +0 -124
- package/esm/util/openDisplays.d.ts +0 -23
- package/esm/util/openDisplays.js +0 -79
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #api
|
|
3
|
+
* Where a channel's value comes from: a feature field name, read natively
|
|
4
|
+
* (`feature.get(name)`), or a `jexl:` expression over `feature` — the opt-in
|
|
5
|
+
* escape, three orders of magnitude slower per feature.
|
|
6
|
+
*/
|
|
7
|
+
export type FieldRef = string;
|
|
8
|
+
/**
|
|
9
|
+
* #api
|
|
10
|
+
* The ramp a continuous colour scale samples: a named ramp, or evenly spaced
|
|
11
|
+
* CSS colour stops.
|
|
12
|
+
*/
|
|
13
|
+
export type RampRef = 'viridis' | string[];
|
|
14
|
+
/**
|
|
15
|
+
* #api
|
|
16
|
+
* A field bound to a categorical scale: each distinct value takes one entry
|
|
17
|
+
* of the channel's range — a palette entry for `color`, a glyph name for
|
|
18
|
+
* `glyph`. With a `domain`, the listed values take the range in that order
|
|
19
|
+
* and whatever else the region meets follows, sorted; without one each value
|
|
20
|
+
* derives its entry from itself (an integer takes the slot it names, anything
|
|
21
|
+
* else hashes in), so every region agrees on a value it shares with another at
|
|
22
|
+
* the cost of an occasional collision, and `domain` is the way to spend the
|
|
23
|
+
* range deliberately.
|
|
24
|
+
*/
|
|
25
|
+
export interface CategoricalRef {
|
|
26
|
+
field: FieldRef;
|
|
27
|
+
scale: 'categorical';
|
|
28
|
+
domain?: (string | number)[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* #api
|
|
32
|
+
* How a mark's `color` channel resolves. A CSS colour or a `jexl:` expression
|
|
33
|
+
* returning one paints per feature with no scale; the two object forms bind a
|
|
34
|
+
* field to a scale, which is what a legend can describe. A continuous scale
|
|
35
|
+
* reads the field through `domain` (the region's own extremes when absent)
|
|
36
|
+
* into `ramp`, and there a listed `domain` is what pins the answer across a
|
|
37
|
+
* whole view.
|
|
38
|
+
*/
|
|
39
|
+
export type ColorEncoding = string | (CategoricalRef & {
|
|
40
|
+
palette?: string[];
|
|
41
|
+
}) | {
|
|
42
|
+
field: FieldRef;
|
|
43
|
+
scale: 'linear' | 'log';
|
|
44
|
+
domain?: [number, number];
|
|
45
|
+
ramp?: RampRef;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* #api
|
|
49
|
+
* How a mark's `y` channel resolves: a feature field (or `jexl:` expression)
|
|
50
|
+
* read on a linear scale over the loaded regions' extremes, or the same field
|
|
51
|
+
* with the scale spelled out — `log` to read the domain logarithmically,
|
|
52
|
+
* `domain` to pin `[min, max]` instead of autoscaling. The declaration is the
|
|
53
|
+
* one owner: the display's axis, its ticks and the shader's placement are all
|
|
54
|
+
* resolved from it.
|
|
55
|
+
*
|
|
56
|
+
* `resolve` is which axis the mark reads. `shared` — the default — folds it
|
|
57
|
+
* into the display's one y domain with every other mark. `independent` gives
|
|
58
|
+
* it a domain folded from its layers alone and a second axis on the right, so
|
|
59
|
+
* a coverage run and the raw features can share a plot; one mark per display
|
|
60
|
+
* may ask for it.
|
|
61
|
+
*/
|
|
62
|
+
export type ValueEncoding = FieldRef | {
|
|
63
|
+
field: FieldRef;
|
|
64
|
+
scale?: 'linear' | 'log';
|
|
65
|
+
domain?: [number, number];
|
|
66
|
+
resolve?: 'shared' | 'independent';
|
|
67
|
+
};
|
|
68
|
+
export type GlyphName = 'disc' | 'triangle' | 'diamond';
|
|
69
|
+
/**
|
|
70
|
+
* #api
|
|
71
|
+
* A {@link GlyphName}, a `jexl:` expression over `feature` returning one, or
|
|
72
|
+
* a field bound to a categorical scale whose `range` lists the glyph names
|
|
73
|
+
* handed out — the three glyphs, in order, when absent.
|
|
74
|
+
*/
|
|
75
|
+
export type GlyphEncoding = GlyphName | `jexl:${string}` | (CategoricalRef & {
|
|
76
|
+
range?: GlyphName[];
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* #api
|
|
80
|
+
* The declared mapping from a feature's fields to a mark's channels. `x`
|
|
81
|
+
* defaults to `start` and `x2` to `end`; a mark that plots no value leaves `y`
|
|
82
|
+
* off. `glyph` is read by the `point` shape alone, `row` — an integer field,
|
|
83
|
+
* 0 where missing — by the `span` shape, which stacks a feature on the band
|
|
84
|
+
* it names.
|
|
85
|
+
*/
|
|
86
|
+
export interface MarkEncoding {
|
|
87
|
+
x?: FieldRef;
|
|
88
|
+
x2?: FieldRef;
|
|
89
|
+
y?: ValueEncoding;
|
|
90
|
+
row?: FieldRef;
|
|
91
|
+
color?: ColorEncoding;
|
|
92
|
+
glyph?: GlyphEncoding;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* #api
|
|
96
|
+
* The lanes a caller asks the encoder to fill, beyond `x`, `x2` and
|
|
97
|
+
* `featureIndex`, which every payload carries: a shape's channels, and
|
|
98
|
+
* `index` for the Flatbush a hover reads. A lane not asked for is neither
|
|
99
|
+
* allocated nor transferred, and a caller that never hovers declines the
|
|
100
|
+
* index, which is most of the encoder's cost after the walk.
|
|
101
|
+
*/
|
|
102
|
+
export type LaneName = 'y' | 'color' | 'colorValue' | 'glyph' | 'row' | 'index';
|
|
103
|
+
/**
|
|
104
|
+
* #api
|
|
105
|
+
* The scale a colour channel was resolved through, as the legend reads it —
|
|
106
|
+
* the same table the colours in the payload came from, so the key cannot
|
|
107
|
+
* disagree with the painting.
|
|
108
|
+
*/
|
|
109
|
+
export type ColorScaleTable = {
|
|
110
|
+
kind: 'categorical';
|
|
111
|
+
field: string;
|
|
112
|
+
entries: {
|
|
113
|
+
label: string;
|
|
114
|
+
color: number;
|
|
115
|
+
}[];
|
|
116
|
+
} | {
|
|
117
|
+
kind: 'ramp';
|
|
118
|
+
field: string;
|
|
119
|
+
scale: 'linear' | 'log';
|
|
120
|
+
/** What the ramp spans here: the declared domain, else `extent`. */
|
|
121
|
+
domain: [number, number];
|
|
122
|
+
/** Whether `domain` was declared, and so already agrees across regions. */
|
|
123
|
+
pinned: boolean;
|
|
124
|
+
/** This region's own extremes of the field, what a display unions. */
|
|
125
|
+
extent: [number, number];
|
|
126
|
+
lut: Uint8Array;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* #api
|
|
130
|
+
* The scale a glyph channel was resolved through: which glyph each value of
|
|
131
|
+
* the field took.
|
|
132
|
+
*/
|
|
133
|
+
export interface GlyphScaleTable {
|
|
134
|
+
kind: 'glyph';
|
|
135
|
+
field: string;
|
|
136
|
+
entries: {
|
|
137
|
+
label: string;
|
|
138
|
+
glyph: GlyphName;
|
|
139
|
+
}[];
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* #api
|
|
143
|
+
* Any channel's scale table; the kind names the channel.
|
|
144
|
+
*/
|
|
145
|
+
export type ScaleTable = ColorScaleTable | GlyphScaleTable;
|
|
146
|
+
/**
|
|
147
|
+
* #api
|
|
148
|
+
* One encoding's channels over one region's features, dense and
|
|
149
|
+
* index-aligned: instance `i` of every array is the same feature, and
|
|
150
|
+
* `featureIndex[i]` says which one of the input list it was. A lane is
|
|
151
|
+
* present when the caller asked for it ({@link LaneName}); {@link Encoded}
|
|
152
|
+
* is this type with a known lane set required.
|
|
153
|
+
*/
|
|
154
|
+
export interface EncodedChannels {
|
|
155
|
+
count: number;
|
|
156
|
+
/**
|
|
157
|
+
* Features the walk left out: one whose `x`, `x2` or `y` read as missing
|
|
158
|
+
* or not a number. A mistyped field skips every feature, so a display
|
|
159
|
+
* reads this beside `count` to say so.
|
|
160
|
+
*/
|
|
161
|
+
skipped: number;
|
|
162
|
+
x: Uint32Array;
|
|
163
|
+
x2: Uint32Array;
|
|
164
|
+
featureIndex: Uint32Array;
|
|
165
|
+
y?: Float32Array;
|
|
166
|
+
color?: Uint32Array;
|
|
167
|
+
/**
|
|
168
|
+
* The raw values of a ramp colour channel, for a caller that named the
|
|
169
|
+
* `colorValue` lane: the scale then resolves on the main thread against a
|
|
170
|
+
* domain unioned over the loaded regions, and `scale.extent` is this
|
|
171
|
+
* region's contribution to it.
|
|
172
|
+
*/
|
|
173
|
+
colorValue?: Float32Array;
|
|
174
|
+
glyph?: Uint8Array;
|
|
175
|
+
row?: Uint32Array;
|
|
176
|
+
/** The finite `y` extremes, `Infinity`/`-Infinity` when nothing plotted. */
|
|
177
|
+
yMin: number;
|
|
178
|
+
yMax: number;
|
|
179
|
+
/** A Flatbush over (x, y, x2, y), when `index` was asked for and `count` is not 0. */
|
|
180
|
+
flatbushData?: ArrayBuffer;
|
|
181
|
+
/** The colour channel's table, when `color` is a scale. */
|
|
182
|
+
scale?: ColorScaleTable;
|
|
183
|
+
/** The glyph channel's table, when `glyph` is a scale. */
|
|
184
|
+
glyphScale?: GlyphScaleTable;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* #api
|
|
188
|
+
* {@link EncodedChannels} with the lanes in `L` present — what
|
|
189
|
+
* `encodeFeatures` answers a caller that named them.
|
|
190
|
+
*/
|
|
191
|
+
export type Encoded<L extends LaneName> = EncodedChannels & Required<Pick<EncodedChannels, Exclude<L, 'index'>>>;
|
|
192
|
+
/**
|
|
193
|
+
* #api
|
|
194
|
+
* One layer of a `CoreEncodeFeatures` request: the encoding to evaluate and
|
|
195
|
+
* the lanes the display's shape reads.
|
|
196
|
+
*/
|
|
197
|
+
export interface LayerRequest {
|
|
198
|
+
encoding: MarkEncoding;
|
|
199
|
+
lanes: LaneName[];
|
|
200
|
+
/** This layer's own steps, run after the request's shared ones. */
|
|
201
|
+
transform?: TransformStep[];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* #api
|
|
205
|
+
* What `CoreEncodeFeatures` answers for one region: `layers[i]` is the
|
|
206
|
+
* request's `layers[i]` over the region's features, so a display's mark
|
|
207
|
+
* list indexes straight into it.
|
|
208
|
+
*/
|
|
209
|
+
export interface EncodedFeaturesResult {
|
|
210
|
+
layers: EncodedChannels[];
|
|
211
|
+
bytes?: number;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* #api
|
|
215
|
+
* Keep the features a `jexl:` expression over `feature` admits.
|
|
216
|
+
*/
|
|
217
|
+
export interface FilterStep {
|
|
218
|
+
type: 'filter';
|
|
219
|
+
expr: string;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* #api
|
|
223
|
+
* Write a `jexl:` expression's value over `feature` into the field `as` of
|
|
224
|
+
* every feature.
|
|
225
|
+
*/
|
|
226
|
+
export interface FormulaStep {
|
|
227
|
+
type: 'formula';
|
|
228
|
+
expr: string;
|
|
229
|
+
as: string;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* #api
|
|
233
|
+
* Snap every feature to the genome-aligned bin of `step` bp its `field`
|
|
234
|
+
* (`start` by default) falls in, writing the bin's edges over the fields
|
|
235
|
+
* `as` names — `start` and `end` by default, so an `aggregate` grouped by
|
|
236
|
+
* those counts per bin and the bar spans the bin.
|
|
237
|
+
*/
|
|
238
|
+
export interface BinStep {
|
|
239
|
+
type: 'bin';
|
|
240
|
+
step: number;
|
|
241
|
+
field?: FieldRef;
|
|
242
|
+
as?: [string, string];
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* #api
|
|
246
|
+
* One summary over a group: `count` needs no field; `sum`, `mean`, `min` and
|
|
247
|
+
* `max` read one, skipping values that are not numbers. The output field is
|
|
248
|
+
* `as`, else `count` or `<op>_<field>`.
|
|
249
|
+
*/
|
|
250
|
+
export interface AggregateOp {
|
|
251
|
+
op: 'count' | 'sum' | 'mean' | 'min' | 'max';
|
|
252
|
+
field?: FieldRef;
|
|
253
|
+
as?: string;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* #api
|
|
257
|
+
* One feature per distinct `groupby` value set (one for the whole region
|
|
258
|
+
* with none), spanning its members' extent, carrying the group's fields and
|
|
259
|
+
* every `ops` entry.
|
|
260
|
+
*/
|
|
261
|
+
export interface AggregateStep {
|
|
262
|
+
type: 'aggregate';
|
|
263
|
+
groupby?: FieldRef[];
|
|
264
|
+
ops: AggregateOp[];
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* #api
|
|
268
|
+
* Replace the features with runs of constant depth: how many of them overlap
|
|
269
|
+
* each stretch of the region, in a field `as` (`coverage` by default), with
|
|
270
|
+
* the stretches nothing overlaps left out.
|
|
271
|
+
*/
|
|
272
|
+
export interface CoverageStep {
|
|
273
|
+
type: 'coverage';
|
|
274
|
+
as?: string;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* #api
|
|
278
|
+
* Fan each feature out into one feature per element of an array-valued field
|
|
279
|
+
* — `subfeatures`, so a gene answers its transcripts and a transcript its
|
|
280
|
+
* exons. Each answer reads the element's own fields first and the feature it
|
|
281
|
+
* came from for everything else, so an exon still knows its gene's name and
|
|
282
|
+
* strand. A feature whose field holds no array drops out unless `keepEmpty`
|
|
283
|
+
* says otherwise.
|
|
284
|
+
*/
|
|
285
|
+
export interface FlattenStep {
|
|
286
|
+
type: 'flatten';
|
|
287
|
+
field?: FieldRef;
|
|
288
|
+
/** Written with the element's position in its parent's array. */
|
|
289
|
+
index?: string;
|
|
290
|
+
keepEmpty?: boolean;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* #api
|
|
294
|
+
* Assign every feature the lowest row on which it overlaps nothing already
|
|
295
|
+
* there — greedy first fit in start order, the packing a pileup is — and
|
|
296
|
+
* write it to the field `as` (`row`). `fields` names the interval read
|
|
297
|
+
* (`start`, `end`); `padding` is bp of clearance kept between two features
|
|
298
|
+
* sharing a row; `groupby` packs each distinct value set on its own rows,
|
|
299
|
+
* each numbered from 0. The answer is the input in start order, so a `span`
|
|
300
|
+
* encoding `row` stacks it.
|
|
301
|
+
*/
|
|
302
|
+
export interface StackStep {
|
|
303
|
+
type: 'stack';
|
|
304
|
+
as?: string;
|
|
305
|
+
fields?: [string, string];
|
|
306
|
+
padding?: number;
|
|
307
|
+
groupby?: FieldRef[];
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* #api
|
|
311
|
+
* One step over the features before a layer is encoded, named by `type` the
|
|
312
|
+
* way GenomeSpy spells a transform; every step runs in order and the next
|
|
313
|
+
* reads what the last answered.
|
|
314
|
+
*/
|
|
315
|
+
export type TransformStep = FilterStep | FormulaStep | FlattenStep | BinStep | AggregateStep | CoverageStep | StackStep;
|
|
316
|
+
export type CoreEncodeFeaturesArgs = {
|
|
317
|
+
adapterConfig: Record<string, unknown>;
|
|
318
|
+
region: {
|
|
319
|
+
refName: string;
|
|
320
|
+
start: number;
|
|
321
|
+
end: number;
|
|
322
|
+
assemblyName: string;
|
|
323
|
+
};
|
|
324
|
+
layers: LayerRequest[];
|
|
325
|
+
/** The steps over the features, in order, before every layer encodes. */
|
|
326
|
+
transform?: TransformStep[];
|
|
327
|
+
/** Sugar for leading `filter` steps: `jexl:`-prefixed expressions. */
|
|
328
|
+
filters?: string[];
|
|
329
|
+
byteLimit?: number;
|
|
330
|
+
sequenceAdapter?: Record<string, unknown>;
|
|
331
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// The declared shape of a mark encoding and what evaluating one produces —
|
|
2
|
+
// split from markEncoding.ts because that file's runtime half reaches
|
|
3
|
+
// render-core's whole HAL/color-ramp graph for encodeFeatures' native scale
|
|
4
|
+
// tables, and RpcRegistry.ts needs only these types for CoreEncodeFeatures'
|
|
5
|
+
// wire shape. Importing them from markEncoding.ts would carry that graph into
|
|
6
|
+
// every leaf that reaches the RPC registry. scripts/moduleClosure.test.ts
|
|
7
|
+
// holds the ceiling.
|
|
8
|
+
export {};
|
|
@@ -50,7 +50,7 @@ export function renderToStaticMarkup(node) {
|
|
|
50
50
|
// they cannot parse, so the alpha is stripped rather than left to break the
|
|
51
51
|
// whole shape. It is *dropped*, not converted, so a translucent color exports
|
|
52
52
|
// fully opaque: components that need transparency to survive set a separate
|
|
53
|
-
// opacity attribute instead (`CrossHatches`, `
|
|
53
|
+
// opacity attribute instead (`CrossHatches`, `RowSeparatorLines`).
|
|
54
54
|
//
|
|
55
55
|
// Rewriting `fill="rgba(r,g,b,a)"` into `fill="rgb(r,g,b)" fill-opacity="a"`
|
|
56
56
|
// would preserve the appearance and let those two drop their workarounds, but
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type FusionBreakpoint = {
|
|
2
|
+
refName: string;
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
strand?: number;
|
|
6
|
+
/** which way the sequence this end keeps runs from it: 1 right, -1 left, 0 unknown */
|
|
7
|
+
mateDirection: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The column names of a STAR-Fusion `fusion_predictions.tsv` header line. The
|
|
11
|
+
* leading `#` is not universal across STAR-Fusion versions and wrappers, so it
|
|
12
|
+
* is stripped when present. Throws a named error for a header without the two
|
|
13
|
+
* breakpoint columns, which is the wrong file or the wrong File Type guess.
|
|
14
|
+
*/
|
|
15
|
+
export declare function starFusionColumns(header: string | undefined): string[];
|
|
16
|
+
/**
|
|
17
|
+
* A STAR-Fusion `refName:pos:strand` breakpoint as an interbase feature, read
|
|
18
|
+
* from the RIGHT because a refName may contain colons (GRCh38's
|
|
19
|
+
* `HLA-A*01:01:01:01`). The position is 1-based in the file. The strand is the
|
|
20
|
+
* gene's transcription strand, and the fusion transcript keeps the donor's
|
|
21
|
+
* sequence 5' of the junction and the acceptor's 3' of it, so `mateDirection`
|
|
22
|
+
* is the strand negated for a donor and taken as read for an acceptor: the
|
|
23
|
+
* convention `parseSvAlt` states for a breakend and the paired-arc display
|
|
24
|
+
* draws its ticks from.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseStarFusionBreakpoint(str: string, isDonor: boolean): FusionBreakpoint;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The column names of a STAR-Fusion `fusion_predictions.tsv` header line. The
|
|
3
|
+
* leading `#` is not universal across STAR-Fusion versions and wrappers, so it
|
|
4
|
+
* is stripped when present. Throws a named error for a header without the two
|
|
5
|
+
* breakpoint columns, which is the wrong file or the wrong File Type guess.
|
|
6
|
+
*/
|
|
7
|
+
export function starFusionColumns(header) {
|
|
8
|
+
const columns = (header?.startsWith('#') ? header.slice(1) : header)?.split('\t') ?? [];
|
|
9
|
+
const missing = ['LeftBreakpoint', 'RightBreakpoint'].filter(c => !columns.includes(c));
|
|
10
|
+
if (missing.length) {
|
|
11
|
+
throw new Error(`Not a STAR-Fusion file: no ${missing.join(' or ')} column. Found: ${columns.slice(0, 6).join(', ')}`);
|
|
12
|
+
}
|
|
13
|
+
return columns;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A STAR-Fusion `refName:pos:strand` breakpoint as an interbase feature, read
|
|
17
|
+
* from the RIGHT because a refName may contain colons (GRCh38's
|
|
18
|
+
* `HLA-A*01:01:01:01`). The position is 1-based in the file. The strand is the
|
|
19
|
+
* gene's transcription strand, and the fusion transcript keeps the donor's
|
|
20
|
+
* sequence 5' of the junction and the acceptor's 3' of it, so `mateDirection`
|
|
21
|
+
* is the strand negated for a donor and taken as read for an acceptor: the
|
|
22
|
+
* convention `parseSvAlt` states for a breakend and the paired-arc display
|
|
23
|
+
* draws its ticks from.
|
|
24
|
+
*/
|
|
25
|
+
export function parseStarFusionBreakpoint(str, isDonor) {
|
|
26
|
+
const parts = str.split(':');
|
|
27
|
+
const strandStr = parts.length >= 3 ? parts.pop() : undefined;
|
|
28
|
+
const pos = parts.length >= 2 ? +parts.pop() : Number.NaN;
|
|
29
|
+
const strand = strandStr === '+' ? 1 : strandStr === '-' ? -1 : undefined;
|
|
30
|
+
return {
|
|
31
|
+
refName: parts.join(':'),
|
|
32
|
+
start: pos - 1,
|
|
33
|
+
end: pos,
|
|
34
|
+
strand,
|
|
35
|
+
mateDirection: strand === undefined ? 0 : isDonor ? -strand : strand,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -22,10 +22,8 @@
|
|
|
22
22
|
* What it is NOT free to conflate is a removal with a reset. Both diff to an
|
|
23
23
|
* empty delta, and `SessionTracks.updateTrackConfiguration` used to read that as
|
|
24
24
|
* "the edit netted back to the base" and revert the track's working copy — which
|
|
25
|
-
* undid a removal on screen 400ms after it landed.
|
|
26
|
-
*
|
|
27
|
-
* admin config is free to set one. That branch now keeps the working copy; see
|
|
28
|
-
* the comment there.
|
|
25
|
+
* undid a removal on screen 400ms after it landed. That branch now keeps the
|
|
26
|
+
* working copy; see the comment there.
|
|
29
27
|
*
|
|
30
28
|
* `displays` is merged by `displayId` so an edit to one display doesn't pin the
|
|
31
29
|
* others. Nested config objects (e.g. `adapter`) recurse. Any other array (value
|
|
@@ -58,10 +56,8 @@ export declare function mergeTrackConfig(base: Record<string, unknown>, delta: R
|
|
|
58
56
|
/** A single overridden slot: the dotted `path`, its base `from` and edited `to`. */
|
|
59
57
|
export interface TrackConfigChange {
|
|
60
58
|
/**
|
|
61
|
-
* Where the setting lives
|
|
62
|
-
*
|
|
63
|
-
* default's path back into the type and slot it clears. So a producer that
|
|
64
|
-
* wants a friendlier heading sets `label` and leaves this alone.
|
|
59
|
+
* Where the setting lives. A producer that wants a friendlier heading sets
|
|
60
|
+
* `label` and leaves this alone.
|
|
65
61
|
*/
|
|
66
62
|
path: string[];
|
|
67
63
|
from: Json;
|
|
@@ -22,10 +22,8 @@
|
|
|
22
22
|
* What it is NOT free to conflate is a removal with a reset. Both diff to an
|
|
23
23
|
* empty delta, and `SessionTracks.updateTrackConfiguration` used to read that as
|
|
24
24
|
* "the edit netted back to the base" and revert the track's working copy — which
|
|
25
|
-
* undid a removal on screen 400ms after it landed.
|
|
26
|
-
*
|
|
27
|
-
* admin config is free to set one. That branch now keeps the working copy; see
|
|
28
|
-
* the comment there.
|
|
25
|
+
* undid a removal on screen 400ms after it landed. That branch now keeps the
|
|
26
|
+
* working copy; see the comment there.
|
|
29
27
|
*
|
|
30
28
|
* `displays` is merged by `displayId` so an edit to one display doesn't pin the
|
|
31
29
|
* others. Nested config objects (e.g. `adapter`) recurse. Any other array (value
|
package/esm/util/tracks.d.ts
CHANGED
|
@@ -383,11 +383,17 @@ export declare function viewDisplayNames(pluginManager: PluginManager, viewType:
|
|
|
383
383
|
* so the pickers agree on it.
|
|
384
384
|
*/
|
|
385
385
|
export declare function viewCanDisplayTrack(pluginManager: PluginManager, viewDisplays: Set<string>, trackType: string): boolean;
|
|
386
|
-
export declare function pickDisplayForView({ declaredDisplays, requestedType, trackDisplayTypes, viewDisplayTypes, }: {
|
|
386
|
+
export declare function pickDisplayForView({ declaredDisplays, requestedType, trackDisplayTypes, viewDisplayTypes, preferredDisplayTypes, }: {
|
|
387
387
|
declaredDisplays: DisplayConfSnapshot[];
|
|
388
388
|
requestedType: string | undefined;
|
|
389
389
|
trackDisplayTypes: string[];
|
|
390
390
|
viewDisplayTypes: string[];
|
|
391
|
+
/**
|
|
392
|
+
* The display types the view registered as its own, ahead of those it
|
|
393
|
+
* inherits through `extendedName`: a variant track on the circular view
|
|
394
|
+
* draws its chords, not the linear display the view also accepts as a ring.
|
|
395
|
+
*/
|
|
396
|
+
preferredDisplayTypes?: Set<string>;
|
|
391
397
|
}): {
|
|
392
398
|
type: string;
|
|
393
399
|
conf: DisplayConfSnapshot | undefined;
|
package/esm/util/tracks.js
CHANGED
|
@@ -564,10 +564,31 @@ export function viewCanDisplayTrack(pluginManager, viewDisplays, trackType) {
|
|
|
564
564
|
.getTrackType(trackType)
|
|
565
565
|
.displayTypes.some(d => viewDisplays.has(d.name)));
|
|
566
566
|
}
|
|
567
|
-
export function pickDisplayForView({ declaredDisplays, requestedType, trackDisplayTypes, viewDisplayTypes, }) {
|
|
567
|
+
export function pickDisplayForView({ declaredDisplays, requestedType, trackDisplayTypes, viewDisplayTypes, preferredDisplayTypes = new Set(), }) {
|
|
568
568
|
const supported = new Set(viewDisplayTypes);
|
|
569
|
-
|
|
570
|
-
|
|
569
|
+
// A requested type is CHECKED, not taken on faith. It used to pass straight
|
|
570
|
+
// through: an unsupported or misspelled one produced a synthesized
|
|
571
|
+
// `<trackId>-<type>` displayId that no config declares, and the display
|
|
572
|
+
// configuration reference then resolved that dangling id back to the track's
|
|
573
|
+
// DEFAULT display by type — so a caller that asked for read arcs got the
|
|
574
|
+
// pileup, and every layer reported success. The caller turns this
|
|
575
|
+
// `undefined` into an error naming what the track can be drawn as.
|
|
576
|
+
//
|
|
577
|
+
// Callers pass a CANONICAL name (resolveTrackDisplayChoice resolves an alias
|
|
578
|
+
// first), because these two lists hold canonical names only.
|
|
579
|
+
if (requestedType !== undefined) {
|
|
580
|
+
return supported.has(requestedType) &&
|
|
581
|
+
trackDisplayTypes.includes(requestedType)
|
|
582
|
+
? {
|
|
583
|
+
type: requestedType,
|
|
584
|
+
conf: declaredDisplays.find(d => d.type === requestedType),
|
|
585
|
+
}
|
|
586
|
+
: undefined;
|
|
587
|
+
}
|
|
588
|
+
const declared = declaredDisplays.filter(d => supported.has(d.type));
|
|
589
|
+
const type = declared.find(d => preferredDisplayTypes.has(d.type))?.type ??
|
|
590
|
+
declared[0]?.type ??
|
|
591
|
+
trackDisplayTypes.find(name => preferredDisplayTypes.has(name)) ??
|
|
571
592
|
trackDisplayTypes.find(name => supported.has(name));
|
|
572
593
|
return type === undefined
|
|
573
594
|
? undefined
|
|
@@ -637,14 +658,32 @@ function resolveTrackDisplayChoice(self, trackId, displayInitialSnapshot, inline
|
|
|
637
658
|
// getContainingView already resolves to for everything else beneath it.
|
|
638
659
|
const view = isViewModel(self) ? self : getContainingView(self);
|
|
639
660
|
const viewType = pluginManager.getViewType(view.type);
|
|
661
|
+
const trackDisplayTypes = trackType.displayTypes.map(d => d.name);
|
|
662
|
+
const viewDisplayTypes = viewType.displayTypes.map(d => d.name);
|
|
663
|
+
// An alias first, so a session spec or a caller naming a pre-consolidation
|
|
664
|
+
// display type (`LinearPileupDisplay`) reaches the type that replaced it
|
|
665
|
+
// instead of being refused — and so the membership checks below, which are
|
|
666
|
+
// over canonical names, ask the right question.
|
|
667
|
+
const requested = displayInitialSnapshot.type;
|
|
668
|
+
const requestedType = requested === undefined
|
|
669
|
+
? undefined
|
|
670
|
+
: pluginManager.resolveDisplayTypeRecord(requested)?.name;
|
|
640
671
|
const picked = pickDisplayForView({
|
|
641
672
|
declaredDisplays: conf.displays ?? [],
|
|
642
|
-
requestedType
|
|
643
|
-
trackDisplayTypes
|
|
644
|
-
viewDisplayTypes
|
|
673
|
+
requestedType,
|
|
674
|
+
trackDisplayTypes,
|
|
675
|
+
viewDisplayTypes,
|
|
676
|
+
preferredDisplayTypes: new Set(viewType.displayTypes
|
|
677
|
+
.filter(d => d.viewType === view.type)
|
|
678
|
+
.map(d => d.name)),
|
|
645
679
|
});
|
|
646
680
|
if (!picked) {
|
|
647
|
-
|
|
681
|
+
const drawable = trackDisplayTypes.filter(name => viewDisplayTypes.includes(name));
|
|
682
|
+
throw new Error(requested === undefined
|
|
683
|
+
? `Could not find a compatible display for view type ${view.type}`
|
|
684
|
+
: `Track "${trackId}" cannot be shown as "${requested}" in a ${view.type}. ${drawable.length > 0
|
|
685
|
+
? `It takes: ${drawable.join(', ')}`
|
|
686
|
+
: 'This view draws none of its display types'}`);
|
|
648
687
|
}
|
|
649
688
|
return { rawConf, conf, trackType, picked };
|
|
650
689
|
}
|
|
@@ -727,6 +766,32 @@ inlineConf) {
|
|
|
727
766
|
// took the message away with it.
|
|
728
767
|
const displaySettings = Object.fromEntries(Object.entries(displayInitialSnapshot).filter(([key]) => key !== 'type'));
|
|
729
768
|
const report = track.applyDisplaySettings(displaySettings);
|
|
769
|
+
// A key that reached NOTHING, told apart from the ones `unapplied` holds
|
|
770
|
+
// legitimately. `unapplied` means "not a config slot", which covers both an
|
|
771
|
+
// MST display prop the snapshot spread above already applied and a
|
|
772
|
+
// misspelling that did nothing at all — so reporting the list wholesale
|
|
773
|
+
// called a correct spec broken, and reporting none of it let
|
|
774
|
+
// `{ trackId, colorSchem: 'x' }` load a plausible track with the setting
|
|
775
|
+
// silently missing. The display's own model type says which is which.
|
|
776
|
+
// Asked of the display NODE, not of its model type: `type.properties` sees
|
|
777
|
+
// declared props and misses everything else a key can legitimately reach —
|
|
778
|
+
// a volatile the snapshot spread above just set (`resolution` on the GC
|
|
779
|
+
// content display is one) reads as unreached and gets reported over a
|
|
780
|
+
// correct call.
|
|
781
|
+
// `unapplied` holds three kinds of entry, and only one of them means the
|
|
782
|
+
// key did nothing at all: applyDisplaySettings annotates `type` and the
|
|
783
|
+
// "a setter exists, pass allowSetters" case in parentheses, and pushes a
|
|
784
|
+
// BARE key when the display has neither a slot nor a setter for it. So the
|
|
785
|
+
// bare ones are the candidates, and the node itself settles the rest — the
|
|
786
|
+
// snapshot spread above may already have landed the key as a prop or a
|
|
787
|
+
// volatile, which is what `resolution` on the GC content display is.
|
|
788
|
+
const drawn = track.displays[0];
|
|
789
|
+
const reachedNothing = drawn
|
|
790
|
+
? report.unapplied.filter(entry => !entry.includes(' (') && !(entry in drawn))
|
|
791
|
+
: [];
|
|
792
|
+
if (reachedNothing.length > 0) {
|
|
793
|
+
session.notifyError(`Track "${trackId}" ignored ${reachedNothing.join(', ')}: neither a setting the ${displayType} accepts nor one of its properties`);
|
|
794
|
+
}
|
|
730
795
|
if (report.failed.length) {
|
|
731
796
|
session.notifyError(`Track "${trackId}" rejected ${report.failed
|
|
732
797
|
.map(f => `${f.key}: ${f.error}`)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ViewSnapshotInput } from '../../PluginManager.ts';
|
|
2
2
|
import type TextSearchManager from '../../TextSearch/TextSearchManager.ts';
|
|
3
|
-
import type { AnyConfigurationModel
|
|
3
|
+
import type { AnyConfigurationModel } from '../../configuration/index.ts';
|
|
4
4
|
import type { BaseInternetAccountModel } from '../../pluggableElementTypes/models/index.ts';
|
|
5
5
|
import type { PluginDefinition } from '../../pluginDefinitions.ts';
|
|
6
6
|
import type RpcManager from '../../rpc/RpcManager.ts';
|
|
@@ -82,8 +82,6 @@ export interface AbstractSessionModel extends AbstractViewContainer, RenderingSe
|
|
|
82
82
|
setPreferenceOverride: (key: string, value: unknown) => void;
|
|
83
83
|
clearPreferenceOverrides: () => void;
|
|
84
84
|
setScrollZoom: (flag: boolean) => void;
|
|
85
|
-
getDisplayTypeDefault: (displayType: string, slot: string) => unknown;
|
|
86
|
-
setDisplayTypeDefault: (displayType: string, slot: string, value: unknown) => void;
|
|
87
85
|
hovered: unknown;
|
|
88
86
|
setHovered: (arg: unknown) => void;
|
|
89
87
|
setFocusedViewId?: (id: string) => void;
|
|
@@ -425,7 +423,10 @@ export interface TrackContainer {
|
|
|
425
423
|
configuration: {
|
|
426
424
|
trackId: string;
|
|
427
425
|
};
|
|
428
|
-
displays:
|
|
426
|
+
displays: {
|
|
427
|
+
type: string;
|
|
428
|
+
configuration: AnyConfigurationModel;
|
|
429
|
+
}[];
|
|
429
430
|
}[];
|
|
430
431
|
assemblyNames?: string[];
|
|
431
432
|
/**
|
|
@@ -479,6 +480,13 @@ export interface AbstractViewModel {
|
|
|
479
480
|
* the view itself.
|
|
480
481
|
*/
|
|
481
482
|
trackContainerFor?: (id: string) => TrackContainer | undefined;
|
|
483
|
+
/**
|
|
484
|
+
* the node a display in this view lays its regions out against, where that
|
|
485
|
+
* is not the view's own box — the circular view's strip. A display's
|
|
486
|
+
* foundation reads its host through `containingHost`, which answers this
|
|
487
|
+
* before the view itself.
|
|
488
|
+
*/
|
|
489
|
+
regionHost?: unknown;
|
|
482
490
|
/**
|
|
483
491
|
* every track container this view owns INSTEAD of a `tracks` array of its
|
|
484
492
|
* own. The synteny view is the only one: its tracks hang off the levels, one
|
|
@@ -3,6 +3,15 @@ export interface SettleableView {
|
|
|
3
3
|
error: unknown;
|
|
4
4
|
pendingLaunch?: unknown;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* A view that is up AND has finished applying whatever launched it.
|
|
8
|
+
*
|
|
9
|
+
* Both terms, for the reason spelled out on {@link whenViewSettled} below.
|
|
10
|
+
* Exported because AppReadyMarker decides the same thing from the same model
|
|
11
|
+
* for the whole app, the two drifted on exactly this second term, and
|
|
12
|
+
* `readinessTerms.test.tsx` in app-core now holds them together.
|
|
13
|
+
*/
|
|
14
|
+
export declare const viewSettled: (view: SettleableView) => boolean;
|
|
6
15
|
/**
|
|
7
16
|
* Wait until a view has either initialized — launch blob consumed and all — or
|
|
8
17
|
* failed, and report which.
|