Skip to main content

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 /editor with 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​

Routing + data flow​

Mental model​

  • Layout: outer GlassCard wrapper; top-right GlassSwitch toggles Color vs Preview.
  • Viewport: inner GlassCard captures pointer + wheel; div.inner carries translate + 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]; apply translate(${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: nextTx=mxβˆ’cxβ‹…nextScale,nextTy=myβˆ’cyβ‹…nextScalenextTx = m_x - c_x \cdot nextScale, \quad nextTy = m_y - c_y \cdot nextScale where (mx,my)(m_x, m_y) is the screen midpoint and (cx,cy)(c_x, c_y) 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 add styles.coloredRegion (one-way reveal, no toggle-off).

Key classes​

ClassPurpose
viewportClipped interaction surface; touch-action: none for consistent pointer handling
innerTransform wrapper (translate + scale); uses will-change: transform
grabbingApplied during drag to show a grabbing cursor
colorModeApplied on the outer card when color mode is active
previewModeApplied on the outer card when preview mode is active
coloredRegionAdded on shapes to reveal original fills

Styling and selectors​

  • SHAPE_SELECTOR = 'path,rect,circle,polygon,ellipse'.
  • Color mode: primitives without .coloredRegion are forced to white; adding .coloredRegion restores original fill.
  • Preview mode: common primitives get pointer-events: none so current reveal state is view-only.
  • Adding new SVG primitives: update SHAPE_SELECTOR and mirror rules in Editor.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_SELECTOR and CSS selectors cover it.

Tests and docs​