dagre graph rendering for spaday
Overview
spaday-dagre renders directed graphs in spaday from a
serializable node/edge config, laid out by @dagrejs/dagre and
drawn as light-DOM SVG. Colors ride the spaday shell's --spa-* tokens, so
bind_root_class("wa-dark", ...) re-themes the graph with the rest of the page, and application CSS
reaches every shape. dagre-node-click bubbles {id, label, x, y} and dagre-edge-click bubbles
{source, target, label, x, y} — the graph context plus the pointer position — so
SetField("selected", event_value("id")) selects and open_popup(..., x=event_value("x"), y=event_value("y")) positions. Right-clicking a node or edge bubbles dagre-node-contextmenu /
dagre-edge-contextmenu with the same shape, pairing with spaday's open_popup for context menus.
Navigation is dagre-d3-class: cursor-anchored wheel zoom, drag pan (clamped so the graph can never
be dragged out of view), double-click reset, and an optional GitHub-mermaid-style D-pad
(controls) with pan arrows around a center reset circle. The view is automatic — fit and
centered, re-fitted on every host resize or graph change, so a graph built inside a hidden or
not-yet-sized tab, accordion, or drawer fits when it is shown — until the user pans or zooms or a
node is focused; a reset, or the fit() method (Invoke(by_id("graph"), "fit")), makes it
automatic again.
The host draws into an absolutely positioned frame and contributes no intrinsic height: give
<spaday-dagre> or an ancestor an explicit height (e.g. style="height: 32rem"). An unsized host
falls back to the graph's natural height, with a one-time console warning.
Quick example
from spaday import element
from spaday.backends.starlette import serve
from spaday_dagre import Dagre, package
graph = Dagre(
graph={
"nodes": [{"id": "a", "label": "Alpha"}, {"id": "b", "shape": "diamond"}],
"edges": [{"source": "a", "target": "b", "label": "flow"}],
},
layout={"rankdir": "LR"},
controls=True,
)
app = serve(element("main").child(graph), packages=[package])
Node sizes default from label measurement; per-node width/height/class/shape (rect,
diamond, ellipse) and per-edge label/class override. The maxLabelWidth prop (px) caps
label-driven width: wider labels are ellipsized, with the full label as a native tooltip. layout
passes through to dagre (rankdir, align, nodesep,
ranksep, edgesep, marginx/marginy, ranker). Installing the package registers the dagre
entry point, so packages=["dagre"] also works.
A node with parent nests inside the cluster named by another node's id (dagre's compound
layout): the cluster renders as a rounded container behind its children, labeled along its top
edge, and clicks/right-clicks on it dispatch the node events with the same detail shape.
Parentless nodes mix freely with clustered ones; graphs without parents keep the flat layout
path.
The emphasis prop (a list of node ids; a single id string works too, null clears) toggles the
.emphasis class on the matching rendered nodes by pure class reconciliation — no re-layout, no
graph rebuild — and re-applies after re-renders, so a live selection binds directly:
.bind("emphasis", "selected"). The focusNode(id) method (declared in the
manifest for spaday's Invoke) pans — and zooms to a comfortable level when needed — so the node
or cluster is centered in the view; the bindable focus prop is a property spelling that calls
it on set, with the method as the primary API.
Theming
Component-scoped tokens layer over the shell's --spa-* tokens, so an application can theme the
graph from the host (or any ancestor) without knowing its internals — a token set once wins in both
light and dark page modes:
| Token | Themes |
|---|---|
--dagre-node-fill |
node shape fill |
--dagre-node-stroke |
node shape outline |
--dagre-node-text |
node and cluster label text |
--dagre-edge-stroke |
edge lines and arrowheads |
--dagre-edge-label |
edge label text |
--dagre-cluster-fill |
cluster container fill |
--dagre-cluster-stroke |
cluster container outline |
--dagre-accent |
hover, connected-endpoint, and emphasis affordances |
Node and edge class values are forwarded onto the rendered <g> groups (alongside
spaday-dagre-node / spaday-dagre-edge), so custom classes are CSS-targetable directly. One
variant is built in: a node or edge whose class includes emphasis gets an accent outline.
Run the local example
python -m spaday_dagre.example
Open http://127.0.0.1:8016: a pipeline DAG live over a transports wire — the server sweeps an
active-stage highlight through the graph while node/edge selection rides back as model edits — with
direction switching, mixed node shapes, a "modeling" cluster grouping the middle stages, selection
mirrored into the emphasis prop, a right-click menu for nodes and edges (its Focus item centers
via focusNode), view controls, and the dark-mode toggle.
Metadata
Release files for spaday-dagre 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| spaday_dagre-0.3.0.tar.gz | 194.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spaday_dagre-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 333.6 kB
Release files / spaday_dagre-0.3.0.tar.gz
| Download URL | spaday_dagre-0.3.0.tar.gz |
|---|---|
| Size | 194.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4291d5c54a722c4230d320e7b2cd4cbd1c3e68b997986cd41fb641ef5c1ba7f0
|
|
BLAKE2b-256 checksum How to use checksums |
110849b595330570598483c8bb018bdbe0933f3238cf13bf0ed4ed1b03530201
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / spaday_dagre-0.3.0-py3-none-any.whl
| Download URL | spaday_dagre-0.3.0-py3-none-any.whl |
|---|---|
| Size | 139.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
82be43ccac733cccc32d10dd7fa13c28a3c91842938c263458f5cba5757fb6b6
|
|
BLAKE2b-256 checksum How to use checksums |
6485e09356eed7a0245236a37ed84f1d53aeb79f620926982f4a5909812b8288
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|