import React , { FC , useEffect , useState } from "react" ; import { SigmaContainer , ZoomControl , FullScreenControl } from "react-sigma-v2" ; import { omit , mapValues , keyBy , constant } from "lodash" ; import getNodeProgramImage from "sigma/rendering/webgl/programs/node.image" ; import GraphSettingsController from "./GraphSettingsController" ; import GraphEventsController from "./GraphEventsController" ; import GraphDataController from "./GraphDataController" ; import DescriptionPanel from "./DescriptionPanel" ; import { Dataset , FiltersState } from "../types" ; import ClustersPanel from "./ClustersPanel" ; import SearchField from "./SearchField" ; import drawLabel from "../canvas-utils" ; import GraphTitle from "./GraphTitle" ; import TagsPanel from "./TagsPanel" ; import "react-sigma-v2/lib/react-sigma-v2.css" ; import { GrClose } from "react-icons/gr" ; import { BiRadioCircleMarked , BiBookContent } from "react-icons/bi" ; import { BsArrowsFullscreen , BsFullscreenExit , BsZoomIn , BsZoomOut } from "react-icons/bs" ; const Root = ( ) => { const [ showContents , setShowContents ] = useState ( false ) ; const [ dataReady , setDataReady ] = useState ( false ) ; const [ dataset , setDataset ] = useState < Dataset | null > ( null ) ; const [ filtersState , setFiltersState ] = useState < FiltersState > ( { clusters : { } , tags : { } , } ) ; const [ hoveredNode , setHoveredNode ] = useState < string | null > ( null ) ; useEffect ( ( ) => { fetch ( `${ process . env . PUBLIC_URL }/dataset.json` ) . then ( ( res ) => res . json ( ) ) . then ( ( dataset ) => { setDataset ( dataset ) ; setFiltersState ( { clusters : mapValues ( keyBy ( dataset . clusters , "key" ) , constant ( true ) ) , tags : mapValues ( keyBy ( dataset . tags , "key" ) , constant ( true ) ) , } ) ; requestAnimationFrame ( ( ) => setDataReady ( true ) ) ; } ) ; } , [ ] ) ; if ( ! dataset ) return null ; return ( < div id = "app-root" className = { showContents ? "show-contents" : "" } > < SigmaContainer graphOptions = { { type : "directed" } } initialSettings = { { nodeProgramClasses : { image : getNodeProgramImage ( ) } , labelRenderer : drawLabel , defaultNodeType : "image" , defaultEdgeType : "arrow" , labelDensity : 0.07 , labelGridCellSize : 60 , labelRenderedSizeThreshold : 15 , labelFont : "Lato, sans-serif" , zIndex : true , } } className = "react-sigma" > < GraphSettingsController hoveredNode = { hoveredNode } /> < GraphEventsController setHoveredNode = { setHoveredNode } / > < GraphDataController dataset = { dataset } filters = { filtersState } / > { dataReady && ( < > < div className = "controls" > < div className = "ico" > < button type = "button" className = "show-contents" onClick = { ( ) => setShowContents ( true ) } title = "Show caption and description" > < BiBookContent /> < /button> < /div> < FullScreenControl className = "ico" customEnterFullScreen = { < BsArrowsFullscreen / > } customExitFullScreen = { < BsFullscreenExit / > } /> < ZoomControl className = "ico" customZoomIn = { < BsZoomIn / > } customZoomOut = { < BsZoomOut / > } customZoomCenter = { < BiRadioCircleMarked / > } /> < /div> < div className = "contents" > < div className = "ico" > < button type = "button" className = "ico hide-contents" onClick = { ( ) => setShowContents ( false ) } title = "Show caption and description" > < GrClose /> < /button> < /div> < GraphTitle filters = { filtersState } / > < div className = "panels" > < SearchField filters = { filtersState } /> < DescriptionPanel / > < ClustersPanel clusters = { dataset . clusters } filters = { filtersState } setClusters = { ( clusters ) => setFiltersState ( ( filters ) => ( { ... filters , clusters , } ) ) } toggleCluster = { ( cluster ) => { setFiltersState ( ( filters ) => ( { ... filters , clusters : filters . clusters [ cluster ] ? omit ( filters . clusters , cluster ) : { ... filters . clusters , [ cluster ] : true } , } ) ) ; } } /> < TagsPanel tags = { dataset . tags } filters = { filtersState } setTags = { ( tags ) => setFiltersState ( ( filters ) => ( { ... filters , tags , } ) ) } toggleTag = { ( tag ) => { setFiltersState ( ( filters ) => ( { ... filters , tags : filters . tags [ tag ] ? omit ( filters . tags , tag ) : { ... filters . tags , [ tag ] : true } , } ) ) ; } } /> < /div> < /div> < />)} < /SigmaContainer> < /div>); } ; export default Root ;