import { useLoadGraph, useRegisterEvents, useSetSettings, useSigma } from '@react-sigma/core' // import { useLayoutCircular } from '@react-sigma/layout-circular' import { useLayoutForceAtlas2 } from '@react-sigma/layout-forceatlas2' import { useEffect } from 'react' // import useRandomGraph, { EdgeType, NodeType } from '@/hooks/useRandomGraph' import useLightragGraph, { EdgeType, NodeType } from '@/hooks/useLightragGraph' import useTheme from '@/hooks/useTheme' import * as Constants from '@/lib/constants' import { useSettingsStore } from '@/stores/settings' import { useGraphStore } from '@/stores/graph' const isButtonPressed = (ev: MouseEvent | TouchEvent) => { if (ev.type.startsWith('mouse')) { if ((ev as MouseEvent).buttons !== 0) { return true } } return false } const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean }) => { const { lightrageGraph } = useLightragGraph() const sigma = useSigma() const registerEvents = useRegisterEvents() const setSettings = useSetSettings() const loadGraph = useLoadGraph() const { assign: assignLayout } = useLayoutForceAtlas2({ iterations: 20 }) const { theme } = useTheme() const hideUnselectedEdges = useSettingsStore.use.enableHideUnselectedEdges() const selectedNode = useGraphStore.use.selectedNode() const focusedNode = useGraphStore.use.focusedNode() const selectedEdge = useGraphStore.use.selectedEdge() const focusedEdge = useGraphStore.use.focusedEdge() /** * When component mount * => load the graph */ useEffect(() => { // Create & load the graph const graph = lightrageGraph() loadGraph(graph) if (!(graph as any).__force_applied) { assignLayout() Object.assign(graph, { __force_applied: true }) } const { setFocusedNode, setSelectedNode, setFocusedEdge, setSelectedEdge, clearSelection } = useGraphStore.getState() // Register the events registerEvents({ enterNode: (event) => { if (!isButtonPressed(event.event.original)) { setFocusedNode(event.node) } }, leaveNode: (event) => { if (!isButtonPressed(event.event.original)) { setFocusedNode(null) } }, clickNode: (event) => { setSelectedNode(event.node) setSelectedEdge(null) }, clickEdge: (event) => { setSelectedEdge(event.edge) setSelectedNode(null) }, enterEdge: (event) => { if (!isButtonPressed(event.event.original)) { setFocusedEdge(event.edge) } }, leaveEdge: (event) => { if (!isButtonPressed(event.event.original)) { setFocusedEdge(null) } }, clickStage: () => clearSelection() }) }, [assignLayout, loadGraph, registerEvents, lightrageGraph]) /** * When component mount or hovered node change * => Setting the sigma reducers */ useEffect(() => { const isDarkTheme = theme === 'dark' const labelColor = isDarkTheme ? Constants.labelColorDarkTheme : undefined const edgeColor = isDarkTheme ? Constants.edgeColorDarkTheme : undefined setSettings({ nodeReducer: (node, data) => { const graph = sigma.getGraph() const newData: NodeType & { labelColor?: string borderColor?: string } = { ...data, highlighted: data.highlighted || false, labelColor } if (!disableHoverEffect) { newData.highlighted = false const _focusedNode = focusedNode || selectedNode const _focusedEdge = focusedEdge || selectedEdge if (_focusedNode) { if (node === _focusedNode || graph.neighbors(_focusedNode).includes(node)) { newData.highlighted = true if (node === selectedNode) { newData.borderColor = Constants.nodeBorderColorSelected } } } else if (_focusedEdge) { if (graph.extremities(_focusedEdge).includes(node)) { newData.highlighted = true newData.size = 3 } } else { return newData } if (newData.highlighted) { if (isDarkTheme) { newData.labelColor = Constants.LabelColorHighlightedDarkTheme } } else { newData.color = Constants.nodeColorDisabled } } return newData }, edgeReducer: (edge, data) => { const graph = sigma.getGraph() const newData = { ...data, hidden: false, labelColor, color: edgeColor } if (!disableHoverEffect) { const _focusedNode = focusedNode || selectedNode if (_focusedNode) { if (hideUnselectedEdges) { if (!graph.extremities(edge).includes(_focusedNode)) { newData.hidden = true } } else { if (graph.extremities(edge).includes(_focusedNode)) { newData.color = Constants.edgeColorHighlighted } } } else { if (focusedEdge || selectedEdge) { if (edge === selectedEdge) { newData.color = Constants.edgeColorSelected } else if (edge === focusedEdge) { newData.color = Constants.edgeColorHighlighted } else if (hideUnselectedEdges) { newData.hidden = true } } } } return newData } }) }, [ selectedNode, focusedNode, selectedEdge, focusedEdge, setSettings, sigma, disableHoverEffect, theme, hideUnselectedEdges ]) return null } export default GraphControl