import React , { useState , useEffect } from 'react' ; import * as d3 from 'd3' ; import makeRelationshipLinks from '../../utils/makeRelationshipLinks' ; import { useAppSelector } from '../../state-management/hooks' ; import { filteredSnapshot } from '../../../types' ; const AtomNetworkVisual = ( ) => { const snapshotHistory = useAppSelector ( state => state . snapshot . snapshotHistory ) ; const renderIndex = useAppSelector ( state => state . snapshot . renderIndex ) ; const filteredCurSnap = snapshotHistory [ renderIndex ] . filteredSnapshot ; const searchValue = useAppSelector ( state => state . atomNetwork . searchValue ) ; useEffect ( ( ) => { const newFilteredCurSnap = { } ; const filter = ( filteredCurSnap ) => { for ( let key in filteredCurSnap ) { if ( key . toLowerCase ( ) . includes ( searchValue . toLowerCase ( ) ) ) { newFilteredCurSnap [ key ] = filteredCurSnap [ key ] ; grabNodeToNodeSubscriptions ( newFilteredCurSnap [ key ] ) ; grabNodeDeps ( newFilteredCurSnap [ key ] ) ; } } } ; const grabNodeToNodeSubscriptions = ( node ) => { let nodeSubscriptionLength = node . nodeToNodeSubscriptions . length ; if ( nodeSubscriptionLength > 0 ) { for ( let i = 0 ; i < nodeSubscriptionLength ; i += 1 ) { let currSN = node . nodeToNodeSubscriptions [ i ] ; newFilteredCurSnap [ currSN ] = filteredCurSnap [ currSN ] ; grabNodeToNodeSubscriptions ( filteredCurSnap [ currSN ] ) ; } } } ; const grabNodeDeps = ( node ) => { let nodeDepsLength = node . nodeDeps . length ; if ( nodeDepsLength > 0 ) { for ( let i = 0 ; i < nodeDepsLength ; i += 1 ) { let currDepNode = node . nodeDeps [ i ] ; newFilteredCurSnap [ currDepNode ] = filteredCurSnap [ currDepNode ] ; grabNodeDeps ( filteredCurSnap [ currDepNode ] ) ; } } } ; filter ( filteredCurSnap ) ; document . getElementById ( 'networkCanvas' ) . innerHTML = '' ; let edgepaths ; let edgelabels ; const networkContainer = document . querySelector ( '.networkContainer' ) ; const width = networkContainer . clientWidth ; const height = networkContainer . clientHeight ; let snap = searchValue ? newFilteredCurSnap : filteredCurSnap ; const networkData = makeRelationshipLinks ( snap ) ; const chart = ( data ) => { const links = data . links . map ( ( d ) => Object . create ( d ) ) ; const nodes = data . nodes . map ( ( d ) => { return Object . create ( d ) ; } ) ; const simulation = d3 . forceSimulation ( nodes ) . force ( 'link' , d3 . forceLink ( links ) . id ( ( d ) => d . id ) ) . force ( 'charge' , d3 . forceManyBody ( ) ) . force ( 'x' , d3 . forceX ( ) ) . force ( 'y' , d3 . forceY ( ) ) ; const svg = d3 . select ( '#networkCanvas' ) . attr ( 'viewBox' , [ - width / 2 , - height / 2 , width , height ] ) ; const link = svg . append ( 'g' ) . attr ( 'stroke' , '#999' ) . attr ( 'stroke-opacity' , 0.6 ) . selectAll ( 'line' ) . data ( links ) . join ( 'line' ) . attr ( 'stroke-width' , ( d ) => Math . sqrt ( d . value ) ) ; const node = svg . append ( 'g' ) . attr ( 'stroke' , '#fff' ) . attr ( 'stroke-width' , 1.5 ) . selectAll ( 'circle' ) . data ( nodes ) . join ( 'circle' ) . attr ( 'r' , 5 ) . style ( 'fill' , function ( d , i ) { return d . name === 'Atom' ? '#9580FF' : '#FF80BF' ; } ) ; node . append ( 'title' ) . attr ( 'dx' , 12 ) . attr ( 'dy' , '.35em' ) . text ( ( d ) => d . label ) . attr ( 'stroke' , 'white' ) . attr ( 'stroke-width' , 3 ) ; node . append ( 'text' ) . attr ( 'dx' , 12 ) . attr ( 'dy' , '.35em' ) . text ( function ( d ) { return d . name ; } ) ; simulation . on ( 'tick' , ( ) => { link . attr ( 'x1' , ( d ) => d . source . x ) . attr ( 'y1' , ( d ) => d . source . y ) . attr ( 'x2' , ( d ) => d . target . x ) . attr ( 'y2' , ( d ) => d . target . y ) ; node . attr ( 'cx' , ( d ) => d . x ) . attr ( 'cy' , ( d ) => d . y ) ; } ) ; simulation . alpha ( 1 ) . restart ( ) ; return svg . node ( ) ; } ; chart ( networkData ) ; } ) ; return ( < div className = "Network" > < svg data - testid = "networkCanvas" id = "networkCanvas" > < /svg> < /div>); } ; export default AtomNetworkVisual ;