UNPKG

taxonium-component

Version:

React component for exploring large phylogenetic trees in the browser

419 lines (418 loc) 16.1 kB
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