xxxxxxxxxx
165
class TreeNode {
constructor(value, level) {
this.value = value;
this.level = level;
this.children = [];
}
}
class Tree {
constructor(rootValue) {
this.root = new TreeNode(rootValue, 0);
this.levels = new Map();
this.levels[0] = 1;
this.maxChildrenList = [];
this.offsetList = [];
}
// Add a child to a given parent node
addChild(parentNode, childValue) {
// create the child
const childNode = new TreeNode(childValue, parentNode.level + 1);
// update the level count
if (this.levels.has(parentNode.level + 1)) {
this.levels.set(
parentNode.level + 1,
this.levels.get(parentNode.level + 1) + 1
);
} else {
this.levels.set(parentNode.level + 1, 1);
}
// push the child
parentNode.children.push(childNode);
return childNode;
}
calculateMaxChildrenList() {
// this.maxChildrenList[i] = maximum number of children that a node in level i has.
this.traverseBF(node => {
const level = node.level;
if (!this.maxChildrenList[level]) {
this.maxChildrenList[level] = node.children.length;
} else {
this.maxChildrenList[level] = Math.max(this.maxChildrenList[level], node.children.length);
}
});
}
calculateOffsetList() {
// this.offsetList[last] = 100;
// this.offsetList[i] = this.maxChildrenList[i+1] * 100
this.calculateMaxChildrenList();
for (let i = 0; i < this.maxChildrenList.length - 2; i++) {
this.offsetList.push(this.maxChildrenList[i + 1] * R*1.6);
}
this.offsetList.push(10); // Assuming the last level starts with an offset of 100
}
// Depth-first traversal (pre-order)
traverseDF(callback) {
function traverse(node) {
callback(node);
node.children.forEach((child) => traverse(child));
}
traverse(this.root);
}
// Breadth-first traversal
traverseBF(callback) {
const queue = [this.root];
while (queue.length > 0) {
const node = queue.shift();
callback(node);
node.children.forEach((child) => queue.push(child));
}
}
}
let R = 0;
let X_OFFSET = 30;
let Y_OFFSET = 30;
function drawTreeNodes(node, x, y, tree) {
// circle for node
fill(25);
stroke(255);
circle(x, y, R*2);
// node's text
noStroke();
fill(255);
textSize(min(R*2/node.value.length, R/1.3));
textAlign(CENTER, CENTER);
text(node.value, x, y);
// recursively draw it's children
let n = node.children.length;
for(let i=0; i<n; i++) {
let xoffset = tree.offsetList[node.level];
let newX = x-(n-1)*R-(n-1)*(xoffset/2)+i*(2*R+xoffset);
let newY = y+2*R+Y_OFFSET;
// node and it's children
drawTreeNodes(node.children[i], newX, newY, tree);
}
}
function drawTreeEdges(node, x, y, tree) {
stroke(255);
// recursively draw it's children
let n = node.children.length;
for(let i=0; i<n; i++) {
let xoffset = tree.offsetList[node.level];
let newX = x-(n-1)*R-(n-1)*(xoffset/2)+i*(2*R+xoffset);
let newY = y+2*R+Y_OFFSET;
line(x, y, newX, newY);
// node and it's children
drawTreeEdges(node.children[i], newX, newY, tree);
}
}
function drawTree(tree, x, y) {
tree.calculateOffsetList();
drawTreeEdges(tree.root, 0, 0, tree);
drawTreeNodes(tree.root, 0, 0, tree);
}
function setup() {
createCanvas(400, 400);
R = width/20;
}
function draw() {
background(20);
// Construct a sample tree
const tree = new Tree("A, BCDEFG");
const node1 = tree.addChild(tree.root, "B");
const node4 = tree.addChild(node1, "E");
const node5 = tree.addChild(node1, "F");
const node2 = tree.addChild(tree.root, "C");
const node7 = tree.addChild(node2, "H")
const node10 = tree.addChild(node7, "K")
const node11 = tree.addChild(node7, "L")
const node12 = tree.addChild(node7, "M")
const node8 = tree.addChild(node2, "I")
const node9 = tree.addChild(node2, "J")
const node3 = tree.addChild(tree.root, "D");
const node6 = tree.addChild(node3, "G");
// Draw the tree
translate(width/2, 50);
scale(map(mouseY, 0, height, 3, 1));
drawTree(tree, 0, 0);
}