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