Embed contract: data-* attributes and driver API
This is the reference for the stable surface a host depends on. If you are starting out, read the task-oriented Embedding guide first - it explains which output to produce and how to size, theme, and drive a map - and come here for the exact attribute vocabulary and driver method signatures.
An nf-metro SVG is a self-describing, driveable artifact. A host page can:
- Inline the SVG (or load it via
<img>/<object>). - Load one driver script.
- Call a documented API to highlight lines, select nodes by process pattern, or read the embedded manifest without touching internals.
This page documents the two halves of the contract: the data-* attributes
carried by the SVG and the driver API that a host uses to manipulate it.
The Data manifest page covers the manifest format (nodes, groups,
regions, overlays) in more depth.
data-* attribute contract
Section titled “data-* attribute contract”Every rendered SVG carries two complementary sets of attributes.
Interactive set
Section titled “Interactive set”These attributes are consumed by the driver and are the stable addresses for CSS-level interaction:
| Attribute | Element | Value |
|---|---|---|
data-station-id | Station marker <rect>/<circle> and associated label/icon <g> | The station’s stable id (matches node.id in the manifest). |
data-station-lines | Station marker element only | Comma-separated list of line ids passing through the station. |
data-station-label | Station marker element only | Human-readable label (HTML-escaped). |
data-section-id | Section box and associated label <g> | The section’s stable id (matches region.id in the manifest). |
data-section-name | Station marker elements within a section | Human-readable section name (HTML-escaped). |
data-section-lines | Section box element only | Comma-separated list of line ids present in the section. |
data-line-id | Edge path elements | The id of the line this edge belongs to. |
Querying examples:
// All station markers for a specific station id:svg.querySelectorAll('[data-station-id="align"]');
// All edges belonging to a line:svg.querySelectorAll('[data-line-id="star_salmon"]');
// All section boxes that include a given line:svg.querySelectorAll("[data-section-lines]").forEach((el) => { const lines = el.getAttribute("data-section-lines").split(","); if (lines.includes("star_salmon")) { /* ... */ }});Manifest set
Section titled “Manifest set”A second set - data-node-id and data-node-cx/-cy/-r (plus
data-node-groups/-region) - carries the coordinate and pattern data overlays
need. It is written by the manifest system and specified in full under
Per-node attributes on the Data manifest page.
Both sets join on the station id (data-station-id = data-node-id =
node.id in the manifest JSON).
Driver API
Section titled “Driver API”Obtaining the driver
Section titled “Obtaining the driver”Option A - embed the HTML output (simplest). nf-metro render --format html produces a fully self-contained interactive page with the driver already
inlined. Copy the inline snippet from the Embed modal to paste it into any
host page.
Option B - load the driver separately. Export the driver script and load it alongside the SVG:
nf-metro embed-script -o nf-metro-embed.jsThen on the host page:
<!-- 1. Inline the SVG (must contain data-* attributes and manifest) --><div id="my-map"> <div class="nf-metro-canvas"> <!-- paste SVG here --> </div> <div class="nf-metro-legend"></div> <div class="nf-metro-tip"></div></div>
<!-- 2. Load the driver --><script src="nf-metro-embed.js"></script>
<!-- 3. Attach and capture the API --><script> const api = attachMetroMap({ root: document.getElementById("my-map"), lines: [ { id: "star_salmon", label: "STAR + Salmon", color: "#e05c5c", style: "solid", }, /* ... */ ], embed: null, });</script>The lines array must match the lines embedded in the SVG. The easiest way to
obtain it is from the groups array in the manifest (see
getManifest below).
API methods
Section titled “API methods”attachMetroMap(opts) returns an API object with the following methods. All
methods are no-ops when the SVG has no manifest or no matching elements.
highlightLine(id)
Section titled “highlightLine(id)”Activate a line by its id string. All stations and edges not belonging to
that line are hidden; the map zooms to the visible subset. Calling with the
currently active id clears the filter (same as clearHighlight()).
api.highlightLine("star_salmon");clearHighlight()
Section titled “clearHighlight()”Remove any active line filter and station selection, returning the map to its initial unfiltered state.
api.clearHighlight();getManifest()
Section titled “getManifest()”Return the embedded manifest JSON object (parsed from the <metadata id="diagram-manifest"> element), or null if the SVG has no manifest. Use
this to build lines arrays, read node coordinates for overlays, or look up
process patterns.
const manifest = api.getManifest();if (manifest) { console.log(manifest.nodes.map((n) => n.id));}selectNode(processName)
Section titled “selectNode(processName)”Match processName against each node’s patterns array (case-insensitive
regex) and visually highlight the matching stations. Non-matching stations are
dimmed. Calling with a string that matches no node is a no-op.
// Highlight the station(s) whose patterns match this Nextflow process name:api.selectNode("NFCORE_RNASEQ:RNASEQ:ALIGN_STAR_SALMON:STAR_ALIGN");CSS classes written by selectNode:
| Class | Applied to |
|---|---|
nf-metro-station-selected | Matching station marker elements ([data-station-lines]). |
nf-metro-station-dim | All [data-station-id] elements that are not a match. |
nf-metro-selecting | The root element while a selection is active. |
The default templates ship CSS for these classes. When loading the driver separately, add your own styles:
.nf-metro-station-selected rect,.nf-metro-station-selected circle { stroke: #fff; stroke-width: 2;}.nf-metro-station-dim { opacity: 0.2; transition: opacity 0.2s;}reset()
Section titled “reset()”Alias for clearHighlight().
Overlay path
Section titled “Overlay path”For a coordinate-accurate progress overlay (e.g. lighting up stations as a
pipeline runs), draw a transparent layer that shares the base SVG’s viewBox
and place markers at each node’s manifest coordinates. The
overlay_svg() helper builds that layer, and the
manifest tutorial,
Light up a diagram as a job runs,
walks the full read-match-draw recipe end to end.
The highlightLine / selectNode API and the overlay approach are
complementary:
- Driver API - manipulates the base SVG’s existing DOM elements by adding CSS classes. Zero extra elements; works without the manifest.
- Overlay - adds new elements in a separate layer at exact coordinates from the manifest. Suitable for progress indicators, status badges, and annotation.
Integration example
Section titled “Integration example”The following snippet builds a self-contained host page that loads a separately-generated SVG and driver, then wires keyboard shortcuts to the public API.
<!doctype html><html> <head> <style> #map-root { position: relative; } .nf-metro-canvas svg { width: 100%; height: auto; } .nf-metro-legend { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px; } .nf-metro-tip { position: fixed; pointer-events: none; } /* Station selection styles */ .nf-metro-station-selected rect, .nf-metro-station-selected circle { stroke: #4cf; stroke-width: 2; } .nf-metro-station-dim { opacity: 0.15; transition: opacity 0.2s; } </style> </head> <body> <div id="map-root"> <div class="nf-metro-canvas"> <!-- Inline the SVG exported by: nf-metro render map.mmd -o map.svg --> </div> <div class="nf-metro-legend"></div> <div class="nf-metro-tip"></div> </div>
<script src="nf-metro-embed.js"></script> <script> const manifest = (() => { const el = document.querySelector("#diagram-manifest"); return el ? JSON.parse(el.textContent) : null; })();
const lines = (manifest?.groups || []).map((g) => ({ id: g.id, label: g.label, color: g.color, style: "solid", }));
const api = attachMetroMap({ root: document.getElementById("map-root"), lines, embed: null, });
// Example: drive from your application state function onProcessStarted(fqProcessName) { api.selectNode(fqProcessName); }
function onPipelineDone() { api.clearHighlight(); } </script> </body></html>Versioning
Section titled “Versioning”Both the manifest schema and the driver contract are versioned. The Python constants are:
from nf_metro.manifest import MANIFEST_SCHEMA_VERSION # e.g. "1.0"from nf_metro.render.driver import DRIVER_CONTRACT_VERSION # e.g. "1.0"The schema version follows major.minor semantics: the minor part increments
for additive (backward-compatible) changes; the major part increments for
breaking changes. Consumers must ignore unknown fields (additive tolerance).
This surface is stable as of nf-metro 1.0: within a major version the contract only grows in backward-compatible ways. Pin to a specific nf-metro release only if you depend on the exact bytes of the output.