@jbrowse/core 5.0.0-beta.10 → 5.0.0-beta.11
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 +113 -5
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +0 -2
- package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.js +22 -6
- package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.js +3 -4
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/useSequenceData.js +8 -5
- package/esm/CorePlugin.js +32 -1
- package/esm/ReExports/coreModules.generated.js +248 -246
- package/esm/ReExports/coreWorkerModules.generated.js +246 -244
- package/esm/ReExports/list.js +3 -2
- package/esm/configuration/index.d.ts +2 -0
- package/esm/configuration/index.js +1 -0
- package/esm/configuration/plot.d.ts +61 -0
- package/esm/configuration/plot.js +142 -0
- package/esm/pluggableElementTypes/DisplayType.d.ts +7 -0
- package/esm/pluggableElementTypes/DisplayType.js +6 -0
- package/esm/pluggableElementTypes/WidgetType.d.ts +6 -0
- package/esm/pluggableElementTypes/WidgetType.js +6 -0
- package/esm/pluggableElementTypes/index.js +1 -8
- package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +57 -1
- package/esm/pluggableElementTypes/models/BaseDisplayModel.js +84 -2
- package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +2 -2
- package/esm/pluggableElementTypes/models/BaseViewModel.js +1 -1
- package/esm/ui/JexlFilterDialog.d.ts +1 -1
- package/esm/ui/JexlFilterDialog.js +2 -3
- package/esm/util/TimeTraveller.d.ts +3 -0
- package/esm/util/TimeTraveller.js +34 -2
- package/esm/util/baseDisplayConfig.d.ts +8 -0
- package/esm/util/baseDisplayConfig.js +27 -0
- package/esm/util/cachedSetup.d.ts +16 -6
- package/esm/util/cachedSetup.js +108 -38
- package/esm/util/cellMatches.d.ts +23 -0
- package/esm/util/cellMatches.js +264 -0
- package/esm/util/cellsStep.d.ts +29 -0
- package/esm/util/cellsStep.js +437 -0
- package/esm/util/copyToClipboard.js +8 -1
- package/esm/util/createAbortRotation.js +3 -3
- package/esm/util/featureTransforms.d.ts +7 -6
- package/esm/util/featureTransforms.js +131 -479
- package/esm/util/fetchPhases.d.ts +1 -1
- package/esm/util/formatBytes.js +1 -1
- package/esm/util/formatGuessers.d.ts +25 -14
- package/esm/util/formatGuessers.js +42 -27
- package/esm/util/formatRelativeTime.js +1 -1
- package/esm/util/getLocationUri.d.ts +2 -1
- package/esm/util/getLocationUri.js +8 -2
- package/esm/util/groupKeys.d.ts +4 -5
- package/esm/util/groupKeys.js +7 -6
- package/esm/util/intervals.js +9 -4
- package/esm/util/io/index.js +3 -1
- package/esm/util/jexlFilters.d.ts +31 -49
- package/esm/util/jexlFilters.js +29 -39
- package/esm/util/locString.js +5 -2
- package/esm/util/markEncoding.js +48 -8
- package/esm/util/markEncodingTypes.d.ts +8 -1
- package/esm/util/springAnimate.js +1 -1
- package/esm/util/stepTables.d.ts +14 -0
- package/esm/util/stepTables.js +38 -4
- package/esm/util/tabix.d.ts +6 -2
- package/esm/util/tabix.js +2 -2
- package/esm/util/tracks.d.ts +3 -30
- package/esm/util/tracks.js +4 -39
- package/esm/util/unknownSnapshotKeys.d.ts +3 -1
- package/esm/util/unknownSnapshotKeys.js +5 -11
- package/esm/util/usePanZoom.js +10 -3
- package/esm/util/useRafCommit.js +1 -0
- package/esm/util/withFeatureDetails.js +4 -0
- package/package.json +9 -8
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
// The `cells` step: each row's runs against the reference it was fanned out
|
|
2
|
+
// of, and the texts its walk reads, which the fused identity kernel in
|
|
3
|
+
// cellMatches.ts walks too. Imported by relative path only.
|
|
4
|
+
import { DerivedTable, numberReaderOf, readerOf, valueAt, } from './featureTable.js';
|
|
5
|
+
import { FannedTable, boundsThrough } from './stepTables.js';
|
|
6
|
+
export const DEFAULT_CELLS_FIELD = 'seq';
|
|
7
|
+
export const DASH = 45;
|
|
8
|
+
export const SPACE = 32;
|
|
9
|
+
const LOWER_BIT = 0x20;
|
|
10
|
+
const CELL_STATES = ['match', 'mismatch', 'gap', 'insertion'];
|
|
11
|
+
export const MATCH = 0;
|
|
12
|
+
export const MISMATCH = 1;
|
|
13
|
+
const GAP = 2;
|
|
14
|
+
const INSERTION = 3;
|
|
15
|
+
export const NO_STATE = 255;
|
|
16
|
+
export function isGapByte(b) {
|
|
17
|
+
return b === DASH || b === SPACE;
|
|
18
|
+
}
|
|
19
|
+
// The columns carrying the row's own sequence: a gap run reaching either end
|
|
20
|
+
// of the row measures where the block was cut, not the alignment, so it is no
|
|
21
|
+
// cell either.
|
|
22
|
+
export function firstDrawn(bytes, at, len) {
|
|
23
|
+
let first = 0;
|
|
24
|
+
while (first < len && isGapByte(bytes[at + first])) {
|
|
25
|
+
first++;
|
|
26
|
+
}
|
|
27
|
+
return first;
|
|
28
|
+
}
|
|
29
|
+
export function lastDrawn(bytes, at, len, first) {
|
|
30
|
+
let last = len - 1;
|
|
31
|
+
while (last > first && isGapByte(bytes[at + last])) {
|
|
32
|
+
last--;
|
|
33
|
+
}
|
|
34
|
+
return last;
|
|
35
|
+
}
|
|
36
|
+
// A reference base's cell: no state outside the drawn columns, else the row's
|
|
37
|
+
// gap, or its base matched or not regardless of case.
|
|
38
|
+
export function cellState(refByte, rowByte, drawn) {
|
|
39
|
+
return !drawn
|
|
40
|
+
? NO_STATE
|
|
41
|
+
: isGapByte(rowByte)
|
|
42
|
+
? GAP
|
|
43
|
+
: (refByte | LOWER_BIT) === (rowByte | LOWER_BIT)
|
|
44
|
+
? MATCH
|
|
45
|
+
: MISMATCH;
|
|
46
|
+
}
|
|
47
|
+
// The row a cell step reads against: past any table that only reordered or
|
|
48
|
+
// annotated the rows, the one they were fanned out of.
|
|
49
|
+
function containerOf(table) {
|
|
50
|
+
let at = table;
|
|
51
|
+
let toBase;
|
|
52
|
+
while (at instanceof DerivedTable && !at.madeFrom) {
|
|
53
|
+
toBase = at.parentRow ? compose(toBase, at.parentRow) : toBase;
|
|
54
|
+
at = at.parent;
|
|
55
|
+
}
|
|
56
|
+
if (!(at instanceof DerivedTable)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
made: at,
|
|
61
|
+
toMade: toBase,
|
|
62
|
+
table: at.parent,
|
|
63
|
+
row: at.parentRow ? compose(toBase, at.parentRow) : toBase,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function compose(outer, inner) {
|
|
67
|
+
if (!outer) {
|
|
68
|
+
return inner;
|
|
69
|
+
}
|
|
70
|
+
const out = new Uint32Array(outer.length);
|
|
71
|
+
for (let i = 0; i < outer.length; i++) {
|
|
72
|
+
out[i] = inner[outer[i]];
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
// Below this length a character loop copies a string faster than
|
|
77
|
+
// `encodeInto`, as the MAF packer measured.
|
|
78
|
+
const ASCII_COPY_MAX_LENGTH = 64;
|
|
79
|
+
const encoder = new TextEncoder();
|
|
80
|
+
// A column's text as bytes, one per character: an adapter's own, or the
|
|
81
|
+
// strings a feature holds copied into one buffer.
|
|
82
|
+
function textOf(column, n) {
|
|
83
|
+
if (column.kind === 'text') {
|
|
84
|
+
return column;
|
|
85
|
+
}
|
|
86
|
+
const read = readerOf(column);
|
|
87
|
+
const texts = new Array(n);
|
|
88
|
+
let total = 0;
|
|
89
|
+
for (let i = 0; i < n; i++) {
|
|
90
|
+
const v = read(i);
|
|
91
|
+
if (typeof v === 'string') {
|
|
92
|
+
texts[i] = v;
|
|
93
|
+
total += v.length;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const bytes = new Uint8Array(total);
|
|
97
|
+
const offset = new Uint32Array(n);
|
|
98
|
+
const length = new Uint32Array(n);
|
|
99
|
+
let pos = 0;
|
|
100
|
+
for (let i = 0; i < n; i++) {
|
|
101
|
+
const text = texts[i];
|
|
102
|
+
if (text === undefined) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
offset[i] = pos;
|
|
106
|
+
if (text.length <= ASCII_COPY_MAX_LENGTH) {
|
|
107
|
+
for (let c = 0; c < text.length; c++) {
|
|
108
|
+
bytes[pos + c] = text.charCodeAt(c);
|
|
109
|
+
}
|
|
110
|
+
length[i] = text.length;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
length[i] = encoder.encodeInto(text, bytes.subarray(pos, pos + text.length)).written;
|
|
114
|
+
}
|
|
115
|
+
pos += text.length;
|
|
116
|
+
}
|
|
117
|
+
return { kind: 'text', bytes, offset, length, at: undefined };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The texts a `cells` walk reads, by the row of the table it walked: each
|
|
121
|
+
* row's own, and the reference it is read against, which a row fanned out of
|
|
122
|
+
* a container reads off the container.
|
|
123
|
+
*/
|
|
124
|
+
class WalkedTexts {
|
|
125
|
+
row;
|
|
126
|
+
reference;
|
|
127
|
+
refRow;
|
|
128
|
+
constructor(row, ref, refRow) {
|
|
129
|
+
this.row = row;
|
|
130
|
+
this.reference = ref;
|
|
131
|
+
this.refRow = refRow;
|
|
132
|
+
}
|
|
133
|
+
rowOf(r) {
|
|
134
|
+
const { at } = this.row;
|
|
135
|
+
return at ? at[r] : r;
|
|
136
|
+
}
|
|
137
|
+
refOf(r) {
|
|
138
|
+
const p = this.refRow ? this.refRow[r] : r;
|
|
139
|
+
const { at } = this.reference;
|
|
140
|
+
return at ? at[p] : p;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export function walkedTexts(table, field) {
|
|
144
|
+
const row = textOf(table.column(field), table.length);
|
|
145
|
+
const container = containerOf(table);
|
|
146
|
+
const made = container?.made;
|
|
147
|
+
if (container && !(made instanceof FannedTable && made.hasKept)) {
|
|
148
|
+
const { table: base } = container;
|
|
149
|
+
return new WalkedTexts(row, textOf(base.column(field), base.length), container.row);
|
|
150
|
+
}
|
|
151
|
+
// A container a flatten kept with nothing to fan out is the row itself, so
|
|
152
|
+
// its reference is its own container's, as its `parent()` says.
|
|
153
|
+
const byParent = (r) => table.row(r).parent?.()?.get(field);
|
|
154
|
+
const readContainer = container
|
|
155
|
+
? readerOf(container.table.column(field))
|
|
156
|
+
: undefined;
|
|
157
|
+
const read = readContainer && made instanceof FannedTable
|
|
158
|
+
? (r) => {
|
|
159
|
+
const { toMade, row: refRow } = container;
|
|
160
|
+
return made.isKept(toMade ? toMade[r] : r)
|
|
161
|
+
? byParent(r)
|
|
162
|
+
: readContainer(refRow ? refRow[r] : r);
|
|
163
|
+
}
|
|
164
|
+
: byParent;
|
|
165
|
+
return new WalkedTexts(row, textOf({ kind: 'value', read }, table.length));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The runs a `cells` step answers, one per stretch of one state against the
|
|
169
|
+
* reference, typed: each run's span, its state and the text column it starts
|
|
170
|
+
* at, with `base`, `match` and `length` read back out of the texts when asked
|
|
171
|
+
* for.
|
|
172
|
+
*/
|
|
173
|
+
class CellTable extends DerivedTable {
|
|
174
|
+
start;
|
|
175
|
+
end;
|
|
176
|
+
state;
|
|
177
|
+
textAt;
|
|
178
|
+
texts;
|
|
179
|
+
firstOfRow;
|
|
180
|
+
derived = new Map();
|
|
181
|
+
constructor(parent, parentRow, lanes, texts) {
|
|
182
|
+
super(parent, parentRow);
|
|
183
|
+
this.start = lanes.start;
|
|
184
|
+
this.end = lanes.end;
|
|
185
|
+
this.state = lanes.state;
|
|
186
|
+
this.textAt = lanes.textAt;
|
|
187
|
+
this.texts = texts;
|
|
188
|
+
}
|
|
189
|
+
get madeFrom() {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
laneOf(name, build) {
|
|
193
|
+
let column = this.derived.get(name);
|
|
194
|
+
if (!column) {
|
|
195
|
+
column = build();
|
|
196
|
+
this.derived.set(name, column);
|
|
197
|
+
}
|
|
198
|
+
return column;
|
|
199
|
+
}
|
|
200
|
+
own(name) {
|
|
201
|
+
switch (name) {
|
|
202
|
+
case 'start': {
|
|
203
|
+
return { kind: 'number', values: this.start, at: undefined };
|
|
204
|
+
}
|
|
205
|
+
case 'end': {
|
|
206
|
+
return { kind: 'number', values: this.end, at: undefined };
|
|
207
|
+
}
|
|
208
|
+
case 'state': {
|
|
209
|
+
return {
|
|
210
|
+
kind: 'category',
|
|
211
|
+
codes: this.state,
|
|
212
|
+
labels: CELL_STATES,
|
|
213
|
+
at: undefined,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
case 'match': {
|
|
217
|
+
return this.laneOf(name, () => {
|
|
218
|
+
const values = new Float32Array(this.length);
|
|
219
|
+
for (let i = 0; i < this.length; i++) {
|
|
220
|
+
const s = this.state[i];
|
|
221
|
+
values[i] = s === MATCH ? 1 : s === MISMATCH ? 0 : Number.NaN;
|
|
222
|
+
}
|
|
223
|
+
return { kind: 'number', values, at: undefined, nanIsAbsent: true };
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
case 'length': {
|
|
227
|
+
return this.laneOf(name, () => {
|
|
228
|
+
const values = new Float32Array(this.length).fill(Number.NaN);
|
|
229
|
+
for (let i = 0; i < this.length; i++) {
|
|
230
|
+
if (this.state[i] === INSERTION) {
|
|
231
|
+
values[i] = this.inserted(i).length;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return { kind: 'number', values, at: undefined, nanIsAbsent: true };
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
case 'base': {
|
|
238
|
+
return this.laneOf(name, () => {
|
|
239
|
+
const values = new Array(this.length);
|
|
240
|
+
for (let i = 0; i < this.length; i++) {
|
|
241
|
+
const s = this.state[i];
|
|
242
|
+
values[i] =
|
|
243
|
+
s === MISMATCH
|
|
244
|
+
? this.mismatched(i)
|
|
245
|
+
: s === INSERTION
|
|
246
|
+
? this.inserted(i)
|
|
247
|
+
: undefined;
|
|
248
|
+
}
|
|
249
|
+
return { kind: 'value', read: i => values[i] };
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
default: {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
mismatched(i) {
|
|
258
|
+
const { bytes, offset } = this.texts.row;
|
|
259
|
+
const k = this.texts.rowOf(this.parentOf(i));
|
|
260
|
+
return String.fromCharCode(bytes[offset[k] + this.textAt[i]]);
|
|
261
|
+
}
|
|
262
|
+
// The bases a row holds where the reference has none, from the column the
|
|
263
|
+
// insertion starts at to the reference's next base.
|
|
264
|
+
inserted(i) {
|
|
265
|
+
const { row, reference: ref } = this.texts;
|
|
266
|
+
const r = this.parentOf(i);
|
|
267
|
+
const k = this.texts.rowOf(r);
|
|
268
|
+
const f = this.texts.refOf(r);
|
|
269
|
+
const rowAt = row.offset[k];
|
|
270
|
+
const refAt = ref.offset[f];
|
|
271
|
+
const end = Math.min(row.length[k], ref.length[f]);
|
|
272
|
+
let out = '';
|
|
273
|
+
for (let col = this.textAt[i]; col < end && ref.bytes[refAt + col] === DASH; col++) {
|
|
274
|
+
const b = row.bytes[rowAt + col];
|
|
275
|
+
if (!isGapByte(b)) {
|
|
276
|
+
out += String.fromCharCode(b);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
id(i) {
|
|
282
|
+
const p = this.parentOf(i);
|
|
283
|
+
this.firstOfRow ??= firstRowIndex(this.parentRow, this.parent.length);
|
|
284
|
+
return `${this.parent.row(p).id()}#${i - this.firstOfRow[p]}`;
|
|
285
|
+
}
|
|
286
|
+
json(i) {
|
|
287
|
+
const out = {
|
|
288
|
+
...this.parent.row(this.parentOf(i)).toJSON(),
|
|
289
|
+
start: this.start[i],
|
|
290
|
+
end: this.end[i],
|
|
291
|
+
state: CELL_STATES[this.state[i]],
|
|
292
|
+
};
|
|
293
|
+
for (const name of ['base', 'match', 'length']) {
|
|
294
|
+
const v = valueAt(this.column(name), i);
|
|
295
|
+
if (v !== undefined) {
|
|
296
|
+
out[name] = v;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// The lanes a `cells` walk writes, doubled as a row would overrun them.
|
|
303
|
+
class RunLanes {
|
|
304
|
+
start;
|
|
305
|
+
end;
|
|
306
|
+
state;
|
|
307
|
+
textAt;
|
|
308
|
+
parentRow;
|
|
309
|
+
length = 0;
|
|
310
|
+
constructor(capacity) {
|
|
311
|
+
this.start = new Uint32Array(capacity);
|
|
312
|
+
this.end = new Uint32Array(capacity);
|
|
313
|
+
this.state = new Uint8Array(capacity);
|
|
314
|
+
this.textAt = new Uint32Array(capacity);
|
|
315
|
+
this.parentRow = new Uint32Array(capacity);
|
|
316
|
+
}
|
|
317
|
+
reserve(more) {
|
|
318
|
+
const need = this.length + more;
|
|
319
|
+
if (need <= this.start.length) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const size = Math.max(this.start.length * 2, need);
|
|
323
|
+
const widen = (a) => {
|
|
324
|
+
const next = new a.constructor(size);
|
|
325
|
+
next.set(a);
|
|
326
|
+
return next;
|
|
327
|
+
};
|
|
328
|
+
this.start = widen(this.start);
|
|
329
|
+
this.end = widen(this.end);
|
|
330
|
+
this.state = widen(this.state);
|
|
331
|
+
this.textAt = widen(this.textAt);
|
|
332
|
+
this.parentRow = widen(this.parentRow);
|
|
333
|
+
}
|
|
334
|
+
// One row's runs against its reference: a run per column is the most it
|
|
335
|
+
// can answer, so the lanes grow once and the walk writes through locals.
|
|
336
|
+
walk(r, startPos, rowBytes, rowAt, rowLen, refBytes, refAt, refLen) {
|
|
337
|
+
this.reserve(refLen + 1);
|
|
338
|
+
const { start, end, state, textAt, parentRow } = this;
|
|
339
|
+
let n = this.length;
|
|
340
|
+
let pos = startPos;
|
|
341
|
+
const first = firstDrawn(rowBytes, rowAt, rowLen);
|
|
342
|
+
const last = lastDrawn(rowBytes, rowAt, rowLen, first);
|
|
343
|
+
let runStart = -1;
|
|
344
|
+
let runState = NO_STATE;
|
|
345
|
+
let runBase = -1;
|
|
346
|
+
let runCol = 0;
|
|
347
|
+
let insertAt = -1;
|
|
348
|
+
for (let col = 0; col < refLen; col++) {
|
|
349
|
+
const refByte = refBytes[refAt + col];
|
|
350
|
+
const rowByte = col < rowLen ? rowBytes[rowAt + col] : SPACE;
|
|
351
|
+
if (refByte === DASH) {
|
|
352
|
+
if (insertAt < 0 && col < rowLen && !isGapByte(rowByte)) {
|
|
353
|
+
insertAt = col;
|
|
354
|
+
}
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (insertAt >= 0) {
|
|
358
|
+
start[n] = pos;
|
|
359
|
+
end[n] = pos;
|
|
360
|
+
state[n] = INSERTION;
|
|
361
|
+
textAt[n] = insertAt;
|
|
362
|
+
parentRow[n] = r;
|
|
363
|
+
n++;
|
|
364
|
+
insertAt = -1;
|
|
365
|
+
}
|
|
366
|
+
const st = cellState(refByte, rowByte, col >= first && col <= last && col < rowLen);
|
|
367
|
+
const base = st === MISMATCH ? rowByte : -1;
|
|
368
|
+
if (st !== runState || base !== runBase) {
|
|
369
|
+
if (runStart >= 0) {
|
|
370
|
+
start[n] = runStart;
|
|
371
|
+
end[n] = pos;
|
|
372
|
+
state[n] = runState;
|
|
373
|
+
textAt[n] = runCol;
|
|
374
|
+
parentRow[n] = r;
|
|
375
|
+
n++;
|
|
376
|
+
}
|
|
377
|
+
runStart = st === NO_STATE ? -1 : pos;
|
|
378
|
+
runState = st;
|
|
379
|
+
runBase = base;
|
|
380
|
+
runCol = col;
|
|
381
|
+
}
|
|
382
|
+
pos++;
|
|
383
|
+
}
|
|
384
|
+
if (runStart >= 0) {
|
|
385
|
+
start[n] = runStart;
|
|
386
|
+
end[n] = pos;
|
|
387
|
+
state[n] = runState;
|
|
388
|
+
textAt[n] = runCol;
|
|
389
|
+
parentRow[n] = r;
|
|
390
|
+
n++;
|
|
391
|
+
}
|
|
392
|
+
this.length = n;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// Where each parent row's children start, for children written parent by
|
|
396
|
+
// parent in order.
|
|
397
|
+
function firstRowIndex(parentRow, parents) {
|
|
398
|
+
const first = new Uint32Array(parents);
|
|
399
|
+
for (let i = parentRow.length - 1; i >= 0; i--) {
|
|
400
|
+
first[parentRow[i]] = i;
|
|
401
|
+
}
|
|
402
|
+
return first;
|
|
403
|
+
}
|
|
404
|
+
export function cells({ table, bounds }, step) {
|
|
405
|
+
const { field = DEFAULT_CELLS_FIELD } = step;
|
|
406
|
+
const texts = walkedTexts(table, field);
|
|
407
|
+
const readStart = numberReaderOf(table.column('start'));
|
|
408
|
+
const { bytes: rowBytes, offset: rowOffset, length: rowLength } = texts.row;
|
|
409
|
+
const { bytes: refBytes, offset: refOffset, length: refLength, } = texts.reference;
|
|
410
|
+
// A run per reference base is the most a row can answer and far past what
|
|
411
|
+
// one does, so the lanes start at an eighth of it.
|
|
412
|
+
let bound = 0;
|
|
413
|
+
for (let r = 0; r < table.length; r++) {
|
|
414
|
+
bound += refLength[texts.refOf(r)] + 1;
|
|
415
|
+
}
|
|
416
|
+
const lanes = new RunLanes(Math.max(1024, bound >>> 3));
|
|
417
|
+
for (let r = 0; r < table.length; r++) {
|
|
418
|
+
const f = texts.refOf(r);
|
|
419
|
+
const refLen = refLength[f];
|
|
420
|
+
const pos = readStart(r);
|
|
421
|
+
if (refLen > 0 && pos >= 0) {
|
|
422
|
+
const k = texts.rowOf(r);
|
|
423
|
+
lanes.walk(r, pos, rowBytes, rowOffset[k], rowLength[k], refBytes, refOffset[f], refLen);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const n = lanes.length;
|
|
427
|
+
const rows = lanes.parentRow.subarray(0, n);
|
|
428
|
+
return {
|
|
429
|
+
table: new CellTable(table, rows, {
|
|
430
|
+
start: lanes.start.subarray(0, n),
|
|
431
|
+
end: lanes.end.subarray(0, n),
|
|
432
|
+
state: lanes.state.subarray(0, n),
|
|
433
|
+
textAt: lanes.textAt.subarray(0, n),
|
|
434
|
+
}, texts),
|
|
435
|
+
bounds: boundsThrough(bounds, rows),
|
|
436
|
+
};
|
|
437
|
+
}
|
|
@@ -7,7 +7,14 @@ export default async function copyToClipboard(text, options = {}) {
|
|
|
7
7
|
// navigator.clipboard is only present in secure contexts; isSecureContext is
|
|
8
8
|
// the real gate, so insecure http:// falls through to execCommand below
|
|
9
9
|
if (format === 'text/plain' && window.isSecureContext) {
|
|
10
|
-
|
|
10
|
+
try {
|
|
11
|
+
await navigator.clipboard.writeText(text);
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
if (!execCommandCopy(text, format)) {
|
|
15
|
+
throw e;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
11
18
|
}
|
|
12
19
|
else if (!execCommandCopy(text, format)) {
|
|
13
20
|
throw new Error('the browser rejected the clipboard write');
|
|
@@ -81,9 +81,9 @@ export function createAbortRotation(self, report) {
|
|
|
81
81
|
// Opened before the superseded slot retires, so the window is never idle
|
|
82
82
|
// across the handover and the label on screen survives it (ADR-080).
|
|
83
83
|
// Retired here rather than left to the superseded run's `finally`, which
|
|
84
|
-
// comes only when its work settles — and a CRAM record read or a shared
|
|
85
|
-
// parse the
|
|
86
|
-
// reading summed into this fetch's bar the whole time.
|
|
84
|
+
// comes only when its work settles — and a CRAM record read, or a shared
|
|
85
|
+
// `cachedSetup` parse the replacement rejoins, runs on past the abort,
|
|
86
|
+
// its last reading summed into this fetch's bar the whole time.
|
|
87
87
|
const stream = statusWindow.open({ isCurrent });
|
|
88
88
|
openStream?.clear();
|
|
89
89
|
openStream = stream;
|
|
@@ -5,19 +5,20 @@ import type { Feature } from './simpleFeature.ts';
|
|
|
5
5
|
export { BIN_OVERLAP_FIELD, DEFAULT_BIN_AS } from './stepTables.ts';
|
|
6
6
|
export declare const DEFAULT_BIN_FIELD = "start";
|
|
7
7
|
export declare const DEFAULT_FLATTEN_FIELD = "subfeatures";
|
|
8
|
-
export
|
|
8
|
+
export { DEFAULT_CELLS_FIELD } from './cellsStep.ts';
|
|
9
9
|
export declare const DEFAULT_COVERAGE_AS = "coverage";
|
|
10
10
|
export declare const DEFAULT_PILEUP_AS = "row";
|
|
11
11
|
export declare const DEFAULT_PILEUP_FIELDS: [string, string];
|
|
12
12
|
/**
|
|
13
13
|
* #api
|
|
14
14
|
* How a record states its other end, or undefined where it states none: the
|
|
15
|
-
* `mate` a paired adapter fills (BEDPE, STAR-Fusion),
|
|
16
|
-
* and symbolic-SV readers resolve
|
|
17
|
-
* this names one for, so a caller
|
|
18
|
-
* track wants asks here rather than
|
|
15
|
+
* `mate` a paired adapter fills (BEDPE, STAR-Fusion), an `ALT` the breakend
|
|
16
|
+
* and symbolic-SV readers resolve, or a read's `next_ref` and `next_pos`. The
|
|
17
|
+
* `mate` step admits exactly the features this names one for, so a caller
|
|
18
|
+
* deciding whether links are the picture a track wants asks here rather than
|
|
19
|
+
* re-reading the fields.
|
|
19
20
|
*/
|
|
20
|
-
export declare function matedBy(f: Feature): "alt" | "mate" | undefined;
|
|
21
|
+
export declare function matedBy(f: Feature): "alt" | "mate" | "pair" | undefined;
|
|
21
22
|
/**
|
|
22
23
|
* #api
|
|
23
24
|
* One layer of a faceted request: its rows in section order, and the stacked
|