OG
JS
Docs
Demos
Examples
Filter workbench
Compose predicates over a large graph, then inspect visible topology and local elapsed time.
Minimum score
0
50
70
90
Region
All
North
South
Apply filters
Clear filters
building workload…
—
// The URL controls workload size while node data supplies filterable region and risk fields. // OGJS keeps each control as a named filter. Either one can change or clear without // rebuilding the graph or disturbing the other. import { Ogjs } from '../../src/index'; const params = new URLSearchParams(location.search); const requested = params.has('nodes') ? Number(params.get('nodes')) : Number.NaN; const nodeCount = Number.isInteger(requested) ? Math.max(100, Math.min(100000, requested)) : 20000; const edgeCount = nodeCount * 2; const regions = ['north', 'east', 'south', 'west']; const nodes = Array.from({ length: nodeCount }, (_, index) => ({ id: index, size: 2.5, color: ['#2563eb', '#0891b2', '#059669', '#9333ea'][index % 4], data: { score: index % 100, region: regions[Math.floor(index / 100) % 4] }, })); const edges = Array.from({ length: edgeCount }, (_, index) => { const source = index % nodeCount; const blockStart = Math.floor(source / 100) * 100; const blockSize = Math.min(100, nodeCount - blockStart); const offset = index < nodeCount ? 1 : 2; const target = blockStart + (source - blockStart + offset) % blockSize; return { source, target }; }); const og = new Ogjs({ container: '#viz', theme: 'light', accessibility: false, labels: { minZoom: 99 } }); og.setGraph({ nodes, edges }); // A grid is presentation intent, not workload data. OGJS derives its row and column count // from the requested graph size and keeps the fixture free of canvas geometry. og.layouts.grid(8); og.camera.fit(); const score = document.querySelector('#score'); const region = document.querySelector('#region'); const status = document.querySelector('#status'); const metrics = document.querySelector('#metrics'); function report(elapsedMs) { const graph = og.stats(); const resolved = og.predicates.resolve(); const visibleIds = new Set(Array.from(resolved.nodes, (index) => og.graph.getNodeId(index))); const visibleNodes = visibleIds.size; const visibleEdges = og.getVisibleEdges() .filter(({ source, target }) => visibleIds.has(source) && visibleIds.has(target)) .length; const filterReport = { schema: 'ogjs-filter-run/v1', workload: { nodes: graph.nodes, edges: graph.edges }, predicates: { minimumScore: Number(score.value), region: region.value, count: resolved.active.length }, timing: { elapsedMs }, result: { visibleNodes, hiddenNodes: graph.nodes - visibleNodes, visibleEdges, hiddenEdges: graph.edges - visibleEdges, }, }; status.textContent = `${visibleNodes.toLocaleString()} match · ${graph.nodes - visibleNodes} outside the filters`; metrics.textContent = `${visibleEdges.toLocaleString()} matching links · ${filterReport.timing.elapsedMs.toFixed(2)} ms`; } document.querySelector('#apply').addEventListener('click', () => { const started = performance.now(); const minimum = Number(score.value); const selected = region.value; og.predicates.set('minimum-score', { target:'nodes', active:true, expression:{ op:'range', field:{ kind:'data', path:'score' }, min:minimum, max:99 }, }); if (selected === 'all') og.predicates.remove('region'); else og.predicates.set('region', { target:'nodes', active:true, expression:{ op:'compare', field:{ kind:'data', path:'region' }, compare:'eq', value:selected }, }); report(performance.now() - started); }); document.querySelector('#clear').addEventListener('click', () => { og.predicates.clear(); report(0); }); status.textContent = `ready · ${nodeCount.toLocaleString()} nodes`;
<!doctype html> <html lang="en"><head><meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Ogjs example — Filter workbench</title> <link rel="stylesheet" href="../site.css"/><link rel="stylesheet" href="./data-lifecycle.css"/> <style> #viz { left: 452px; } @media (max-width: 760px) { #viz { left: 0; } } </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 class="workbench-frame"><div id="viz"></div> <section class="workflow-panel"><h1>Filter workbench</h1> <p>Compose predicates over a large graph, then inspect visible topology and local elapsed time.</p> <div class="controls"> <label>Minimum score <select id="score" aria-label="Minimum score"> <option value="0">0</option><option value="50">50</option><option value="70" selected>70</option><option value="90">90</option> </select></label> <label>Region <select id="region" aria-label="Region"> <option value="all" selected>All</option><option value="north">North</option><option value="south">South</option> </select></label> <button id="apply">Apply filters</button><button id="clear">Clear filters</button> </div> <div class="status" id="status" role="status" aria-live="polite">building workload…</div> <div class="status" id="metrics">—</div> </section></main> <script type="module"> // The URL controls workload size while node data supplies filterable region and risk fields. // OGJS keeps each control as a named filter. Either one can change or clear without // rebuilding the graph or disturbing the other. import { Ogjs } from '../../src/index'; const params = new URLSearchParams(location.search); const requested = params.has('nodes') ? Number(params.get('nodes')) : Number.NaN; const nodeCount = Number.isInteger(requested) ? Math.max(100, Math.min(100000, requested)) : 20000; const edgeCount = nodeCount * 2; const regions = ['north', 'east', 'south', 'west']; const nodes = Array.from({ length: nodeCount }, (_, index) => ({ id: index, size: 2.5, color: ['#2563eb', '#0891b2', '#059669', '#9333ea'][index % 4], data: { score: index % 100, region: regions[Math.floor(index / 100) % 4] }, })); const edges = Array.from({ length: edgeCount }, (_, index) => { const source = index % nodeCount; const blockStart = Math.floor(source / 100) * 100; const blockSize = Math.min(100, nodeCount - blockStart); const offset = index < nodeCount ? 1 : 2; const target = blockStart + (source - blockStart + offset) % blockSize; return { source, target }; }); const og = new Ogjs({ container: '#viz', theme: 'light', accessibility: false, labels: { minZoom: 99 } }); og.setGraph({ nodes, edges }); // A grid is presentation intent, not workload data. OGJS derives its row and column count // from the requested graph size and keeps the fixture free of canvas geometry. og.layouts.grid(8); og.camera.fit(); const score = document.querySelector('#score'); const region = document.querySelector('#region'); const status = document.querySelector('#status'); const metrics = document.querySelector('#metrics'); function report(elapsedMs) { const graph = og.stats(); const resolved = og.predicates.resolve(); const visibleIds = new Set(Array.from(resolved.nodes, (index) => og.graph.getNodeId(index))); const visibleNodes = visibleIds.size; const visibleEdges = og.getVisibleEdges() .filter(({ source, target }) => visibleIds.has(source) && visibleIds.has(target)) .length; const filterReport = { schema: 'ogjs-filter-run/v1', workload: { nodes: graph.nodes, edges: graph.edges }, predicates: { minimumScore: Number(score.value), region: region.value, count: resolved.active.length }, timing: { elapsedMs }, result: { visibleNodes, hiddenNodes: graph.nodes - visibleNodes, visibleEdges, hiddenEdges: graph.edges - visibleEdges, }, }; status.textContent = `${visibleNodes.toLocaleString()} match · ${graph.nodes - visibleNodes} outside the filters`; metrics.textContent = `${visibleEdges.toLocaleString()} matching links · ${filterReport.timing.elapsedMs.toFixed(2)} ms`; } document.querySelector('#apply').addEventListener('click', () => { const started = performance.now(); const minimum = Number(score.value); const selected = region.value; og.predicates.set('minimum-score', { target:'nodes', active:true, expression:{ op:'range', field:{ kind:'data', path:'score' }, min:minimum, max:99 }, }); if (selected === 'all') og.predicates.remove('region'); else og.predicates.set('region', { target:'nodes', active:true, expression:{ op:'compare', field:{ kind:'data', path:'region' }, compare:'eq', value:selected }, }); report(performance.now() - started); }); document.querySelector('#clear').addEventListener('click', () => { og.predicates.clear(); report(0); }); status.textContent = `ready · ${nodeCount.toLocaleString()} nodes`; </script></body></html>