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-react.esm.js
CHANGED
|
@@ -5759,15 +5759,15 @@ class TwoBitFile {
|
|
|
5759
5759
|
*/
|
|
5760
5760
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
5761
5761
|
// Cache TwoBitFile instances by URL to reuse parsed headers and indices.
|
|
5762
|
-
const readerCache$
|
|
5762
|
+
const readerCache$5 = new Map();
|
|
5763
5763
|
// Parallel filehandle cache for direct batched reads (bypasses @gmod/twobit).
|
|
5764
5764
|
const filehandleCache = new Map();
|
|
5765
|
-
function getReader$
|
|
5766
|
-
let reader = readerCache$
|
|
5765
|
+
function getReader$4(url, fetchImpl) {
|
|
5766
|
+
let reader = readerCache$5.get(url);
|
|
5767
5767
|
if (!reader) {
|
|
5768
5768
|
const filehandle = getFilehandle(url, fetchImpl);
|
|
5769
5769
|
reader = new TwoBitFile({ filehandle });
|
|
5770
|
-
readerCache$
|
|
5770
|
+
readerCache$5.set(url, reader);
|
|
5771
5771
|
}
|
|
5772
5772
|
return reader;
|
|
5773
5773
|
}
|
|
@@ -5796,14 +5796,14 @@ function getFilehandle(url, fetchImpl) {
|
|
|
5796
5796
|
function createTwoBitSequenceProvider(url, fetchImpl) {
|
|
5797
5797
|
return async (locus) => {
|
|
5798
5798
|
var _a;
|
|
5799
|
-
const reader = getReader$
|
|
5799
|
+
const reader = getReader$4(url, fetchImpl);
|
|
5800
5800
|
try {
|
|
5801
5801
|
const sequence = await reader.getSequence(locus.chr, locus.start, locus.end);
|
|
5802
5802
|
return sequence !== null && sequence !== void 0 ? sequence : '';
|
|
5803
5803
|
}
|
|
5804
5804
|
catch (err) {
|
|
5805
5805
|
if (err instanceof Error && (err.name === 'AbortError' || ((_a = err.message) === null || _a === void 0 ? void 0 : _a.includes('aborted')))) {
|
|
5806
|
-
readerCache$
|
|
5806
|
+
readerCache$5.delete(url);
|
|
5807
5807
|
filehandleCache.delete(url);
|
|
5808
5808
|
}
|
|
5809
5809
|
throw err;
|
|
@@ -9703,10 +9703,10 @@ class BgzipIndexedFasta extends IndexedFasta {
|
|
|
9703
9703
|
*/
|
|
9704
9704
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
9705
9705
|
// Cache reader instances by URL to reuse parsed indices.
|
|
9706
|
-
const readerCache$
|
|
9707
|
-
function getReader$
|
|
9706
|
+
const readerCache$4 = new Map();
|
|
9707
|
+
function getReader$3(fastaURL, indexURL, compressedIndexURL, fetchImpl) {
|
|
9708
9708
|
const cacheKey = fastaURL;
|
|
9709
|
-
let reader = readerCache$
|
|
9709
|
+
let reader = readerCache$4.get(cacheKey);
|
|
9710
9710
|
if (!reader) {
|
|
9711
9711
|
const fileOpts = fetchImpl ? { fetch: fetchImpl } : undefined;
|
|
9712
9712
|
if (compressedIndexURL) {
|
|
@@ -9722,7 +9722,7 @@ function getReader$2(fastaURL, indexURL, compressedIndexURL, fetchImpl) {
|
|
|
9722
9722
|
fai: new RemoteFile(indexURL, fileOpts),
|
|
9723
9723
|
});
|
|
9724
9724
|
}
|
|
9725
|
-
readerCache$
|
|
9725
|
+
readerCache$4.set(cacheKey, reader);
|
|
9726
9726
|
}
|
|
9727
9727
|
return reader;
|
|
9728
9728
|
}
|
|
@@ -9742,14 +9742,14 @@ function createFastaSequenceProvider(fastaURL, indexURL, compressedIndexURL, fet
|
|
|
9742
9742
|
const faiURL = indexURL !== null && indexURL !== void 0 ? indexURL : fastaURL + '.fai';
|
|
9743
9743
|
return async (locus, signal) => {
|
|
9744
9744
|
var _a;
|
|
9745
|
-
const reader = getReader$
|
|
9745
|
+
const reader = getReader$3(fastaURL, faiURL, compressedIndexURL, fetchImpl);
|
|
9746
9746
|
try {
|
|
9747
9747
|
const sequence = await reader.getSequence(locus.chr, locus.start, locus.end, { signal });
|
|
9748
9748
|
return sequence !== null && sequence !== void 0 ? sequence : '';
|
|
9749
9749
|
}
|
|
9750
9750
|
catch (err) {
|
|
9751
9751
|
if (err instanceof Error && (err.name === 'AbortError' || ((_a = err.message) === null || _a === void 0 ? void 0 : _a.includes('aborted')))) {
|
|
9752
|
-
readerCache$
|
|
9752
|
+
readerCache$4.delete(fastaURL);
|
|
9753
9753
|
}
|
|
9754
9754
|
throw err;
|
|
9755
9755
|
}
|
|
@@ -10011,6 +10011,12 @@ const binaryFormats = new Set(['bigwig', 'bw', 'bigbed', 'bb', 'biginteract', 'b
|
|
|
10011
10011
|
function isBinaryFormat(format) {
|
|
10012
10012
|
return binaryFormats.has(format.toLowerCase());
|
|
10013
10013
|
}
|
|
10014
|
+
/** BigBed-specific formats (annotation data, not quantitative). */
|
|
10015
|
+
const bigBedFormats = new Set(['bigbed', 'bb', 'biginteract', 'biggenepred', 'bignarrowpeak']);
|
|
10016
|
+
/** Check if a format string represents a BigBed (annotation) format vs BigWig (quantitative). */
|
|
10017
|
+
function isBigBedFormat(format) {
|
|
10018
|
+
return bigBedFormats.has(format.toLowerCase());
|
|
10019
|
+
}
|
|
10014
10020
|
/**
|
|
10015
10021
|
* Check if a URL is likely tabix-indexed.
|
|
10016
10022
|
*
|
|
@@ -10050,7 +10056,7 @@ function inferIndexURL(url) {
|
|
|
10050
10056
|
* Layer 1 (Data): no DOM, no canvas.
|
|
10051
10057
|
*/
|
|
10052
10058
|
/** Known data source config types. */
|
|
10053
|
-
const KNOWN_DS_TYPES = new Set(['bigwig', 'gtx', 'ucsc', 'text', 'memory']);
|
|
10059
|
+
const KNOWN_DS_TYPES = new Set(['bigwig', 'bigbed', 'gtx', 'ucsc', 'text', 'memory']);
|
|
10054
10060
|
/** Check whether a data source config type is one of the known concrete types. */
|
|
10055
10061
|
function isKnownDataSourceType(type) {
|
|
10056
10062
|
return KNOWN_DS_TYPES.has(type);
|
|
@@ -10084,7 +10090,16 @@ function resolveDataSourceConfig(config) {
|
|
|
10084
10090
|
auth.headers = config.headers;
|
|
10085
10091
|
if (config.withCredentials)
|
|
10086
10092
|
auth.withCredentials = config.withCredentials;
|
|
10087
|
-
//
|
|
10093
|
+
// BigBed binary formats (annotation data)
|
|
10094
|
+
if (format && isBigBedFormat(format)) {
|
|
10095
|
+
log.warn(`Unknown data source type "${type}", inferred "bigbed" from URL: ${url}`);
|
|
10096
|
+
return {
|
|
10097
|
+
type: 'bigbed',
|
|
10098
|
+
url,
|
|
10099
|
+
...auth,
|
|
10100
|
+
};
|
|
10101
|
+
}
|
|
10102
|
+
// BigWig / other binary formats (quantitative data)
|
|
10088
10103
|
if (format && (format === 'bigwig' || format === 'bw' || isBinaryFormat(format))) {
|
|
10089
10104
|
log.warn(`Unknown data source type "${type}", inferred "bigwig" from URL: ${url}`);
|
|
10090
10105
|
return {
|
|
@@ -13384,14 +13399,14 @@ class BinaryParser {
|
|
|
13384
13399
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
13385
13400
|
// Cache BigWig instances by URL to reuse parsed headers and trees.
|
|
13386
13401
|
// Auth-aware readers share the cache key (URL) — the fetchImpl is bound at creation.
|
|
13387
|
-
const readerCache$
|
|
13402
|
+
const readerCache$3 = new Map();
|
|
13388
13403
|
function getGmodReader(url, fetchImpl) {
|
|
13389
13404
|
const resolvedUrl = normalizeGoogleURL(url);
|
|
13390
|
-
let reader = readerCache$
|
|
13405
|
+
let reader = readerCache$3.get(resolvedUrl);
|
|
13391
13406
|
if (!reader) {
|
|
13392
13407
|
const fileOpts = fetchImpl ? { fetch: fetchImpl } : undefined;
|
|
13393
13408
|
reader = new BigWig({ filehandle: new RemoteFile(resolvedUrl, fileOpts) });
|
|
13394
|
-
readerCache$
|
|
13409
|
+
readerCache$3.set(resolvedUrl, reader);
|
|
13395
13410
|
}
|
|
13396
13411
|
return reader;
|
|
13397
13412
|
}
|
|
@@ -13512,7 +13527,7 @@ async function fetchBigWigFeatures(url, locus, options = {}) {
|
|
|
13512
13527
|
// Evict the cached reader so the next fetch gets a fresh one.
|
|
13513
13528
|
// @gmod/bbi caches the header promise; an aborted parse poisons it permanently.
|
|
13514
13529
|
if (err instanceof Error && (err.name === 'AbortError' || ((_b = err.message) === null || _b === void 0 ? void 0 : _b.includes('aborted')))) {
|
|
13515
|
-
readerCache$
|
|
13530
|
+
readerCache$3.delete(url);
|
|
13516
13531
|
}
|
|
13517
13532
|
throw err;
|
|
13518
13533
|
}
|
|
@@ -13640,6 +13655,102 @@ class BigWigDataSource {
|
|
|
13640
13655
|
}
|
|
13641
13656
|
}
|
|
13642
13657
|
|
|
13658
|
+
/**
|
|
13659
|
+
* BigBed data source — fetches BED features from BigBed binary files.
|
|
13660
|
+
*
|
|
13661
|
+
* Uses @gmod/bbi's BigBed class for binary parsing and range queries.
|
|
13662
|
+
* Returns BedFeature[] suitable for annotation track rendering.
|
|
13663
|
+
*
|
|
13664
|
+
* Mirrors igv.js BWSource behavior for bigbed format:
|
|
13665
|
+
* - Features are decoded from BED rest fields via decodeBed()
|
|
13666
|
+
* - No zoom-level summarization (unlike BigWig)
|
|
13667
|
+
* - Feature density estimation from header dataCount
|
|
13668
|
+
*
|
|
13669
|
+
* Layer 1 (Data + Layout): no DOM.
|
|
13670
|
+
*/
|
|
13671
|
+
// Cache BigBed instances by URL to reuse parsed headers and index trees.
|
|
13672
|
+
const readerCache$2 = new Map();
|
|
13673
|
+
function getReader$2(url, fetchImpl) {
|
|
13674
|
+
const resolvedUrl = normalizeGoogleURL(url);
|
|
13675
|
+
let reader = readerCache$2.get(resolvedUrl);
|
|
13676
|
+
if (!reader) {
|
|
13677
|
+
const fileOpts = fetchImpl ? { fetch: fetchImpl } : undefined;
|
|
13678
|
+
reader = new BigBed({ filehandle: new RemoteFile(resolvedUrl, fileOpts) });
|
|
13679
|
+
readerCache$2.set(resolvedUrl, reader);
|
|
13680
|
+
}
|
|
13681
|
+
return reader;
|
|
13682
|
+
}
|
|
13683
|
+
class BigBedDataSource {
|
|
13684
|
+
constructor(url, fetchImpl) {
|
|
13685
|
+
this.url = url;
|
|
13686
|
+
this.fetchImpl = fetchImpl;
|
|
13687
|
+
this.bb = getReader$2(url, fetchImpl);
|
|
13688
|
+
}
|
|
13689
|
+
/** Set a chromosome name resolver for alias resolution (e.g., "1" → "chr1"). */
|
|
13690
|
+
setChromNameResolver(resolver) {
|
|
13691
|
+
this._resolveChromName = resolver;
|
|
13692
|
+
}
|
|
13693
|
+
async fetch(locus, _bpPerPixel, signal) {
|
|
13694
|
+
var _a;
|
|
13695
|
+
const chr = this._resolveChromName
|
|
13696
|
+
? this._resolveChromName(locus.chr)
|
|
13697
|
+
: locus.chr;
|
|
13698
|
+
try {
|
|
13699
|
+
const rawFeatures = await this.bb.getFeatures(chr, locus.start, locus.end, { signal });
|
|
13700
|
+
const result = [];
|
|
13701
|
+
for (const f of rawFeatures) {
|
|
13702
|
+
const parsed = parseBigBedFeature(chr, f.start, f.end, f.rest);
|
|
13703
|
+
if (parsed)
|
|
13704
|
+
result.push(parsed);
|
|
13705
|
+
}
|
|
13706
|
+
return result;
|
|
13707
|
+
}
|
|
13708
|
+
catch (err) {
|
|
13709
|
+
// Evict poisoned reader on abort (same pattern as BigWig)
|
|
13710
|
+
if (err instanceof Error && (err.name === 'AbortError' || ((_a = err.message) === null || _a === void 0 ? void 0 : _a.includes('aborted')))) {
|
|
13711
|
+
readerCache$2.delete(normalizeGoogleURL(this.url));
|
|
13712
|
+
}
|
|
13713
|
+
throw err;
|
|
13714
|
+
}
|
|
13715
|
+
}
|
|
13716
|
+
/**
|
|
13717
|
+
* Search for a feature by name via BigBed extra index.
|
|
13718
|
+
* Returns matching features, or empty array if not found or not indexed.
|
|
13719
|
+
*/
|
|
13720
|
+
async search(name) {
|
|
13721
|
+
const header = await this.bb.getHeader();
|
|
13722
|
+
const results = await this.bb.searchExtraIndex(name);
|
|
13723
|
+
if (results.length === 0)
|
|
13724
|
+
return [];
|
|
13725
|
+
const refsByNumber = header.refsByNumber;
|
|
13726
|
+
const features = [];
|
|
13727
|
+
for (const r of results) {
|
|
13728
|
+
const chromId = r.chromId;
|
|
13729
|
+
if (chromId == null || !(refsByNumber === null || refsByNumber === void 0 ? void 0 : refsByNumber[chromId]))
|
|
13730
|
+
continue;
|
|
13731
|
+
const chr = refsByNumber[chromId].name;
|
|
13732
|
+
const parsed = parseBigBedFeature(chr, r.start, r.end, r.rest);
|
|
13733
|
+
if (parsed)
|
|
13734
|
+
features.push(parsed);
|
|
13735
|
+
}
|
|
13736
|
+
return features;
|
|
13737
|
+
}
|
|
13738
|
+
dispose() {
|
|
13739
|
+
readerCache$2.delete(normalizeGoogleURL(this.url));
|
|
13740
|
+
}
|
|
13741
|
+
}
|
|
13742
|
+
/**
|
|
13743
|
+
* Parse a BigBed feature's rest field into a BedFeature.
|
|
13744
|
+
* Reconstructs BED tokens from chr/start/end + tab-delimited rest, then uses decodeBed().
|
|
13745
|
+
*/
|
|
13746
|
+
function parseBigBedFeature(chr, start, end, rest) {
|
|
13747
|
+
const tokens = [chr, String(start), String(end)];
|
|
13748
|
+
if (rest) {
|
|
13749
|
+
tokens.push(...rest.split('\t'));
|
|
13750
|
+
}
|
|
13751
|
+
return decodeBed(tokens);
|
|
13752
|
+
}
|
|
13753
|
+
|
|
13643
13754
|
/**
|
|
13644
13755
|
* HTTP range request reader using native fetch.
|
|
13645
13756
|
* Replaces igvxhr + BufferedReader for BigWig file reading.
|
|
@@ -20551,6 +20662,8 @@ function createDataSource(config) {
|
|
|
20551
20662
|
switch (config.type) {
|
|
20552
20663
|
case 'bigwig':
|
|
20553
20664
|
return new BigWigDataSource(config.url, config.windowFunction);
|
|
20665
|
+
case 'bigbed':
|
|
20666
|
+
return new BigBedDataSource(config.url);
|
|
20554
20667
|
case 'gtx':
|
|
20555
20668
|
return new GtxDataSource(config.url, config.experimentId, config.windowFunction);
|
|
20556
20669
|
case 'ucsc':
|
|
@@ -20832,6 +20945,11 @@ registerTypeAlias('broadpeak', 'annotation');
|
|
|
20832
20945
|
registerTypeAlias('genepred', 'annotation');
|
|
20833
20946
|
registerTypeAlias('genepredext', 'annotation');
|
|
20834
20947
|
registerTypeAlias('refflat', 'annotation');
|
|
20948
|
+
// BigBed format → annotation track type aliases
|
|
20949
|
+
registerTypeAlias('bigbed', 'annotation');
|
|
20950
|
+
registerTypeAlias('bedtype', 'annotation');
|
|
20951
|
+
registerTypeAlias('biggenepred', 'annotation');
|
|
20952
|
+
registerTypeAlias('bignarrowpeak', 'annotation');
|
|
20835
20953
|
// Merged/overlay aliases
|
|
20836
20954
|
registerTypeAlias('overlay', 'merged');
|
|
20837
20955
|
// Interaction format aliases
|
|
@@ -22670,6 +22788,9 @@ function wireDataSource(ds, ctx) {
|
|
|
22670
22788
|
if (ds instanceof BigWigDataSource || ds instanceof GtxDataSource) {
|
|
22671
22789
|
ds.setChromNameResolver(alias => ctx.genome.getChromosomeName(alias));
|
|
22672
22790
|
}
|
|
22791
|
+
else if (ds instanceof BigBedDataSource) {
|
|
22792
|
+
ds.setChromNameResolver(alias => ctx.genome.getChromosomeName(alias));
|
|
22793
|
+
}
|
|
22673
22794
|
else if (ds instanceof TextFeatureSource) {
|
|
22674
22795
|
ds.setChromNameResolver(alias => ctx.genome.getChromosomeName(alias));
|
|
22675
22796
|
if (ctx.cumulativeOffsets) {
|
|
@@ -22857,6 +22978,30 @@ function createBedTrack(ctx, url, options) {
|
|
|
22857
22978
|
searchableFields: options === null || options === void 0 ? void 0 : options.searchableFields,
|
|
22858
22979
|
};
|
|
22859
22980
|
}
|
|
22981
|
+
function createBigBedTrack(ctx, url, options) {
|
|
22982
|
+
var _a;
|
|
22983
|
+
const { canvas } = ctx.canvasProvider.createCanvas(0, 0);
|
|
22984
|
+
const track = new AnnotationTrackCanvas(canvas, {
|
|
22985
|
+
locus: ctx.locus,
|
|
22986
|
+
features: [],
|
|
22987
|
+
config: options === null || options === void 0 ? void 0 : options.config,
|
|
22988
|
+
theme: ctx.theme,
|
|
22989
|
+
canvasProvider: ctx.canvasProvider,
|
|
22990
|
+
name: options === null || options === void 0 ? void 0 : options.name,
|
|
22991
|
+
});
|
|
22992
|
+
const dataSourceConfig = { type: 'bigbed', url, ...options === null || options === void 0 ? void 0 : options.auth };
|
|
22993
|
+
const fetchImpl = resolveTrackFetchImpl(ctx, options);
|
|
22994
|
+
const { dataSource } = getOrCreateDataSource(dataSourceConfig, () => new BigBedDataSource(url, fetchImpl), ctx);
|
|
22995
|
+
return {
|
|
22996
|
+
track,
|
|
22997
|
+
dataSource,
|
|
22998
|
+
dataSourceConfig,
|
|
22999
|
+
maxTrackHeight: options === null || options === void 0 ? void 0 : options.maxTrackHeight,
|
|
23000
|
+
metadata: options === null || options === void 0 ? void 0 : options.metadata,
|
|
23001
|
+
searchable: (_a = options === null || options === void 0 ? void 0 : options.searchable) !== null && _a !== void 0 ? _a : true,
|
|
23002
|
+
searchableFields: options === null || options === void 0 ? void 0 : options.searchableFields,
|
|
23003
|
+
};
|
|
23004
|
+
}
|
|
22860
23005
|
function createInteractionTrack(ctx, url, options) {
|
|
22861
23006
|
var _a;
|
|
22862
23007
|
const { canvas } = ctx.canvasProvider.createCanvas(0, 0);
|
|
@@ -23206,10 +23351,10 @@ class HeadlessGenomeBrowser {
|
|
|
23206
23351
|
}
|
|
23207
23352
|
// ─── Track lifecycle ─────────────────────────────────────────────────────
|
|
23208
23353
|
/** Add a track with an optional data source for automatic data management. */
|
|
23209
|
-
addTrack(track, dataSource, dataSourceConfig, maxTrackHeight, order) {
|
|
23354
|
+
addTrack(track, dataSource, dataSourceConfig, maxTrackHeight, order, id) {
|
|
23210
23355
|
var _a;
|
|
23211
23356
|
this._snapshotForUndo('track-add');
|
|
23212
|
-
|
|
23357
|
+
id !== null && id !== void 0 ? id : (id = generateTrackId(track.type));
|
|
23213
23358
|
const mt = {
|
|
23214
23359
|
id,
|
|
23215
23360
|
track,
|
|
@@ -24086,11 +24231,9 @@ class HeadlessGenomeBrowser {
|
|
|
24086
24231
|
if (!this.dataSourceWorkerProvider && dataSource) {
|
|
24087
24232
|
wireDataSource(dataSource, ctx);
|
|
24088
24233
|
}
|
|
24089
|
-
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);
|
|
24234
|
+
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);
|
|
24090
24235
|
// Restore bookkeeping fields for round-trip serialization
|
|
24091
24236
|
const mt = this.findMT(created.track);
|
|
24092
|
-
if (trackConfig.id)
|
|
24093
|
-
mt.id = trackConfig.id;
|
|
24094
24237
|
if (created.name)
|
|
24095
24238
|
mt.name = created.name;
|
|
24096
24239
|
if (trackConfig.metadata)
|
|
@@ -24176,10 +24319,8 @@ class HeadlessGenomeBrowser {
|
|
|
24176
24319
|
wireDataSource(dataSource, ctx);
|
|
24177
24320
|
}
|
|
24178
24321
|
}
|
|
24179
|
-
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);
|
|
24322
|
+
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);
|
|
24180
24323
|
const mt = this.findMT(created.track);
|
|
24181
|
-
if (trackConfig.id)
|
|
24182
|
-
mt.id = trackConfig.id;
|
|
24183
24324
|
if (created.name)
|
|
24184
24325
|
mt.name = created.name;
|
|
24185
24326
|
if (trackConfig.metadata)
|
|
@@ -24238,6 +24379,10 @@ class HeadlessGenomeBrowser {
|
|
|
24238
24379
|
addBedTrack(url, options) {
|
|
24239
24380
|
return this.registerFactory(createBedTrack(this.factoryContext(), url, options));
|
|
24240
24381
|
}
|
|
24382
|
+
/** Add a BigBed annotation track from a URL. */
|
|
24383
|
+
addBigBedTrack(url, options) {
|
|
24384
|
+
return this.registerFactory(createBigBedTrack(this.factoryContext(), url, options));
|
|
24385
|
+
}
|
|
24241
24386
|
/** Add an interaction (arc/BEDPE) track from a URL. */
|
|
24242
24387
|
addInteractionTrack(url, options) {
|
|
24243
24388
|
return this.registerFactory(createInteractionTrack(this.factoryContext(), url, options));
|
|
@@ -28436,23 +28581,26 @@ const LoomBrowser = forwardRef(function LoomBrowser(props, ref) {
|
|
|
28436
28581
|
options.genome = genome;
|
|
28437
28582
|
const b = new GenomeBrowser(container, options);
|
|
28438
28583
|
browserRef.current = b;
|
|
28439
|
-
// Load session tracks if provided
|
|
28584
|
+
// Load session tracks if provided — a session is a complete state
|
|
28585
|
+
// snapshot, so skip default tracks to avoid duplicates.
|
|
28440
28586
|
if (session) {
|
|
28441
28587
|
b.loadSession(session);
|
|
28442
28588
|
}
|
|
28589
|
+
else {
|
|
28590
|
+
// Convenience default tracks (default: true)
|
|
28591
|
+
if (ruler !== false)
|
|
28592
|
+
b.addRuler();
|
|
28593
|
+
if (genes !== false)
|
|
28594
|
+
b.addGeneTrack();
|
|
28595
|
+
if (sequence !== false)
|
|
28596
|
+
b.addSequenceTrack();
|
|
28597
|
+
}
|
|
28443
28598
|
// Add config-driven tracks
|
|
28444
28599
|
if (trackConfigs) {
|
|
28445
28600
|
for (const tc of trackConfigs) {
|
|
28446
28601
|
b.addTrackFromConfig(tc);
|
|
28447
28602
|
}
|
|
28448
28603
|
}
|
|
28449
|
-
// Convenience default tracks (default: true)
|
|
28450
|
-
if (ruler !== false)
|
|
28451
|
-
b.addRuler();
|
|
28452
|
-
if (genes !== false)
|
|
28453
|
-
b.addGeneTrack();
|
|
28454
|
-
if (sequence !== false)
|
|
28455
|
-
b.addSequenceTrack();
|
|
28456
28604
|
// Forward locus changes to onLocusChange / onFrameChange (for controlled mode)
|
|
28457
28605
|
b.on(BrowserEvent.LocusChange, (event) => {
|
|
28458
28606
|
var _a, _b;
|