Draw tree with nodes and lines
by Rajesh Danabal
HTML
<div>
<label>Node Size: <input type="number" id="nodeSize" value="20" min="10" max="50" /></label>
<button onclick="redraw()">Redraw</button>
</div>
<canvas id="treeCanvas" width="900" height="600" style="border:1px solid #ccc; margin-top: 10px;"></canvas>
JavaScript
const canvas = document.getElementById("treeCanvas");
const ctx = canvas.getContext("2d");
const nodeSizeInput = document.getElementById("nodeSize");
let paginationState = {}; // { level: pageIndex }
let nodesPerPage = {}; // { level: count }
const verticalSpacing = 100;
// Sample tree (3 levels deep)
const tree = {
label: "Root",
children: Array.from({ length: 10 }, (_, i) => ({
label: `Child ${i + 1}`,
children: Array.from({ length: i % 2 === 0 ? 4 : 2 }, (_, j) => ({
label: `Grandchild ${i + 1}.${j + 1}`,
children: []
}))
}))
};
// Flatten tree into levels and track parent-child X mappings
function flattenByLevel(root) {
const result = [];
const queue = [{ node: root, level: 0, parent: null }];
while (queue.length) {
const { node, level, parent } = queue.shift();
if (!result[level]) result[level] = [];
result[level].push({ ...node, parent });
if (node.children) {
node.children.forEach(child => {
queue.push({ node: child, level: level + 1, parent: node });
});
}
}
return result;
}
function computeNodesPerPage(radius) {
const margin = 20;
const spacing = radius * 2 + margin;
return Math.max(1, Math.floor(canvas.width / spacing));
}
function drawNode(x, y, radius, label) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = "#ffe082";
ctx.fill();
ctx.strokeStyle = "#ff6f00";
ctx.stroke();
ctx.fillStyle = "#000";
ctx.font = `${Math.min(radius, 14)}px Arial`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(label, x, y);
}
function drawTree(treeData, radius) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const levels = flattenByLevel(treeData);
paginationState = paginationState || {};
const yStart = radius + 20;
const nodePositions = new Map(); // Map node => {x, y}
levels.forEach((nodes, level) => {
const page = paginationState[level] || 0;
nodesPerPage[level] =...