OG
JS
Docs
Demos
Examples
Pattern-aware group layouts
Choose a readable local grammar from topology intent while OGJS owns every group center.
ISOLATED → TRACK · MESH → RING · STAR → ORBIT
// The application supplies group membership and a familiar local grammar, not member or // group coordinates. OGJS packs the broad view before applying each scoped layout recipe. import { Ogjs } from '../../src/index'; const og = new Ogjs({ container: '#viz', theme: 'light' }); og.animationDuration = 350; const nodes = []; const edges = []; // Membership and internal topology describe each group. Member coordinates are intentionally // absent so the local layout calls—not fixture arithmetic—own their arrangement. const isolatedSizes = [4, 6, 5, 7, 4, 6]; isolatedSizes.forEach((size, index) => nodes.push({ id: `isolated-${index}`, size, color: '#0ea5e9', label: `iso-${index}`, data: { group: 'Isolated' }, })); const meshIds = []; for (let index = 0; index < 8; index++) { meshIds.push(`mesh-${index}`); nodes.push({ id: `mesh-${index}`, size: index === 0 ? 8 : 5, color: '#8b5cf6', label: `mesh-${index}`, data: { group: 'Mesh' }, }); edges.push({ source: `mesh-${index}`, target: `mesh-${(index + 1) % 8}` }); } edges.push({ source: 'mesh-0', target: 'mesh-4' }, { source: 'mesh-2', target: 'mesh-6' }); nodes.push({ id: 'star-hub', size: 10, color: '#f97316', label: 'hub', data: { group: 'Star' }, }); const starIds = []; for (let index = 0; index < 5; index++) { const id = `star-${index}`; starIds.push(id); nodes.push({ id, size: 5, color: '#f97316', label: `leaf-${index}`, data: { group: 'Star' }, }); edges.push({ source: 'star-hub', target: id }); } og.setGraph({ nodes, edges }); // One broad grouping recipe derives group centers. Scoped recipes then express the local visual // grammar without hand-authored centers: a track, a cycle, and a degree-ranked hub orbit. og.layouts.clustered({ groupBy: ({ data }) => data.group, groupGap: 80, memberGap: 10 }); og.layouts.track({ nodeIds: isolatedSizes.map((_, index) => `isolated-${index}`), gap: 12 }); og.layouts.circular({ nodeIds: meshIds, radius: 44 }); og.layouts.orbit({ nodeIds: ['star-hub', ...starIds], ringGap: 42, nodeGap: 8 }); // Visual grouping retains member geometry and topology while adding group context around it; // it does not replace source records with aggregate meta-nodes. og.groupVisually(({ data }) => data.group, { relax:false }); og.camera.fit({ target: 'visible', avoid: document.querySelector('.panel'), paddingPx: 24 });
<!doctype html> <html lang="en"><head><meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Ogjs example — Pattern-aware group layouts</title> <link rel="stylesheet" href="../site.css"/> <style> #viz { position: fixed; inset: 52px 0 0 0; } .panel { position: fixed; top: 66px; left: 14px; z-index: 5; max-width: 390px; background: #ffffff; border: 1px solid #e2e6ec; border-radius: 8px; padding: 12px 14px; box-shadow: 0 2px 12px rgba(15, 23, 42, 0.08); } .panel h1 { font: 700 16px var(--sans); color: #0f172a; margin-bottom: 4px; } .panel p { font: 400 12.5px/1.5 var(--sans); color: #475569; } .legend { display: flex; gap: 12px; margin-top: 8px; font: 700 10px var(--mono); color: #64748b; } </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> <div id="viz"></div> <div class="panel"> <h1>Pattern-aware group layouts</h1> <p>Choose a readable local grammar from topology intent while OGJS owns every group center.</p> <div class="legend"><span>ISOLATED → TRACK · MESH → RING · STAR → ORBIT</span></div> </div> <script type="module"> // The application supplies group membership and a familiar local grammar, not member or // group coordinates. OGJS packs the broad view before applying each scoped layout recipe. import { Ogjs } from '../../src/index'; const og = new Ogjs({ container: '#viz', theme: 'light' }); og.animationDuration = 350; const nodes = []; const edges = []; // Membership and internal topology describe each group. Member coordinates are intentionally // absent so the local layout calls—not fixture arithmetic—own their arrangement. const isolatedSizes = [4, 6, 5, 7, 4, 6]; isolatedSizes.forEach((size, index) => nodes.push({ id: `isolated-${index}`, size, color: '#0ea5e9', label: `iso-${index}`, data: { group: 'Isolated' }, })); const meshIds = []; for (let index = 0; index < 8; index++) { meshIds.push(`mesh-${index}`); nodes.push({ id: `mesh-${index}`, size: index === 0 ? 8 : 5, color: '#8b5cf6', label: `mesh-${index}`, data: { group: 'Mesh' }, }); edges.push({ source: `mesh-${index}`, target: `mesh-${(index + 1) % 8}` }); } edges.push({ source: 'mesh-0', target: 'mesh-4' }, { source: 'mesh-2', target: 'mesh-6' }); nodes.push({ id: 'star-hub', size: 10, color: '#f97316', label: 'hub', data: { group: 'Star' }, }); const starIds = []; for (let index = 0; index < 5; index++) { const id = `star-${index}`; starIds.push(id); nodes.push({ id, size: 5, color: '#f97316', label: `leaf-${index}`, data: { group: 'Star' }, }); edges.push({ source: 'star-hub', target: id }); } og.setGraph({ nodes, edges }); // One broad grouping recipe derives group centers. Scoped recipes then express the local visual // grammar without hand-authored centers: a track, a cycle, and a degree-ranked hub orbit. og.layouts.clustered({ groupBy: ({ data }) => data.group, groupGap: 80, memberGap: 10 }); og.layouts.track({ nodeIds: isolatedSizes.map((_, index) => `isolated-${index}`), gap: 12 }); og.layouts.circular({ nodeIds: meshIds, radius: 44 }); og.layouts.orbit({ nodeIds: ['star-hub', ...starIds], ringGap: 42, nodeGap: 8 }); // Visual grouping retains member geometry and topology while adding group context around it; // it does not replace source records with aggregate meta-nodes. og.groupVisually(({ data }) => data.group, { relax:false }); og.camera.fit({ target: 'visible', avoid: document.querySelector('.panel'), paddingPx: 24 }); </script> </body></html>