How the Panzoom and Modal Image Viewer Uses URL Parameters for State Persistence in Astro Big Doc
The panzoom and modal image viewer in astro-big-doc encodes modal state, pan coordinates, zoom level, and text focus into URL query parameters, enabling shareable deep links and automatic state restoration on page load.
The microwebstacks/astro-big-doc repository implements a stateless, URL-driven image viewer that transforms user interactions into persistent query strings. By treating the browser address bar as the single source of truth, the system allows users to bookmark specific zoom levels, pan positions, and modal states without server-side sessions.
Architecture Overview
The state persistence mechanism relies on a bidirectional data flow between the panzoom instance and the browser's location.search API. When users interact with the canvas, the system pushes updates to the URL; when the page loads, parsers read those parameters and reconstruct the view.
Initialization Flow
The boot sequence begins in src/components/panzoom/panzoom_common.js, where a DOMContentLoaded handler invokes the init() function. This routine registers modal event listeners and immediately calls checkURLModal() to scan for pre-existing state:
// From panzoom_common.js
function init() {
initModalEvents(); // Attaches "open" listeners
checkURLModal(); // Parses ?modal=... on load
}
The checkURLModal() function extracts the modal parameter from location.search and programmatically fires a custom "open" event on the matching container, triggering the modal creation pipeline.
URL Parameter Encoding
Once a modal opens via openModal() in src/components/panzoom/lib_panzoommodal.js, the system instantiates a panzoom object and attaches callbacks to the panend and zoom events. These callbacks serialize the current transform state into the URL using dedicated helper functions:
window_url_add_pan(x, y)→ appends?pan=x120_y-30window_url_add_zoom(z)→ appends?zoom=1.5window_url_add_modal()→ appends?modal=NAME
// Excerpt from lib_panzoommodal.js
pzref.on('panend', () => {
const {x, y} = pzref.getTransform();
window_url_add_pan(x, y);
});
pzref.on('zoom', () => {
const {scale} = pzref.getTransform();
window_url_add_zoom(scale);
});
State Restoration
When the modal opens with existing URL parameters, handle_url_modal() executes after the content renders. This function parses the query string and invokes specific restoration methods:
pzref.smoothMoveTo(x, y)forpan=coordinatespzref.smoothZoom(cx, cy, zoom)forzoom=levelssvg_text_focus()fortext=anchors targeting specific SVG element IDs
// From lib_panzoommodal.js
function handle_url_modal() {
const params = new URLSearchParams(location.search);
if (params.has('pan')) {
const [x, y] = parsePan(params.get('pan'));
pzref.smoothMoveTo(x, y);
}
if (params.has('zoom')) {
pzref.smoothZoom(centerX, centerY, params.get('zoom'));
}
}
Key Implementation Files
| File | Role |
|---|---|
src/components/panzoom/panzoom_common.js |
Boots the system, registers modal events, and parses modal= parameters on load via init() and checkURLModal(). |
src/components/panzoom/lib_panzoommodal.js |
Core logic for modal creation, panzoom instantiation, URL serialization (window_url_add_*), and state restoration (handle_url_modal()). |
src/components/panzoom/panzoom.astro |
Astro component markup that defines the panzoom container, assigns data-name attributes for modal identification, and includes the modal stub. |
src/components/panzoom/lib_svg_utils.js |
Utility functions including svg_text_focus() for handling text= URL parameters that target specific SVG element IDs. |
src/components/panzoom/panzoommodal.astro |
Minimal modal skeleton providing the background overlay and inner container that receives cloned SVG or IMG content. |
URL Parameter Format and Examples
The viewer recognizes four distinct query parameters that control different aspects of the viewing state.
Modal Identification
The modal parameter specifies which image container to open in fullscreen mode. The value must match the data-name attribute assigned in panzoom.astro.
?modal=architecture-diagram
When checkURLModal() detects this parameter, it triggers the "open" event on the container with data-name="architecture-diagram".
Pan and Zoom Coordinates
The pan parameter encodes the X and Y translation values of the transform matrix using an x and y delimiter:
?pan=x120_y-30
The zoom parameter stores the scale factor as a decimal:
?zoom=1.5
These values are parsed by handle_url_modal() and applied via smoothMoveTo() and smoothZoom() to recreate the exact viewport.
Text Focus Anchors
For SVG diagrams, the text parameter accepts an element ID that the viewer should focus on after loading:
?text=critical-path-node
This invokes svg_text_focus() from lib_svg_utils.js, which centers the viewport on the specified element and optionally applies a highlight effect.
Code Examples
Creating a Shareable Deep Link
To generate a link that opens a specific modal with predefined view settings, construct a URL combining the modal name, pan coordinates, and zoom level:
<a href="/docs?modal=my-diagram&pan=x120_y-30&zoom=1.5">
Open diagram at specific view
</a>
When clicked, checkURLModal() in panzoom_common.js detects the parameters, fires the "open" event, and handle_url_modal() applies the transform values after the modal renders.
Listening to State Changes
The panzoom instance emits events that automatically update the URL. You can observe this behavior in lib_panzoommodal.js where the callbacks serialize state:
// From lib_panzoommodal.js
pzref.on('panend', () => {
const {x, y} = pzref.getTransform();
// Serializes to ?pan=x[value]_y[value]
window_url_add_pan(x, y);
});
pzref.on('zoom', () => {
const {scale} = pzref.getTransform();
// Serializes to ?zoom=[scale]
window_url_add_zoom(scale);
});
Focusing on SVG Elements via URL
To link directly to a specific node within an SVG diagram, use the text parameter targeting an element ID:
<a href="/docs?modal=architecture-diagram&text=database-layer">
Jump to database layer
</a>
The handle_url_modal() function parses this parameter and invokes svg_text_focus(modal, svg, "database-layer", pzref) from lib_svg_utils.js, which centers the viewport on that element.
Summary
- Stateless Architecture: The viewer treats the URL query string as the single source of truth, eliminating the need for server-side sessions or localStorage.
- Automatic Serialization: User interactions (pan, zoom, modal open) trigger callbacks in
lib_panzoommodal.jsthat update the URL viawindow_url_add_pan(),window_url_add_zoom(), andwindow_url_add_modal(). - Deep Linking Support: Four query parameters control the viewer state:
modal(container name),pan(x/y coordinates),zoom(scale factor), andtext(SVG element ID). - Restoration Pipeline: On page load,
checkURLModal()andhandle_url_modal()inpanzoom_common.jsparse parameters and reconstruct the view usingsmoothMoveTo(),smoothZoom(), andsvg_text_focus().
Frequently Asked Questions
How do I generate a shareable link to a specific zoom level and position?
Append the modal, pan, and zoom query parameters to your URL. The pan value uses the format x[value]_y[value] (e.g., pan=x120_y-30), while zoom accepts a decimal scale factor (e.g., zoom=2.0). When the page loads, handle_url_modal() in lib_panzoommodal.js automatically applies these values via smoothMoveTo() and smoothZoom().
What happens to the URL when I close the modal?
Closing the modal triggers window_url_remove_modal() in lib_panzoommodal.js, which strips the modal parameter from the query string. The pan and zoom parameters are also cleared, returning the URL to its clean state and ensuring that refreshing the page does not reopen the modal unexpectedly.
Can I link directly to a specific element within an SVG diagram?
Yes. Use the text query parameter with a value matching the target element's id attribute. For example, ?modal=diagram&text=critical-path invokes svg_text_focus() from lib_svg_utils.js, which centers the viewport on that element and applies the current zoom level. This is useful for referencing specific nodes in architecture diagrams or flowcharts.
Does this implementation require server-side support or browser storage?
No. The implementation is completely stateless and relies solely on the URL query string. All state persistence happens through window_url_add_* functions in lib_panzoommodal.js that use the History API to update location.search. This design allows the viewer to work on static sites, CDNs, and serverless deployments without cookies, localStorage, or session backends.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →