1
+ import TreeNode from "../data-structures/TreeNode"
2
+ import { CONFIG } from "../utils/tree" ;
3
+
4
+
5
+ function renderTree ( rootNode : TreeNode , canvasEle : HTMLCanvasElement | null ) {
6
+
7
+ // set canvas dimension same as window dimension
8
+ const windowWidth = window . innerWidth ;
9
+ const windowHeight = window . innerHeight ;
10
+
11
+ if ( canvasEle ) {
12
+ canvasEle . width = windowWidth ;
13
+ canvasEle . height = windowHeight ;
14
+ }
15
+
16
+ const { nodeContainerHeight, nodeContainersWidth } = getTreeHeightWidth ( rootNode ) ;
17
+
18
+ const windowCenter = windowWidth / 2 ;
19
+ const nodeContainerWidthCenter = nodeContainersWidth / 2 ;
20
+
21
+ const xStart = windowCenter - nodeContainerWidthCenter ;
22
+ const xEnd = windowCenter + nodeContainerWidthCenter ;
23
+
24
+ const horizontalConfig = { xStart, xEnd } ;
25
+
26
+ // Draw tree
27
+ drawTreeRecursively ( rootNode , canvasEle , 0.5 , horizontalConfig ) ;
28
+ }
29
+
30
+ function getTreeHeightWidth ( node : TreeNode ) {
31
+ const heightOfTree = node . getHeight ( ) ;
32
+ const maxLeafNodeAtLlevel = Math . pow ( 2 , heightOfTree ) ;
33
+
34
+ const nodeContainerHeight = heightOfTree * CONFIG . HEIGHT_SPACING ;
35
+ const nodeContainersWidth = maxLeafNodeAtLlevel * CONFIG . WIDTH_SPACING ;
36
+
37
+ return {
38
+ nodeContainerHeight,
39
+ nodeContainersWidth
40
+ } ;
41
+ }
42
+
43
+ function drawTreeRecursively ( node : TreeNode , canvasEle : HTMLCanvasElement | null , currentLevel : number , horizontalConfig : { xStart : number , xEnd : number } ) {
44
+ const { xStart, xEnd } = horizontalConfig ;
45
+
46
+ const xPos = ( xStart + xEnd ) / 2 ;
47
+ const yPos = currentLevel * CONFIG . HEIGHT_SPACING ;
48
+
49
+ const nodeValue = node . getNodeValue ( node ) ?. toString ( ) || "" ;
50
+ drawNode ( nodeValue , canvasEle , xPos , yPos ) ;
51
+
52
+
53
+ if ( node . isLeftNodeAvailable ( node ) ) {
54
+ const leftNodeHorizontalConfig = { xStart, xEnd : xPos } ;
55
+ drawTreeRecursively ( node . getLeftNode ( node ) , canvasEle , currentLevel + 1 , leftNodeHorizontalConfig ) ;
56
+
57
+ const xCord = { xStart : xPos , xEnd : ( xStart + xPos ) / 2 } ;
58
+ const yCord = { yStart : yPos + CONFIG . RADIUS , yEnd : ( ( currentLevel + 1 ) * CONFIG . HEIGHT_SPACING ) - CONFIG . RADIUS } ;
59
+
60
+ connectNodesEdge ( canvasEle , xCord , yCord )
61
+ }
62
+
63
+ if ( node . isRightNodeAvailable ( node ) ) {
64
+ const rightNodeHorizontalConfig = { xStart : xPos , xEnd} ;
65
+ drawTreeRecursively ( node . getRightNode ( node ) , canvasEle , currentLevel + 1 , rightNodeHorizontalConfig ) ;
66
+
67
+ const xCord = { xStart : xPos , xEnd : ( xPos + xEnd ) / 2 } ;
68
+ const yCord = { yStart : yPos + CONFIG . RADIUS , yEnd : ( ( currentLevel + 1 ) * CONFIG . HEIGHT_SPACING ) - CONFIG . RADIUS } ;
69
+
70
+ connectNodesEdge ( canvasEle , xCord , yCord )
71
+ }
72
+ }
73
+
74
+ function drawNode ( value : string , canvasEle : HTMLCanvasElement | null , x : number , y : number ) {
75
+
76
+ const context = canvasEle ?. getContext ( "2d" ) ;
77
+
78
+ // Draw circle
79
+ context ?. beginPath ( ) ;
80
+ context ?. arc ( x , y , CONFIG . RADIUS , 0 , 2 * Math . PI , false ) ;
81
+ ( context as CanvasRenderingContext2D ) . fillStyle = "#6a00f4" ; // type assertion
82
+ context ?. fill ( ) ;
83
+
84
+ // Draw circle border
85
+ context ?. arc ( x , y , CONFIG . RADIUS , 0 , 2 * Math . PI , false ) ;
86
+ ( context as CanvasRenderingContext2D ) . strokeStyle = "#10002b" ; // type assertion
87
+ ( context as CanvasRenderingContext2D ) . lineWidth = 3 ;
88
+ context ?. stroke ( ) ;
89
+
90
+ // fill the node value
91
+ ( context as CanvasRenderingContext2D ) . font = `bold ${ CONFIG . FONT_SIZE } px Arial` ;
92
+ ( context as CanvasRenderingContext2D ) . fillStyle = "#f0fff1" ; // type assertion
93
+ ( context as CanvasRenderingContext2D ) . textAlign = "center" ;
94
+
95
+
96
+ ( context as CanvasRenderingContext2D ) . fillText ( value , x , y + ( CONFIG . FONT_SIZE / 3 ) ) ;
97
+
98
+ }
99
+
100
+ function connectNodesEdge ( canvasEle : HTMLCanvasElement | null , xCord : { xStart : number , xEnd : number } , yCord : { yStart : number , yEnd : number } ) {
101
+ const { xStart, xEnd } = xCord ;
102
+ const { yStart, yEnd } = yCord ;
103
+
104
+ const start = { x : xStart , y : yStart } ;
105
+ const end = { x : xEnd , y : yEnd } ;
106
+
107
+
108
+ const context = canvasEle ?. getContext ( "2d" ) ;
109
+ context ?. beginPath ( ) ;
110
+ ( context as CanvasRenderingContext2D ) . strokeStyle = "#6a00f4" ;
111
+ ( context as CanvasRenderingContext2D ) . lineWidth = 2 ;
112
+ context ?. moveTo ( start . x , start . y ) ;
113
+ context ?. lineTo ( end . x , end . y ) ;
114
+ context ?. stroke ( ) ;
115
+ }
116
+
117
+ export default renderTree ;
0 commit comments