adding iterative animation again
This commit is contained in:
committed by
JamesFlare1212
parent
421ae870a4
commit
3fd45d0b8c
18223
animations/trees/iterative/konva.js
Normal file
18223
animations/trees/iterative/konva.js
Normal file
File diff suppressed because it is too large
Load Diff
146
animations/trees/iterative/traversal.css
Normal file
146
animations/trees/iterative/traversal.css
Normal file
@@ -0,0 +1,146 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Roboto:400,500&display=swap');
|
||||
|
||||
/*base styling */
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #f7f8fa;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/*layout containers */
|
||||
#main-container {
|
||||
display: flex;
|
||||
width: 90%;
|
||||
max-width: 1200px;
|
||||
margin: 30px auto;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
#tree-container,
|
||||
#stack-container {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
#tree-container {
|
||||
flex: 3;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
#stack-container {
|
||||
flex: 1;
|
||||
height: 600px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/*stack title */
|
||||
#stack-title {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
margin-bottom: 12px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
/*controls */
|
||||
#tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
background: transparent;
|
||||
color: #555;
|
||||
padding: 8px 16px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s, border-color 0.2s;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.tab-btn.active,
|
||||
.tab-btn[style*="font-weight: bold"] {
|
||||
color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
#controls {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease, transform 0.1s ease;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #006ae6;
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
/*status & logs */
|
||||
#status,
|
||||
#log,
|
||||
#final-seq {
|
||||
width: 90%;
|
||||
max-width: 1200px;
|
||||
margin: 10px auto;
|
||||
padding: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
#status {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#log {
|
||||
height: 120px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#currentVal {
|
||||
color: #007bff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#reason {
|
||||
color: #ff5722;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#final-seq {
|
||||
font-weight: 500;
|
||||
color: #28a745;
|
||||
}
|
||||
30
animations/trees/iterative/traversal.html
Normal file
30
animations/trees/iterative/traversal.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>In-Order Traversal (Step-by-Step)</title>
|
||||
<script src="konva.js"></script>
|
||||
<link rel="stylesheet" href="inorder.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main-container">
|
||||
<div id="tree-container"></div>
|
||||
<div id="stack-container">
|
||||
<div id="stack-title">Stack</div>
|
||||
<div id="stack-visual"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="controls">
|
||||
<button id="stepBtn">Step</button>
|
||||
<button id="resetBtn">Start Over</button>
|
||||
</div>
|
||||
<div id="status">
|
||||
<span class="label">Now checking:</span> <span id="currentVal">None</span> |
|
||||
<span class="label">Status:</span> <span id="reason">Ready</span>
|
||||
</div>
|
||||
<div id="log"><strong>Traversal Sequence:</strong> <span id="seq"></span></div>
|
||||
<div id="final-seq"><strong>Final Sequence:</strong> 4 2 6 5 7 1 3 8 9</div>
|
||||
|
||||
<script src="inorder.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
275
animations/trees/iterative/traversal.js
Normal file
275
animations/trees/iterative/traversal.js
Normal file
@@ -0,0 +1,275 @@
|
||||
// In-Order / Pre-Order / Post-Order Traversal Visualization (combined)
|
||||
|
||||
//canvas dimensions for tree visualization
|
||||
const width = window.innerWidth * 0.9 * 0.75;
|
||||
const height = 600;
|
||||
|
||||
//create the main stage and layer for the tree
|
||||
const stage = new Konva.Stage({
|
||||
container: 'tree-container',
|
||||
width: width,
|
||||
height: height
|
||||
});
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
//adjusted positions: node 9 is left child of 8
|
||||
const positions = {
|
||||
1: { x: width / 2, y: 80 },
|
||||
2: { x: width / 2 - 200, y: 180 },
|
||||
3: { x: width / 2 + 200, y: 180 },
|
||||
4: { x: width / 2 - 300, y: 280 },
|
||||
5: { x: width / 2 - 100, y: 280 },
|
||||
6: { x: width / 2 - 150, y: 380 },
|
||||
7: { x: width / 2 - 50, y: 380 },
|
||||
8: { x: width / 2 + 300, y: 280 },
|
||||
9: { x: width / 2 + 250, y: 380 } // left child of 8
|
||||
};
|
||||
|
||||
//tree structure
|
||||
const tree = {
|
||||
val: 1,
|
||||
left: {
|
||||
val: 2,
|
||||
left: { val: 4, left: null, right: null },
|
||||
right: {
|
||||
val: 5,
|
||||
left: { val: 6, left: null, right: null },
|
||||
right: { val: 7, left: null, right: null }
|
||||
}
|
||||
},
|
||||
right: {
|
||||
val: 3,
|
||||
left: null,
|
||||
right: {
|
||||
val: 8,
|
||||
left: { val: 9, left: null, right: null },
|
||||
right: null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//store node references for highlighting
|
||||
const nodes = {};
|
||||
|
||||
//recursive tree draw with shortened lines
|
||||
function drawTree(node, parent = null) {
|
||||
if (!node) return;
|
||||
const pos = positions[node.val];
|
||||
if (parent) {
|
||||
const p = positions[parent.val];
|
||||
const dx = pos.x - p.x, dy = pos.y - p.y;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
const offX = (dx/dist)*20, offY = (dy/dist)*20;
|
||||
layer.add(new Konva.Line({
|
||||
points: [p.x + offX, p.y + offY, pos.x - offX, pos.y - offY],
|
||||
stroke: 'black', strokeWidth: 2
|
||||
}));
|
||||
}
|
||||
const circle = new Konva.Circle({ x: pos.x, y: pos.y, radius: 20, fill: 'white', stroke: 'black', strokeWidth: 2 });
|
||||
const text = new Konva.Text({ x: pos.x - 5, y: pos.y - 8, text: node.val.toString(), fontSize: 16, fill: 'black' });
|
||||
layer.add(circle);
|
||||
layer.add(text);
|
||||
nodes[node.val] = { circle, text };
|
||||
drawTree(node.left, node);
|
||||
drawTree(node.right, node);
|
||||
}
|
||||
|
||||
//stack visualization setup
|
||||
const stackStage = new Konva.Stage({ container: 'stack-visual', width: 200, height: 500 });
|
||||
const stackLayer = new Konva.Layer();
|
||||
stackStage.add(stackLayer);
|
||||
let stackVisual = [];
|
||||
|
||||
function pushStack(val) {
|
||||
const box = new Konva.Rect({ x: 50, y: 400 - stackVisual.length * 30, width: 40, height: 25, fill: '#89CFF0', stroke: 'black' });
|
||||
const label = new Konva.Text({ x: 60, y: 405 - stackVisual.length * 30, text: val.toString(), fontSize: 16, fill: 'black' });
|
||||
stackLayer.add(box);
|
||||
stackLayer.add(label);
|
||||
stackVisual.push({ box, label });
|
||||
stackLayer.draw();
|
||||
}
|
||||
|
||||
function popStack() {
|
||||
const item = stackVisual.pop();
|
||||
if (item) {
|
||||
item.box.destroy();
|
||||
item.label.destroy();
|
||||
stackLayer.draw();
|
||||
}
|
||||
}
|
||||
|
||||
function highlight(val, color = 'yellow') {
|
||||
const n = nodes[val];
|
||||
if (n) {
|
||||
n.circle.fill(color);
|
||||
layer.draw();
|
||||
}
|
||||
}
|
||||
|
||||
function resetHighlights() {
|
||||
for (let v in nodes) {
|
||||
nodes[v].circle.fill('white');
|
||||
}
|
||||
layer.draw();
|
||||
}
|
||||
|
||||
function updateStatus(current, reason) {
|
||||
document.getElementById('currentVal').innerText = current ?? 'None';
|
||||
document.getElementById('reason').innerText = reason;
|
||||
}
|
||||
|
||||
function logVisit(val) {
|
||||
document.getElementById('seq').innerText += ` ${val}`;
|
||||
}
|
||||
|
||||
//traversal state
|
||||
let current = tree;
|
||||
const stack = [];
|
||||
let stepReady = true;
|
||||
let lastVisited = null;
|
||||
|
||||
//final sequences for display
|
||||
const finalSeqs = {
|
||||
'In-Order': '4 2 6 5 7 1 3 8 9',
|
||||
'Pre-Order': '1 2 4 5 6 7 3 8 9',
|
||||
'Post-Order': '4 6 7 5 2 9 8 3 1'
|
||||
};
|
||||
|
||||
//create tabs dynamically
|
||||
const modes = ['In-Order', 'Pre-Order', 'Post-Order'];
|
||||
let currentMode = modes[0];
|
||||
const tabsDiv = document.createElement('div');
|
||||
tabsDiv.id = 'tabs';
|
||||
tabsDiv.style.textAlign = 'center';
|
||||
tabsDiv.style.margin = '10px';
|
||||
modes.forEach((mode) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.innerText = mode;
|
||||
btn.className = 'tab-btn';
|
||||
btn.style.margin = '0 5px';
|
||||
btn.onclick = () => {
|
||||
currentMode = mode;
|
||||
document.querySelectorAll('.tab-btn').forEach((b) => (b.style.fontWeight = 'normal'));
|
||||
btn.style.fontWeight = 'bold';
|
||||
document.getElementById('final-seq').innerHTML = `<strong>Final Sequence (${mode}):</strong> ${finalSeqs[mode]}`;
|
||||
resetAll();
|
||||
};
|
||||
if (mode === currentMode) btn.style.fontWeight = 'bold';
|
||||
tabsDiv.appendChild(btn);
|
||||
});
|
||||
document.body.insertBefore(tabsDiv, document.getElementById('main-container'));
|
||||
document.getElementById('final-seq').innerHTML = `<strong>Final Sequence (${currentMode}):</strong> ${finalSeqs[currentMode]}`;
|
||||
|
||||
//step functions for each traversal
|
||||
function stepInOrder() {
|
||||
if (current) {
|
||||
highlight(current.val, 'yellow');
|
||||
updateStatus(current.val, `Push ${current.val} into stack`);
|
||||
stack.push(current);
|
||||
pushStack(current.val);
|
||||
current = current.left;
|
||||
stepReady = true;
|
||||
return;
|
||||
}
|
||||
if (stack.length > 0) {
|
||||
const peek = stack[stack.length - 1];
|
||||
updateStatus(peek.val, `Peek stack (current = ${peek.val})`);
|
||||
current = stack.pop();
|
||||
popStack();
|
||||
updateStatus(current.val, `Visit ${current.val}`);
|
||||
highlight(current.val, 'orange');
|
||||
logVisit(current.val);
|
||||
setTimeout(() => {
|
||||
resetHighlights();
|
||||
current = current.right;
|
||||
stepReady = true;
|
||||
}, 500);
|
||||
} else {
|
||||
updateStatus('None', 'Done');
|
||||
}
|
||||
}
|
||||
|
||||
function stepPreOrder() {
|
||||
if (current) {
|
||||
updateStatus(current.val, `Visit ${current.val}`);
|
||||
highlight(current.val, 'orange');
|
||||
logVisit(current.val);
|
||||
updateStatus(current.val, `Push ${current.val} into stack`);
|
||||
stack.push(current);
|
||||
pushStack(current.val);
|
||||
current = current.left;
|
||||
stepReady = true;
|
||||
return;
|
||||
}
|
||||
if (stack.length > 0) {
|
||||
const node = stack.pop();
|
||||
popStack();
|
||||
updateStatus(node.val, `Move to right of ${node.val}`);
|
||||
current = node.right;
|
||||
stepReady = true;
|
||||
} else {
|
||||
updateStatus('None', 'Done');
|
||||
}
|
||||
}
|
||||
|
||||
function stepPostOrder() {
|
||||
if (current) {
|
||||
highlight(current.val, 'yellow');
|
||||
updateStatus(current.val, `Push ${current.val} into stack`);
|
||||
stack.push(current);
|
||||
pushStack(current.val);
|
||||
current = current.left;
|
||||
stepReady = true;
|
||||
return;
|
||||
}
|
||||
if (stack.length > 0) {
|
||||
const peek = stack[stack.length - 1];
|
||||
if (peek.right && lastVisited !== peek.right) {
|
||||
updateStatus(peek.val, `Move to right of ${peek.val}`);
|
||||
current = peek.right;
|
||||
stepReady = true;
|
||||
} else {
|
||||
const node = stack.pop();
|
||||
popStack();
|
||||
lastVisited = node;
|
||||
updateStatus(node.val, `Visit ${node.val}`);
|
||||
highlight(node.val, 'orange');
|
||||
logVisit(node.val);
|
||||
current = null; // avoid re-visiting the same node
|
||||
setTimeout(() => {
|
||||
resetHighlights();
|
||||
stepReady = true;
|
||||
}, 500);
|
||||
}
|
||||
} else {
|
||||
updateStatus('None', 'Done');
|
||||
}
|
||||
}
|
||||
|
||||
//bind the step button
|
||||
document.getElementById('stepBtn').onclick = () => {
|
||||
if (!stepReady) return;
|
||||
stepReady = false;
|
||||
if (currentMode === 'In-Order') stepInOrder();
|
||||
else if (currentMode === 'Pre-Order') stepPreOrder();
|
||||
else if (currentMode === 'Post-Order') stepPostOrder();
|
||||
};
|
||||
|
||||
//reset button and function
|
||||
function resetAll() {
|
||||
while (stackVisual.length) popStack();
|
||||
stack.length = 0;
|
||||
current = tree;
|
||||
lastVisited = null;
|
||||
stepReady = true;
|
||||
document.getElementById('seq').innerText = '';
|
||||
updateStatus('None', 'Ready');
|
||||
resetHighlights();
|
||||
}
|
||||
|
||||
document.getElementById('resetBtn').onclick = resetAll;
|
||||
|
||||
//initial render of the tree
|
||||
drawTree(tree);
|
||||
layer.draw();
|
||||
Reference in New Issue
Block a user