loom-browser 0.0.13 → 0.0.14
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/loom-react.esm.js +182 -34
- package/dist/loom-react.esm.min.js +1 -1
- package/dist/loom-react.esm.min.js.map +1 -1
- package/dist/loom-worker.min.js.map +1 -1
- package/dist/loom.esm.js +240 -61
- package/dist/loom.esm.min.js +1 -1
- package/dist/loom.esm.min.js.map +1 -1
- package/dist/loom.js +240 -60
- package/dist/loom.min.js +1 -1
- package/dist/loom.min.js.map +1 -1
- package/dist/tsconfig.src.tsbuildinfo +1 -1
- package/dist/types/browser/headless/headlessGenomeBrowser.d.ts +3 -1
- package/dist/types/browser/headless/trackFactories.d.ts +15 -0
- package/dist/types/dataSources/bigBedDataSource.d.ts +33 -0
- package/dist/types/dataSources/config.d.ts +5 -1
- package/dist/types/formats/formatDetection.d.ts +2 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/loom.js
CHANGED
|
@@ -3557,14 +3557,14 @@
|
|
|
3557
3557
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
3558
3558
|
// Cache BigWig instances by URL to reuse parsed headers and trees.
|
|
3559
3559
|
// Auth-aware readers share the cache key (URL) — the fetchImpl is bound at creation.
|
|
3560
|
-
const readerCache$
|
|
3560
|
+
const readerCache$5 = new Map();
|
|
3561
3561
|
function getGmodReader(url, fetchImpl) {
|
|
3562
3562
|
const resolvedUrl = normalizeGoogleURL(url);
|
|
3563
|
-
let reader = readerCache$
|
|
3563
|
+
let reader = readerCache$5.get(resolvedUrl);
|
|
3564
3564
|
if (!reader) {
|
|
3565
3565
|
const fileOpts = fetchImpl ? { fetch: fetchImpl } : undefined;
|
|
3566
3566
|
reader = new BigWig({ filehandle: new RemoteFile(resolvedUrl, fileOpts) });
|
|
3567
|
-
readerCache$
|
|
3567
|
+
readerCache$5.set(resolvedUrl, reader);
|
|
3568
3568
|
}
|
|
3569
3569
|
return reader;
|
|
3570
3570
|
}
|
|
@@ -3685,7 +3685,7 @@
|
|
|
3685
3685
|
// Evict the cached reader so the next fetch gets a fresh one.
|
|
3686
3686
|
// @gmod/bbi caches the header promise; an aborted parse poisons it permanently.
|
|
3687
3687
|
if (err instanceof Error && (err.name === 'AbortError' || ((_b = err.message) === null || _b === void 0 ? void 0 : _b.includes('aborted')))) {
|
|
3688
|
-
readerCache$
|
|
3688
|
+
readerCache$5.delete(url);
|
|
3689
3689
|
}
|
|
3690
3690
|
throw err;
|
|
3691
3691
|
}
|
|
@@ -3701,7 +3701,7 @@
|
|
|
3701
3701
|
}
|
|
3702
3702
|
/** Clear the BigWig reader cache (useful for testing or memory management). */
|
|
3703
3703
|
function clearBigWigCache() {
|
|
3704
|
-
readerCache$
|
|
3704
|
+
readerCache$5.clear();
|
|
3705
3705
|
}
|
|
3706
3706
|
|
|
3707
3707
|
/**
|
|
@@ -5046,12 +5046,12 @@
|
|
|
5046
5046
|
* Layer 1 (Data + Layout): no DOM, no canvas.
|
|
5047
5047
|
*/
|
|
5048
5048
|
// Cache readers by URL to reuse parsed headers, dictionaries, and indexes
|
|
5049
|
-
const readerCache$
|
|
5050
|
-
function getReader$
|
|
5051
|
-
let reader = readerCache$
|
|
5049
|
+
const readerCache$4 = new Map();
|
|
5050
|
+
function getReader$4(url, fetchImpl) {
|
|
5051
|
+
let reader = readerCache$4.get(url);
|
|
5052
5052
|
if (!reader) {
|
|
5053
5053
|
reader = new GtxReader(url, fetchImpl);
|
|
5054
|
-
readerCache$
|
|
5054
|
+
readerCache$4.set(url, reader);
|
|
5055
5055
|
}
|
|
5056
5056
|
return reader;
|
|
5057
5057
|
}
|
|
@@ -5060,7 +5060,7 @@
|
|
|
5060
5060
|
*/
|
|
5061
5061
|
async function fetchGtxFeatures(url, experimentId, locus, options = {}) {
|
|
5062
5062
|
var _a;
|
|
5063
|
-
const reader = getReader$
|
|
5063
|
+
const reader = getReader$4(url, options.fetchImpl);
|
|
5064
5064
|
await reader.init(options.signal);
|
|
5065
5065
|
const expIdx = reader.resolveExperimentIndex(experimentId);
|
|
5066
5066
|
if (expIdx === undefined) {
|
|
@@ -5074,7 +5074,7 @@
|
|
|
5074
5074
|
* Returns features with per-chromosome coordinates (caller transforms to genome-wide).
|
|
5075
5075
|
*/
|
|
5076
5076
|
async function fetchGtxWGFeatures(url, experimentId, chromNames, bpPerPixel, options = {}) {
|
|
5077
|
-
const reader = getReader$
|
|
5077
|
+
const reader = getReader$4(url, options.fetchImpl);
|
|
5078
5078
|
await reader.init(options.signal);
|
|
5079
5079
|
const expIdx = reader.resolveExperimentIndex(experimentId);
|
|
5080
5080
|
if (expIdx === undefined) {
|
|
@@ -5103,7 +5103,7 @@
|
|
|
5103
5103
|
*/
|
|
5104
5104
|
async function fetchGtxMultiFeatures(url, experimentIds, locus, options = {}) {
|
|
5105
5105
|
var _a;
|
|
5106
|
-
const reader = getReader$
|
|
5106
|
+
const reader = getReader$4(url, options.fetchImpl);
|
|
5107
5107
|
await reader.init(options.signal);
|
|
5108
5108
|
const idToIdx = new Map();
|
|
5109
5109
|
const indexes = [];
|
|
@@ -5125,10 +5125,10 @@
|
|
|
5125
5125
|
}
|
|
5126
5126
|
/** Clear the GTX reader cache (useful for testing or memory management). */
|
|
5127
5127
|
function clearGtxCache() {
|
|
5128
|
-
for (const reader of readerCache$
|
|
5128
|
+
for (const reader of readerCache$4.values()) {
|
|
5129
5129
|
reader.dispose();
|
|
5130
5130
|
}
|
|
5131
|
-
readerCache$
|
|
5131
|
+
readerCache$4.clear();
|
|
5132
5132
|
clearCoordinators();
|
|
5133
5133
|
}
|
|
5134
5134
|
|
|
@@ -5150,12 +5150,12 @@
|
|
|
5150
5150
|
* Layer 1 (Data + Layout): no DOM, no canvas.
|
|
5151
5151
|
*/
|
|
5152
5152
|
// Cache readers by URL (shared with gtx/index.ts reader cache)
|
|
5153
|
-
const readerCache$
|
|
5154
|
-
function getReader$
|
|
5155
|
-
let reader = readerCache$
|
|
5153
|
+
const readerCache$3 = new Map();
|
|
5154
|
+
function getReader$3(url, fetchImpl) {
|
|
5155
|
+
let reader = readerCache$3.get(url);
|
|
5156
5156
|
if (!reader) {
|
|
5157
5157
|
reader = new GtxReader(url, fetchImpl);
|
|
5158
|
-
readerCache$
|
|
5158
|
+
readerCache$3.set(url, reader);
|
|
5159
5159
|
}
|
|
5160
5160
|
return reader;
|
|
5161
5161
|
}
|
|
@@ -5165,7 +5165,7 @@
|
|
|
5165
5165
|
this.experimentId = experimentId;
|
|
5166
5166
|
this._windowFunction = windowFunction;
|
|
5167
5167
|
this.fetchImpl = fetchImpl;
|
|
5168
|
-
this.reader = getReader$
|
|
5168
|
+
this.reader = getReader$3(url, fetchImpl);
|
|
5169
5169
|
}
|
|
5170
5170
|
get windowFunction() { return this._windowFunction; }
|
|
5171
5171
|
/** Update the window function for future fetches. */
|
|
@@ -15399,6 +15399,12 @@
|
|
|
15399
15399
|
}
|
|
15400
15400
|
/** BigWig/BigBed format set — these use BWSource in igv.js. */
|
|
15401
15401
|
const bbFormats = new Set(['bigwig', 'bw', 'bigbed', 'bb', 'biginteract', 'biggenepred', 'bignarrowpeak']);
|
|
15402
|
+
/** BigBed-specific formats (annotation data, not quantitative). */
|
|
15403
|
+
const bigBedFormats = new Set(['bigbed', 'bb', 'biginteract', 'biggenepred', 'bignarrowpeak']);
|
|
15404
|
+
/** Check if a format string represents a BigBed (annotation) format vs BigWig (quantitative). */
|
|
15405
|
+
function isBigBedFormat(format) {
|
|
15406
|
+
return bigBedFormats.has(format.toLowerCase());
|
|
15407
|
+
}
|
|
15402
15408
|
/**
|
|
15403
15409
|
* Check if a URL is likely tabix-indexed.
|
|
15404
15410
|
*
|
|
@@ -22081,15 +22087,15 @@
|
|
|
22081
22087
|
*/
|
|
22082
22088
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
22083
22089
|
// Cache TwoBitFile instances by URL to reuse parsed headers and indices.
|
|
22084
|
-
const readerCache$
|
|
22090
|
+
const readerCache$2 = new Map();
|
|
22085
22091
|
// Parallel filehandle cache for direct batched reads (bypasses @gmod/twobit).
|
|
22086
22092
|
const filehandleCache = new Map();
|
|
22087
|
-
function getReader$
|
|
22088
|
-
let reader = readerCache$
|
|
22093
|
+
function getReader$2(url, fetchImpl) {
|
|
22094
|
+
let reader = readerCache$2.get(url);
|
|
22089
22095
|
if (!reader) {
|
|
22090
22096
|
const filehandle = getFilehandle(url, fetchImpl);
|
|
22091
22097
|
reader = new TwoBitFile({ filehandle });
|
|
22092
|
-
readerCache$
|
|
22098
|
+
readerCache$2.set(url, reader);
|
|
22093
22099
|
}
|
|
22094
22100
|
return reader;
|
|
22095
22101
|
}
|
|
@@ -22153,7 +22159,7 @@
|
|
|
22153
22159
|
* instead of 100K+.
|
|
22154
22160
|
*/
|
|
22155
22161
|
async function fetchChromSizesBatched(url, fetchImpl) {
|
|
22156
|
-
const reader = getReader$
|
|
22162
|
+
const reader = getReader$2(url, fetchImpl);
|
|
22157
22163
|
const fh = getFilehandle(url, fetchImpl);
|
|
22158
22164
|
// Step 1: get the index (name → file offset). Cached after first call.
|
|
22159
22165
|
const index = await reader.getIndex();
|
|
@@ -22221,14 +22227,14 @@
|
|
|
22221
22227
|
function createTwoBitSequenceProvider(url, fetchImpl) {
|
|
22222
22228
|
return async (locus) => {
|
|
22223
22229
|
var _a;
|
|
22224
|
-
const reader = getReader$
|
|
22230
|
+
const reader = getReader$2(url, fetchImpl);
|
|
22225
22231
|
try {
|
|
22226
22232
|
const sequence = await reader.getSequence(locus.chr, locus.start, locus.end);
|
|
22227
22233
|
return sequence !== null && sequence !== void 0 ? sequence : '';
|
|
22228
22234
|
}
|
|
22229
22235
|
catch (err) {
|
|
22230
22236
|
if (err instanceof Error && (err.name === 'AbortError' || ((_a = err.message) === null || _a === void 0 ? void 0 : _a.includes('aborted')))) {
|
|
22231
|
-
readerCache$
|
|
22237
|
+
readerCache$2.delete(url);
|
|
22232
22238
|
filehandleCache.delete(url);
|
|
22233
22239
|
}
|
|
22234
22240
|
throw err;
|
|
@@ -22256,12 +22262,12 @@
|
|
|
22256
22262
|
* individual sequence records.
|
|
22257
22263
|
*/
|
|
22258
22264
|
async function fetchTwoBitSequenceNames(url, fetchImpl) {
|
|
22259
|
-
const reader = getReader$
|
|
22265
|
+
const reader = getReader$2(url, fetchImpl);
|
|
22260
22266
|
return reader.getSequenceNames();
|
|
22261
22267
|
}
|
|
22262
22268
|
/** Clear the TwoBit reader cache (useful for testing or memory management). */
|
|
22263
22269
|
function clearTwoBitCache() {
|
|
22264
|
-
readerCache$
|
|
22270
|
+
readerCache$2.clear();
|
|
22265
22271
|
filehandleCache.clear();
|
|
22266
22272
|
}
|
|
22267
22273
|
|
|
@@ -22465,10 +22471,10 @@
|
|
|
22465
22471
|
*/
|
|
22466
22472
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
22467
22473
|
// Cache reader instances by URL to reuse parsed indices.
|
|
22468
|
-
const readerCache = new Map();
|
|
22469
|
-
function getReader(fastaURL, indexURL, compressedIndexURL, fetchImpl) {
|
|
22474
|
+
const readerCache$1 = new Map();
|
|
22475
|
+
function getReader$1(fastaURL, indexURL, compressedIndexURL, fetchImpl) {
|
|
22470
22476
|
const cacheKey = fastaURL;
|
|
22471
|
-
let reader = readerCache.get(cacheKey);
|
|
22477
|
+
let reader = readerCache$1.get(cacheKey);
|
|
22472
22478
|
if (!reader) {
|
|
22473
22479
|
const fileOpts = fetchImpl ? { fetch: fetchImpl } : undefined;
|
|
22474
22480
|
if (compressedIndexURL) {
|
|
@@ -22484,7 +22490,7 @@
|
|
|
22484
22490
|
fai: new RemoteFile(indexURL, fileOpts),
|
|
22485
22491
|
});
|
|
22486
22492
|
}
|
|
22487
|
-
readerCache.set(cacheKey, reader);
|
|
22493
|
+
readerCache$1.set(cacheKey, reader);
|
|
22488
22494
|
}
|
|
22489
22495
|
return reader;
|
|
22490
22496
|
}
|
|
@@ -22504,14 +22510,14 @@
|
|
|
22504
22510
|
const faiURL = indexURL !== null && indexURL !== void 0 ? indexURL : fastaURL + '.fai';
|
|
22505
22511
|
return async (locus, signal) => {
|
|
22506
22512
|
var _a;
|
|
22507
|
-
const reader = getReader(fastaURL, faiURL, compressedIndexURL, fetchImpl);
|
|
22513
|
+
const reader = getReader$1(fastaURL, faiURL, compressedIndexURL, fetchImpl);
|
|
22508
22514
|
try {
|
|
22509
22515
|
const sequence = await reader.getSequence(locus.chr, locus.start, locus.end, { signal });
|
|
22510
22516
|
return sequence !== null && sequence !== void 0 ? sequence : '';
|
|
22511
22517
|
}
|
|
22512
22518
|
catch (err) {
|
|
22513
22519
|
if (err instanceof Error && (err.name === 'AbortError' || ((_a = err.message) === null || _a === void 0 ? void 0 : _a.includes('aborted')))) {
|
|
22514
|
-
readerCache.delete(fastaURL);
|
|
22520
|
+
readerCache$1.delete(fastaURL);
|
|
22515
22521
|
}
|
|
22516
22522
|
throw err;
|
|
22517
22523
|
}
|
|
@@ -22525,7 +22531,7 @@
|
|
|
22525
22531
|
*/
|
|
22526
22532
|
async function fetchFastaChromSizes(fastaURL, indexURL, fetchImpl) {
|
|
22527
22533
|
const faiURL = indexURL !== null && indexURL !== void 0 ? indexURL : fastaURL + '.fai';
|
|
22528
|
-
const reader = getReader(fastaURL, faiURL, undefined, fetchImpl);
|
|
22534
|
+
const reader = getReader$1(fastaURL, faiURL, undefined, fetchImpl);
|
|
22529
22535
|
return reader.getSequenceSizes();
|
|
22530
22536
|
}
|
|
22531
22537
|
/**
|
|
@@ -22533,12 +22539,12 @@
|
|
|
22533
22539
|
*/
|
|
22534
22540
|
async function fetchFastaSequenceNames(fastaURL, indexURL, fetchImpl) {
|
|
22535
22541
|
const faiURL = indexURL !== null && indexURL !== void 0 ? indexURL : fastaURL + '.fai';
|
|
22536
|
-
const reader = getReader(fastaURL, faiURL, undefined, fetchImpl);
|
|
22542
|
+
const reader = getReader$1(fastaURL, faiURL, undefined, fetchImpl);
|
|
22537
22543
|
return reader.getSequenceNames();
|
|
22538
22544
|
}
|
|
22539
22545
|
/** Clear the FASTA reader cache (useful for testing or memory management). */
|
|
22540
22546
|
function clearFastaCache() {
|
|
22541
|
-
readerCache.clear();
|
|
22547
|
+
readerCache$1.clear();
|
|
22542
22548
|
}
|
|
22543
22549
|
|
|
22544
22550
|
/**
|
|
@@ -23062,7 +23068,7 @@
|
|
|
23062
23068
|
* Layer 1 (Data): no DOM, no canvas.
|
|
23063
23069
|
*/
|
|
23064
23070
|
/** Known data source config types. */
|
|
23065
|
-
const KNOWN_DS_TYPES = new Set(['bigwig', 'gtx', 'ucsc', 'text', 'memory']);
|
|
23071
|
+
const KNOWN_DS_TYPES = new Set(['bigwig', 'bigbed', 'gtx', 'ucsc', 'text', 'memory']);
|
|
23066
23072
|
/** Check whether a data source config type is one of the known concrete types. */
|
|
23067
23073
|
function isKnownDataSourceType(type) {
|
|
23068
23074
|
return KNOWN_DS_TYPES.has(type);
|
|
@@ -23096,7 +23102,16 @@
|
|
|
23096
23102
|
auth.headers = config.headers;
|
|
23097
23103
|
if (config.withCredentials)
|
|
23098
23104
|
auth.withCredentials = config.withCredentials;
|
|
23099
|
-
//
|
|
23105
|
+
// BigBed binary formats (annotation data)
|
|
23106
|
+
if (format && isBigBedFormat(format)) {
|
|
23107
|
+
log.warn(`Unknown data source type "${type}", inferred "bigbed" from URL: ${url}`);
|
|
23108
|
+
return {
|
|
23109
|
+
type: 'bigbed',
|
|
23110
|
+
url,
|
|
23111
|
+
...auth,
|
|
23112
|
+
};
|
|
23113
|
+
}
|
|
23114
|
+
// BigWig / other binary formats (quantitative data)
|
|
23100
23115
|
if (format && (format === 'bigwig' || format === 'bw' || isBinaryFormat(format))) {
|
|
23101
23116
|
log.warn(`Unknown data source type "${type}", inferred "bigwig" from URL: ${url}`);
|
|
23102
23117
|
return {
|
|
@@ -23534,6 +23549,106 @@
|
|
|
23534
23549
|
}
|
|
23535
23550
|
}
|
|
23536
23551
|
|
|
23552
|
+
/**
|
|
23553
|
+
* BigBed data source — fetches BED features from BigBed binary files.
|
|
23554
|
+
*
|
|
23555
|
+
* Uses @gmod/bbi's BigBed class for binary parsing and range queries.
|
|
23556
|
+
* Returns BedFeature[] suitable for annotation track rendering.
|
|
23557
|
+
*
|
|
23558
|
+
* Mirrors igv.js BWSource behavior for bigbed format:
|
|
23559
|
+
* - Features are decoded from BED rest fields via decodeBed()
|
|
23560
|
+
* - No zoom-level summarization (unlike BigWig)
|
|
23561
|
+
* - Feature density estimation from header dataCount
|
|
23562
|
+
*
|
|
23563
|
+
* Layer 1 (Data + Layout): no DOM.
|
|
23564
|
+
*/
|
|
23565
|
+
// Cache BigBed instances by URL to reuse parsed headers and index trees.
|
|
23566
|
+
const readerCache = new Map();
|
|
23567
|
+
function getReader(url, fetchImpl) {
|
|
23568
|
+
const resolvedUrl = normalizeGoogleURL(url);
|
|
23569
|
+
let reader = readerCache.get(resolvedUrl);
|
|
23570
|
+
if (!reader) {
|
|
23571
|
+
const fileOpts = fetchImpl ? { fetch: fetchImpl } : undefined;
|
|
23572
|
+
reader = new BigBed({ filehandle: new RemoteFile(resolvedUrl, fileOpts) });
|
|
23573
|
+
readerCache.set(resolvedUrl, reader);
|
|
23574
|
+
}
|
|
23575
|
+
return reader;
|
|
23576
|
+
}
|
|
23577
|
+
class BigBedDataSource {
|
|
23578
|
+
constructor(url, fetchImpl) {
|
|
23579
|
+
this.url = url;
|
|
23580
|
+
this.fetchImpl = fetchImpl;
|
|
23581
|
+
this.bb = getReader(url, fetchImpl);
|
|
23582
|
+
}
|
|
23583
|
+
/** Set a chromosome name resolver for alias resolution (e.g., "1" → "chr1"). */
|
|
23584
|
+
setChromNameResolver(resolver) {
|
|
23585
|
+
this._resolveChromName = resolver;
|
|
23586
|
+
}
|
|
23587
|
+
async fetch(locus, _bpPerPixel, signal) {
|
|
23588
|
+
var _a;
|
|
23589
|
+
const chr = this._resolveChromName
|
|
23590
|
+
? this._resolveChromName(locus.chr)
|
|
23591
|
+
: locus.chr;
|
|
23592
|
+
try {
|
|
23593
|
+
const rawFeatures = await this.bb.getFeatures(chr, locus.start, locus.end, { signal });
|
|
23594
|
+
const result = [];
|
|
23595
|
+
for (const f of rawFeatures) {
|
|
23596
|
+
const parsed = parseBigBedFeature(chr, f.start, f.end, f.rest);
|
|
23597
|
+
if (parsed)
|
|
23598
|
+
result.push(parsed);
|
|
23599
|
+
}
|
|
23600
|
+
return result;
|
|
23601
|
+
}
|
|
23602
|
+
catch (err) {
|
|
23603
|
+
// Evict poisoned reader on abort (same pattern as BigWig)
|
|
23604
|
+
if (err instanceof Error && (err.name === 'AbortError' || ((_a = err.message) === null || _a === void 0 ? void 0 : _a.includes('aborted')))) {
|
|
23605
|
+
readerCache.delete(normalizeGoogleURL(this.url));
|
|
23606
|
+
}
|
|
23607
|
+
throw err;
|
|
23608
|
+
}
|
|
23609
|
+
}
|
|
23610
|
+
/**
|
|
23611
|
+
* Search for a feature by name via BigBed extra index.
|
|
23612
|
+
* Returns matching features, or empty array if not found or not indexed.
|
|
23613
|
+
*/
|
|
23614
|
+
async search(name) {
|
|
23615
|
+
const header = await this.bb.getHeader();
|
|
23616
|
+
const results = await this.bb.searchExtraIndex(name);
|
|
23617
|
+
if (results.length === 0)
|
|
23618
|
+
return [];
|
|
23619
|
+
const refsByNumber = header.refsByNumber;
|
|
23620
|
+
const features = [];
|
|
23621
|
+
for (const r of results) {
|
|
23622
|
+
const chromId = r.chromId;
|
|
23623
|
+
if (chromId == null || !(refsByNumber === null || refsByNumber === void 0 ? void 0 : refsByNumber[chromId]))
|
|
23624
|
+
continue;
|
|
23625
|
+
const chr = refsByNumber[chromId].name;
|
|
23626
|
+
const parsed = parseBigBedFeature(chr, r.start, r.end, r.rest);
|
|
23627
|
+
if (parsed)
|
|
23628
|
+
features.push(parsed);
|
|
23629
|
+
}
|
|
23630
|
+
return features;
|
|
23631
|
+
}
|
|
23632
|
+
dispose() {
|
|
23633
|
+
readerCache.delete(normalizeGoogleURL(this.url));
|
|
23634
|
+
}
|
|
23635
|
+
}
|
|
23636
|
+
/**
|
|
23637
|
+
* Parse a BigBed feature's rest field into a BedFeature.
|
|
23638
|
+
* Reconstructs BED tokens from chr/start/end + tab-delimited rest, then uses decodeBed().
|
|
23639
|
+
*/
|
|
23640
|
+
function parseBigBedFeature(chr, start, end, rest) {
|
|
23641
|
+
const tokens = [chr, String(start), String(end)];
|
|
23642
|
+
if (rest) {
|
|
23643
|
+
tokens.push(...rest.split('\t'));
|
|
23644
|
+
}
|
|
23645
|
+
return decodeBed(tokens);
|
|
23646
|
+
}
|
|
23647
|
+
/** Clear the BigBed reader cache (useful for testing or memory management). */
|
|
23648
|
+
function clearBigBedCache() {
|
|
23649
|
+
readerCache.clear();
|
|
23650
|
+
}
|
|
23651
|
+
|
|
23537
23652
|
/**
|
|
23538
23653
|
* DataSource backed by an in-memory feature array.
|
|
23539
23654
|
*
|
|
@@ -26678,6 +26793,8 @@
|
|
|
26678
26793
|
switch (config.type) {
|
|
26679
26794
|
case 'bigwig':
|
|
26680
26795
|
return new BigWigDataSource(config.url, config.windowFunction);
|
|
26796
|
+
case 'bigbed':
|
|
26797
|
+
return new BigBedDataSource(config.url);
|
|
26681
26798
|
case 'gtx':
|
|
26682
26799
|
return new GtxDataSource(config.url, config.experimentId, config.windowFunction);
|
|
26683
26800
|
case 'ucsc':
|
|
@@ -26959,6 +27076,11 @@
|
|
|
26959
27076
|
registerTypeAlias('genepred', 'annotation');
|
|
26960
27077
|
registerTypeAlias('genepredext', 'annotation');
|
|
26961
27078
|
registerTypeAlias('refflat', 'annotation');
|
|
27079
|
+
// BigBed format → annotation track type aliases
|
|
27080
|
+
registerTypeAlias('bigbed', 'annotation');
|
|
27081
|
+
registerTypeAlias('bedtype', 'annotation');
|
|
27082
|
+
registerTypeAlias('biggenepred', 'annotation');
|
|
27083
|
+
registerTypeAlias('bignarrowpeak', 'annotation');
|
|
26962
27084
|
// Merged/overlay aliases
|
|
26963
27085
|
registerTypeAlias('overlay', 'merged');
|
|
26964
27086
|
// Interaction format aliases
|
|
@@ -27049,6 +27171,10 @@
|
|
|
27049
27171
|
'gtf': 'annotation',
|
|
27050
27172
|
'narrowpeak': 'annotation',
|
|
27051
27173
|
'broadpeak': 'annotation',
|
|
27174
|
+
'bigbed': 'annotation',
|
|
27175
|
+
'biggenepred': 'annotation',
|
|
27176
|
+
'bignarrowpeak': 'annotation',
|
|
27177
|
+
'biginteract': 'interact',
|
|
27052
27178
|
'sequence': 'sequence',
|
|
27053
27179
|
'interact': 'interact',
|
|
27054
27180
|
'bedpe': 'interact',
|
|
@@ -27166,23 +27292,35 @@
|
|
|
27166
27292
|
return result;
|
|
27167
27293
|
}
|
|
27168
27294
|
function convertIgvAnnotationTrack(igvTrack) {
|
|
27295
|
+
var _a, _b;
|
|
27169
27296
|
const result = { type: 'annotation' };
|
|
27170
27297
|
if (igvTrack.name)
|
|
27171
27298
|
result.name = igvTrack.name;
|
|
27172
27299
|
if (igvTrack.order != null)
|
|
27173
27300
|
result.order = igvTrack.order;
|
|
27174
|
-
// Data source — gene tracks in igv.js can come from
|
|
27301
|
+
// Data source — gene tracks in igv.js can come from BigBed, text files, or UCSC
|
|
27175
27302
|
if (igvTrack.url) {
|
|
27176
|
-
const
|
|
27177
|
-
|
|
27178
|
-
|
|
27179
|
-
|
|
27180
|
-
|
|
27181
|
-
|
|
27182
|
-
|
|
27183
|
-
|
|
27184
|
-
|
|
27185
|
-
|
|
27303
|
+
const format = (_b = (_a = igvTrack.format) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : '';
|
|
27304
|
+
if (isBigBedFormat(format) || /\.bb$/i.test(igvTrack.url) || /\.bigbed$/i.test(igvTrack.url)) {
|
|
27305
|
+
const ds = {
|
|
27306
|
+
type: 'bigbed',
|
|
27307
|
+
url: igvTrack.url,
|
|
27308
|
+
...extractAuthFromIgv(igvTrack),
|
|
27309
|
+
};
|
|
27310
|
+
result.dataSource = ds;
|
|
27311
|
+
}
|
|
27312
|
+
else {
|
|
27313
|
+
const ds = {
|
|
27314
|
+
type: 'text',
|
|
27315
|
+
url: igvTrack.url,
|
|
27316
|
+
...extractAuthFromIgv(igvTrack),
|
|
27317
|
+
};
|
|
27318
|
+
if (igvTrack.indexURL)
|
|
27319
|
+
ds.indexURL = igvTrack.indexURL;
|
|
27320
|
+
if (igvTrack.format)
|
|
27321
|
+
ds.format = igvTrack.format;
|
|
27322
|
+
result.dataSource = ds;
|
|
27323
|
+
}
|
|
27186
27324
|
}
|
|
27187
27325
|
// Config overrides
|
|
27188
27326
|
const config = {};
|
|
@@ -27278,13 +27416,23 @@
|
|
|
27278
27416
|
return igv;
|
|
27279
27417
|
}
|
|
27280
27418
|
function convertToIgvAnnotationTrack(track) {
|
|
27281
|
-
var _a;
|
|
27419
|
+
var _a, _b;
|
|
27282
27420
|
const igv = { type: 'annotation' };
|
|
27283
27421
|
if (track.name)
|
|
27284
27422
|
igv.name = track.name;
|
|
27285
27423
|
if (track.order != null)
|
|
27286
27424
|
igv.order = track.order;
|
|
27287
27425
|
if (((_a = track.dataSource) === null || _a === void 0 ? void 0 : _a.type) === 'text') {
|
|
27426
|
+
igv.url = track.dataSource.url;
|
|
27427
|
+
if (track.dataSource.format)
|
|
27428
|
+
igv.format = track.dataSource.format;
|
|
27429
|
+
if (track.dataSource.indexURL)
|
|
27430
|
+
igv.indexURL = track.dataSource.indexURL;
|
|
27431
|
+
Object.assign(igv, extractAuthForIgv(track.dataSource));
|
|
27432
|
+
}
|
|
27433
|
+
else if (((_b = track.dataSource) === null || _b === void 0 ? void 0 : _b.type) === 'bigbed') {
|
|
27434
|
+
igv.url = track.dataSource.url;
|
|
27435
|
+
igv.format = 'bigbed';
|
|
27288
27436
|
Object.assign(igv, extractAuthForIgv(track.dataSource));
|
|
27289
27437
|
}
|
|
27290
27438
|
if (track.config) {
|
|
@@ -28833,6 +28981,9 @@
|
|
|
28833
28981
|
if (ds instanceof BigWigDataSource || ds instanceof GtxDataSource) {
|
|
28834
28982
|
ds.setChromNameResolver(alias => ctx.genome.getChromosomeName(alias));
|
|
28835
28983
|
}
|
|
28984
|
+
else if (ds instanceof BigBedDataSource) {
|
|
28985
|
+
ds.setChromNameResolver(alias => ctx.genome.getChromosomeName(alias));
|
|
28986
|
+
}
|
|
28836
28987
|
else if (ds instanceof TextFeatureSource) {
|
|
28837
28988
|
ds.setChromNameResolver(alias => ctx.genome.getChromosomeName(alias));
|
|
28838
28989
|
if (ctx.cumulativeOffsets) {
|
|
@@ -29020,6 +29171,30 @@
|
|
|
29020
29171
|
searchableFields: options === null || options === void 0 ? void 0 : options.searchableFields,
|
|
29021
29172
|
};
|
|
29022
29173
|
}
|
|
29174
|
+
function createBigBedTrack(ctx, url, options) {
|
|
29175
|
+
var _a;
|
|
29176
|
+
const { canvas } = ctx.canvasProvider.createCanvas(0, 0);
|
|
29177
|
+
const track = new AnnotationTrackCanvas(canvas, {
|
|
29178
|
+
locus: ctx.locus,
|
|
29179
|
+
features: [],
|
|
29180
|
+
config: options === null || options === void 0 ? void 0 : options.config,
|
|
29181
|
+
theme: ctx.theme,
|
|
29182
|
+
canvasProvider: ctx.canvasProvider,
|
|
29183
|
+
name: options === null || options === void 0 ? void 0 : options.name,
|
|
29184
|
+
});
|
|
29185
|
+
const dataSourceConfig = { type: 'bigbed', url, ...options === null || options === void 0 ? void 0 : options.auth };
|
|
29186
|
+
const fetchImpl = resolveTrackFetchImpl(ctx, options);
|
|
29187
|
+
const { dataSource } = getOrCreateDataSource(dataSourceConfig, () => new BigBedDataSource(url, fetchImpl), ctx);
|
|
29188
|
+
return {
|
|
29189
|
+
track,
|
|
29190
|
+
dataSource,
|
|
29191
|
+
dataSourceConfig,
|
|
29192
|
+
maxTrackHeight: options === null || options === void 0 ? void 0 : options.maxTrackHeight,
|
|
29193
|
+
metadata: options === null || options === void 0 ? void 0 : options.metadata,
|
|
29194
|
+
searchable: (_a = options === null || options === void 0 ? void 0 : options.searchable) !== null && _a !== void 0 ? _a : true,
|
|
29195
|
+
searchableFields: options === null || options === void 0 ? void 0 : options.searchableFields,
|
|
29196
|
+
};
|
|
29197
|
+
}
|
|
29023
29198
|
function createInteractionTrack(ctx, url, options) {
|
|
29024
29199
|
var _a;
|
|
29025
29200
|
const { canvas } = ctx.canvasProvider.createCanvas(0, 0);
|
|
@@ -29369,10 +29544,10 @@
|
|
|
29369
29544
|
}
|
|
29370
29545
|
// ─── Track lifecycle ─────────────────────────────────────────────────────
|
|
29371
29546
|
/** Add a track with an optional data source for automatic data management. */
|
|
29372
|
-
addTrack(track, dataSource, dataSourceConfig, maxTrackHeight, order) {
|
|
29547
|
+
addTrack(track, dataSource, dataSourceConfig, maxTrackHeight, order, id) {
|
|
29373
29548
|
var _a;
|
|
29374
29549
|
this._snapshotForUndo('track-add');
|
|
29375
|
-
|
|
29550
|
+
id !== null && id !== void 0 ? id : (id = generateTrackId(track.type));
|
|
29376
29551
|
const mt = {
|
|
29377
29552
|
id,
|
|
29378
29553
|
track,
|
|
@@ -30251,11 +30426,9 @@
|
|
|
30251
30426
|
if (!this.dataSourceWorkerProvider && dataSource) {
|
|
30252
30427
|
wireDataSource(dataSource, ctx);
|
|
30253
30428
|
}
|
|
30254
|
-
this.addTrack(created.track, dataSource !== null && dataSource !== void 0 ? dataSource : undefined, (_a = created.dataSourceConfig) !== null && _a !== void 0 ? _a : undefined, undefined, (_b = created.order) !== null && _b !== void 0 ? _b : undefined);
|
|
30429
|
+
this.addTrack(created.track, dataSource !== null && dataSource !== void 0 ? dataSource : undefined, (_a = created.dataSourceConfig) !== null && _a !== void 0 ? _a : undefined, undefined, (_b = created.order) !== null && _b !== void 0 ? _b : undefined, trackConfig.id);
|
|
30255
30430
|
// Restore bookkeeping fields for round-trip serialization
|
|
30256
30431
|
const mt = this.findMT(created.track);
|
|
30257
|
-
if (trackConfig.id)
|
|
30258
|
-
mt.id = trackConfig.id;
|
|
30259
30432
|
if (created.name)
|
|
30260
30433
|
mt.name = created.name;
|
|
30261
30434
|
if (trackConfig.metadata)
|
|
@@ -30341,10 +30514,8 @@
|
|
|
30341
30514
|
wireDataSource(dataSource, ctx);
|
|
30342
30515
|
}
|
|
30343
30516
|
}
|
|
30344
|
-
this.addTrack(created.track, dataSource !== null && dataSource !== void 0 ? dataSource : undefined, dataSourceConfig !== null && dataSourceConfig !== void 0 ? dataSourceConfig : undefined, undefined, (_a = created.order) !== null && _a !== void 0 ? _a : undefined);
|
|
30517
|
+
this.addTrack(created.track, dataSource !== null && dataSource !== void 0 ? dataSource : undefined, dataSourceConfig !== null && dataSourceConfig !== void 0 ? dataSourceConfig : undefined, undefined, (_a = created.order) !== null && _a !== void 0 ? _a : undefined, trackConfig.id);
|
|
30345
30518
|
const mt = this.findMT(created.track);
|
|
30346
|
-
if (trackConfig.id)
|
|
30347
|
-
mt.id = trackConfig.id;
|
|
30348
30519
|
if (created.name)
|
|
30349
30520
|
mt.name = created.name;
|
|
30350
30521
|
if (trackConfig.metadata)
|
|
@@ -30403,6 +30574,10 @@
|
|
|
30403
30574
|
addBedTrack(url, options) {
|
|
30404
30575
|
return this.registerFactory(createBedTrack(this.factoryContext(), url, options));
|
|
30405
30576
|
}
|
|
30577
|
+
/** Add a BigBed annotation track from a URL. */
|
|
30578
|
+
addBigBedTrack(url, options) {
|
|
30579
|
+
return this.registerFactory(createBigBedTrack(this.factoryContext(), url, options));
|
|
30580
|
+
}
|
|
30406
30581
|
/** Add an interaction (arc/BEDPE) track from a URL. */
|
|
30407
30582
|
addInteractionTrack(url, options) {
|
|
30408
30583
|
return this.registerFactory(createInteractionTrack(this.factoryContext(), url, options));
|
|
@@ -35882,8 +36057,12 @@ tr.border-top td {
|
|
|
35882
36057
|
const windowFunction = (_d = config.windowFunction) !== null && _d !== void 0 ? _d : 'mean';
|
|
35883
36058
|
dataSource = new GtxDataSource(config.url, (_e = config.experimentId) !== null && _e !== void 0 ? _e : '', windowFunction);
|
|
35884
36059
|
}
|
|
36060
|
+
else if (isBigBedFormat(format)) {
|
|
36061
|
+
// BigBed → BigBedDataSource (annotation features)
|
|
36062
|
+
dataSource = new BigBedDataSource(config.url);
|
|
36063
|
+
}
|
|
35885
36064
|
else if (isBinaryFormat(format)) {
|
|
35886
|
-
// BigWig
|
|
36065
|
+
// BigWig → BigWigDataSource (quantitative features)
|
|
35887
36066
|
const windowFunction = (_f = config.windowFunction) !== null && _f !== void 0 ? _f : 'mean';
|
|
35888
36067
|
dataSource = new BigWigDataSource(config.url, windowFunction);
|
|
35889
36068
|
}
|
|
@@ -35906,6 +36085,7 @@ tr.border-top td {
|
|
|
35906
36085
|
exports.BaseCompositeTrack = BaseCompositeTrack;
|
|
35907
36086
|
exports.BaseTrackCanvas = BaseTrackCanvas;
|
|
35908
36087
|
exports.BigBedAnnotationSource = BigBedAnnotationSource;
|
|
36088
|
+
exports.BigBedDataSource = BigBedDataSource;
|
|
35909
36089
|
exports.BigWigDataSource = BigWigDataSource;
|
|
35910
36090
|
exports.BigWigReader = BigWigReader;
|
|
35911
36091
|
exports.BrowserEvent = BrowserEvent;
|