d3-flame-graph
Version:
A d3.js library to produce flame graphs.
434 lines (433 loc) • 16.1 kB
JavaScript
import { select as R } from "d3-selection";
import { format as nt } from "d3-format";
import { ascending as yt } from "d3-array";
import { partition as vt, hierarchy as wt } from "d3-hierarchy";
import { scaleLinear as rt } from "d3-scale";
import { easeCubic as xt } from "d3-ease";
import "d3-transition";
import "d3-dispatch";
import './d3-flamegraph.css';function bt(l) {
let o = 0, a = 0, u = 1;
const g = 10;
if (l) {
for (let s = 0; s < l.length && !(s > 6); s++)
o += u * (l.charCodeAt(s) % g), a += u * (g - 1), u *= 0.7;
a > 0 && (o = o / a);
}
return o;
}
function lt(l) {
let i = 0;
if (l) {
const o = l.split("`");
o.length > 1 && (l = o[o.length - 1]), l = l.split("(")[0], i = bt(l);
}
return i;
}
function Ht(l, i) {
let o, a, u;
return l === "red" ? (o = 200 + Math.round(55 * i), a = 50 + Math.round(80 * i), u = a) : l === "orange" ? (o = 190 + Math.round(65 * i), a = 90 + Math.round(65 * i), u = 0) : l === "yellow" ? (o = 175 + Math.round(55 * i), a = o, u = 50 + Math.round(20 * i)) : l === "green" ? (o = 50 + Math.round(60 * i), a = 200 + Math.round(55 * i), u = o) : l === "pastelgreen" ? (o = 163 + Math.round(75 * i), a = 195 + Math.round(49 * i), u = 72 + Math.round(149 * i)) : l === "blue" ? (o = 91 + Math.round(126 * i), a = 156 + Math.round(76 * i), u = 221 + Math.round(26 * i)) : l === "aqua" ? (o = 50 + Math.round(60 * i), a = 165 + Math.round(55 * i), u = a) : l === "cold" ? (o = 0 + Math.round(55 * (1 - i)), a = 0 + Math.round(230 * (1 - i)), u = 200 + Math.round(55 * i)) : (o = 200 + Math.round(55 * i), a = 0 + Math.round(230 * (1 - i)), u = 0 + Math.round(55 * (1 - i))), "rgb(" + o + "," + a + "," + u + ")";
}
function it(l) {
return l.data.name;
}
function Ct() {
var l = R("body"), i = null, o = it, a = it, u = !1;
function g() {
i = l.append("div").style("display", "none").style("position", "absolute").style("opacity", 0).style("pointer-events", "none").attr("class", "d3-flame-graph-tip");
}
return g.show = function(s, M) {
u ? i.html(o(M)) : i.text(a(M));
var y = i.node().offsetWidth, w = i.node().offsetHeight, x = s.pageX + 5, b = s.pageY + 5;
return x + y > window.innerWidth && (x = s.pageX - y - 5), x < 0 && (x = 5), b + w > window.innerHeight && (b = s.pageY - w - 5), b < 0 && (b = 5), i.style("display", "block").style("left", x + "px").style("top", b + "px").transition().duration(200).style("opacity", 1).style("pointer-events", "all"), g;
}, g.hide = function() {
return i.style("display", "none").transition().duration(200).style("opacity", 0).style("pointer-events", "none"), g;
}, g.text = function(s) {
return arguments.length ? (a = s, u = !1, g) : a;
}, g.html = function(s) {
return arguments.length ? (o = s, u = !0, g) : o;
}, g.destroy = function() {
i.remove();
}, g;
}
const Zt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
defaultFlamegraphTooltip: Ct
}, Symbol.toStringTag, { value: "Module" }));
function Dt(l, i, o) {
const a = o, u = 1 - a;
return [
Math.round(l[0] * a + i[0] * u),
Math.round(l[1] * a + i[1] * u),
Math.round(l[2] * a + i[2] * u)
];
}
function Et(l, i) {
if (l.highlight) return i;
const o = l.data.value, a = l.value;
return `rgb(${Dt([0, 255, 40], [196, 245, 233], o / a).join()})`;
}
function _t(l, i) {
if (l.highlight) return i;
const o = l.data.n || l.data.name, a = lt(o), u = 0 + Math.round(55 * (1 - a)), g = 0 + Math.round(230 * (1 - a)), s = 200 + Math.round(55 * a);
return "rgb(" + u + "," + g + "," + s + ")";
}
function kt(l, i) {
let o = i;
const { v8_jit: a, javascript: u, optimized: g } = l.data.extras || {};
if (a && !u && (o = "#dadada"), u) {
let s = (g || 0) / l.value, M = 255, y = 0, w = 0;
s < 0.4 ? (s = s * 2.5, M = 240 - s * 200) : s < 0.9 ? (s = (s - 0.4) * 2, M = 0, w = 200 - 200 * s, y = 100 * s) : (s = (s - 0.9) * 10, M = 0, w = 0, y = 100 + 150 * s), o = `rgb(${M} , ${y}, ${w})`;
}
return o;
}
function Ot(l, i) {
if (l.highlight) return i;
let o = 220, a = 220, u = 220;
const g = l.delta || l.data.d || l.data.delta, s = Math.abs(g);
let M = l.value || l.data.v || l.data.value;
M <= s && (M = s);
const y = s / M;
return g === M ? (o = 255, a = 190, u = 90) : g > 0 ? (u = Math.round(235 * (1 - y)), a = u) : g < 0 && (o = Math.round(235 * (1 - y)), a = o), "rgb(" + o + "," + a + "," + u + ")";
}
const Rt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
allocationColorMapper: Et,
differentialColorMapper: Ot,
nodeJsColorMapper: kt,
offCpuColorMapper: _t
}, Symbol.toStringTag, { value: "Module" }));
function Ft() {
let l = 960, i = null, o = 18, a = null, u = null, g = "", s = 750, M = xt, y = !1, w = !1, x = null, b = null, L = 0, D = null, j = null, F = !1, I = !1, X = !1, k = null, $ = !1, T = null, H = function(t) {
return t.data.n || t.data.name;
}, O = function(t) {
return "v" in t ? t.v : t.value;
}, W = function(t) {
return t.c || t.children;
}, q = function(t) {
return t.data.l || t.data.libtype;
}, J = function(t) {
return "d" in t.data ? t.data.d : t.data.delta;
}, V = function(t, r, n) {
j = () => {
D && (D.textContent = "search: " + r + " of " + n + " total samples ( " + nt(".3f")(100 * (r / n), 3) + "%)");
}, j();
};
const at = V;
let z = (t, r, n = !1) => {
if (!r)
return !1;
let f = H(t);
n && (r = r.toLowerCase(), f = f.toLowerCase());
const c = new RegExp(r);
return typeof f < "u" && f && f.match(c);
};
const ot = z;
let E = function(t) {
D && (t ? D.textContent = t : typeof j == "function" ? j() : D.textContent = "");
};
const ut = E;
let N = function(t) {
return H(t) + " (" + nt(".3f")(100 * (t.x1 - t.x0), 3) + "%, " + O(t) + " samples)";
}, Z = function(t) {
return t.highlight ? "#E600E6" : ft(H(t), q(t));
};
const P = Z;
function ft(t, r) {
let n = T || "warm";
!T && !(typeof r > "u" || r === "") && (n = "red", typeof t < "u" && t && t.match(/::/) && (n = "yellow"), r === "kernel" ? n = "orange" : r === "jit" ? n = "green" : r === "inlined" && (n = "aqua"));
const f = lt(t);
return Ht(n, f);
}
function G(t) {
t.data.fade = !1, t.data.hide = !1, t.children && t.children.forEach(G);
}
function st(t) {
let r = t, n = r.parent, f, c, d;
for (; n; ) {
for (f = n.children, c = f.length; c--; )
d = f[c], d !== r && (d.data.hide = !0);
r = n, n = r.parent;
}
}
function K(t) {
t.parent && (t.parent.data.fade = !0, K(t.parent));
}
function Y(t, r) {
if (u && u.hide(), st(t), G(t), K(t), S(), X) {
const n = r.parentNode.offsetTop, f = (window.innerHeight - n) / o, c = (t.height - f + 10) * o;
window.scrollTo({
top: n + c,
left: 0,
behavior: "smooth"
});
}
typeof x == "function" && x(t);
}
function ct(t, r) {
const n = [];
let f = 0;
function c(d, m) {
let p = !1;
z(d, r) ? (d.highlight = !0, p = !0, m || (f += O(d)), n.push(d)) : d.highlight = !1, d.children && d.children.forEach(function(C) {
c(C, m || p);
});
}
return c(t, !1), [n, f];
}
function Q(t, r) {
if (t.id === r)
return t;
{
const n = t.children;
if (n)
for (let f = 0; f < n.length; f++) {
const c = Q(n[f], r);
if (c)
return c;
}
}
}
function U(t) {
t.highlight = !1, t.children && t.children.forEach(function(r) {
U(r);
});
}
function ht(t, r) {
if (typeof y == "function")
return y(t, r);
if (y)
return yt(H(t), H(r));
}
const dt = vt();
function gt(t) {
let r = t.descendants();
if (L > 0) {
const n = l / (t.x1 - t.x0);
r = r.filter(function(f) {
return (f.x1 - f.x0) * n > L;
});
}
return r;
}
function S() {
a.each(function(t) {
const r = rt().range([0, l]), n = rt().range([0, o]);
y && t.sort(ht), et(t), dt(t);
const f = l / (t.x1 - t.x0);
function c(h) {
return (h.x1 - h.x0) * f;
}
const d = gt(t), m = R(this).select("svg");
m.attr("width", l);
let p = m.selectAll("g").data(d, function(h) {
return h.id;
});
if (!i || I) {
let h = 0;
for (let v = 0; v < d.length; ++v)
d[v].depth > h && (h = d[v].depth);
i = (h + 3) * o, i < k && (i = k), m.attr("height", i);
}
p.transition().duration(s).ease(M).attr("transform", function(h) {
return "translate(" + r(h.x0) + "," + (w ? n(h.depth) : i - n(h.depth) - o) + ")";
}), p.select("rect").transition().duration(s).ease(M).attr("width", c);
const C = p.enter().append("svg:g").attr("transform", function(h) {
return "translate(" + r(h.x0) + "," + (w ? n(h.depth) : i - n(h.depth) - o) + ")";
});
C.append("svg:rect").transition().delay(s / 2).attr("width", c), u || C.append("svg:title"), C.append("foreignObject").append("xhtml:div"), p = m.selectAll("g").data(d, function(h) {
return h.id;
}), p.attr("width", c).attr("height", function(h) {
return o;
}).attr("name", function(h) {
return H(h);
}).attr("class", function(h) {
return h.data.fade ? "frame fade" : "frame";
}), p.select("rect").attr("height", function(h) {
return o;
}).attr("fill", function(h) {
return Z(h);
}), u || p.select("title").text(N), p.select("foreignObject").attr("width", c).attr("height", function(h) {
return o;
}).style("pointer-events", "none").select("div").attr("class", "d3-flame-graph-label").style("display", function(h) {
return c(h) < 35 ? "none" : "block";
}).transition().delay(s).text(H), p.on("click", function(h, v) {
Y(v, this);
}), p.exit().remove(), p.on("mouseover", function(h, v) {
u && u.show(h, v), E(N(v)), typeof b == "function" && b(v);
}).on("mouseout", function() {
u && u.hide(), E(null);
});
});
}
function tt(t, r) {
r.forEach(function(n) {
const f = t.find(function(c) {
return c.name === n.name;
});
f ? (f.value += n.value, n.children && (f.children || (f.children = []), tt(f.children, n.children))) : t.push(n);
});
}
function pt(t, r) {
r(t);
let n = t.children;
if (n) {
const f = [n];
let c, d, m;
for (; f.length; )
for (n = f.pop(), c = n.length; c--; )
d = n[c], r(d), m = d.children, m && f.push(m);
}
}
function mt(t) {
let r = 0;
pt(t, function(n) {
n.id = r++;
});
}
function et(t) {
let r, n, f, c, d, m, p, C;
const h = [], v = [], A = [], Mt = !F;
let _ = t.data;
for (_.hide ? (t.value = 0, n = t.children, n && A.push(n)) : (t.value = _.fade ? 0 : O(_), h.push(t)); r = h.pop(); )
if (n = r.children, n && (d = n.length)) {
for (c = 0; d--; ) {
if (p = n[d], _ = p.data, _.hide) {
p.value = 0, f = p.children, f && A.push(f);
continue;
}
_.fade ? p.value = 0 : (C = O(_), p.value = C, c += C), h.push(p);
}
Mt && r.value && (r.value -= c), v.push(n);
}
for (d = v.length; d--; ) {
for (n = v[d], c = 0, m = n.length; m--; )
c += n[m].value;
n[0].parent.value += c;
}
for (; A.length; )
for (n = A.pop(), m = n.length; m--; )
p = n[m], p.value = 0, f = p.children, f && A.push(f);
}
function B() {
a.datum((t) => {
if (t.constructor.name !== "Node") {
const r = wt(t, W);
return mt(r), et(r), r.originalValue = r.value, $ && r.eachAfter((n) => {
let f = J(n);
const c = n.children;
let d = c && c.length;
for (; --d >= 0; ) f += c[d].delta;
n.delta = f;
}), r;
}
});
}
function e(t) {
if (!arguments.length)
return e;
a = t, B(), a.each(function(r) {
if (R(this).select("svg").size() === 0) {
const n = R(this).append("svg:svg").attr("width", l).attr("class", "partition d3-flame-graph");
i && (i < k && (i = k), n.attr("height", i)), n.append("svg:text").attr("class", "title").attr("text-anchor", "middle").attr("y", "25").attr("x", l / 2).attr("fill", "#808080").text(g), u && n.call(u);
}
}), S();
}
return e.height = function(t) {
return arguments.length ? (i = t, e) : i;
}, e.minHeight = function(t) {
return arguments.length ? (k = t, e) : k;
}, e.width = function(t) {
return arguments.length ? (l = t, e) : l;
}, e.cellHeight = function(t) {
return arguments.length ? (o = t, e) : o;
}, e.tooltip = function(t) {
return arguments.length ? (typeof t == "function" && (u = t), e) : u;
}, e.title = function(t) {
return arguments.length ? (g = t, e) : g;
}, e.transitionDuration = function(t) {
return arguments.length ? (s = t, e) : s;
}, e.transitionEase = function(t) {
return arguments.length ? (M = t, e) : M;
}, e.sort = function(t) {
return arguments.length ? (y = t, e) : y;
}, e.inverted = function(t) {
return arguments.length ? (w = t, e) : w;
}, e.computeDelta = function(t) {
return arguments.length ? ($ = t, e) : $;
}, e.setLabelHandler = function(t) {
return arguments.length ? (N = t, e) : N;
}, e.label = e.setLabelHandler, e.search = function(t) {
const r = [];
let n = 0, f = 0;
a.each(function(c) {
const d = ct(c, t);
r.push(...d[0]), n += d[1], f += c.originalValue;
}), V(r, n, f), S();
}, e.findById = function(t) {
if (typeof t > "u" || t === null)
return null;
let r = null;
return a.each(function(n) {
r === null && (r = Q(n, t));
}), r;
}, e.clear = function() {
E(null), a.each(function(t) {
U(t), S();
});
}, e.zoomTo = function(t) {
Y(t, a.node());
}, e.resetZoom = function() {
a.each(function(t) {
Y(t, a.node());
});
}, e.onClick = function(t) {
return arguments.length ? (x = t, e) : x;
}, e.onHover = function(t) {
return arguments.length ? (b = t, e) : b;
}, e.merge = function(t) {
return a && (this.resetZoom(), j = null, E(null), a.datum((r) => (tt([r.data], [t]), r.data)), B(), S()), e;
}, e.update = function(t) {
return a && (t && (a.datum(t), B()), S()), e;
}, e.destroy = function() {
return a && (u && (u.hide(), typeof u.destroy == "function" && u.destroy()), a.selectAll("svg").remove()), e;
}, e.setColorMapper = function(t) {
return arguments.length ? (Z = (r) => {
const n = P(r);
return t(r, n);
}, e) : (Z = P, e);
}, e.color = e.setColorMapper, e.setColorHue = function(t) {
return arguments.length ? (T = t, e) : (T = null, e);
}, e.minFrameSize = function(t) {
return arguments.length ? (L = t, e) : L;
}, e.setDetailsElement = function(t) {
return arguments.length ? (D = t, e) : D;
}, e.details = e.setDetailsElement, e.selfValue = function(t) {
return arguments.length ? (F = t, e) : F;
}, e.resetHeightOnZoom = function(t) {
return arguments.length ? (I = t, e) : I;
}, e.scrollOnZoom = function(t) {
return arguments.length ? (X = t, e) : X;
}, e.getName = function(t) {
return arguments.length ? (H = t, e) : H;
}, e.getValue = function(t) {
return arguments.length ? (O = t, e) : O;
}, e.getChildren = function(t) {
return arguments.length ? (W = t, e) : W;
}, e.getLibtype = function(t) {
return arguments.length ? (q = t, e) : q;
}, e.getDelta = function(t) {
return arguments.length ? (J = t, e) : J;
}, e.setSearchHandler = function(t) {
return arguments.length ? (V = t, e) : (V = at, e);
}, e.setDetailsHandler = function(t) {
return arguments.length ? (E = t, e) : (E = ut, e);
}, e.setSearchMatch = function(t) {
return arguments.length ? (z = t, e) : (z = ot, e);
}, e;
}
export {
Rt as colorMapper,
Ft as default,
Zt as tooltip
};