Skip to content

Instantly share code, notes, and snippets.

@frio80
Last active September 16, 2016 22:27
Show Gist options
  • Save frio80/638a19618494ec29ea4aecad726f1b65 to your computer and use it in GitHub Desktop.
Save frio80/638a19618494ec29ea4aecad726f1b65 to your computer and use it in GitHub Desktop.
Fun with Binary Tree
<!DOCTYPE html>
<html>
<head>
<title>Binary Tree Fun</title>
<meta charset="UTF-8">
<style>
blink, .blink {
-webkit-animation: blink 1s step-end infinite;
-moz-animation: blink 1s step-end infinite;
-o-animation: blink 1s step-end infinite;
animation: blink 1s step-end infinite;
color: red;
font-weight: bold;
font-size: 2rem;
}
@-webkit-keyframes blink {
67% { opacity: 0 }
}
@-moz-keyframes blink {
67% { opacity: 0 }
}
@-o-keyframes blink {
67% { opacity: 0 }
}
@keyframes blink {
67% { opacity: 0 }
}
</style>
<script>
if (typeof window.customElements === 'undefined') {
alert('Y U NO USE GOOD BROWSER?! Try Chrome Canary!');
}
class BinaryTree extends HTMLElement {
static get observedAttributes() {
return ["tree", "nonleafnode"];
}
set tree(t) {
this.setAttribute('tree', t);
}
get tree() {
return this._tree;
}
/**
* Expose Shadow DOM
*/
get DOMTree() {
return this.shadowRoot.childNodes[3];
}
constructor(/*list, makeNodeForNonLeaf = false*/) {
super(); // always call super() first in the ctor.
this._tree = null;
this.div = document.createElement('div');
this.template = document.querySelector('#binary-tree-template');
}
_createNode(val) {
var node = this.div.cloneNode(false);
node.textContent = val;
return node;
}
_buildDOMTree(root, tree) {
var div;
if (tree[0] !== null) {
div = this._createNode(tree[0]);
root.appendChild(div);
if (tree[1] !== null) this._buildDOMTree(div, tree[1]);
}
if (tree[2] !== null) {
div = this._createNode(tree[2]);
root.appendChild(div);
if (tree[3] !== null) this._buildDOMTree(div, tree[3]);
}
return;
}
connectedCallback() {
this._drawTree(this._tree);
}
disconnectCallback() {}
attributeChangedCallback(name, oldValue, newValue) {
switch (name) {
case "tree": this._tree = newValue; break;
default: break;
}
}
_drawTree(binaryTree) {
let root, tree, DOMtree, shadowRoot;
shadowRoot = this.attachShadow({mode: 'open'});
[root, tree] = JSON.parse(binaryTree);
DOMtree = this._createNode(root);
shadowRoot.appendChild(this.template.content.cloneNode(true));
this._buildDOMTree(DOMtree, tree);
shadowRoot.appendChild(DOMtree);
}
}
window.customElements.define('binary-tree', BinaryTree);
</script>
</head>
<body>
<h1>Binary Tree Fun!</h1>
<h3>Pre-Order Traversal with TreeWalker!</h3>
<p>A tree is "superbalanced" if the difference between the depths of any two leaf nodes is no greater than one.</p>
<template id="binary-tree-template">
<style>
* {
line-height: 50px;
text-align: center;
color: white;
background-color: lightgrey;
}
span {
display: block;
}
div {
margin-top: 54px;
height: 50px;
border: 1px solid #333333;
border-radius: 26px;
min-width: 50px;
float: left;
}
div > div:last-child {
float:right;
}
</style>
</template>
<binary-tree
tree="[100, [50, [10, [4, [1, null, 6, null], 11, null], 60, [50, null, 70, [65, null, 71, null]]], 150, [140, [130, null, 150, null], 160, [159, null, 161, null]]]]">
<!--
Non Super Balanced
[100, [50, [10, [4, [1, null, 6, [5, null, 7, null]], 11, null], 60, [50, null, 70, [65, null, 71, null]]], 150, [140, null, 160, null]]]
Super Balanced
[100, [50, [10, [4, [1, null, 6, null], 11, null], 60, [50, null, 70, [65, null, 71, null]]], 150, [140, [130, null, 150, null], 160, [159, null, 161, null]]]]
-->
</binary-tree>
<script>
customElements.whenDefined('binary-tree').then(() => {
let treeWalker = document.createTreeWalker(
document.getElementsByTagName('binary-tree')[0].DOMTree,
NodeFilter.SHOW_ELEMENT
);
let maxHeight = 0;
let minHeight = 0;
const isLeaf = (node) => node.children.length === 0;
const visitLeaf = (node) => node.style.backgroundColor = '#167F31';
const visitNonLeaf = (node) => node.style.backgroundColor = '#865B45';
const visitNode = (node) => {
node.dataset.height = parseInt(node.parentNode.dataset.height) + 1;
isLeaf(node) ? visitLeaf(node) : visitNonLeaf(node);
return node.dataset.height;
};
const runner = (generatorObject) => {
if (!generatorObject.next().done) setTimeout(() => runner(generatorObject), 200);
};
visitNonLeaf(treeWalker.currentNode);
treeWalker.currentNode.dataset.height = 0;
/**
* Pre Order Traversal
*
* We visit the nodes, check if it's a leaf and then check the height.
*
*/
runner(function* preOrderTraversal() {
let blink = document.createElement('blink');
while (treeWalker.nextNode()) {
let height = parseInt(visitNode(treeWalker.currentNode));
if (isLeaf(treeWalker.currentNode))
if (minHeight === 0) minHeight = height;
else if (height > maxHeight) maxHeight = height;
else if (height < minHeight) minHeight = height;
yield;
}
blink.textContent = ((maxHeight - minHeight > 1) ? 'Not ' : '') + 'SuperBalanced';
document.body.appendChild(blink);
}());
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment