<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:400,400i,700">
</head>
<body>
<div class="container">
<canvas id="myCanvas" width="270px" height="180px"></canvas>
<div class="result">
<div class="label">Preorder</div>
<div id="preorder"></div>
</div>
<div class="result">
<div class="label">Inorder</div>
<div id="inorder"></div>
</div>
<div class="result">
<div class="label">Postorder</div>
<div id="postorder"></div>
</div>
<button type="button" onclick="window.preOrder()">Preorder</button>
<button type="button" onclick="window.inOrder()">Inorder</button>
<button type="button" onclick="window.postOrder()">Postorder</button>
</div>
</body>
body {
--black: #2e2e2e;
--box-shadow: 1px 4px 5px 1px rgb(0 0 0 / 35%);
font-family: Montserrat, sans-serif;
display: flex;
justify-content: center;
margin-top: 2rem;
}
canvas {
display: block;
margin: auto;
}
.result {
height: 3.5rem;
}
.label {
font-weight: bold;
}
button {
font-family: Montserrat, sans-serif;
margin: 1rem 0;
padding: 6px 10px;
border-radius: 5px;
cursor: pointer;
color: #FFFFFF;
box-shadow: var(--box-shadow);
background: var(--black);
}
button:hover, button:focus {
transform: scale(1.05);
}
button:disabled {
opacity: 0.5;
}
paper.install(window);
const btns = [...document.getElementsByTagName("button")];
function BinaryTree(el){
this.element = el;
this.left = null;
this.right = null;
this.node = null;
}
function createTree(nodes){ // it is kind of preorder style, because we have node itself first then its children
function datum(tree){ return tree[0] }
function leftChild(tree){ return tree[1] }
function rightChild(tree){ return tree[2] }
if(nodes == null)
return null;
var tree = new BinaryTree( datum(nodes) || nodes );
tree.left = createTree( leftChild(nodes) );
tree.right = createTree( rightChild(nodes) );
return tree;
}
nodes = [5, [3, 2, 4], [8, 6, 9] ];
var tree = createTree(nodes)
new VisualTree(tree, false)
function VisualTree(tree, animation){
var origin = [190, 25];
var height = getHeight(tree);
paper.setup("myCanvas");
document.getElementById("myCanvas").height = height*60+10;
function BinaryNode(tree, depth, x){
var pos = new Point(origin[0]+ x*height*30 , origin[1] + depth*50)
function drawEdge(pos1, pos2){
return new Path.Line({from: pos1, to: pos2, strokeColor: 'black', strokeWidth:2}).sendToBack()
}
if(tree.left) // if left exists, the right child also exists
this.leftEdge = drawEdge(pos, pos.add([-(1 / Math.pow(2,depth))*height*30, 50]))
if(tree.right)
this.rightEdge = drawEdge(pos, pos.add([(1 / Math.pow(2,depth))*height*30, 50]))
this.circle = new Path.Circle( { radius:20, strokeWidth:2, fillColor: 'white', strokeColor:'black', center: pos });
this.text = new PointText({ position: new Point(pos.x-8, pos.y+10), fontSize: '30px', fillColor: 'black', content:''+ tree.element});
this.text.bringToFront();
view.update();
}
t=0
function drawPreOrder(tree, depth, x){ // depth: depth of the current node, x: x-coordinate of the current node
if(tree == null)
return
if(animation)
setTimeout(function() { tree.node = new BinaryNode(tree, depth, x); }, 500*(t++));
else
tree.node = new BinaryNode(tree, depth, x);
drawPreOrder(tree.left, depth+1, x-(1 / Math.pow(2,depth)))
drawPreOrder(tree.right, depth+1, x+(1 / Math.pow(2,depth)))
}
function getHeight(tree){
if(tree == null)
return 0;
return Math.max(getHeight(tree.left)+1, getHeight(tree.right)+1)
}
drawPreOrder(tree, 0, 0)
}
var time = 0;
function deleteTreeVisual(tree){
if(tree == null)
return;
deleteTreeVisual(tree.left);
deleteTreeVisual(tree.right);
if(tree.node.leftEdge)
tree.node.leftEdge.remove();
if(tree.node.rightEdge)
tree.node.rightEdge.remove();
tree.node.circle.remove();
tree.node.text.remove();
view.update();
}
var time = 0;
function postOrderTraverse(tree){
if(tree == null)
return;
// disable buttons during animation
btns.forEach(btn => btn.disabled = true);
setTimeout(function() {
btns.forEach(btn => btn.disabled = false);
}, 10000);
setTimeout(function() {
tree.node.circle.strokeColor = 'red';
view.update();
}, 750*(time++));
postOrderTraverse(tree.left)
postOrderTraverse(tree.right)
setTimeout(function() {
tree.node.circle.fillColor = 'black';
tree.node.text.fillColor = 'white';
document.getElementById("postorder").innerHTML += tree.element + ' ';
view.update()
}, 750*(time++));
}
function inOrderTraverse(tree){
if(tree == null)
return;
// disable buttons during animation
btns.forEach(btn => btn.disabled = true);
setTimeout(function() {
btns.forEach(btn => btn.disabled = false);
}, 10000);
setTimeout(function() {
tree.node.circle.strokeColor = 'red';
view.update()
}, 750*(time++));
inOrderTraverse(tree.left)
setTimeout(function() {
tree.node.circle.fillColor = 'black';
tree.node.text.fillColor = 'white';
document.getElementById("inorder").innerHTML += tree.element + ' ';
view.update()
}, 750*(time++));
inOrderTraverse(tree.right)
}
function preOrderTraverse(tree){
if(tree == null)
return;
// disable buttons during animation
btns.forEach(btn => btn.disabled = true);
setTimeout(function() {
btns.forEach(btn => btn.disabled = false);
}, 10000);
setTimeout(function() {
tree.node.circle.strokeColor = 'red';
view.update()
}, 750*(time++));
setTimeout(function() {
tree.node.circle.fillColor = 'black';
tree.node.text.fillColor = 'white';
document.getElementById("preorder").innerHTML += tree.element + ' ';
view.update()
}, 750*(time++));
preOrderTraverse(tree.left)
preOrderTraverse(tree.right)
}
window.preOrder = function(){
document.getElementById("preorder").innerHTML = '';
deleteTreeVisual(tree)
new VisualTree(tree, false)
time = 0; preOrderTraverse(tree);
}
window.inOrder = function(){
document.getElementById("inorder").innerHTML = '';
deleteTreeVisual(tree)
new VisualTree(tree, false)
time = 0; inOrderTraverse(tree);
}
window.postOrder = function(){
document.getElementById("postorder").innerHTML = ''
deleteTreeVisual(tree)
new VisualTree(tree, false)
time = 0; postOrderTraverse(tree);
}
This Pen doesn't use any external CSS resources.