summaryrefslogtreecommitdiff
path: root/internal/flamegraph/livehtml.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-27 18:54:17 +0200
committerPaul Buetow <paul@buetow.org>2026-02-27 18:54:17 +0200
commit0887c715150fcf391191a924491737bd58b8af9c (patch)
tree26c82a02a8afc1a887e04e008333f927c2b7ca8c /internal/flamegraph/livehtml.go
parent5f23af510bd9031c515f2a3cc495bd996c795e69 (diff)
flamegraph: scale live view to viewport height
Diffstat (limited to 'internal/flamegraph/livehtml.go')
-rw-r--r--internal/flamegraph/livehtml.go64
1 files changed, 63 insertions, 1 deletions
diff --git a/internal/flamegraph/livehtml.go b/internal/flamegraph/livehtml.go
index 8ca74cd..2db5137 100644
--- a/internal/flamegraph/livehtml.go
+++ b/internal/flamegraph/livehtml.go
@@ -73,6 +73,7 @@ const liveHTML = `<!doctype html>
#flamegraph {
display: block;
width: 100%;
+ height: calc(100vh - 56px);
min-height: calc(100vh - 56px);
background: transparent;
}
@@ -120,6 +121,7 @@ const liveHTML = `<!doctype html>
var fg = {
paused: false,
resetting: false,
+ lastTreeData: null,
pendingData: null,
searchQuery: '',
zoomStack: [],
@@ -137,6 +139,7 @@ const liveHTML = `<!doctype html>
resetZoomBtn: document.getElementById('btn-reset-zoom'),
resetBaselineBtn: document.getElementById('btn-reset-baseline'),
cfg: {
+ baseFrameHeight: 16,
width: 1200,
frameHeight: 16,
fontSize: 12,
@@ -171,6 +174,46 @@ const liveHTML = `<!doctype html>
return maxDepth;
}
+ function fgDefaultCanvasHeight(maxDepth) {
+ return (fg.cfg.baseFrameHeight * (maxDepth + 1)) + 80;
+ }
+
+ function fgViewportLayout(maxDepth) {
+ var rows = Math.max(maxDepth + 1, 1);
+ var defaultCanvasHeight = fgDefaultCanvasHeight(maxDepth);
+ var viewportHeight = Number(window.innerHeight || 0);
+ if (viewportHeight <= 0) {
+ return {
+ frameHeight: fg.cfg.baseFrameHeight,
+ canvasHeight: defaultCanvasHeight
+ };
+ }
+
+ var controls = document.getElementById('controls');
+ var controlsHeight = 56;
+ if (controls && typeof controls.getBoundingClientRect === 'function') {
+ controlsHeight = Number(controls.getBoundingClientRect().height || controlsHeight);
+ }
+
+ var availableHeight = viewportHeight - controlsHeight;
+ if (availableHeight <= 0) {
+ return {
+ frameHeight: fg.cfg.baseFrameHeight,
+ canvasHeight: defaultCanvasHeight
+ };
+ }
+
+ var canvasHeight = Math.max(defaultCanvasHeight, availableHeight);
+ var frameHeight = (canvasHeight - 80) / rows;
+ if (frameHeight < fg.cfg.baseFrameHeight) {
+ frameHeight = fg.cfg.baseFrameHeight;
+ }
+ return {
+ frameHeight: frameHeight,
+ canvasHeight: canvasHeight
+ };
+ }
+
function fgBuildFrames(node, rootTotal, x, depth, canvasHeight, isRoot, out, path) {
if (!node || rootTotal <= 0) {
return;
@@ -522,6 +565,9 @@ const liveHTML = `<!doctype html>
function fgRender(treeData) {
if (!treeData || Number(treeData.t || 0) <= 0) {
+ var emptyLayout = fgViewportLayout(0);
+ fg.cfg.frameHeight = emptyLayout.frameHeight;
+ fg.svg.style.height = String(emptyLayout.canvasHeight) + 'px';
fg.frames = [];
fg.svg.innerHTML = '';
fgSetStatus('');
@@ -529,7 +575,9 @@ const liveHTML = `<!doctype html>
}
var rootTotal = Number(treeData.t || 0);
var maxDepth = fgMaxDepth(treeData, 0);
- var canvasHeight = (fg.cfg.frameHeight * (maxDepth + 1)) + 80;
+ var layout = fgViewportLayout(maxDepth);
+ fg.cfg.frameHeight = layout.frameHeight;
+ var canvasHeight = layout.canvasHeight;
var frames = [];
fgBuildFrames(treeData, rootTotal, 0, 0, canvasHeight, true, frames, '');
@@ -552,6 +600,7 @@ const liveHTML = `<!doctype html>
fg.svg.setAttribute('viewBox', '0 0 ' + fg.cfg.width + ' ' + canvasHeight);
fg.svg.setAttribute('preserveAspectRatio', 'xMinYMin meet');
+ fg.svg.style.height = String(canvasHeight) + 'px';
fg.svg.innerHTML = parts.join('');
fg.frames = Array.prototype.slice.call(fg.svg.querySelectorAll('g.frame'));
fg.rootWidth = fgDetectRootWidth();
@@ -569,6 +618,7 @@ const liveHTML = `<!doctype html>
fgSetStatus('parse error');
return;
}
+ fg.lastTreeData = treeData;
fgRender(treeData);
fgApplyZoom();
fgApplySearch();
@@ -590,6 +640,17 @@ const liveHTML = `<!doctype html>
};
}
+ function fgHandleResize() {
+ if (!fg.lastTreeData) {
+ return;
+ }
+ requestAnimationFrame(function () {
+ fgRender(fg.lastTreeData);
+ fgApplyZoom();
+ fgApplySearch();
+ });
+ }
+
function fgIsTextEntryTarget(target) {
if (!target) {
return false;
@@ -634,6 +695,7 @@ const liveHTML = `<!doctype html>
fg.resetZoomBtn.addEventListener('click', fgResetZoom);
fg.resetBaselineBtn.addEventListener('click', fgResetBaseline);
document.addEventListener('keydown', fgHandleKeydown);
+ window.addEventListener('resize', fgHandleResize);
fgSetStatus('');
fgConnect();