File size: 6,168 Bytes
03cc6ab |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
import { useGraphStore } from '@/stores/graph'
/**
* Interface for tracking edges that need updating when a node ID changes
*/
interface EdgeToUpdate {
originalDynamicId: string
newEdgeId: string
edgeIndex: number
}
/**
* Update node in the graph visualization
* Handles both property updates and entity ID changes
*
* @param nodeId - ID of the node to update
* @param propertyName - Name of the property being updated
* @param newValue - New value for the property
*/
export const updateGraphNode = async (nodeId: string, propertyName: string, newValue: string) => {
// Get graph state from store
const sigmaGraph = useGraphStore.getState().sigmaGraph
const rawGraph = useGraphStore.getState().rawGraph
// Validate graph state
if (!sigmaGraph || !rawGraph || !sigmaGraph.hasNode(String(nodeId))) {
return
}
try {
const nodeAttributes = sigmaGraph.getNodeAttributes(String(nodeId))
// Special handling for entity_id changes (node renaming)
if (propertyName === 'entity_id') {
// Create new node with updated ID but same attributes
sigmaGraph.addNode(newValue, { ...nodeAttributes, label: newValue })
const edgesToUpdate: EdgeToUpdate[] = []
// Process all edges connected to this node
sigmaGraph.forEachEdge(String(nodeId), (edge, attributes, source, target) => {
const otherNode = source === String(nodeId) ? target : source
const isOutgoing = source === String(nodeId)
// Get original edge dynamic ID for later reference
const originalEdgeDynamicId = edge
const edgeIndexInRawGraph = rawGraph.edgeDynamicIdMap[originalEdgeDynamicId]
// Create new edge with updated node reference
const newEdgeId = sigmaGraph.addEdge(
isOutgoing ? newValue : otherNode,
isOutgoing ? otherNode : newValue,
attributes
)
// Track edges that need updating in the raw graph
if (edgeIndexInRawGraph !== undefined) {
edgesToUpdate.push({
originalDynamicId: originalEdgeDynamicId,
newEdgeId: newEdgeId,
edgeIndex: edgeIndexInRawGraph
})
}
// Remove the old edge
sigmaGraph.dropEdge(edge)
})
// Remove the old node after all edges are processed
sigmaGraph.dropNode(String(nodeId))
// Update node reference in raw graph data
const nodeIndex = rawGraph.nodeIdMap[String(nodeId)]
if (nodeIndex !== undefined) {
rawGraph.nodes[nodeIndex].id = newValue
rawGraph.nodes[nodeIndex].properties.entity_id = newValue
delete rawGraph.nodeIdMap[String(nodeId)]
rawGraph.nodeIdMap[newValue] = nodeIndex
}
// Update all edge references in raw graph data
edgesToUpdate.forEach(({ originalDynamicId, newEdgeId, edgeIndex }) => {
if (rawGraph.edges[edgeIndex]) {
// Update source/target references
if (rawGraph.edges[edgeIndex].source === String(nodeId)) {
rawGraph.edges[edgeIndex].source = newValue
}
if (rawGraph.edges[edgeIndex].target === String(nodeId)) {
rawGraph.edges[edgeIndex].target = newValue
}
// Update dynamic ID mappings
rawGraph.edges[edgeIndex].dynamicId = newEdgeId
delete rawGraph.edgeDynamicIdMap[originalDynamicId]
rawGraph.edgeDynamicIdMap[newEdgeId] = edgeIndex
}
})
// Update selected node in store
useGraphStore.getState().setSelectedNode(newValue)
} else {
// For other properties, just update the property in raw graph
const nodeIndex = rawGraph.nodeIdMap[String(nodeId)]
if (nodeIndex !== undefined) {
rawGraph.nodes[nodeIndex].properties[propertyName] = newValue
}
}
} catch (error) {
console.error('Error updating node in graph:', error)
throw new Error('Failed to update node in graph')
}
}
/**
* Update edge in the graph visualization
*
* @param sourceId - ID of the source node
* @param targetId - ID of the target node
* @param propertyName - Name of the property being updated
* @param newValue - New value for the property
*/
export const updateGraphEdge = async (sourceId: string, targetId: string, propertyName: string, newValue: string) => {
// Get graph state from store
const sigmaGraph = useGraphStore.getState().sigmaGraph
const rawGraph = useGraphStore.getState().rawGraph
// Validate graph state
if (!sigmaGraph || !rawGraph) {
return
}
try {
// Find the edge between source and target nodes
const allEdges = sigmaGraph.edges()
let keyToUse = null
for (const edge of allEdges) {
const edgeSource = sigmaGraph.source(edge)
const edgeTarget = sigmaGraph.target(edge)
// Match edge in either direction (undirected graph support)
if ((edgeSource === sourceId && edgeTarget === targetId) ||
(edgeSource === targetId && edgeTarget === sourceId)) {
keyToUse = edge
break
}
}
if (keyToUse !== null) {
// Special handling for keywords property (updates edge label)
if(propertyName === 'keywords') {
sigmaGraph.setEdgeAttribute(keyToUse, 'label', newValue)
} else {
sigmaGraph.setEdgeAttribute(keyToUse, propertyName, newValue)
}
// Update edge in raw graph data using dynamic ID mapping
if (keyToUse && rawGraph.edgeDynamicIdMap[keyToUse] !== undefined) {
const edgeIndex = rawGraph.edgeDynamicIdMap[keyToUse]
if (rawGraph.edges[edgeIndex]) {
rawGraph.edges[edgeIndex].properties[propertyName] = newValue
}
} else if (keyToUse !== null) {
// Fallback: try to find edge by key in edge ID map
const edgeIndexByKey = rawGraph.edgeIdMap[keyToUse]
if (edgeIndexByKey !== undefined && rawGraph.edges[edgeIndexByKey]) {
rawGraph.edges[edgeIndexByKey].properties[propertyName] = newValue
}
}
}
} catch (error) {
console.error(`Error updating edge ${sourceId}->${targetId} in graph:`, error)
throw new Error('Failed to update edge in graph')
}
}
|