Omni-Search
@@ -105,45 +102,54 @@
network.fit({ animation: { duration: 500, easingFunction: 'easeInOutQuad' } });
}
- // Graph Initialization
+ // Graph Initialization
let network = null;
+ let nodesData = new vis.DataSet();
+ let edgesData = new vis.DataSet();
+
async function loadGraph() {
try {
const res = await fetch('/api/graph');
const data = await res.json();
- const nodes = [];
- const edges = [];
+ const newNodes = [];
+ const newEdges = [];
const nodeIds = new Set();
for (const [name, entity] of Object.entries(data.entities)) {
- nodes.push({ id: name, label: name, title: entity.observations.join('\n') });
+ newNodes.push({ id: name, label: name, title: entity.observations.join('\n') });
nodeIds.add(name);
}
data.relations.forEach(r => {
if (nodeIds.has(r.from) && nodeIds.has(r.to)) {
- edges.push({ from: r.from, to: r.to, label: r.relationType, arrows: 'to' });
+ newEdges.push({ id: r.from + '-' + r.to + '-' + r.relationType, from: r.from, to: r.to, label: r.relationType, arrows: 'to' });
}
});
- const container = document.getElementById('network-container');
- const graphData = { nodes: new vis.DataSet(nodes), edges: new vis.DataSet(edges) };
- const options = {
- nodes: { shape: 'dot', size: 16, font: { size: 12, color: '#333' }, color: { background: '#3498db', border: '#2980b9' } },
- edges: { color: { color: '#bdc3c7' }, font: { size: 10, align: 'middle' } },
- physics: { barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 } }
- };
+ // Sync nodes
+ const currentNodes = nodesData.getIds();
+ const toRemoveNodes = currentNodes.filter(id => !nodeIds.has(id));
+ nodesData.remove(toRemoveNodes);
+ nodesData.update(newNodes);
+
+ // Sync edges
+ const currentEdges = edgesData.getIds();
+ const newEdgeIds = new Set(newEdges.map(e => e.id));
+ const toRemoveEdges = currentEdges.filter(id => !newEdgeIds.has(id));
+ edgesData.remove(toRemoveEdges);
+ edgesData.update(newEdges);
- if (network) {
- network.setData(graphData);
- } else {
- network = new vis.Network(container, graphData, options);
+ if (!network) {
+ const container = document.getElementById('network-container');
+ const options = {
+ nodes: { shape: 'dot', size: 16, font: { size: 12, color: '#333' }, color: { background: '#3498db', border: '#2980b9' } },
+ edges: { color: { color: '#bdc3c7' }, font: { size: 10, align: 'middle' } },
+ physics: { barnesHut: { gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95 } }
+ };
+ network = new vis.Network(container, { nodes: nodesData, edges: edgesData }, options);
}
- } catch (err) {
- console.error("Failed to load graph", err); document.getElementById("network-container").innerHTML = "
Error loading graph: " + err.message + "
";
- }
- }
+ } catch (err) { console.error("Failed to load graph", err); document.getElementById("network-container").innerHTML = "
Error loading graph: " + err.message + "
"; } }
// Kanban Board Initialization
async function loadTasks() {
@@ -228,3 +234,6 @@
+
+
+