Embedding & shareable links🔗
The dashboard keeps its window state in readable URL query params, so any URL copied from the address bar (or via the sidebar 🔗 Copy link to this view button) restores the exact same view when pasted.
State params🔗
| Param | Format | Meaning |
|---|---|---|
selected_lake |
12-char geohash | Currently selected lake |
lat, lon |
float (5 decimals) | Map center |
zoom |
float (2 decimals) | Map zoom level |
drained |
1 |
"Show temporal drainage statistics" toggle is on |
month |
YYYY-MM |
Selected historical-drainage analysis month |
hide_stable |
1 |
"Hide stable lakes" toggle is on |
Params at their default value are omitted. Example:
https://dashboard.example.org/?selected_lake=b7zpm2xq4k9d&lat=66.512&lon=-164.087&zoom=12&drained=1&month=2024-06
The visualization preset (--viz-configuration) is fixed per deployment and is
not part of the URL.
Embed config params🔗
These configure how the app behaves when embedded; they're read once on load and are never part of the shareable state above (an embedding parent sets them, they're not echoed back via postMessage or included in copied links).
| Param | Format | Meaning |
|---|---|---|
theme |
light | dark |
Forces the color scheme, overriding the browser's prefers-color-scheme |
show_share |
false |
Hides the sidebar 🔗 Copy link to this view button (e.g. when the embedding parent offers its own shareable link) |
Embedding in a parent site🔗
When the dashboard is embedded in an iframe, links must point at the parent
page, not the framed app. The parent page cooperates via
embed/water-timeseries-embed.js:
<iframe id="wt-frame" allow="clipboard-write" title="Water Timeseries dashboard"></iframe>
<script src="water-timeseries-embed.js"></script>
<script>
WaterTimeseriesEmbed.init({
iframe: "#wt-frame",
appUrl: "https://your-dashboard.example.org",
});
</script>
The snippet:
- On load, copies
wt_-prefixed params from the parent URL into the iframesrc(unprefixed), plusembed=true— so a pasted parent link restores the embedded dashboard state. - Mirrors live state (
mcui:statemessages) onto the parent URL viahistory.replaceState(state params carried with thewt_prefix to avoid collisions with the parent page's own params), so the parent address bar stays shareable as the user pans, zooms, selects lakes, and flips toggles.
Requirements:
allow="clipboard-write"on the iframe tag — without it, the copy button cannot write to the clipboard directly and falls back to a selectable text field.- The snippet only accepts messages whose origin matches
appUrl.
Locking down the message target🔗
By default the dashboard posts state messages with target origin * (they
contain only the state params above — nothing sensitive). To restrict them to
a single parent origin, set an environment variable on the dashboard host:
WT_PARENT_ORIGIN=https://parent-site.example.org
With this set, messages are only delivered to that origin; framed by anyone else, the message is silently dropped by the browser instead of leaking state.
postMessage protocol reference🔗
All messages are objects with type and version: 1.
| Type | Direction | Payload |
|---|---|---|
mcui:state |
dashboard → parent (window.top) |
{ url } — this app's own current URL (shareable state params only, no embed config); the parent extracts state from it directly |
The dashboard posts its own URL rather than a bespoke params object so a parent
doesn't need to hardcode this app's param names. A parent with a richer
integration (e.g. one that already owns an RFC 6570 URI template for its
iframe config, such as MetacatUI) can run that template's de-substitution
against the incoming URL to extract and whitelist state instead of trusting
it outright. The reference snippet here does the simpler equivalent: it
copies the incoming URL's query params onto the parent URL under the wt_
prefix, relying on the event.origin check above rather than a template
whitelist.
Local end-to-end test🔗
- Start the dashboard as usual (it listens on
http://localhost:8501):
water-timeseries dashboard --pmtiles-file <tiles.pmtiles> \
--viz-configuration nrt_drainage --precomputed-nrt-dir <dir>
- Create a minimal parent page next to
water-timeseries-embed.js(e.g.embed/parent.html— kept out of version control):
<!DOCTYPE html>
<html>
<body>
<iframe id="wt-frame" allow="clipboard-write"
style="width: 100%; height: 90vh; border: 1px solid #ccc;"></iframe>
<script src="water-timeseries-embed.js"></script>
<script>
WaterTimeseriesEmbed.init({
iframe: "#wt-frame",
appUrl: "http://localhost:8501",
});
</script>
</body>
</html>
- Serve the repo over a different origin (realistic cross-origin setup) and open http://localhost:8000/embed/parent.html:
python -m http.server 8000
- Pan, zoom, select a lake, flip toggles — the parent page's address bar
gains
wt_*params live. Copy it (e.g.Cmd/Ctrl+L,Cmd/Ctrl+C) and paste into a fresh tab: the parent page loads with the iframe restored to the same state. The dashboard's own 🔗 Copy link to this view button copies the dashboard's own direct URL instead — useful standalone, or to link straight to the framed app outside the parent page.