OG
JS
Docs
Demos
Examples
Data export studio
Generate portable graph data from the live typed-array store, preview it, then download it.
JSON
CSV
GraphML
GEXF
XLSX
Download generated file ↓
// The live OGJS graph is the export source of truth. Each exporter reads the same stable ids // and attributes and produces a portable format; the application chooses the format and // destination without reconstructing nodes or edges from renderer storage. import { Ogjs, parseXLSX } from '../../src/index'; const og = new Ogjs({ container: '#viz', theme: 'light' }); og.setGraph({ nodes: [ { id: 'case', x: 0, y: 0, size: 15, color: '#0f172a', label: 'Case 1042' }, { id: 'account', x: -170, y: 95, size: 10, color: '#2563eb', label: 'Account' }, { id: 'device', x: 170, y: 95, size: 10, color: '#7c3aed', label: 'Device' }, { id: 'merchant', x: 170, y: -95, size: 10, color: '#ea580c', label: 'Merchant' }, { id: 'location', x: -170, y: -95, size: 10, color: '#059669', label: 'Location' }, ], edges: [ { source: 'case', target: 'account' }, { source: 'case', target: 'device' }, { source: 'case', target: 'merchant' }, { source: 'case', target: 'location' }, ] }); og.camera.fit({ target: 'all', avoid: document.querySelector('.workflow-panel'), paddingPx: 24, maxOccupancy: .52, }); let objectUrl; async function generate(format) { // Every branch exports the same live graph. Only the serialization changes, so there is no // export-only topology that can drift from what the developer and user currently see. let content, filename, type; if (format === 'json') { content = JSON.stringify(og.export.json(), null, 2); filename = 'network.json'; type = 'application/json'; } else if (format === 'csv') { const csv = og.export.csv(); content = csv.nodes; filename = 'network-nodes.csv'; type = 'text/csv'; } else if (format === 'graphml') { content = og.export.graphml(); filename = 'network.graphml'; type = 'application/graphml+xml'; } else if (format === 'gexf') { content = og.export.gexf(); filename = 'network.gexf'; type = 'application/gexf+xml'; } else { content = og.export.xlsx(); filename = 'network.xlsx'; type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; } // OGJS produces the document bytes; the application decides how to deliver them. This page // uses a temporary browser URL and revokes the previous one to avoid retaining old blobs. const blob = new Blob([content], { type }); if (objectUrl) URL.revokeObjectURL(objectUrl); objectUrl = URL.createObjectURL(blob); const download = document.querySelector('#download'); download.href = objectUrl; download.download = filename; download.classList.add('ready'); document.querySelector('#preview').textContent = typeof content === 'string' ? content.split('\\n').slice(0, 10).join('\\n') : 'PK · Nodes + Edges · real XLSX workbook'; document.querySelector('#export-status').textContent = `${format.toUpperCase()} · ${blob.size} bytes · ${og.stats().nodes} nodes`; document.querySelectorAll('[data-export]').forEach((button) => button.setAttribute('aria-pressed', String(button.dataset.export === format))); // Round-trip the workbook as a concrete validity check that both node and edge sheets can // be consumed again, rather than assuming a completed download means a correct document. const imported = format === 'xlsx' ? await parseXLSX(content) : undefined; } document.querySelectorAll('[data-export]').forEach((button) => button.addEventListener('click', () => void generate(button.dataset.export))); void generate('json');
<!doctype html> <html lang="en"><head><meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Ogjs example — Data export studio</title> <link rel="stylesheet" href="../site.css"/><link rel="stylesheet" href="./data-lifecycle.css"/> </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> <section class="workflow-panel"><h1>Data export studio</h1> <p>Generate portable graph data from the live typed-array store, preview it, then download it.</p> <div class="controls"> <button data-export="json">JSON</button><button data-export="csv">CSV</button> <button data-export="graphml">GraphML</button><button data-export="gexf">GEXF</button> <button data-export="xlsx">XLSX</button> </div> <div class="status" id="export-status" aria-live="polite"></div> <pre id="preview"></pre><a class="download" id="download">Download generated file ↓</a> </section> <script type="module"> // The live OGJS graph is the export source of truth. Each exporter reads the same stable ids // and attributes and produces a portable format; the application chooses the format and // destination without reconstructing nodes or edges from renderer storage. import { Ogjs, parseXLSX } from '../../src/index'; const og = new Ogjs({ container: '#viz', theme: 'light' }); og.setGraph({ nodes: [ { id: 'case', x: 0, y: 0, size: 15, color: '#0f172a', label: 'Case 1042' }, { id: 'account', x: -170, y: 95, size: 10, color: '#2563eb', label: 'Account' }, { id: 'device', x: 170, y: 95, size: 10, color: '#7c3aed', label: 'Device' }, { id: 'merchant', x: 170, y: -95, size: 10, color: '#ea580c', label: 'Merchant' }, { id: 'location', x: -170, y: -95, size: 10, color: '#059669', label: 'Location' }, ], edges: [ { source: 'case', target: 'account' }, { source: 'case', target: 'device' }, { source: 'case', target: 'merchant' }, { source: 'case', target: 'location' }, ] }); og.camera.fit({ target: 'all', avoid: document.querySelector('.workflow-panel'), paddingPx: 24, maxOccupancy: .52, }); let objectUrl; async function generate(format) { // Every branch exports the same live graph. Only the serialization changes, so there is no // export-only topology that can drift from what the developer and user currently see. let content, filename, type; if (format === 'json') { content = JSON.stringify(og.export.json(), null, 2); filename = 'network.json'; type = 'application/json'; } else if (format === 'csv') { const csv = og.export.csv(); content = csv.nodes; filename = 'network-nodes.csv'; type = 'text/csv'; } else if (format === 'graphml') { content = og.export.graphml(); filename = 'network.graphml'; type = 'application/graphml+xml'; } else if (format === 'gexf') { content = og.export.gexf(); filename = 'network.gexf'; type = 'application/gexf+xml'; } else { content = og.export.xlsx(); filename = 'network.xlsx'; type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; } // OGJS produces the document bytes; the application decides how to deliver them. This page // uses a temporary browser URL and revokes the previous one to avoid retaining old blobs. const blob = new Blob([content], { type }); if (objectUrl) URL.revokeObjectURL(objectUrl); objectUrl = URL.createObjectURL(blob); const download = document.querySelector('#download'); download.href = objectUrl; download.download = filename; download.classList.add('ready'); document.querySelector('#preview').textContent = typeof content === 'string' ? content.split('\\n').slice(0, 10).join('\\n') : 'PK · Nodes + Edges · real XLSX workbook'; document.querySelector('#export-status').textContent = `${format.toUpperCase()} · ${blob.size} bytes · ${og.stats().nodes} nodes`; document.querySelectorAll('[data-export]').forEach((button) => button.setAttribute('aria-pressed', String(button.dataset.export === format))); // Round-trip the workbook as a concrete validity check that both node and edge sheets can // be consumed again, rather than assuming a completed download means a correct document. const imported = format === 'xlsx' ? await parseXLSX(content) : undefined; } document.querySelectorAll('[data-export]').forEach((button) => button.addEventListener('click', () => void generate(button.dataset.export))); void generate('json'); </script></body></html>