Editor Page
Overviewβ
- Interactive SVG viewer that supports pan, zoom (wheel/pinch), and a one-way βreveal colorβ mode; preview mode disables interaction but keeps revealed regions visible.
- Reached at
/editorwith an SVG string passed via navigation state (navigate('/editor', { state: { svg } })); if missing, the page shows βNo SVG data found.β - Layout: outer GlassCard with a top-right mode switch; inner viewport applies translate + scale to a wrapper while the SVG is parsed by
html-react-parser.
Where things liveβ
- Page: src/pages/Editor/index.jsx
- Helmet: src/pages/Editor/EditorHelmet.jsx
- Styles: src/pages/Editor/Editor.module.css
Routing + data flowβ
- Route:
/editorvia src/App.jsx. - Entry:
navigate('/editor', { state: { svg } });from the pipeline end (src/components/WasmImageProcessor.jsx). - No
svgin navigation state β render the βNo SVG data foundβ empty state.
Mental modelβ
- Layout: outer
GlassCardwrapper; top-rightGlassSwitchtoggles Color vs Preview. - Viewport: inner
GlassCardcaptures pointer + wheel;div.innercarriestranslate + scale. - Rendering: SVG string β React elements via
html-react-parser; transform sits on the wrapper, not the<svg>.
Core state + refsβ
isColorMode: true = reveal-on-tap; false = preview (interaction off, reveal state kept).transform { scale, tx, ty }: clamp scale[0.25, 6]; applytranslate(${tx}px, ${ty}px) scale(${scale}).- Refs:
viewportRef(captures + pointer lock),innerRef(locate<svg>),activePointersRef(multi-touch map),pinchRef(pinch anchor data).
Interactionsβ
- Wheel zoom: step
1.12, clamp to[0.25, 6]. - Pan: one active pointer; movement must exceed ~5px before treating as drag.
- Pinch: two pointers; keeps midpoint fixed by anchoring the content point beneath it: where is the screen midpoint and is the content point under it at pinch start.
- Tap-to-reveal (Color mode only): on pointer up with no drag,
elementFromPoint(...).closest(SHAPE_SELECTOR)then addstyles.coloredRegion(one-way reveal, no toggle-off).
Key classesβ
| Class | Purpose |
|---|---|
viewport | Clipped interaction surface; touch-action: none for consistent pointer handling |
inner | Transform wrapper (translate + scale); uses will-change: transform |
grabbing | Applied during drag to show a grabbing cursor |
colorMode | Applied on the outer card when color mode is active |
previewMode | Applied on the outer card when preview mode is active |
coloredRegion | Added on shapes to reveal original fills |
Styling and selectorsβ
SHAPE_SELECTOR = 'path,rect,circle,polygon,ellipse'.- Color mode: primitives without
.coloredRegionare forced to white; adding.coloredRegionrestores original fill. - Preview mode: common primitives get
pointer-events: noneso current reveal state is view-only. - Adding new SVG primitives: update
SHAPE_SELECTORand mirror rules inEditor.module.css(color override + preview pointer-events).
Helmetβ
- Non-indexable workspace view:
<meta name="robots" content="noindex, nofollow" />plus title/description and canonical in EditorHelmet.jsx.
Troubleshooting quick hitsβ
- βTapβ doesnβt reveal: ensure pointer movement stayed under the drag threshold and you are in Color mode.
- Zoom feels jumpy: check scale clamps and the fixed wheel step (
1.12). - Pinch drifts: confirm midpoint math uses the content point captured at gesture start.
- Shapes not affected: verify the element tag is in
SHAPE_SELECTORand CSS selectors cover it.
Tests and docsβ
- Behavior coverage: src/pages/Editor/Editor.test.jsx.
- Helmet: src/pages/Editor/EditorHelmet.test.jsx.
- Extra guidance: docs/docs/reference/pages/Editor/tests.md.