feat: adaptive zoom/pan engine for Mermaid diagrams#1
Conversation
Replace CSS zoom-based zoom/pan with vector-based SVG resizing engine that stays crisp at any zoom level and handles charts of all sizes. Key improvements: - Vector-based zoom: resizes SVG via viewBox + CSS width/height instead of CSS zoom or transform: scale(). Text stays sharp at 500%+. - Smart initial fit: contain mode for small charts, width-priority or height-priority for large charts that would be unreadably tiny. Readability floor (58%) prevents diagrams from rendering too small. - Adaptive container height: auto-sizes based on chart aspect ratio, clamped between 360px-960px. No more guessing min-height values. - Zoom toward cursor: Ctrl/Cmd+wheel zooms toward mouse position. - Pan constraining: diagram stays within visible bounds, can't be dragged offscreen. - Regular scroll pans: when diagram overflows, scroll wheel pans without requiring Ctrl/Cmd modifier. - Touch support: single-finger pan, two-finger pinch-to-zoom. - 1:1 button: view diagram at native rendered size. - Double-click to re-fit. - Preserves click-to-expand (open full-size in new tab). - ResizeObserver re-fits on container resize. Files changed: - templates/mermaid-flowchart.html: full rewrite of zoom/pan system - references/css-patterns.md: updated zoom controls documentation
📝 WalkthroughWalkthroughThis PR replaces the CSS zoom/scroll approach for Mermaid diagrams with an adaptive, vector-based zoom/pan engine. It introduces a new container structure, transform-based panning, smart-fit modes, and enhanced user interactions including Ctrl/Cmd+wheel zoom, touch gestures, drag-to-pan, and full-size diagram export. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Container as Diagram Container
participant Engine as Zoom/Pan Engine
participant SVG as SVG Viewport
participant Handlers as Input Handlers
User->>Container: Load diagram
Container->>Engine: Initialize with Mermaid SVG
Engine->>SVG: Extract natural dimensions
Engine->>Engine: Compute smart-fit mode
Engine->>SVG: Set viewBox & apply scaling
Engine->>Container: Render with initial fit
User->>Handlers: Ctrl/Cmd + Wheel (zoom)
Handlers->>Engine: Calculate zoom toward cursor
Engine->>SVG: Update viewBox & transform
Engine->>Container: Re-render
User->>Handlers: Drag mouse
Handlers->>Engine: Update pan offset
Engine->>SVG: Apply translate transform
Engine->>Container: Update position
User->>Handlers: Touch (two-finger pinch)
Handlers->>Engine: Compute zoom gesture
Engine->>SVG: Update viewBox
Engine->>Container: Re-render
User->>Handlers: Double-click or Fit button
Handlers->>Engine: Trigger smart-fit
Engine->>SVG: Reset to initial fit
Engine->>Container: Render fitted view
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
references/css-patterns.md (2)
794-810: Minor style inconsistency:varvsconst/let.The documented
openMermaidInNewTab()function usesvar(Lines 796-801) while the template implementation usesconst. Consider updating toconst/letfor consistency with modern JavaScript conventions.🧹 Suggested alignment with template
function openMermaidInNewTab() { - var svg = canvas.querySelector('svg'); + const svg = canvas.querySelector('svg'); if (!svg) return; - var clone = svg.cloneNode(true); + const clone = svg.cloneNode(true); clone.style.width = ''; clone.style.height = ''; - var styles = getComputedStyle(document.documentElement); - var bg = styles.getPropertyValue('--bg').trim() || '#ffffff'; - var html = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">' + + const bg = getComputedStyle(document.documentElement).getPropertyValue('--bg').trim() || '#ffffff'; + const html = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">' +🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@references/css-patterns.md` around lines 794 - 810, The function openMermaidInNewTab uses legacy var declarations; update the variable declarations (svg, clone, styles, bg, html) to appropriate const or let to match modern JS and the project's template conventions (use const for values that don't change and let for mutable ones) while preserving the existing logic inside openMermaidInNewTab.
548-624: Minor inconsistency between documented CSS and template implementation.The documentation uses generic variable names (e.g.,
--accent-dimat Line 624) while the template uses palette-specific names (--primary-dim). This is likely intentional for reusability, but thefont-sizevalues also differ slightly:
- Doc Line 550:
font-size: 0.74rem(~11.84px)- Template Line 155:
font-size: 12pxConsider aligning these for easier copy-paste usage, or add a note that templates may adapt variable names to their specific color palette.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@references/css-patterns.md` around lines 548 - 624, The docs show slightly different sizing and CSS variable names than the template: align .diagram-shell__hint font-size and the color variable used in .zoom-controls button; either change .diagram-shell__hint to match the template's 12px (or change the template to 0.74rem) and standardize the color variable (replace --accent-dim with the palette-specific --primary-dim or vice versa), or add a short note in the documentation near the .diagram-shell__hint and .zoom-controls rules explaining that templates may rename palette variables (e.g., --accent-dim → --primary-dim) and may adjust font-size slightly for visual parity to ease copy-paste usage.templates/mermaid-flowchart.html (1)
533-547: Consider revoking Blob URL after opening the new tab.The Blob URL created at Line 546 is not revoked. While the browser typically cleans these up when the document unloads, explicitly revoking prevents accumulation if users open many diagrams.
🧹 Suggested improvement
- window.open(URL.createObjectURL(new Blob([html], { type: 'text/html' })), '_blank'); + const url = URL.createObjectURL(new Blob([html], { type: 'text/html' })); + window.open(url, '_blank'); + setTimeout(() => URL.revokeObjectURL(url), 1000);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@templates/mermaid-flowchart.html` around lines 533 - 547, The function openMermaidInNewTab creates a Blob URL but never revokes it; update openMermaidInNewTab to store the result of URL.createObjectURL(...) in a variable, pass that variable to window.open, and then revoke it (e.g., via URL.revokeObjectURL(url) after a short delay or after the new window is created) so the Blob URL is cleaned up and doesn't accumulate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@references/css-patterns.md`:
- Around line 794-810: The function openMermaidInNewTab uses legacy var
declarations; update the variable declarations (svg, clone, styles, bg, html) to
appropriate const or let to match modern JS and the project's template
conventions (use const for values that don't change and let for mutable ones)
while preserving the existing logic inside openMermaidInNewTab.
- Around line 548-624: The docs show slightly different sizing and CSS variable
names than the template: align .diagram-shell__hint font-size and the color
variable used in .zoom-controls button; either change .diagram-shell__hint to
match the template's 12px (or change the template to 0.74rem) and standardize
the color variable (replace --accent-dim with the palette-specific --primary-dim
or vice versa), or add a short note in the documentation near the
.diagram-shell__hint and .zoom-controls rules explaining that templates may
rename palette variables (e.g., --accent-dim → --primary-dim) and may adjust
font-size slightly for visual parity to ease copy-paste usage.
In `@templates/mermaid-flowchart.html`:
- Around line 533-547: The function openMermaidInNewTab creates a Blob URL but
never revokes it; update openMermaidInNewTab to store the result of
URL.createObjectURL(...) in a variable, pass that variable to window.open, and
then revoke it (e.g., via URL.revokeObjectURL(url) after a short delay or after
the new window is created) so the Blob URL is cleaned up and doesn't accumulate.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 530807cc-fa5b-4b35-ac33-58b88067746c
📒 Files selected for processing (2)
references/css-patterns.mdtemplates/mermaid-flowchart.html
Replace CSS zoom-based zoom/pan with vector-based SVG resizing engine that stays crisp at any zoom level and handles charts of all sizes.
Key improvements:
Files changed:
Summary by CodeRabbit
Release Notes