import { useEffect, useState, useCallback, useMemo } from 'react' // import { MiniMap } from '@react-sigma/minimap' import { SigmaContainer, useRegisterEvents, useSigma } from '@react-sigma/core' import { Settings as SigmaSettings } from 'sigma/settings' import { GraphSearchOption, OptionItem } from '@react-sigma/graph-search' import { EdgeArrowProgram, NodePointProgram, NodeCircleProgram } from 'sigma/rendering' import { NodeBorderProgram } from '@sigma/node-border' import EdgeCurveProgram, { EdgeCurvedArrowProgram } from '@sigma/edge-curve' import FocusOnNode from '@/components/FocusOnNode' import LayoutsControl from '@/components/LayoutsControl' import GraphControl from '@/components/GraphControl' import ThemeToggle from '@/components/ThemeToggle' import ZoomControl from '@/components/ZoomControl' import FullScreenControl from '@/components/FullScreenControl' import Settings from '@/components/Settings' import GraphSearch from '@/components/GraphSearch' import GraphLabels from '@/components/GraphLabels' import PropertiesView from '@/components/PropertiesView' import { useSettingsStore } from '@/stores/settings' import { useGraphStore } from '@/stores/graph' import '@react-sigma/core/lib/style.css' import '@react-sigma/graph-search/lib/style.css' // Sigma settings const defaultSigmaSettings: Partial = { allowInvalidContainer: true, defaultNodeType: 'default', defaultEdgeType: 'curvedArrow', renderEdgeLabels: false, edgeProgramClasses: { arrow: EdgeArrowProgram, curvedArrow: EdgeCurvedArrowProgram, curvedNoArrow: EdgeCurveProgram }, nodeProgramClasses: { default: NodeBorderProgram, circel: NodeCircleProgram, point: NodePointProgram }, labelGridCellSize: 60, labelRenderedSizeThreshold: 12, enableEdgeEvents: true, labelColor: { color: '#000', attribute: 'labelColor' }, edgeLabelColor: { color: '#000', attribute: 'labelColor' }, edgeLabelSize: 8, labelSize: 12 // minEdgeThickness: 2 // labelFont: 'Lato, sans-serif' } const GraphEvents = () => { const registerEvents = useRegisterEvents() const sigma = useSigma() const [draggedNode, setDraggedNode] = useState(null) useEffect(() => { // Register the events registerEvents({ downNode: (e) => { setDraggedNode(e.node) sigma.getGraph().setNodeAttribute(e.node, 'highlighted', true) }, // On mouse move, if the drag mode is enabled, we change the position of the draggedNode mousemovebody: (e) => { if (!draggedNode) return // Get new position of node const pos = sigma.viewportToGraph(e) sigma.getGraph().setNodeAttribute(draggedNode, 'x', pos.x) sigma.getGraph().setNodeAttribute(draggedNode, 'y', pos.y) // Prevent sigma to move camera: e.preventSigmaDefault() e.original.preventDefault() e.original.stopPropagation() }, // On mouse up, we reset the autoscale and the dragging mode mouseup: () => { if (draggedNode) { setDraggedNode(null) sigma.getGraph().removeNodeAttribute(draggedNode, 'highlighted') } }, // Disable the autoscale at the first down interaction mousedown: () => { if (!sigma.getCustomBBox()) sigma.setCustomBBox(sigma.getBBox()) } }) }, [registerEvents, sigma, draggedNode]) return null } const GraphViewer = () => { const [sigmaSettings, setSigmaSettings] = useState(defaultSigmaSettings) const selectedNode = useGraphStore.use.selectedNode() const focusedNode = useGraphStore.use.focusedNode() const moveToSelectedNode = useGraphStore.use.moveToSelectedNode() const showPropertyPanel = useSettingsStore.use.showPropertyPanel() const showNodeSearchBar = useSettingsStore.use.showNodeSearchBar() const renderLabels = useSettingsStore.use.showNodeLabel() const enableEdgeEvents = useSettingsStore.use.enableEdgeEvents() const enableNodeDrag = useSettingsStore.use.enableNodeDrag() const renderEdgeLabels = useSettingsStore.use.showEdgeLabel() useEffect(() => { setSigmaSettings({ ...defaultSigmaSettings, enableEdgeEvents, renderEdgeLabels, renderLabels }) }, [renderLabels, enableEdgeEvents, renderEdgeLabels]) const onSearchFocus = useCallback((value: GraphSearchOption | null) => { if (value === null) useGraphStore.getState().setFocusedNode(null) else if (value.type === 'nodes') useGraphStore.getState().setFocusedNode(value.id) }, []) const onSearchSelect = useCallback((value: GraphSearchOption | null) => { if (value === null) { useGraphStore.getState().setSelectedNode(null) } else if (value.type === 'nodes') { useGraphStore.getState().setSelectedNode(value.id, true) } }, []) const autoFocusedNode = useMemo(() => focusedNode ?? selectedNode, [focusedNode, selectedNode]) const searchInitSelectedNode = useMemo( (): OptionItem | null => (selectedNode ? { type: 'nodes', id: selectedNode } : null), [selectedNode] ) return ( {enableNodeDrag && }
{showNodeSearchBar && ( )}
{showPropertyPanel && (
)} {/*
*/}
) } export default GraphViewer