Optimize node degree and size calculation for expanded graph nodes
This commit is contained in:
@@ -407,10 +407,21 @@ const useLightrangeGraph = () => {
|
|||||||
// Get existing node IDs
|
// Get existing node IDs
|
||||||
const existingNodeIds = new Set(sigmaGraph.nodes());
|
const existingNodeIds = new Set(sigmaGraph.nodes());
|
||||||
|
|
||||||
// STEP 1: Identify nodes and edges to keep
|
// Identify nodes and edges to keep
|
||||||
const nodesToAdd = new Set<string>();
|
const nodesToAdd = new Set<string>();
|
||||||
const edgesToAdd = new Set<string>();
|
const edgesToAdd = new Set<string>();
|
||||||
const nodesWithDiscardedEdges = new Set<string>();
|
|
||||||
|
// Get degree range from existing graph for size calculations
|
||||||
|
const minDegree = 1;
|
||||||
|
let maxDegree = 0;
|
||||||
|
sigmaGraph.forEachNode(node => {
|
||||||
|
const degree = sigmaGraph.degree(node);
|
||||||
|
maxDegree = Math.max(maxDegree, degree);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculate size formula parameters
|
||||||
|
const range = maxDegree - minDegree || 1; // Avoid division by zero
|
||||||
|
const scale = Constants.maxNodeSize - Constants.minNodeSize;
|
||||||
|
|
||||||
// First identify connectable nodes (nodes connected to the expanded node)
|
// First identify connectable nodes (nodes connected to the expanded node)
|
||||||
for (const node of processedNodes) {
|
for (const node of processedNodes) {
|
||||||
@@ -430,69 +441,59 @@ const useLightrangeGraph = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no new connectable nodes found, show toast and return
|
// Calculate node degrees and track discarded edges in one pass
|
||||||
if (nodesToAdd.size === 0) {
|
const nodeDegrees = new Map<string, number>();
|
||||||
toast.info(t('graphPanel.propertiesView.node.noNewNodes'));
|
const nodesWithDiscardedEdges = new Set<string>();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then identify valid edges (edges where both nodes exist in the graph)
|
|
||||||
for (const edge of processedEdges) {
|
for (const edge of processedEdges) {
|
||||||
const sourceExists = existingNodeIds.has(edge.source) || nodesToAdd.has(edge.source);
|
const sourceExists = existingNodeIds.has(edge.source) || nodesToAdd.has(edge.source);
|
||||||
const targetExists = existingNodeIds.has(edge.target) || nodesToAdd.has(edge.target);
|
const targetExists = existingNodeIds.has(edge.target) || nodesToAdd.has(edge.target);
|
||||||
|
|
||||||
if (sourceExists && targetExists) {
|
if (sourceExists && targetExists) {
|
||||||
edgesToAdd.add(edge.id);
|
edgesToAdd.add(edge.id);
|
||||||
} else {
|
// Add degrees for valid edges
|
||||||
// Mark nodes that had edges discarded
|
|
||||||
if (nodesToAdd.has(edge.source)) {
|
if (nodesToAdd.has(edge.source)) {
|
||||||
nodesWithDiscardedEdges.add(edge.source);
|
nodeDegrees.set(edge.source, (nodeDegrees.get(edge.source) || 0) + 1);
|
||||||
}
|
}
|
||||||
if (nodesToAdd.has(edge.target)) {
|
if (nodesToAdd.has(edge.target)) {
|
||||||
|
nodeDegrees.set(edge.target, (nodeDegrees.get(edge.target) || 0) + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Track discarded edges for both new and existing nodes
|
||||||
|
if (sigmaGraph.hasNode(edge.source)) {
|
||||||
|
nodesWithDiscardedEdges.add(edge.source);
|
||||||
|
} else if (nodesToAdd.has(edge.source)) {
|
||||||
|
nodesWithDiscardedEdges.add(edge.source);
|
||||||
|
nodeDegrees.set(edge.source, (nodeDegrees.get(edge.source) || 0) + 1); // +1 for discarded edge
|
||||||
|
}
|
||||||
|
if (sigmaGraph.hasNode(edge.target)) {
|
||||||
nodesWithDiscardedEdges.add(edge.target);
|
nodesWithDiscardedEdges.add(edge.target);
|
||||||
|
} else if (nodesToAdd.has(edge.target)) {
|
||||||
|
nodesWithDiscardedEdges.add(edge.target);
|
||||||
|
nodeDegrees.set(edge.target, (nodeDegrees.get(edge.target) || 0) + 1); // +1 for discarded edge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 2: Calculate node degrees and sizes
|
// If no new connectable nodes found, show toast and return
|
||||||
const nodeDegrees = new Map<string, number>();
|
if (nodesToAdd.size === 0) {
|
||||||
|
toast.info(t('graphPanel.propertiesView.node.noNewNodes'));
|
||||||
// Calculate degrees from kept edges
|
return;
|
||||||
for (const edgeId of edgesToAdd) {
|
|
||||||
const edge = processedEdges.find(e => e.id === edgeId)!;
|
|
||||||
nodeDegrees.set(edge.source, (nodeDegrees.get(edge.source) || 0) + 1);
|
|
||||||
nodeDegrees.set(edge.target, (nodeDegrees.get(edge.target) || 0) + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add +1 to degree for nodes that had edges discarded
|
|
||||||
for (const nodeId of nodesWithDiscardedEdges) {
|
|
||||||
nodeDegrees.set(nodeId, (nodeDegrees.get(nodeId) || 0) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get degree range from existing graph for size calculations
|
|
||||||
const minDegree = 1;
|
|
||||||
let maxDegree = 0;
|
|
||||||
sigmaGraph.forEachNode(node => {
|
|
||||||
const degree = sigmaGraph.degree(node);
|
|
||||||
maxDegree = Math.max(maxDegree, degree);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update maxDegree with new node degrees
|
// Update maxDegree with new node degrees
|
||||||
for (const [, degree] of nodeDegrees.entries()) {
|
for (const [, degree] of nodeDegrees.entries()) {
|
||||||
maxDegree = Math.max(maxDegree, degree);
|
maxDegree = Math.max(maxDegree, degree);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate size formula parameters
|
// SAdd nodes and edges to the graph
|
||||||
const range = maxDegree - minDegree || 1; // Avoid division by zero
|
|
||||||
const scale = Constants.maxNodeSize - Constants.minNodeSize;
|
|
||||||
|
|
||||||
// STEP 3: Add nodes and edges to the graph
|
|
||||||
// Calculate camera ratio and spread factor once before the loop
|
// Calculate camera ratio and spread factor once before the loop
|
||||||
const cameraRatio = useGraphStore.getState().sigmaInstance?.getCamera().ratio || 1;
|
const cameraRatio = useGraphStore.getState().sigmaInstance?.getCamera().ratio || 1;
|
||||||
const spreadFactor = Math.max(
|
const spreadFactor = Math.max(
|
||||||
Math.sqrt(nodeToExpand.size) * 4, // Base on node size
|
Math.sqrt(nodeToExpand.size) * 4, // Base on node size
|
||||||
Math.sqrt(nodesToAdd.size) * 3 // Scale with number of nodes
|
Math.sqrt(nodesToAdd.size) * 3 // Scale with number of nodes
|
||||||
) / cameraRatio; // Adjust for zoom level
|
) / cameraRatio; // Adjust for zoom level
|
||||||
|
seedrandom(Date.now().toString(), { global: true });
|
||||||
const randomAngle = Math.random() * 2 * Math.PI
|
const randomAngle = Math.random() * 2 * Math.PI
|
||||||
|
|
||||||
console.log('nodeSize:', nodeToExpand.size, 'nodesToAdd:', nodesToAdd.size);
|
console.log('nodeSize:', nodeToExpand.size, 'nodesToAdd:', nodesToAdd.size);
|
||||||
@@ -575,29 +576,25 @@ const useLightrangeGraph = () => {
|
|||||||
searchCache.graph = null;
|
searchCache.graph = null;
|
||||||
searchCache.searchEngine = null;
|
searchCache.searchEngine = null;
|
||||||
|
|
||||||
// STEP 4: Update the expanded node's size
|
// Update sizes for all nodes with discarded edges
|
||||||
if (sigmaGraph.hasNode(nodeId)) {
|
for (const nodeId of nodesWithDiscardedEdges) {
|
||||||
// Get the new degree of the expanded node
|
if (sigmaGraph.hasNode(nodeId)) {
|
||||||
let expandedNodeDegree = sigmaGraph.degree(nodeId);
|
// Get the new degree of the node
|
||||||
|
let newDegree = sigmaGraph.degree(nodeId);
|
||||||
|
newDegree += 1; // Add +1 for discarded edges
|
||||||
|
|
||||||
// Check if the expanded node had any discarded edges
|
// Calculate new size for the node
|
||||||
if (nodesWithDiscardedEdges.has(nodeId)) {
|
const newSize = Math.round(
|
||||||
expandedNodeDegree += 1; // Add +1 for discarded edges
|
Constants.minNodeSize + scale * Math.pow((newDegree - minDegree) / range, 0.5)
|
||||||
}
|
);
|
||||||
|
|
||||||
// Calculate new size for the expanded node
|
// Get current size
|
||||||
const newSize = Math.round(
|
const currentSize = sigmaGraph.getNodeAttribute(nodeId, 'size');
|
||||||
Constants.minNodeSize + scale * Math.pow((expandedNodeDegree - minDegree) / range, 0.5)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the size in sigma graph
|
// Only update if new size is larger
|
||||||
sigmaGraph.setNodeAttribute(nodeId, 'size', newSize);
|
if (newSize > currentSize) {
|
||||||
|
sigmaGraph.setNodeAttribute(nodeId, 'size', newSize);
|
||||||
// Update the size in raw graph
|
}
|
||||||
const expandedNodeIndex = rawGraph.nodeIdMap[nodeId];
|
|
||||||
if (expandedNodeIndex !== undefined) {
|
|
||||||
rawGraph.nodes[expandedNodeIndex].size = newSize;
|
|
||||||
rawGraph.nodes[expandedNodeIndex].degree = expandedNodeDegree;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user