1- import React , { useState } from 'react' ;
1+ import React , { useState , useRef } from 'react' ;
22import { Group } from '@visx/group' ;
33import { hierarchy , Tree } from '@visx/hierarchy' ;
44import { LinearGradient } from '@visx/gradient' ;
55import { pointRadial } from 'd3-shape' ;
66import LinkControls from './axLinkControls' ;
77import getLinkComponent from './getAxLinkComponents' ;
8+ import { useTooltip , useTooltipInPortal , defaultStyles } from '@visx/tooltip' ;
9+ import ToolTipDataDisplay from '../ComponentMap/ToolTipDataDisplay' ;
10+ import { ToolTipStyles } from '../../../FrontendTypes' ;
11+ import { localPoint } from '@visx/event' ;
812
13+ //still using below themes?
914const theme = {
1015 scheme : 'monokai' ,
1116 author : 'wimer hazenberg (http://www.monokai.nl)' ,
@@ -153,6 +158,50 @@ export default function AxTree(props, {
153158 height : totalHeight ,
154159 margin = defaultMargin ,
155160} : LinkTypesProps ) {
161+
162+
163+ const toolTipTimeoutID = useRef ( null ) ; //useRef stores stateful data that’s not needed for rendering.
164+ const {
165+ tooltipData, // value/data that tooltip may need to render
166+ tooltipLeft, // number used for tooltip positioning
167+ tooltipTop, // number used for tooltip positioning
168+ tooltipOpen, // boolean whether the tooltip state is open or closed
169+ showTooltip, // function to set tooltip state
170+ hideTooltip, // function to close a tooltip
171+ } = useTooltip ( ) ; // returns an object with several properties that you can use to manage the tooltip state of your component
172+ console . log ( 'tool tip data: ' , tooltipData ) ;
173+ // let nameVal = JSON.stringify(tooltipData)
174+ // console.log('nameVal', nameVal);
175+ const {
176+ containerRef, // Access to the container's bounding box. This will be empty on first render.
177+ TooltipInPortal, // TooltipWithBounds in a Portal, outside of your component DOM tree
178+ } = useTooltipInPortal ( {
179+ // Visx hook
180+ detectBounds : true , // use TooltipWithBounds
181+ scroll : true , // when tooltip containers are scrolled, this will correctly update the Tooltip position
182+ } ) ;
183+
184+ const tooltipStyles : ToolTipStyles = {
185+ ...defaultStyles ,
186+ minWidth : 60 ,
187+ maxWidth : 300 ,
188+ backgroundColor : 'rgb(15,15,15)' ,
189+ color : 'white' ,
190+ fontSize : '16px' ,
191+ lineHeight : '18px' ,
192+ fontFamily : 'Roboto' ,
193+ zIndex : 100 ,
194+ pointerEvents : 'all !important' ,
195+ } ;
196+
197+ const formatRenderTime = ( time : number ) : string => {
198+ if ( ! time ) return 'No time information' ;
199+ const renderTime = time . toFixed ( 3 ) ;
200+ return `${ renderTime } ms ` ;
201+ } ;
202+
203+
204+
156205 const [ layout , setLayout ] = useState ( 'cartesian' ) ;
157206 const [ orientation , setOrientation ] = useState ( 'horizontal' ) ;
158207 const [ linkType , setLinkType ] = useState ( 'diagonal' ) ;
@@ -284,7 +333,9 @@ export default function AxTree(props, {
284333 />
285334 < svg width = { totalWidth } height = { totalHeight + 0 } >
286335 < LinearGradient id = "links-gradient" from = "#fd9b93" to = "#fe6e9e" />
287- < rect width = { totalWidth } height = { totalHeight } rx = { 14 } fill = "#272b4d" />
336+ < rect width = { totalWidth } height = { totalHeight } rx = { 14 } fill = "#272b4d" onClick = { ( ) => {
337+ hideTooltip ( ) ;
338+ } } />
288339 < Group top = { margin . top } left = { margin . left } >
289340 < Tree
290341 root = { hierarchy ( data , ( d ) => ( d . isExpanded ? null : d . children ) ) }
@@ -398,6 +449,19 @@ export default function AxTree(props, {
398449 } else {
399450 aspect = Math . max ( aspect , 0.2 ) ;
400451 }
452+ const handleMouseAndClickOver = ( event ) : void => {
453+ const coords = localPoint ( event . target . ownerSVGElement , event ) ;
454+ const tooltipObj = { ...node . data } ;
455+ console . log ( "tooltipobj: " , tooltipObj ) ;
456+
457+ showTooltip ( {
458+ tooltipLeft : coords . x ,
459+ tooltipTop : coords . y ,
460+ tooltipData : tooltipObj ,
461+ // this is where the data for state and render time is displayed
462+ // but does not show props functions and etc
463+ } ) ;
464+ } ;
401465
402466 return (
403467 < Group top = { top } left = { left } key = { key } className = 'rect' >
@@ -408,6 +472,7 @@ export default function AxTree(props, {
408472 fill = "url('#root-gradient')"
409473 onClick = { ( ) => {
410474 node . data . isExpanded = ! node . data . isExpanded ;
475+ hideTooltip ( ) ;
411476 } }
412477 />
413478 ) }
@@ -431,6 +496,40 @@ export default function AxTree(props, {
431496 rx = { node . children ? 4 : 10 }
432497 onClick = { ( ) => {
433498 node . data . isExpanded = ! node . data . isExpanded ;
499+ hideTooltip ( ) ;
500+ } }
501+ // Mouse Enter Rect (Component Node) -----------------------------------------------------------------------
502+ /** This onMouseEnter event fires when the mouse first moves/hovers over a component node.
503+ * The supplied event listener callback produces a Tooltip element for the current node. */
504+
505+ onMouseEnter = { ( event ) => {
506+ /** This 'if' statement block checks to see if you've just left another component node
507+ * by seeing if there's a current setTimeout waiting to close that component node's
508+ * tooltip (see onMouseLeave immediately below). If so it clears the tooltip generated
509+ * from that component node so a new tooltip for the node you've just entered can render. */
510+ if ( toolTipTimeoutID . current !== null ) {
511+ clearTimeout ( toolTipTimeoutID . current ) ;
512+ hideTooltip ( ) ;
513+ }
514+ // Removes the previous timeoutID to avoid errors
515+ toolTipTimeoutID . current = null ;
516+ //This generates a tooltip for the component node the mouse has entered.
517+ handleMouseAndClickOver ( event ) ;
518+ } }
519+ // Mouse Leave Rect (Component Node) --------------------------------------------------------------------------
520+ /** This onMouseLeave event fires when the mouse leaves a component node.
521+ * The supplied event listener callback generates a setTimeout call which gives the
522+ * mouse a certain amount of time between leaving the current component node and
523+ * closing the tooltip for that node.
524+ * If the mouse enters the tooltip before the timeout delay has passed, the
525+ * setTimeout event will be canceled. */
526+ onMouseLeave = { ( ) => {
527+ // Store setTimeout ID so timeout can be cleared if necessary
528+ toolTipTimeoutID . current = setTimeout ( ( ) => {
529+ // hideTooltip unmounts the tooltip
530+ hideTooltip ( ) ;
531+ toolTipTimeoutID . current = null ;
532+ } , 300 ) ;
434533 } }
435534 />
436535 ) }
@@ -459,6 +558,42 @@ export default function AxTree(props, {
459558 </ Tree >
460559 </ Group >
461560 </ svg >
561+ { tooltipOpen && tooltipData && (
562+ < TooltipInPortal
563+ // set this to random so it correctly updates with parent bounds
564+ key = { Math . random ( ) }
565+ top = { tooltipTop }
566+ left = { tooltipLeft }
567+ style = { tooltipStyles }
568+ //------------- Mouse Over TooltipInPortal--------------------------------------------------------------------
569+ /** After the mouse enters the tooltip, it's able to persist by clearing the setTimeout
570+ * that would've unmounted it */
571+ onMouseEnter = { ( ) => {
572+ clearTimeout ( toolTipTimeoutID . current ) ;
573+ toolTipTimeoutID . current = null ;
574+ } }
575+ //------------- Mouse Leave TooltipInPortal -----------------------------------------------------------------
576+ /** When the mouse leaves the tooltip, the tooltip unmounts */
577+ onMouseLeave = { ( ) => {
578+ hideTooltip ( ) ;
579+ } }
580+ >
581+ < div >
582+ < div >
583+ < strong > { JSON . stringify ( tooltipData [ 'name' ] . value ) } </ strong >
584+ </ div >
585+ < div >
586+ < ToolTipDataDisplay containerName = 'Props' dataObj = { tooltipData } />
587+ < ToolTipDataDisplay
588+ containerName = 'State'
589+ dataObj = {
590+ tooltipData
591+ }
592+ />
593+ </ div >
594+ </ div >
595+ </ TooltipInPortal >
596+ ) }
462597 </ div >
463598 ) ;
464599}
0 commit comments