taxonium-component
Version:
React component for exploring large phylogenetic trees in the browser
326 lines (325 loc) • 10.4 kB
JavaScript
import { B as _ } from "./bbi-HvSjvn8K.js";
import { A as T } from "./AbortablePromiseCache-CcuMrnn7.js";
import { Q as z } from "./index-BOYufR2k.js";
import { O as R } from "./Observable-D5EkXphs.js";
import { aV as H, a2 as D, a4 as $, a3 as P, u as k } from "./JBrowsePanel-uJIA-L6s.js";
import { a as j, m as L } from "./merge-BRfM1Dxk.js";
import { B as M, a as q } from "./util-X8nqr6IJ.js";
import { B as G } from "./index-BnQfM3Nw.js";
import { r as J } from "./rxjs-BnZkaVAs.js";
function Y(A) {
return A.filter((e) => !!e);
}
class X extends _ {
constructor() {
super(...arguments), this.readIndicesCache = new T({
cache: new z({ maxSize: 1 }),
fill: (e, t) => this._readIndices({ ...e, signal: t })
});
}
readIndices(e = {}) {
const { signal: t, ...a } = e;
return this.readIndicesCache.get(JSON.stringify(a), e, t);
}
/*
* retrieve unzoomed view for any scale
*/
async getView(e, t) {
return this.getUnzoomedView(t);
}
/*
* parse the bigbed extraIndex fields
*
*
* @return a Promise for an array of Index data structure since there can be
* multiple extraIndexes in a bigbed, see bedToBigBed documentation
*/
async _readIndices(e) {
const { extHeaderOffset: t } = await this.getHeader(e), a = await this.bbi.read(64, Number(t)), s = new DataView(a.buffer, a.byteOffset, a.length);
let i = 0;
i += 2;
const p = s.getUint16(i, !0);
i += 2;
const c = Number(s.getBigUint64(i, !0));
if (i += 8, p === 0)
return [];
const o = 20, g = o * p, N = await this.bbi.read(g, Number(c)), m = [];
for (let y = 0; y < p; y += 1) {
const l = N.subarray(y * o), w = new DataView(l.buffer, l.byteOffset, l.length);
let n = 0;
const f = w.getInt16(n, !0);
n += 2;
const d = w.getInt16(n, !0);
n += 2;
const h = Number(w.getBigUint64(n, !0));
n += 12;
const S = w.getInt16(n, !0);
m.push({ type: f, fieldcount: d, offset: Number(h), field: S });
}
return m;
}
/*
* perform a search in the bigbed extraIndex to find which blocks in the
* bigbed data to look for the actual feature data
*
* @param name - the name to search for
*
* @param opts - a SearchOptions argument with optional signal
*
* @return a Promise for an array of bigbed block Loc entries
*/
async searchExtraIndexBlocks(e, t = {}) {
const a = await this.readIndices(t);
if (a.length === 0)
return [];
const s = new TextDecoder("utf8"), i = a.map(async (p) => {
const { offset: c, field: o } = p, g = await this.bbi.read(32, c, t), N = new DataView(g.buffer, g.byteOffset, g.length);
let m = 0;
m += 4;
const y = N.getInt32(m, !0);
m += 4;
const l = N.getInt32(m, !0);
m += 4;
const w = N.getInt32(m, !0);
m += 4, m += 8;
const n = async (f) => {
const d = Number(f), h = 4 + y * (l + w), b = await this.bbi.read(h, d, t), u = new DataView(b.buffer, b.byteOffset, b.length);
let r = 0;
const E = u.getInt8(r);
r += 2;
const C = u.getInt16(r, !0);
r += 2;
const v = [];
if (E === 0) {
const I = [];
for (let x = 0; x < C; x++) {
const O = s.decode(b.subarray(r, r + l)).replaceAll("\0", "");
r += l;
const V = Number(u.getBigUint64(r, !0));
r += 8, I.push({
key: O,
offset: V
});
}
let B = 0;
for (const { key: x, offset: O } of I) {
if (e.localeCompare(x) < 0 && B)
return n(B);
B = O;
}
return n(B);
} else if (E === 1) {
for (let I = 0; I < C; I++) {
const B = s.decode(b.subarray(r, r + l)).replaceAll("\0", "");
r += l;
const x = Number(u.getBigUint64(r, !0));
r += 8;
const O = u.getUint32(r, !0);
r += 4;
const V = u.getUint32(r, !0);
r += 4, v.push({
key: B,
offset: x,
length: O,
reserved: V
});
}
for (const I of v)
if (I.key === e)
return {
...I,
field: o
};
return;
}
};
return n(c + 32);
});
return Y(await Promise.all(i));
}
/*
* retrieve the features from the bigbed data that were found through the
* lookup of the extraIndex note that there can be multiple extraIndex, see
* the BigBed specification and the -extraIndex argument to bedToBigBed
*
* @param name - the name to search for
*
* @param opts - options object with optional AboutSignal
*
* @return array of Feature
*/
async searchExtraIndex(e, t = {}) {
const a = await this.searchExtraIndexBlocks(e, t);
if (a.length === 0)
return [];
const s = await this.getUnzoomedView(t), i = a.map((c) => new R((o) => {
s.readFeatures(o, [c], t).catch((g) => {
o.error(g);
});
}).pipe(H((o, g) => o.concat(g)), j((o) => {
for (const g of o)
g.field = c.field;
return o;
})));
return (await D(L(...i))).filter((c) => {
var o;
return ((o = c.rest) == null ? void 0 : o.split(" ")[(c.field || 0) - 3]) === e;
});
}
}
class ce extends G.BaseFeatureDataAdapter {
async configurePre(e) {
const t = this.pluginManager, a = new X({
filehandle: $.openLocation(this.getConf("bigBedLocation"), t)
}), s = await a.getHeader(e), i = new M({
autoSql: s.autoSql
});
return {
bigbed: a,
header: s,
parser: i
};
}
async configure(e) {
return this.cachedP || (this.cachedP = this.configurePre(e).catch((t) => {
throw this.cachedP = void 0, t;
})), this.cachedP;
}
async getRefNames(e) {
const { header: t } = await this.configure(e);
return Object.keys(t.refsByName);
}
async getRefNameAliases(e) {
const { header: t } = await this.configure(e);
return (await Promise.all(Object.keys(t.refsByName).map(async (s) => (await D(this.getFeatures({
assemblyName: "",
refName: s,
start: 0,
end: 1
}).pipe(P())))[0]))).map((s) => s.toJSON()).map((s) => ({
refName: s.ucsc,
aliases: [s.ncbi, s.refseq, s.genbank],
override: !0
}));
}
async getData() {
const e = await this.getRefNames(), t = [];
for (const a of e) {
const s = await D(this.getFeatures({
assemblyName: "unknown",
refName: a,
start: 0,
end: Number.MAX_SAFE_INTEGER
}).pipe(P()));
t.push(s);
}
return t.flat();
}
async getHeader(e) {
const { parser: t, header: a } = await this.configure(e), { version: s, fileType: i } = a, { fields: p, ...c } = t.autoSql;
return {
version: s,
fileType: i,
autoSql: { ...c },
fields: await this.getMetadata(e)
};
}
async getMetadata(e) {
const { parser: t } = await this.configure(e), { fields: a } = t.autoSql;
return Object.fromEntries(a.map(({ name: s, comment: i }) => [s, i]));
}
async getFeaturesHelper({ query: e, opts: t, observer: a, allowRedispatch: s, originalQuery: i = e }) {
var p;
const { statusCallback: c = () => {
} } = t, o = this.getConf("scoreColumn"), g = this.getConf("aggregateField"), { parser: N, bigbed: m } = await k.updateStatus("Downloading header", c, () => this.configure(t)), y = await k.updateStatus("Downloading features", c, () => m.getFeatures(e.refName, e.start, e.end, {
basesPerSpan: e.end - e.start
})), l = {}, w = [];
if (y.some((n) => n.uniqueId === void 0))
throw new Error("found uniqueId undefined");
for (const n of y) {
const f = [
e.refName,
`${n.start}`,
`${n.end}`,
...((p = n.rest) === null || p === void 0 ? void 0 : p.split(" ")) || []
], d = N.parseLine(f, {
uniqueId: n.uniqueId
}), h = d[g], S = h && h !== "none";
S && !l[h] && (l[h] = []);
const { uniqueId: b, type: u, chrom: r, chromStart: E, chromEnd: C, description: v, chromStarts: I, blockStarts: B, blockSizes: x, score: O, blockCount: V, thickStart: K, thickEnd: Q, strand: W, ...U } = d, F = q({
...U,
scoreColumn: o,
splitLine: f,
parser: N,
uniqueId: b,
start: n.start,
end: n.end,
refName: e.refName
});
S ? (l[h].push(F), w.push(F)) : k.doesIntersect2(F.start, F.end, i.start, i.end) && a.next(new k.SimpleFeature({
id: `${this.id}-${b}`,
data: F
}));
}
if (s && w.length) {
let n = Number.POSITIVE_INFINITY, f = Number.NEGATIVE_INFINITY;
for (const d of w)
d.start < n && (n = d.start), d.end > f && (f = d.end);
if (f > e.end || n < e.start) {
await this.getFeaturesHelper({
query: {
...e,
start: n - 5e5,
end: f + 5e5
},
opts: t,
observer: a,
allowRedispatch: !1,
originalQuery: e
});
return;
}
}
Object.entries(l).map(([n, f]) => {
var d, h;
const S = k.min(f.map((u) => u.start)), b = k.max(f.map((u) => u.end));
if (k.doesIntersect2(S, b, i.start, i.end)) {
const u = f.sort((r, E) => r.uniqueId.localeCompare(E.uniqueId));
a.next(new k.SimpleFeature({
id: `${this.id}-${(d = u[0]) === null || d === void 0 ? void 0 : d.uniqueId}-parent`,
data: {
type: "gene",
subfeatures: u,
strand: ((h = u[0]) === null || h === void 0 ? void 0 : h.strand) || 1,
name: n,
start: S,
end: b,
refName: e.refName
}
}));
}
}), a.complete();
}
getFeatures(e, t = {}) {
return J.ObservableCreate(async (a) => {
try {
await this.getFeaturesHelper({
query: {
...e,
start: e.start,
end: e.end
},
opts: t,
observer: a,
allowRedispatch: !0
});
} catch (s) {
a.error(s);
}
}, t.stopToken);
}
}
export {
ce as default
};
//# sourceMappingURL=BigBedAdapter-LiCn2BXJ.js.map