yangdx commited on
Commit
418d5a7
·
1 Parent(s): cd4e8de

feat: Improve graph zoom reset to fit all nodes with proper scaling

Browse files

- Add smarter node boundary calculation
- Include padding around graph nodes
- Calculate optimal scale ratio
- Add error handling and null checks
- Animate transition to new zoom level

lightrag_webui/src/components/graph/ZoomControl.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { useCamera } from '@react-sigma/core'
2
  import { useCallback } from 'react'
3
  import Button from '@/components/ui/Button'
4
  import { ZoomInIcon, ZoomOutIcon, FullscreenIcon } from 'lucide-react'
@@ -10,11 +10,71 @@ import { useTranslation } from 'react-i18next';
10
  */
11
  const ZoomControl = () => {
12
  const { zoomIn, zoomOut, reset } = useCamera({ duration: 200, factor: 1.5 })
 
13
  const { t } = useTranslation();
14
 
15
  const handleZoomIn = useCallback(() => zoomIn(), [zoomIn])
16
  const handleZoomOut = useCallback(() => zoomOut(), [zoomOut])
17
- const handleResetZoom = useCallback(() => reset(), [reset])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  return (
20
  <>
 
1
+ import { useCamera, useSigma } from '@react-sigma/core'
2
  import { useCallback } from 'react'
3
  import Button from '@/components/ui/Button'
4
  import { ZoomInIcon, ZoomOutIcon, FullscreenIcon } from 'lucide-react'
 
10
  */
11
  const ZoomControl = () => {
12
  const { zoomIn, zoomOut, reset } = useCamera({ duration: 200, factor: 1.5 })
13
+ const sigma = useSigma()
14
  const { t } = useTranslation();
15
 
16
  const handleZoomIn = useCallback(() => zoomIn(), [zoomIn])
17
  const handleZoomOut = useCallback(() => zoomOut(), [zoomOut])
18
+ const handleResetZoom = useCallback(() => {
19
+ if (!sigma) return
20
+
21
+ try {
22
+ // First clear any custom bounding box and refresh
23
+ sigma.setCustomBBox(null)
24
+ sigma.refresh()
25
+
26
+ // Get graph after refresh
27
+ const graph = sigma.getGraph()
28
+
29
+ // Check if graph has nodes before accessing them
30
+ if (!graph || graph.nodes().length === 0) {
31
+ reset()
32
+ return
33
+ }
34
+
35
+ // Get container dimensions for aspect ratio
36
+ const container = sigma.getContainer()
37
+ const containerWidth = container.offsetWidth
38
+ const containerHeight = container.offsetHeight
39
+ console.log('Container W:', containerWidth, 'H:', containerHeight)
40
+
41
+ // Get all node positions
42
+ const nodePositions = graph.nodes().map(node => ({
43
+ x: graph.getNodeAttribute(node, 'x'),
44
+ y: graph.getNodeAttribute(node, 'y')
45
+ }))
46
+
47
+ // Calculate bounding box
48
+ const minX = Math.min(...nodePositions.map(pos => pos.x))
49
+ const maxX = Math.max(...nodePositions.map(pos => pos.x))
50
+ const minY = Math.min(...nodePositions.map(pos => pos.y))
51
+ const maxY = Math.max(...nodePositions.map(pos => pos.y))
52
+
53
+ // Calculate graph dimensions with minimal padding
54
+ const width = maxX - minX
55
+ const height = maxY - minY
56
+ const padding = Math.max(width, height) * 0.05
57
+ console.log('Graph W:', Math.round(width*100)/100, 'H:', Math.round(height*100)/100)
58
+
59
+ // Calculate base scale
60
+ const scale = Math.min(
61
+ containerWidth / (width + padding * 2),
62
+ containerHeight / (height + padding * 2)
63
+ )
64
+ // Apply scaling factor (just don't know why)
65
+ const ratio = (1 / scale) * 10
66
+
67
+ console.log('scale:', Math.round(scale*100)/100, 'ratio:', Math.round(ratio*100)/100)
68
+
69
+ // Animate to center with calculated ratio
70
+ sigma.getCamera().animate(
71
+ { x: 0.5, y: 0.5, ratio },
72
+ { duration: 500 }
73
+ )
74
+ } catch (error) {
75
+ console.error('Error resetting zoom:', error)
76
+ }
77
+ }, [sigma, reset])
78
 
79
  return (
80
  <>