Repository navigation
Conversation
The full-screen Mermaid viewer only stepped the diagram's width in percent inside a scrolling box: the wheel scrolled instead of zooming, a left press did nothing, and a zoom step could not be anchored to the part of the diagram being read. Lay the diagram out at its viewBox pixels and move the wrapper with translate+scale: the wheel zooms around the cursor, a left-drag pans with pointer capture, and the toolbar's reset fits the diagram to the width without enlarging it past its own size. Background-click-to-close now lives in pointerup (the press started on the viewport itself and moved under 3 px), because pointer capture makes every click land on the viewport and a pan ending on empty space would otherwise dismiss the diagram. Opening the modal moved into the layout effect that measures it: a closed <dialog> has no layout box, so fitting beforehand read zeros and a useEffect open painted one unfitted frame.
escapeWu
force-pushed
the
feat/mermaid-viewer-pan-zoom
branch
from
October 22, 2026 07:45
208c1c3 to
b8c12ed
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The full-screen Mermaid viewer (click a rendered diagram) now zooms and pans like a map:
Related: #267, which asked for zoom and pan of a diagram.
Problem on
mainThe viewer steps the diagram's width in percent inside a scrolling box (
overflow: auto). The wheel scrolls the box instead of zooming, a left press does nothing, and a zoom step cannot be anchored to the part of the diagram being read.To see it on
main: ask for a larger flowchart, click Preview, click the rendered diagram, then try the wheel and a drag.How it works
width="100%", amax-widthstyle), so there is nothing to scale and no natural size to pan over. The viewer pins the svg to the pixels of its ownviewBoxand moves the wrapper withtransform: translate(x, y) scale(zoom)andtransform-origin: 0 0. 100% is the diagram's own pixel size.pointer - (pointer - offset) * (next / current). The wheel listener is attached by hand with{ passive: false }, because React'swheelhandler is passive and could not stop the page behind the modal from scrolling.pointerup. Pointer capture makes everyclickland on the viewport, so a click handler would close the viewer after any pan that ended over empty space. Now the press must start on the viewport itself and move less than 3 px.showModal()and the fitting share oneuseLayoutEffect. A closed<dialog>has no layout box, so measuring before it opens reads zeros, and opening in auseEffectpainted one unfitted frame.overflow: hiddenwithtouch-action: noneandgrab/grabbingcursors, and the canvas is absolutely positioned. No new colors and no new strings (it reuses the zoom, fit and close labels).docs/agents/sessions.mdhas the note.Behavior changes worth a look
mainthe diagram opens stretched to the viewport width, so a small diagram is enlarged. Now fit never enlarges past 100%.Verification
node_modules/.bin/tsc --noEmit— clean.npm run lint— clean.npm test— 2870 tests, 2867 pass, 0 fail, 1 skipped. Two tests inlib/session-membership.integration.test.mjstimed out at 15 s in a run where two suites were going at once. That file passes on its own (2/2, 6 s) and this change does not touch session listing.Not run: a browser pass on this branch, and
next build(per AGENTS.md). The change is in pointer and layout behavior that the unit tests do not reach.