fix: canvas resize issues in graph visualization (#1167)
## Description This PR adds **responsive resizing** to the graph container. The `ForceGraph` component now dynamically adjusts its width and height when the browser window is resized, improving the user experience by removing the need to manually click the "Fit Into View" button. solver issue #1164 ## DCO Affirmation I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin. --- ## ✅ Changes Made (Minimal, Additive Only) ### 1. **Added necessary imports** ```typescript import { MutableRefObject, useEffect, useImperativeHandle, useRef, useState, useCallback } from "react"; // Added useCallback to existing imports ``` ### 2. **Added responsive sizing state and refs** ```typescript // State for tracking container dimensions const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const containerRef = useRef<HTMLDivElement>(null); ``` ### 3. **Added resize handling logic** ```typescript // Handle window resize const handleResize = useCallback(() => { if (containerRef.current) { const { clientWidth, clientHeight } = containerRef.current; setDimensions({ width: clientWidth, height: clientHeight }); // Trigger graph refresh after resize if (graphRef.current) { // Small delay to ensure DOM has updated setTimeout(() => { graphRef.current?.refresh(); }, 100); } } }, []); // Set up resize observer useEffect(() => { // Initial size calculation handleResize(); // ResizeObserver for more precise container size tracking const resizeObserver = new ResizeObserver(() => { handleResize(); }); if (containerRef.current) { resizeObserver.observe(containerRef.current); } return () => { resizeObserver.disconnect(); }; }, [handleResize]); ``` ### 4. **Added container ref to wrapping div** ```tsx <div ref={containerRef} className="w-full h-full" id="graph-container"> {/* Graph component rendered here */} </div> ``` ### 5. **Passed dynamic width/height to ForceGraph** ```tsx <ForceGraph ref={graphRef} width={dimensions.width} height={dimensions.height} dagMode={graphShape as unknown as undefined} // ... rest of props unchanged /> ``` --- you can check this video out: https://github.com/user-attachments/assets/e8e42c99-23e9-4acd-a51b-c59e8bee7094
This commit is contained in:
commit
2182f619df
1 changed files with 45 additions and 2 deletions
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { MutableRefObject, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import { MutableRefObject, useEffect, useImperativeHandle, useRef, useState, useCallback } from "react";
|
||||
import { forceCollide, forceManyBody } from "d3-force-3d";
|
||||
import ForceGraph, { ForceGraphMethods, GraphData, LinkObject, NodeObject } from "react-force-graph-2d";
|
||||
import { GraphControlsAPI } from "./GraphControls";
|
||||
|
|
@ -22,6 +22,45 @@ export default function GraphVisualization({ ref, data, graphControls }: GraphVi
|
|||
const nodeSize = 15;
|
||||
// const addNodeDistanceFromSourceNode = 15;
|
||||
|
||||
// State for tracking container dimensions
|
||||
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Handle resize
|
||||
const handleResize = useCallback(() => {
|
||||
if (containerRef.current) {
|
||||
const { clientWidth, clientHeight } = containerRef.current;
|
||||
setDimensions({ width: clientWidth, height: clientHeight });
|
||||
|
||||
// Trigger graph refresh after resize
|
||||
if (graphRef.current) {
|
||||
// Small delay to ensure DOM has updated
|
||||
setTimeout(() => {
|
||||
graphRef.current?.zoomToFit(1000,50);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Set up resize observer
|
||||
useEffect(() => {
|
||||
// Initial size calculation
|
||||
handleResize();
|
||||
|
||||
// ResizeObserver
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
handleResize();
|
||||
});
|
||||
|
||||
if (containerRef.current) {
|
||||
resizeObserver.observe(containerRef.current);
|
||||
}
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, [handleResize]);
|
||||
|
||||
const handleNodeClick = (node: NodeObject) => {
|
||||
graphControls.current?.setSelectedNode(node);
|
||||
// ref.current?.d3ReheatSimulation()
|
||||
|
|
@ -174,10 +213,12 @@ export default function GraphVisualization({ ref, data, graphControls }: GraphVi
|
|||
}));
|
||||
|
||||
return (
|
||||
<div className="w-full h-full" id="graph-container">
|
||||
<div ref={containerRef} className="w-full h-full" id="graph-container">
|
||||
{(data && typeof window !== "undefined") ? (
|
||||
<ForceGraph
|
||||
ref={graphRef}
|
||||
width={dimensions.width}
|
||||
height={dimensions.height}
|
||||
dagMode={graphShape as unknown as undefined}
|
||||
dagLevelDistance={300}
|
||||
onDagError={handleDagError}
|
||||
|
|
@ -201,6 +242,8 @@ export default function GraphVisualization({ ref, data, graphControls }: GraphVi
|
|||
) : (
|
||||
<ForceGraph
|
||||
ref={graphRef}
|
||||
width={dimensions.width}
|
||||
height={dimensions.height}
|
||||
dagMode={graphShape as unknown as undefined}
|
||||
dagLevelDistance={100}
|
||||
graphData={{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue