import { useEffect, useState, useRef, useCallback } from "react"; import ForceGraph3D from "react-force-graph-3d"; import graphData from "../data.json"; import SpriteText from "https://esm.sh/three-spritetext"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faInfoCircle, faExternalLinkAlt, faChevronLeft, faChevronRight } from "@fortawesome/free-solid-svg-icons"; export default function GraphComponent({ selectedCategory }) { const fgRef = useRef(); const [selectedNode, setSelectedNode] = useState(null); const [graphDataState, setGraphDataState] = useState({ nodes: [], links: [] }); const [imageIndex, setImageIndex] = useState(0); // State to track current image in the carousel // Set distance from camera orbit const distance = 400; const speed = 0.3; useEffect(() => { // Clone the original graph data to avoid modifying it directly const updatedGraphData = { nodes: graphData.nodes.map(node => ({ ...node, visible: !selectedCategory || node.category === selectedCategory // Hide nodes not in selected category })), links: graphData.links.map(link => ({ ...link, visible: (!selectedCategory || (graphData.nodes.find(n => n.id === link.source)?.category === selectedCategory && graphData.nodes.find(n => n.id === link.target)?.category === selectedCategory)) // Hide links if either connected node is hidden })) }; setGraphDataState(updatedGraphData); // Camera orbit logic const cameraOrbit = () => { let angle = 0; fgRef.current.cameraPosition({ z: distance }); // Set interval for camera orbit effect const intervalId = setInterval(() => { fgRef.current.cameraPosition({ x: distance * Math.sin(angle), z: distance * Math.cos(angle) }); angle += (Math.PI / 300) * speed; }, 10); // Clear up the interval when the component is unmounted return () => clearInterval(intervalId); }; // Call camera orbit after the graph is set const cleanupCameraOrbit = cameraOrbit(); return cleanupCameraOrbit; }, [selectedCategory]); const handleNodeClick = useCallback((node) => { setSelectedNode(node); setImageIndex(0); // Reset the image index when a new node is clicked }, []); const handleBackgroundClick = useCallback(() => { setSelectedNode(null); }, []); // Carousel navigation functions const prevImage = () => { if (selectedNode && selectedNode.image && Array.isArray(selectedNode.image)) { setImageIndex((prevIndex) => (prevIndex > 0 ? prevIndex - 1 : selectedNode.image.length - 1)); } }; const nextImage = () => { if (selectedNode && selectedNode.image && Array.isArray(selectedNode.image)) { setImageIndex((prevIndex) => (prevIndex < selectedNode.image.length - 1 ? prevIndex + 1 : 0)); } }; return (
{selectedNode.description}