@@ -32,7 +32,6 @@ import './TreeGraph.css';
3232
3333type Props = ZoomProps & {
3434 data : any ,
35- fontSize : number ,
3635 layout : string ,
3736 linkType : string ,
3837 offset : number ,
@@ -47,12 +46,8 @@ type Props = ZoomProps & {
4746 bottom : number ,
4847 left : number
4948 } ,
50- nodeWidth : number ,
51- onClick ?: ( data : any ) => void ,
5249 renderNode ?: ( data : any ) => Element < any > ,
53- renderText ?: ( data : any ) => Element < any > ,
54- stepPercent : number ,
55- textColor : string
50+ stepPercent : number
5651} ;
5752
5853const Layout = {
@@ -71,19 +66,6 @@ const Orientation = {
7166 vertical : 'vertical'
7267} ;
7368
74- const Circle : ComponentType < any > = (props: any) => (
75- < circle
76- r = { props . radius }
77- { ...props }
78- />
79- );
80-
81- const Rectangle: ComponentType< any > = (props: any) => (
82- < rect
83- { ...props }
84- />
85- );
86-
8769const TreeGraph = ( props : Props ) => {
8870 const ref = useRef ( ) ;
8971
@@ -210,59 +192,11 @@ const TreeGraph = (props: Props) => {
210192 } ;
211193 } , [ getMaxDepth , innerHeight , innerWidth , props . data , props . layout , props . orientation ] ) ;
212194
213- /**
214- * Renders the passed node. If provided, only the "renderNode" prop is called.
215- *
216- * @type {(function(*): (*))|* }
217- */
218- const renderNode = useCallback ( ( node ) => {
219- if ( props . renderNode ) {
220- return props . renderNode ( node . data ) ;
221- }
222-
223- if ( node . depth === 0 ) {
224- return (
225- < Circle
226- fill = '#FF4A4A'
227- onClick = { props . onClick && props . onClick . bind ( this , node . data ) }
228- />
229- ) ;
230- }
231-
232- return (
233- < Rectangle
234- fill = '#272b4d'
235- stroke = { node . data . children ? '#03c0dc' : '#26deb0' }
236- strokeWidth = { 1 }
237- strokeDasharray = { node . data . children ? '0' : '2,2' }
238- strokeOpacity = { node . data . children ? 1 : 0.6 }
239- rx = { node . data . children ? 0 : 10 }
240- onClick = { props . onClick && props . onClick . bind ( this , node . data ) }
241- />
242- ) ;
243- } , [ props . onClick , props . renderNode ] ) ;
244-
245- /**
246- * Renders the text for the passed node.
247- *
248- * @type {(function(*): (*))|* }
249- */
250- const renderText = useCallback ( ( node ) => {
251- if ( props . renderText ) {
252- return props . renderText ( node . data ) ;
253- }
254-
255- return (
256- < text
257- dy = '0.33em'
258- fontSize = { props . fontSize }
259- textAnchor = 'middle'
260- fill = { props . textColor }
261- >
262- { node . data . name }
263- </ text >
264- ) ;
265- } , [ props . renderText ] ) ;
195+ const renderNode = useCallback ( ( node ) => (
196+ < foreignObject >
197+ { props . renderNode ( node . data ) }
198+ </ foreignObject >
199+ ) , [ props . renderNode ] ) ;
266200
267201 /**
268202 * Renders the group element for the passed node.
@@ -274,15 +208,16 @@ const TreeGraph = (props: Props) => {
274208
275209 return (
276210 < Group
211+ nodeleft = { left }
212+ nodetop = { top }
277213 top = { top }
278214 left = { left }
279215 key = { key }
280216 >
281217 { renderNode ( node ) }
282- { renderText ( node ) }
283218 </ Group >
284219 ) ;
285- } , [ renderNode , renderText , props . layout , props . orientation ] ) ;
220+ } , [ renderNode , props . layout , props . orientation , props . linkType ] ) ;
286221
287222 /**
288223 * Resizes the "circle" and "rect" elements based on the text contained in the group. This effect will also
@@ -291,81 +226,32 @@ const TreeGraph = (props: Props) => {
291226 useEffect ( ( ) => {
292227 const { current } = ref ;
293228 if ( current ) {
294- const padding = 15 ;
295229 const groups = current . getElementsByTagName ( 'g' ) ;
296230 _ . each ( groups , ( group ) => {
297- const circle = _ . first ( group . getElementsByTagName ( 'circle' ) ) ;
298- const rect = _ . first ( group . getElementsByTagName ( 'rect' ) ) ;
299-
300- const text = _ . first ( group . getElementsByTagName ( 'text' ) ) ;
301- const { height } = text . getBBox ( ) ;
302-
303- if ( ! text . getElementsByTagName ( 'tspan' ) . length ) {
304- const words = text . innerHTML . split ( / \s + / ) ;
231+ const object = _ . first ( group . getElementsByTagName ( 'foreignObject' ) ) ;
232+ if ( object && object . firstChild ) {
233+ const { offsetWidth : width , offsetHeight : height } = object . firstChild ;
305234
306- const lines = [ ] ;
307- let lineIndex = 0 ;
235+ // Set the width and height of the foreignObject element
236+ object . setAttribute ( 'width' , width ) ;
237+ object . setAttribute ( 'height' , height ) ;
308238
309- for ( let i = 0 ; i < words . length ; i += 1 ) {
310- // Initialize the line array for the current line
311- if ( ! lines [ lineIndex ] ) {
312- lines [ lineIndex ] = [ ] ;
313- }
239+ // Transform the position of the group element based on the width and height of the contents
240+ const leftPosition = parseFloat ( group . getAttribute ( 'nodeleft' ) ) ;
241+ const topPosition = parseFloat ( group . getAttribute ( 'nodetop' ) ) ;
314242
315- // Add the current word to the current line
316- lines [ lineIndex ] . push ( words [ i ] ) ;
317-
318- // Look ahead to the next word and increment the line index if necessary
319- if ( i < words . length - 1 ) {
320- const testElement = text . cloneNode ( ) ;
321- testElement . innerHTML = [ ...lines [ lineIndex ] , words [ i + 1 ] ] . join ( ' ' ) ;
322- group . append ( testElement ) ;
323-
324- if ( testElement . getBBox ( ) . width > props . nodeWidth ) {
325- lineIndex += 1 ;
326- }
327-
328- testElement . remove ( ) ;
329- }
330- }
331-
332- // Append the lines to the text element
333- _ . each ( lines , ( line , index ) => {
334- const tspan = document . createElementNS ( 'http://www.w3.org/2000/svg' , 'tspan' ) ;
335- tspan . setAttribute ( 'x' , '0' ) ;
336- if ( index > 0 ) {
337- tspan . setAttribute ( 'dy' , `${ height } px` ) ;
338- }
339- tspan . appendChild ( document . createTextNode ( line . join ( ' ' ) ) ) ;
340-
341- if ( index === 0 ) {
342- text . replaceChildren ( tspan ) ;
343- } else {
344- text . appendChild ( tspan ) ;
345- }
346- } ) ;
347-
348- // Set the shape attributes based on the text size
349- const bbox = text . getBBox ( ) ;
350- if ( circle && text ) {
351- circle . setAttribute ( 'x' , bbox . x - padding ) ;
352- circle . setAttribute ( 'y' , bbox . y - padding ) ;
353- circle . setAttribute ( 'r' , ( bbox . width / 2 ) + padding ) ;
354- } else if ( rect && text ) {
355- rect . setAttribute ( 'x' , bbox . x - padding ) ;
356- rect . setAttribute ( 'y' , bbox . y - padding ) ;
357- rect . setAttribute ( 'width' , bbox . width + 2 * padding ) ;
358- rect . setAttribute ( 'height' , bbox . height + 2 * padding ) ;
243+ if ( ! _ . isNaN ( leftPosition ) && ! _ . isNaN ( topPosition ) ) {
244+ const transform = `translate(${ leftPosition - ( width / 2.0 ) } , ${ topPosition - ( height / 2.0 ) } )` ;
245+ group . setAttribute ( 'transform' , transform ) ;
359246 }
360247 }
361248 } ) ;
362249 }
363- } , [ props . data ] ) ;
250+ } , [ props . data , props . layout , props . orientation , props . linkType ] ) ;
364251
365252 return (
366253 < div
367254 className = 'tree-graph'
368- ref = { ref }
369255 style = { {
370256 display : 'flex' ,
371257 flexGrow : '1'
@@ -389,8 +275,9 @@ const TreeGraph = (props: Props) => {
389275 >
390276 { ( tree ) => (
391277 < Group
392- top = { root . origin . y }
278+ innerRef = { ref }
393279 left = { root . origin . x }
280+ top = { root . origin . y }
394281 >
395282 { tree . links ( ) . map ( ( link , i ) => (
396283 < LinkComponent
@@ -413,7 +300,6 @@ const TreeGraph = (props: Props) => {
413300} ;
414301
415302TreeGraph . defaultProps = {
416- fontSize : 12 ,
417303 layout : Layout . cartesian ,
418304 linkColor : '#B2B09B' ,
419305 linkType : LinkType . line ,
@@ -424,20 +310,10 @@ TreeGraph.defaultProps = {
424310 right : 30 ,
425311 bottom : 70
426312 } ,
427- nodeWidth : 75 ,
428313 offset : 0 ,
429314 orientation : Orientation . horizontal ,
430- stepPercent : 0.5 ,
431- textColor : '#FFFFFF'
432- } ;
433-
434- type TreeGraphType = ComponentType< any > & {
435- Circle : typeof Circle ,
436- Rectangle : typeof Rectangle
315+ stepPercent : 0.5
437316} ;
438317
439- const TreeGraphComponent: TreeGraphType = withParentSize(withZoom(TreeGraph));
440- TreeGraphComponent.Circle = Circle;
441- TreeGraphComponent.Rectangle = Rectangle;
442-
318+ const TreeGraphComponent : ComponentType < any > = withParentSize(withZoom(TreeGraph));
443319export default TreeGraphComponent;
0 commit comments