# How the Panzoom and Modal Image Viewer Uses URL Parameters for State Persistence in Astro Big Doc

> Learn how astro-big-doc uses URL parameters for state persistence. Discover shareable deep links and automatic state restoration for its panzoom and modal image viewer.

- Repository: [Micro Web Stacks/astro-big-doc](https://github.com/microwebstacks/astro-big-doc)
- Tags: internals
- Published: 2026-03-07

---

**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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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:

```javascript
// 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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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-30`
- `window_url_add_zoom(z)` → appends `?zoom=1.5`
- `window_url_add_modal()` → appends `?modal=NAME`

```javascript
// 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)` for `pan=` coordinates
- `pzref.smoothZoom(cx, cy, zoom)` for `zoom=` levels
- `svg_text_focus()` for `text=` anchors targeting specific SVG element IDs

```javascript
// 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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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:

```html
<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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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`](https://github.com/microwebstacks/astro-big-doc/blob/main/lib_panzoommodal.js) where the callbacks serialize state:

```javascript
// 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:

```html
<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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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.js`](https://github.com/microwebstacks/astro-big-doc/blob/main/lib_panzoommodal.js) that update the URL via `window_url_add_pan()`, `window_url_add_zoom()`, and `window_url_add_modal()`.
- **Deep Linking Support**: Four query parameters control the viewer state: `modal` (container name), `pan` (x/y coordinates), `zoom` (scale factor), and `text` (SVG element ID).
- **Restoration Pipeline**: On page load, `checkURLModal()` and `handle_url_modal()` in [`panzoom_common.js`](https://github.com/microwebstacks/astro-big-doc/blob/main/panzoom_common.js) parse parameters and reconstruct the view using `smoothMoveTo()`, `smoothZoom()`, and `svg_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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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`](https://github.com/microwebstacks/astro-big-doc/blob/main/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.