-
-
-
Stale
+
+
IncrementalGraph Visualization
+
+
-
-
-
-
-
-
-
-
-
+ // Helper function to remove a node by ID
+ function removeNode(id) {
+ nodes.remove({ id });
+ }
-
\ No newline at end of file
+ // Helper function to add or update edges in the graph
+ const edgeProps = { arrows: "to" };
+ function updateEdge(id, from, to, variant) {
+ const prop =
+ variant === "normal"
+ ? { id, from, to, arrows: "to" }
+ : variant === "client"
+ ? { id, from, to, arrows: "to,from", color: "#ffffff99", width: 2, label: "[use client]" }
+ : { id, from, to };
+ if (edges.get(id)) {
+ edges.update(prop);
+ } else {
+ edges.add(prop);
+ }
+ }
+
+ // Helper to remove all edges of a node
+ function removeEdges(nodeId) {
+ const edgesToRemove = edges.get({
+ filter: edge => edge.from === nodeId || edge.to === nodeId,
+ });
+ edges.remove(edgesToRemove.map(e => e.id));
+ }
+
+ // Function to update the entire graph when new data is received
+ function updateGraph() {
+ const newEdgeIds = new Set(); // Track new edges
+ const newNodeIds = new Set(); // Track new nodes
+
+ const boundaries = new Map();
+
+ // Update server files
+ serverFiles.forEach((file, index) => {
+ const id = `S_${file.name}`;
+ if (file.deleted) {
+ removeNode(id);
+ removeEdges(id);
+ } else {
+ updateNode(id, file, "server");
+ }
+
+ if (file.isBoundary) {
+ boundaries.set(file.name, { server: index, client: -1 });
+ }
+ newNodeIds.add(id); // Track this node
+ });
+
+ // Update client files
+ clientFiles.forEach((file, index) => {
+ const id = `C_${file.name}`;
+ if (file.deleted) {
+ removeNode(id);
+ removeEdges(id);
+ return;
+ }
+ updateNode(id, file, "client");
+ const b = boundaries.get(file.name);
+ if (b) {
+ b.client = index;
+ }
+ newNodeIds.add(id); // Track this node
+ });
+
+ // Update client edges
+ clientEdges.forEach((edge, index) => {
+ const id = `C_edge_${index}`;
+ updateEdge(id, `C_${clientFiles[edge.from].name}`, `C_${clientFiles[edge.to].name}`, "normal");
+ newEdgeIds.add(id); // Track this edge
+ });
+
+ // Update server edges
+ serverEdges.forEach((edge, index) => {
+ const id = `S_edge_${index}`;
+ updateEdge(id, `S_${serverFiles[edge.from].name}`, `S_${serverFiles[edge.to].name}`, "normal");
+ newEdgeIds.add(id); // Track this edge
+ });
+
+ boundaries.forEach(({ server, client }) => {
+ if (client === -1) return;
+ const id = `S_edge_bound_${server}_${client}`;
+ updateEdge(id, `S_${serverFiles[server].name}`, `C_${clientFiles[client].name}`, "client");
+ newEdgeIds.add(id); // Track this edge
+ });
+
+ // Remove edges that are no longer present
+ currentEdgeIds.forEach(id => {
+ if (!newEdgeIds.has(id)) {
+ edges.remove(id);
+ }
+ });
+
+ // Remove nodes that are no longer present
+ currentNodeIds.forEach(id => {
+ if (!newNodeIds.has(id)) {
+ nodes.remove(id);
+ }
+ });
+
+ // Update the currentEdgeIds set to the new one
+ currentEdgeIds = newEdgeIds;
+ currentNodeIds = newNodeIds;
+
+ if (isFirst) {
+ network.stabilize();
+ isFirst = false;
+ }
+
+ document.getElementById("stat").innerText =
+ `(server: ${serverFiles.length} files, ${serverEdges.length} edges; client: ${clientFiles.length} files, ${clientEdges.length} edges; ${boundaries.size} boundaries)`;
+ }
+
+