From 5cedb6d00367463d68031e1b8b80446dffdbed04 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 27 May 2026 20:27:13 +0300 Subject: showcase: dynamic SVG scaling fills browser window without letterboxing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the fixed viewBox+preserveAspectRatio approach with JS-driven rescale(). The SVG root now has no viewBox; instead rescale() runs on load and on every resize event: - Sets the SVG viewBox to the actual window dimensions. - Computes a uniform scale s = min(W/CHART_W, H/CHART_H) and a centering translate so the chart group fills the window edge-to-edge along the limiting axis with no empty bars. - All chart elements are wrapped in so a single transform attribute repositions everything together. The tooltip coordinate conversion switches from svgEl.getScreenCTM() to chartEl.getScreenCTM() so cursor positions are expressed in chart- local coordinates (CHART_W × CHART_H space) after the rescale transform. Similarly, tooltip boundary clamping uses the CHART_W/CHART_H constants instead of the now-dynamic svgEl.viewBox.baseVal. Co-Authored-By: Claude Sonnet 4.6 --- internal/showcase/rank_history_svg.go | 62 +++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/internal/showcase/rank_history_svg.go b/internal/showcase/rank_history_svg.go index b3f6c3a..3b299ba 100644 --- a/internal/showcase/rank_history_svg.go +++ b/internal/showcase/rank_history_svg.go @@ -309,11 +309,11 @@ func GenerateRankHistorySVG(summaries []ProjectSummary) string { // --- Assemble the full SVG --- var svg strings.Builder - // width/height="100%" makes the SVG fill the browser window while the - // viewBox preserves internal coordinate space and aspect ratio. - fmt.Fprintf(&svg, - ``, - svgViewWidth, svgViewHeight) + // width/height="100%" makes the SVG fill the browser window. No viewBox + // or preserveAspectRatio here — the JS rescale() function sets the viewBox + // to the window size and applies a translate+scale transform on #chart so + // the graph always fits the window without letterboxing. + svg.WriteString(``) // Embedded CSS – kept compact but readable. svg.WriteString(``) - // Solid background rect (belt-and-suspenders for SVG viewers that ignore - // the CSS background property). - fmt.Fprintf(&svg, ``, svgViewWidth, svgViewHeight) + // Solid background rect covers the whole viewport regardless of how the + // chart group is transformed. #chart is opened next so that rescale() + // can reposition all chart elements together as a single unit. + svg.WriteString(``) + svg.WriteString(``) // Title + subtitle. fmt.Fprintf(&svg, `Project Rank History`, svgViewWidth/2) @@ -368,20 +370,43 @@ svg{background:#1a1a2e;font-family:monospace} `) - // Inline JavaScript for interactivity. + // Close the #chart group before the script so all chart elements are + // contained inside it and can be repositioned together by rescale(). + svg.WriteString(``) + + // Inline JavaScript for interactivity and dynamic scaling. // PROJECTS is the JSON array; each entry has name, color, and points[]. + // CHART_W / CHART_H are the fixed viewBox coordinates used when designing + // the chart; rescale() maps them to the actual window size at runtime. fmt.Fprintf(&svg, ``, string(projectsJSON)) +]]>`, string(projectsJSON), svgViewWidth, svgViewHeight) svg.WriteString(``) return svg.String() -- cgit v1.2.3