From 4b34fcdb2a0385f2f32bc9709af05c7d2e99cc5b Mon Sep 17 00:00:00 2001 From: s0lray Date: Thu, 26 Mar 2026 18:37:33 -0400 Subject: [PATCH] Zoom to fill viewport on mobile initial load (THE-119) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On screens ≤768px, pre-compute the bounding box of the collapsed tree layout and apply a zoom transform so the root + top-level categories fill the viewport immediately, instead of starting tiny in the center. Also adds a reusable zoomToFill() utility for future reset-view use. Co-Authored-By: Paperclip --- public/js/arf.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/public/js/arf.js b/public/js/arf.js index 4ad1503..d83ae7b 100644 --- a/public/js/arf.js +++ b/public/js/arf.js @@ -83,6 +83,31 @@ d3.json("arf.json").then(function(json) { } root.children.forEach(collapse); + + // On mobile, pre-compute zoom so the collapsed tree fills the viewport. + if (window.innerWidth <= 768) { + // Run tree layout to get final node positions, then compute zoom from data. + tree(root); + root.descendants().forEach(function(d) { d.y = d.depth * 180; }); + var visibleNodes = root.descendants(); + var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; + visibleNodes.forEach(function(d) { + if (d.x < minX) minX = d.x; + if (d.x > maxX) maxX = d.x; + if (d.y < minY) minY = d.y; + if (d.y > maxY) maxY = d.y; + }); + var pad = 60; + var bw = (maxY - minY) || 1; + var bh = (maxX - minX) || 1; + var k = Math.min((svgW - pad * 2) / bw, (svgH - pad * 2) / bh, 3); + var cx = (minY + maxY) / 2; + var cy = (minX + maxX) / 2; + var tx = svgW / 2 - margin[3] - cx * k; + var ty = svgH / 2 - margin[0] - cy * k; + svgEl.call(zoom.transform, d3.zoomIdentity.translate(tx, ty).scale(k)); + } + update(root); initSearch(); }); @@ -235,6 +260,19 @@ function toggle(d) { } } +// Zoom the tree so visible nodes fill the SVG viewport (used on mobile init). +function zoomToFill() { + var bbox = vis.node().getBBox(); + if (!bbox.width || !bbox.height) return; + var pad = 40; + var scaleX = (svgW - pad * 2) / bbox.width; + var scaleY = (svgH - pad * 2) / bbox.height; + var k = Math.min(scaleX, scaleY, 3); + var tx = svgW / 2 - (bbox.x + bbox.width / 2) * k - margin[3]; + var ty = svgH / 2 - (bbox.y + bbox.height / 2) * k - margin[0]; + svgEl.call(zoom.transform, d3.zoomIdentity.translate(tx, ty).scale(k)); +} + // Auto-pan viewport to center on a node after expand/click. function zoomToNode(d) { var currentK = d3.zoomTransform(svgEl.node()).k;