taxonium-component
Version:
React component for exploring large phylogenetic trees in the browser
419 lines (418 loc) • 16.1 kB
JavaScript
import { s as G, L as F, af as D, u as R, aq as $, bR as Q, ao as H, a as J } from "./JBrowsePanel-uJIA-L6s.js";
import { f as A } from "./color-CalL0laX.js";
import { g as K } from "./getMaximumModificationAtEachPosition-WpooMLNB.js";
function U(t) {
return t.get("is_paired") && t.get("refName") !== t.get("next_ref") ? "#555" : `hsl(${Math.abs(t.get("template_length")) / 10},50%,50%)`;
}
function V(t) {
return `hsl(${t.get("score")},50%,50%)`;
}
function Y(t, c) {
const r = G.readConfObject(c, "orientationType"), P = F[r][t.get("pair_orientation")];
return {
LR: "color_pair_lr",
RR: "color_pair_rr",
RL: "color_pair_rl",
LL: "color_pair_ll"
}[P];
}
function Z(t) {
return t.get("strand") === -1 ? "#8F8FD8" : "#EC8B8B";
}
function W(t, c) {
return A[Y(t, c) || "color_nostrand"];
}
function tt(t) {
const c = t.get("flags"), r = t.get("strand");
if (c & 1) {
const g = c & 64 ? -1 : 1;
return c & 2 ? r * g === 1 ? "color_rev_strand" : "color_fwd_strand" : c & 8 ? r * g === 1 ? "color_rev_missing_mate" : "color_fwd_missing_mate" : t.get("refName") === t.get("next_ref") ? r * g === 1 ? "color_rev_strand_not_proper" : "color_fwd_strand_not_proper" : r === 1 ? "color_fwd_diff_chr" : "color_rev_diff_chr";
}
return "color_unknown";
}
function et(t) {
return A[tt(t)];
}
function ot({ colorType: t, tag: c, feature: r, config: g, defaultColor: P, colorTagMap: s }) {
switch (t) {
case "insertSize":
return U(r);
case "strand":
return Z(r);
case "mappingQuality":
return V(r);
case "pairOrientation":
return W(r, g);
case "stranded":
return et(r);
case "xs":
case "tag": {
const n = r.get("tags"), h = n ? n[c] : r.get(c);
return c === "XS" || c === "TS" ? h === "-" ? A.color_rev_strand : h === "+" ? A.color_fwd_strand : A.color_nostrand : c === "ts" ? h === "-" ? r.get("strand") === -1 ? A.color_fwd_strand : A.color_rev_strand : h === "+" ? r.get("strand") === -1 ? A.color_rev_strand : A.color_fwd_strand : A.color_nostrand : s[h] || A.color_nostrand;
}
case "insertSizeAndPairOrientation":
break;
case "modifications":
case "methylation":
return r.get("flags") & 16 ? "#c8dcc8" : "#c8c8c8";
default:
return P ? "lightgrey" : G.readConfObject(g, "color", { feature: r });
}
}
function nt({ ctx: t, feat: c, renderArgs: r }) {
const { regions: g, bpPerPx: P } = r, { heightPx: s, topPx: n, feature: h } = c, u = g[0], S = h.get("start"), y = h.get("end"), m = h.get("CIGAR"), q = u.reversed ? -1 : 1, _ = h.get("strand") * q, b = P < 10 && s > 5;
if (m != null && m.includes("N")) {
const p = D(m);
if (_ === 1) {
let e = 0, o = S;
for (let i = 0; i < p.length; i += 2) {
const d = +p[i], l = p[i + 1];
if (l === "M" || l === "X" || l === "=" || l === "D")
e += d;
else if (l === "N") {
if (o !== e) {
const [f, w] = R.bpSpanPx(o, o + e, u, P), B = w - f;
t.fillRect(f, n, B, s);
}
o += e + d, e = 0;
}
}
if (o !== e) {
const [i, d] = R.bpSpanPx(o, o + e, u, P), l = d - i;
b ? (t.beginPath(), t.moveTo(i, n), t.lineTo(i, n + s), t.lineTo(d, n + s), t.lineTo(d + 5, n + s / 2), t.lineTo(d, n), t.closePath(), t.fill()) : t.fillRect(i, n, l, s);
}
} else if (_ === -1) {
let e = 0, o = y;
for (let i = p.length - 2; i >= 0; i -= 2) {
const d = +p[i], l = p[i + 1];
if (l === "M" || l === "X" || l === "=" || l === "D")
e += d;
else if (l === "N") {
if (e !== 0) {
const [f, w] = R.bpSpanPx(o - e, o, u, P);
t.fillRect(f, n, w - f, s);
}
o -= e + d, e = 0;
}
}
if (e !== 0) {
const [i, d] = R.bpSpanPx(o - e, o, u, P), l = d - i;
b ? (t.beginPath(), t.moveTo(i - 5, n + s / 2), t.lineTo(i, n + s), t.lineTo(d, n + s), t.lineTo(d, n), t.lineTo(i, n), t.closePath(), t.fill()) : t.fillRect(i, n, l, s);
}
}
} else {
const [p, e] = R.bpSpanPx(S, y, u, P);
P < 10 && s > 5 ? _ === -1 ? (t.beginPath(), t.moveTo(p - 5, n + s / 2), t.lineTo(p, n + s), t.lineTo(e, n + s), t.lineTo(e, n), t.lineTo(p, n), t.closePath(), t.fill()) : (t.beginPath(), t.moveTo(p, n), t.lineTo(p, n + s), t.lineTo(e, n + s), t.lineTo(e + 5, n + s / 2), t.lineTo(e, n), t.closePath(), t.fill()) : t.fillRect(p, n, e - p, s);
}
}
function x(t, c, r, g, P, s, n) {
c + g < 0 || c > s || (n && (t.fillStyle = n), t.fillRect(c, r, g, P));
}
function X(t) {
const { skip: c, deletion: r, insertion: g, hardclip: P, softclip: s, bases: n } = t.palette;
return {
A: n.A.main,
C: n.C.main,
G: n.G.main,
T: n.T.main,
deletion: r,
insertion: g,
hardclip: P,
softclip: s,
skip: c
};
}
function st(t) {
return Object.fromEntries(Object.entries(X(t)).map(([c, r]) => [
c,
t.palette.getContrastText(r)
]));
}
function it(t) {
return ["methylation", "modifications"].includes(t || "");
}
function rt() {
return !0;
}
function z() {
const t = R.measureText("A"), c = R.measureText("M") - 2;
return { charWidth: t, charHeight: c };
}
function lt({ ctx: t, feat: c, region: r, bpPerPx: g, renderArgs: P, canvasWidth: s, cigarOps: n }) {
var h, u, S;
const { feature: y, topPx: m, heightPx: q } = c, { colorBy: _, visibleModifications: b = {} } = P;
if (!y.get("seq"))
return;
const e = y.get("start"), o = (h = _ == null ? void 0 : _.modifications) === null || h === void 0 ? void 0 : h.isolatedModification, i = (u = _ == null ? void 0 : _.modifications) === null || u === void 0 ? void 0 : u.twoColor;
(S = K(y, n)) === null || S === void 0 || S.forEach(({ allProbs: d, prob: l, type: f }, w) => {
const B = e + w, [C, a] = R.bpSpanPx(B, B + 1, r, g), O = b[f];
if (!O) {
console.warn(`${f} not known yet`);
return;
}
if (o && O.type !== o)
return;
const v = O.color || "black", j = 1 - R.sum(d);
if (i && j > R.max(d)) {
const T = $("blue", j), k = a - C + 0.5;
x(t, C, m, k, q, s, T);
} else {
const T = $(v, l), k = a - C + 0.5;
x(t, C, m, k, q, s, T);
}
w++;
});
}
function ct({ ctx: t, feat: c, region: r, bpPerPx: g, colorMap: P, colorContrastMap: s, charWidth: n, charHeight: h, canvasWidth: u, cigarOps: S }) {
const y = h - 2, { feature: m, topPx: q, heightPx: _ } = c, b = m.get("seq"), p = 1 / g, e = m.get("start");
let o = 0, i = 0;
if (b)
for (let d = 0; d < S.length; d += 2) {
const l = +S[d], f = S[d + 1];
if (f === "S" || f === "I")
o += l;
else if (f === "D" || f === "N")
i += l;
else if (f === "M" || f === "X" || f === "=") {
for (let w = 0; w < l; w++) {
const B = b[o + w], C = e + i + w, [a] = R.bpSpanPx(C, C + 1, r, g), O = P[B];
x(t, a, q, p + 0.5, _, u, O), p >= n && _ >= y && (t.fillStyle = s[B], t.fillText(B, a + (p - n) / 2 + 1, q + _));
}
o += l, i += l;
}
}
}
function at({ ctx: t, feat: c, region: r, bpPerPx: g, canvasWidth: P, cigarOps: s }) {
const { feature: n, topPx: h, heightPx: u } = c, y = (n.get("qual") || "").split(" ").map((p) => +p), m = 1 / g, q = n.get("start");
let _ = 0, b = 0;
for (let p = 0; p < s.length; p += 2) {
const e = +s[p], o = s[p + 1];
if (o === "S" || o === "I")
_ += e;
else if (o === "D" || o === "N")
b += e;
else if (o === "M" || o === "X" || o === "=") {
for (let i = 0; i < e; i++) {
const d = y[_ + i], l = q + b + i, f = R.bpSpanPx(l, l + 1, r, g)[0], w = `hsl(${d === 255 ? 150 : d * 1.5},55%,50%)`;
x(t, f, h, m + 0.5, u, P, w);
}
_ += e, b += e;
}
}
}
function ft({ ctx: t, feat: c, region: r, bpPerPx: g, renderArgs: P, canvasWidth: s, cigarOps: n }) {
const { regionSequence: h } = P, { feature: u, topPx: S, heightPx: y } = c;
if (!h)
throw new Error("region sequence required for methylation");
if (!u.get("seq"))
return;
const q = u.get("start"), _ = u.get("end"), { methBins: b, methProbs: p, hydroxyMethBins: e, hydroxyMethProbs: o } = Q(u, n);
function i(l) {
if (b[l]) {
const f = p[l] || 0;
return (f > 0.5 ? H.colord("red").alpha((f - 0.5) * 2) : H.colord("blue").alpha(1 - f * 2)).toHslString();
}
if (e[l]) {
const f = o[l] || 0;
return (f > 0.5 ? H.colord("pink").alpha((f - 0.5) * 2) : H.colord("purple").alpha(1 - f * 2)).toHslString();
}
}
const d = h.toLowerCase();
for (let l = 0; l < _ - q; l++) {
const f = l + q, w = d[f - r.start + 1], B = d[f - r.start + 2];
if (w === "c" && B === "g")
if (g > 2) {
const [C, a] = R.bpSpanPx(f, f + 2, r, g), O = a - C + 0.5, v = i(l) || i(l + 1) || "blue";
x(t, C, S, O, y, s, v);
} else {
const [C, a] = R.bpSpanPx(f, f + 1, r, g), O = a - C + 0.5, v = i(l) || "blue";
x(t, C, S, O, y, s, v);
const [j, T] = R.bpSpanPx(f + 1, f + 2, r, g), k = T - j + 0.5, I = i(l + 1) || "blue";
x(t, j, S, k, y, s, I);
}
}
}
function pt({ ctx: t, feat: c, renderArgs: r, colorMap: g, colorContrastMap: P, charWidth: s, charHeight: n, defaultColor: h, canvasWidth: u }) {
const { config: S, bpPerPx: y, regions: m, colorBy: q, colorTagMap: _ = {} } = r, { tag: b = "", type: p = "" } = q || {}, { feature: e } = c, o = m[0];
switch (t.fillStyle = ot({
feature: e,
config: S,
tag: b,
defaultColor: h,
colorType: p,
colorTagMap: _
}), nt({ ctx: t, feat: c, renderArgs: r }), p) {
case "perBaseQuality": {
const i = D(e.get("CIGAR"));
at({
ctx: t,
feat: c,
region: o,
bpPerPx: y,
canvasWidth: u,
cigarOps: i
});
break;
}
case "perBaseLettering": {
const i = D(e.get("CIGAR"));
ct({
ctx: t,
feat: c,
region: o,
bpPerPx: y,
colorMap: g,
colorContrastMap: P,
charWidth: s,
charHeight: n,
canvasWidth: u,
cigarOps: i
});
break;
}
case "modifications": {
const i = D(e.get("CIGAR"));
lt({
ctx: t,
feat: c,
region: o,
bpPerPx: y,
renderArgs: r,
canvasWidth: u,
cigarOps: i
});
break;
}
case "methylation": {
const i = D(e.get("CIGAR"));
ft({
ctx: t,
feat: c,
region: o,
bpPerPx: y,
renderArgs: r,
canvasWidth: u,
cigarOps: i
});
break;
}
}
}
function gt({ ctx: t, feat: c, renderArgs: r, minSubfeatureWidth: g, largeInsertionIndicatorScale: P, mismatchAlpha: s, charWidth: n, charHeight: h, colorMap: u, colorContrastMap: S, hideSmallIndels: y, canvasWidth: m, drawSNPsMuted: q, drawIndels: _ = !0 }) {
const { bpPerPx: b, regions: p } = r, { heightPx: e, topPx: o, feature: i } = c, d = p[0], l = i.get("start"), f = Math.min(1 / b, 2), w = i.get("mismatches"), B = h - 2, C = d.reversed ? 1 / b + 1 : -1;
if (w) {
for (const a of w) {
const O = l + a.start, v = a.length, j = a.base, [T, k] = R.bpSpanPx(O, O + v, d, b), I = Math.max(g, k - T);
if (a.type === "mismatch") {
if (!q) {
const M = u[a.base] || "#888", E = s && a.qual !== void 0 ? H.colord(M).alpha(Math.min(1, a.qual / 50)).toHslString() : M;
x(t, Math.round(T), o, I, e, m, E);
}
if (I >= n && e >= B) {
const M = q ? "black" : S[a.base] || "black";
t.fillStyle = s && a.qual !== void 0 ? H.colord(M).alpha(Math.min(1, a.qual / 50)).toHslString() : M, t.fillText(j, T + (I - n) / 2 + 1, o + e);
}
} else if (a.type === "deletion" && _) {
const M = a.length;
if (!y || M >= 10) {
x(t, T, o, Math.abs(T - k), e, m, u.deletion);
const E = `${a.length}`, L = R.measureText(E, 10);
I >= L && e >= B && (t.fillStyle = S.deletion, t.fillText(E, (T + k) / 2 - L / 2, o + e));
}
} else if (a.type === "insertion" && _) {
const M = T + C, E = +a.base || a.length, L = Math.max(0, Math.min(1.2, 1 / b));
if (E < 10 && !y && (x(t, M, o, L, e, m, u.insertion), 1 / b >= n && e >= B)) {
const N = Math.round(M - L);
x(t, N, o, L * 3, 1, m), x(t, N, o + e - 1, L * 3, 1, m), t.fillText(`(${a.base})`, M + 3, o + e);
}
} else if (a.type === "hardclip" || a.type === "softclip") {
const M = T + C, E = u[a.type], L = Math.max(g, f);
if (x(t, M, o, L, e, m, E), 1 / b >= n && e >= B) {
const N = M - L;
x(t, N, o, L * 3, 1, m), x(t, N, o + e - 1, L * 3, 1, m), t.fillText(`(${a.base})`, M + 3, o + e);
}
} else if (a.type === "skip" && T + I > 0) {
const M = I - (b > 10 ? 1.5 : 0), E = Math.max(0, T), L = o + e / 2 - 1, N = M + Math.min(T, 0);
x(t, E, L, N, 1, m, u.skip);
}
}
if (_)
for (const a of w) {
const O = l + a.start, v = a.length, j = +a.base || a.length;
if (a.type === "insertion" && j >= 10) {
const [T] = R.bpSpanPx(O, O + v, d, b), k = `${j}`;
if (b > P)
x(t, T - 1, o, 2, e, m, u.insertion);
else if (e > h) {
const I = R.measureText(k), M = 5;
x(t, T - I / 2 - M, o, I + 2 * M, e, m, "purple"), t.fillStyle = S.insertion, t.fillText(k, T - I / 2, o + e);
} else
x(t, T - 2, o, 2 * 2, e, m, u.insertion);
}
}
}
}
function dt({ ctx: t, feat: c, renderArgs: r, config: g, theme: P, colorMap: s, canvasWidth: n }) {
const { feature: h, topPx: u, heightPx: S } = c, { regions: y, bpPerPx: m } = r, q = y[0], _ = G.readConfObject(g, "minSubfeatureWidth"), b = h.get("mismatches"), p = h.get("seq"), { charWidth: e, charHeight: o } = z();
if (!(p && b))
return;
const i = o - 2;
let d = 0, l = 0;
const f = h.get("CIGAR"), w = D(f);
for (let B = 0; B < w.length; B += 2) {
const C = w[B + 1], a = +w[B];
if (C === "S") {
for (let O = 0; O < a; O++) {
const v = p[d + O], j = h.get("start") - (B === 0 ? a : 0) + l + O, [T, k] = R.bpSpanPx(j, j + 1, q, m), I = Math.max(_, k - T), M = s[v] || "#000000";
t.fillStyle = M, x(t, T, u, I, S, n), I >= e && S >= i && (t.fillStyle = P.palette.getContrastText(M), t.fillText(v, T + (I - e) / 2 + 1, u + S));
}
d += a;
}
C === "N" && (l += a), (C === "M" || C === "=" || C === "X") && (l += a, d += a), C === "D" && (l += a), C === "I" && (d += a);
}
}
function bt({ ctx: t, layoutRecords: c, canvasWidth: r, renderArgs: g }) {
const { stopToken: P, config: s, showSoftClip: n, colorBy: h, theme: u } = g, S = G.readConfObject(s, "mismatchAlpha"), y = G.readConfObject(s, "minSubfeatureWidth"), m = G.readConfObject(s, "largeInsertionIndicatorScale"), q = G.readConfObject(s, "hideSmallIndels"), _ = G.readConfObject(s, "color") === "#f0f", b = J.createJBrowseTheme(u), p = X(b), e = st(b);
t.font = "bold 10px Courier New,monospace";
const { charWidth: o, charHeight: i } = z(), d = it(h == null ? void 0 : h.type), l = rt();
R.forEachWithStopTokenCheck(c, P, (f) => {
pt({
ctx: t,
feat: f,
renderArgs: g,
defaultColor: _,
colorMap: p,
colorContrastMap: e,
charWidth: o,
charHeight: i,
canvasWidth: r
}), gt({
ctx: t,
feat: f,
renderArgs: g,
hideSmallIndels: q,
mismatchAlpha: S,
drawSNPsMuted: d,
drawIndels: l,
largeInsertionIndicatorScale: m,
minSubfeatureWidth: y,
charWidth: o,
charHeight: i,
colorMap: p,
colorContrastMap: e,
canvasWidth: r
}), n && dt({
ctx: t,
feat: f,
renderArgs: g,
colorMap: p,
config: s,
theme: b,
canvasWidth: r
});
});
}
export {
bt as makeImageData
};
//# sourceMappingURL=makeImageData-CNjhGwdF.js.map