OG
JS
Docs
Demos
Examples
Helm workbench
Search, legend, and progress controls share named graph constraints and one lifecycle.
// Mount Helm with search, legend, settings, and progress intent; graph data stays unchanged. // OGJS binds those controls to the graph lifecycle and disposes them with the instance, // so applications do not synchronize duplicate selection or render state. import { Ogjs } from '../../src/index'; const records = [ { id:'account-alpha', label:'Account Alpha', x:-120, y:20, color:'#2563eb', data:{ alias:'Aster', time:0 } }, { id:'device-cafe', label:'Café Device', x:0, y:95, color:'#7c3aed', data:{ alias:'Terminal', time:1 } }, { id:'alert-risk', label:'Risk Alert', x:120, y:10, color:'#dc2626', data:{ alias:'Priority', time:2 } }, { id:'merchant-north', label:'North Merchant', x:35, y:-95, color:'#059669', data:{ alias:'Shop', time:3 } }, ]; const edges = [ { source:'account-alpha', target:'device-cafe' }, { source:'device-cafe', target:'alert-risk' }, { source:'alert-risk', target:'merchant-north' }, ]; const primary = new Ogjs({ container:'#graph-primary', theme:'light' }); primary.setGraph({ nodes:records, edges }); primary.camera.fit(); // Helm binds search, legend, settings, and progress to this graph's public lifecycle. Search // can include application aliases without mirroring selection or render state in the host UI. const helm = primary.mountHelm({ placeholder:'Find an entity', searchText:({ data }) => data?.alias ?? '', filterSearch:true, }); // Search and legend choices join the same named filter state. OGJS keeps the camera fixed // and clears those choices when Helm is removed. helm.setLegend([ { id:'account', label:'Account', color:'#2563eb', mark:'node', filter:{ op:'compare', field:{ kind:'id' }, compare:'eq', value:'account-alpha' } }, { id:'link', label:'Observed link', color:'#94a3b8', mark:'edge' }, ]); helm.setProgress(.35, 'Indexing records'); const secondary = new Ogjs({ container:'#graph-secondary', theme:'light' }); secondary.setGraph({ nodes:records.map((node) => ({ ...node, id:`other-${node.id}` })), edges:[] }); secondary.camera.fit(); // A second mount demonstrates instance isolation: the same control system can target another // graph and host element without sharing events, selection, DOM ownership, or teardown. const otherHelm = secondary.mountHelm({ host:document.querySelector('#custom-host'), placeholder:'Find another entity', }); otherHelm.setLegend([{ id:'other', label:'Other graph', color:'#7c3aed', mark:'node' }]);
<!doctype html> <html lang="en"><head><meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Ogjs example — Helm workbench</title> <link rel="stylesheet" href="../site.css"/> <style> body { background:#f8fafc; } main { position:fixed; inset:52px 0 0; display:grid; grid-template-columns:1fr 1fr; gap:1px; background:#cbd5e1; } .graph { position:relative; min-width:0; background:#fff; overflow:hidden; } .intro { position:absolute; z-index:8; left:20px; bottom:20px; width:min(310px,calc(100% - 40px)); padding:12px 14px; border:1px solid #dce2ea; border-radius:8px; background:rgba(255,255,255,.96); } .intro h1 { font:750 18px var(--sans); color:#0f172a; } .intro p { margin-top:4px; font:400 12px/1.45 var(--sans); color:#475569; } #custom-host { position:absolute; z-index:8; top:16px; right:16px; width:min(290px,calc(100% - 32px)); } @media (max-width:760px) { main { grid-template-columns:1fr; grid-template-rows:1fr 1fr; } } </style></head><body> <header class="rail"><a class="wordmark" href="../index.html">OG<b>JS</b></a><nav> <a href="../docs.html">Docs</a><a href="../demos.html">Demos</a> <a href="./index.html" aria-current="page">Examples</a></nav></header> <main> <section id="graph-primary" class="graph"><div class="intro"><h1>Helm workbench</h1> <p>Search, legend, and progress controls share named graph constraints and one lifecycle.</p></div></section> <section id="graph-secondary" class="graph"><div id="custom-host"></div></section> </main> <script type="module"> // Mount Helm with search, legend, settings, and progress intent; graph data stays unchanged. // OGJS binds those controls to the graph lifecycle and disposes them with the instance, // so applications do not synchronize duplicate selection or render state. import { Ogjs } from '../../src/index'; const records = [ { id:'account-alpha', label:'Account Alpha', x:-120, y:20, color:'#2563eb', data:{ alias:'Aster', time:0 } }, { id:'device-cafe', label:'Café Device', x:0, y:95, color:'#7c3aed', data:{ alias:'Terminal', time:1 } }, { id:'alert-risk', label:'Risk Alert', x:120, y:10, color:'#dc2626', data:{ alias:'Priority', time:2 } }, { id:'merchant-north', label:'North Merchant', x:35, y:-95, color:'#059669', data:{ alias:'Shop', time:3 } }, ]; const edges = [ { source:'account-alpha', target:'device-cafe' }, { source:'device-cafe', target:'alert-risk' }, { source:'alert-risk', target:'merchant-north' }, ]; const primary = new Ogjs({ container:'#graph-primary', theme:'light' }); primary.setGraph({ nodes:records, edges }); primary.camera.fit(); // Helm binds search, legend, settings, and progress to this graph's public lifecycle. Search // can include application aliases without mirroring selection or render state in the host UI. const helm = primary.mountHelm({ placeholder:'Find an entity', searchText:({ data }) => data?.alias ?? '', filterSearch:true, }); // Search and legend choices join the same named filter state. OGJS keeps the camera fixed // and clears those choices when Helm is removed. helm.setLegend([ { id:'account', label:'Account', color:'#2563eb', mark:'node', filter:{ op:'compare', field:{ kind:'id' }, compare:'eq', value:'account-alpha' } }, { id:'link', label:'Observed link', color:'#94a3b8', mark:'edge' }, ]); helm.setProgress(.35, 'Indexing records'); const secondary = new Ogjs({ container:'#graph-secondary', theme:'light' }); secondary.setGraph({ nodes:records.map((node) => ({ ...node, id:`other-${node.id}` })), edges:[] }); secondary.camera.fit(); // A second mount demonstrates instance isolation: the same control system can target another // graph and host element without sharing events, selection, DOM ownership, or teardown. const otherHelm = secondary.mountHelm({ host:document.querySelector('#custom-host'), placeholder:'Find another entity', }); otherHelm.setLegend([{ id:'other', label:'Other graph', color:'#7c3aed', mark:'node' }]); </script></body></html>