adding the animation directory

This commit is contained in:
Jidong Xiao
2023-09-11 21:11:17 -04:00
parent 896f54986b
commit aaf6d28ec6
45 changed files with 28133 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Doubly-Linked List: insert operation</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Doubly-Linked List: insert operation</h1>
<p>This animation shows the insert operation in Doubly-Linked List. Click the "next step" button to run the animation. <b>Note:</b> in this animation, we will insert a new node containing the value 15 following the node containing the value 1. </p>
<div id="container"></div>
<script src="insert.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="list_insert_nextstep()" style="position: absolute; top: 125px; left: 10px;">next step</button>
<button onclick="hide_next()" style="position: absolute; top: 125px; left: 110px;">hide next pointers</button>
<button onclick="show_next()" style="position: absolute; top: 125px; left: 250px;">show next pointers</button>
<button onclick="hide_prev()" style="position: absolute; top: 125px; left: 390px;">hide prev pointers</button>
<button onclick="show_prev()" style="position: absolute; top: 125px; left: 530px;">show prev pointers</button>
</body>
</html>

View File

@@ -0,0 +1,408 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the list.
var rect_list = new Konva.Rect({
x: 150,
y: 210,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 1300,
height: 500,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_list);
// Create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
// for the value.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect1);
// for the next pointer.
let rect2 = new Konva.Rect({
x: x,
y: y+50,
id:"next_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect2);
// for the prev pointer.
let rect3 = new Konva.Rect({
x: x,
y: y+100,
id:"prev_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect3);
// value
var text = new Konva.Text({
x: x + 45,
y: y + 20,
text: label,
id: "node_value_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
// the text "next"
var text_next = new Konva.Text({
x: x + 30,
y: y + 70,
text: "next",
id: "node_next_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_next);
// the text "prev"
var text_prev = new Konva.Text({
x: x + 35,
y: y + 120,
text: "prev",
id: "node_prev_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_prev);
var arrow_next = new Konva.Arrow({
points: [x+65, y+80, x+120, y+85, x+250, y],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_next_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow_next);
var arrow_prev = new Konva.Arrow({
points: [x+33, y+130, x-20, y+200, x-300, y+180, x-250, y],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_prev_" + id,
fill: 'orange',
stroke: 'orange',
strokeWidth: 5,
});
layer.add(arrow_prev);
}
drawListNode(300, 460, '13', 1);
drawListNode(550, 460, '1', 2);
drawListNode(800, 460, '3', 3);
drawListNode(1050, 460, '9', 4);
var targetPts = [1050+65, 539, 1050+100, 542, 1552, 462];
stage.find('#arrow_next_4').points(targetPts);
targetPts = [333, 590, 220, 550, 260, 400, 1552, 462];
stage.find('#arrow_prev_1').points(targetPts);
//drawListNode(1300, 460, '9', 4);
var text_null = new Konva.Text({
x: 1555,
y: 460,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_null);
let rect_stack = new Konva.Rect({
x: 1500,
y: 50,
id:"rec_p",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 250,
});
layer.add(rect_stack);
let rect_p = new Konva.Rect({
x: 1500,
y: 100,
id:"rec_p",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
var text_p = new Konva.Text({
x: 1545,
y: 110,
text: "p",
id: 'text_p',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var arrow_p = new Konva.Arrow({
points: [1542, 123, 550, 455],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_p',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
layer.add(rect_p);
layer.add(text_p);
layer.add(arrow_p);
// for pointer tmp
let rect_tmp = new Konva.Rect({
x: 1500,
y: 150,
id:"rec_tmp",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
var text_tmp = new Konva.Text({
x: 1540,
y: 160,
text: "tmp",
id: 'text_tmp',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var arrow_tmp = new Konva.Arrow({
points: [1538, 173, 570, 190, 595, 220],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_tmp',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
// the code rectangle.
var rect_code = new Konva.Rect({
x: 150,
y: 20,
id:"rec_code",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 750,
height: 150,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_code);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 750,
padding: 20,
});
}
var code_list=[
"0. Node<int> * tmp = new Node<int>(15); \t\t\t \t\t\t // create a new node",
"1. tmp->next = p->next; \t\t\t \t\t\t \t\t\t \t\t\t // make its successor be the current successor of p",
"2. tmp->prev = p; \t\t\t \t\t\t \t\t\t \t\t\t \t\t\t \t\t\t \t\t\t // make its predecessor be p",
"3. p->next = tmp; \t\t\t \t\t\t \t\t\t \t\t\t \t\t\t \t\t\t \t\t\t // make p's successor be this new node",
"4. (tmp->next)->prev = tmp; \t\t\t \t\t\t // make tmp's successor's predecessor be this new node",
];
function makeBold_list(id){
for(let i=1; i<=code_list.length; i++){
if(i!=id){
// regarding the parentheses, we must add the two numbers first.
stage.find('#line'+(i+100)).fontStyle('normal');
}else{
stage.find('#line'+(i+100)).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code_list.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
// here we add 100 so as to differentiate from the code array.
let t=makeCode(160,20+(i*20),code_list[i],i+1+100);
layer.add(t);
}
// draw the image
layer.draw();
stage.add(layer);
function hide_next() {
stage.find('#arrow_next_1').hide();
stage.find('#arrow_next_2').hide();
stage.find('#arrow_next_3').hide();
stage.find('#arrow_next_4').hide();
stage.find('#arrow_next_5').hide();
layer.draw();
}
function show_next() {
stage.find('#arrow_next_1').show();
stage.find('#arrow_next_2').show();
stage.find('#arrow_next_3').show();
stage.find('#arrow_next_4').show();
stage.find('#arrow_next_5').show();
layer.draw();
}
function hide_prev() {
stage.find('#arrow_prev_1').hide();
stage.find('#arrow_prev_2').hide();
stage.find('#arrow_prev_3').hide();
stage.find('#arrow_prev_4').hide();
stage.find('#arrow_prev_5').hide();
layer.draw();
}
function show_prev() {
stage.find('#arrow_prev_1').show();
stage.find('#arrow_prev_2').show();
stage.find('#arrow_prev_3').show();
stage.find('#arrow_prev_4').show();
stage.find('#arrow_prev_5').show();
layer.draw();
}
var pc2=1;
// erase 5 from this list.
function list_insert_nextstep() {
if(pc2 == 1){
makeBold_list(1);
drawListNode(600, 220, '15', 5);
layer.add(rect_tmp);
layer.add(text_tmp);
layer.add(arrow_tmp);
targetPts = [665, 300, 1150, 342, 1552, 462];
stage.find('#arrow_next_5').points(targetPts);
targetPts = [635, 350, 580, 400, 1552, 462];
stage.find('#arrow_prev_5').points(targetPts);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 2){
makeBold_list(2);
targetPts = [665, 300, 720, 290, 740, 410, 800, 460];
stage.find('#arrow_next_5').points(targetPts);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 3){
makeBold_list(3);
targetPts = [635, 350, 520, 355, 525, 410, 550, 460];
stage.find('#arrow_prev_5').points(targetPts);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 4){
makeBold_list(4);
targetPts = [616, 539, 665, 530, 660, 430, 545, 420, 547, 240, 595, 222];
stage.find('#arrow_next_2').points(targetPts);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 5){
makeBold_list(5);
targetPts = [835, 590, 765, 530, 660, 415, 500, 410, 595, 220];
stage.find('#arrow_prev_3').points(targetPts);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 6){
makeBold_list(-1);
var shape = stage.find('#arrow_p');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#arrow_tmp');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#text_p');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#text_tmp');
shape.to({
opacity: 0,
duration: 2,
});
layer.draw();
pc2=pc2+1;
}else if(pc2 == 7){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc2=pc2+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Doubly-Linked List: remove operation</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Doubly-Linked List: remove operation</h1>
<p>This animation shows the remove operation in Doubly-Linked List. Click the "next step" button to run the animation. <b>Note:</b> in this animation, we will remove a node containing the value 1, and we have a pointer p points to this node. </p>
<div id="container"></div>
<script src="remove.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="list_remove_nextstep()" style="position: absolute; top: 125px; left: 10px;">next step</button>
<button onclick="hide_next()" style="position: absolute; top: 125px; left: 110px;">hide next pointers</button>
<button onclick="show_next()" style="position: absolute; top: 125px; left: 250px;">show next pointers</button>
<button onclick="hide_prev()" style="position: absolute; top: 125px; left: 390px;">hide prev pointers</button>
<button onclick="show_prev()" style="position: absolute; top: 125px; left: 530px;">show prev pointers</button>
</body>
</html>

View File

@@ -0,0 +1,383 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the list.
var rect_list = new Konva.Rect({
x: 150,
y: 280,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 1300,
height: 520,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_list);
// Create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
// for the value.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect1);
// for the next pointer.
let rect2 = new Konva.Rect({
x: x,
y: y+50,
id:"next_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect2);
// for the prev pointer.
let rect3 = new Konva.Rect({
x: x,
y: y+100,
id:"prev_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect3);
// value
var text = new Konva.Text({
x: x + 45,
y: y + 20,
text: label,
id: "node_value_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
// the text "next"
var text_next = new Konva.Text({
x: x + 30,
y: y + 70,
text: "next",
id: "node_next_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_next);
// the text "prev"
var text_prev = new Konva.Text({
x: x + 35,
y: y + 120,
text: "prev",
id: "node_prev_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_prev);
var arrow_next = new Konva.Arrow({
points: [x+65, y+80, x+120, y+85, x+250, y],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_next_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow_next);
var arrow_prev = new Konva.Arrow({
points: [x+33, y+130, x-20, y+200, x-300, y+180, x-250, y],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_prev_" + id,
fill: 'orange',
stroke: 'orange',
strokeWidth: 5,
});
layer.add(arrow_prev);
}
drawListNode(300, 460, '13', 1);
drawListNode(550, 460, '1', 2);
drawListNode(800, 460, '3', 3);
drawListNode(1050, 460, '9', 4);
var targetPts = [1050+65, 539, 1050+100, 542, 1552, 462];
stage.find('#arrow_next_4').points(targetPts);
targetPts = [333, 590, 220, 550, 260, 400, 1552, 462];
stage.find('#arrow_prev_1').points(targetPts);
//drawListNode(1300, 460, '9', 4);
var text_null = new Konva.Text({
x: 1555,
y: 460,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_null);
let rect_stack = new Konva.Rect({
x: 1500,
y: 50,
id:"rec_p",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 250,
});
layer.add(rect_stack);
let rect_p = new Konva.Rect({
x: 1500,
y: 100,
id:"rec_p",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
var text_p = new Konva.Text({
x: 1545,
y: 110,
text: "p",
id: 'text_p',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var arrow_p = new Konva.Arrow({
points: [1542, 123, 550, 455],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_p',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
layer.add(rect_p);
layer.add(text_p);
layer.add(arrow_p);
// the code rectangle.
var rect_code = new Konva.Rect({
x: 150,
y: 80,
id:"rec_code",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 750,
height: 100,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_code);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 750,
padding: 20,
});
}
var code_list=[
"0. p->next->prev = p->prev;",
"1. p->prev->next = p->next;",
"2. delete p;",
];
function makeBold_list(id){
for(let i=1; i<=code_list.length; i++){
if(i!=id){
// regarding the parentheses, we must add the two numbers first.
stage.find('#line'+(i+100)).fontStyle('normal');
}else{
stage.find('#line'+(i+100)).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code_list.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
// here we add 100 so as to differentiate from the code array.
let t=makeCode(160,80+(i*20),code_list[i],i+1+100);
layer.add(t);
}
// draw the image
layer.draw();
stage.add(layer);
function hide_next() {
stage.find('#arrow_next_1').hide();
stage.find('#arrow_next_2').hide();
stage.find('#arrow_next_3').hide();
stage.find('#arrow_next_4').hide();
stage.find('#arrow_next_5').hide();
layer.draw();
}
function show_next() {
stage.find('#arrow_next_1').show();
stage.find('#arrow_next_2').show();
stage.find('#arrow_next_3').show();
stage.find('#arrow_next_4').show();
stage.find('#arrow_next_5').show();
layer.draw();
}
function hide_prev() {
stage.find('#arrow_prev_1').hide();
stage.find('#arrow_prev_2').hide();
stage.find('#arrow_prev_3').hide();
stage.find('#arrow_prev_4').hide();
stage.find('#arrow_prev_5').hide();
layer.draw();
}
function show_prev() {
stage.find('#arrow_prev_1').show();
stage.find('#arrow_prev_2').show();
stage.find('#arrow_prev_3').show();
stage.find('#arrow_prev_4').show();
stage.find('#arrow_prev_5').show();
layer.draw();
}
var pc2=1;
// remove 1 from this list.
function list_remove_nextstep() {
if(pc2 == 1){
makeBold_list(1);
targetPts = [835, 590, 635, 670, 200, 690, 295, 460];
stage.find('#arrow_prev_3').points(targetPts);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 2){
makeBold_list(2);
targetPts = [367, 540, 500, 420, 800, 460];
stage.find('#arrow_next_1').points(targetPts);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 3){
makeBold_list(3);
var shape = stage.find('#list_node_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#next_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#prev_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#node_value_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#node_next_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#node_prev_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#arrow_prev_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#arrow_next_2');
shape.to({
opacity: 0,
duration: 2,
});
layer.draw();
pc2=pc2+1;
}else if(pc2 == 4){
makeBold_list(-1);
shape = stage.find('#arrow_p');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#text_p');
shape.to({
opacity: 0,
duration: 2,
});
layer.draw();
pc2=pc2+1;
}else if(pc2 == 5){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc2=pc2+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,492 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let content = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(content);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
// create stack
makeMemory(750,100,6,200,100);
makeText(750+250, 175, "0x1014", "addr0");
makeText(750+250, 275, "0x1010", "addr1");
makeText(750+250, 375, "0x100C", "addr2");
makeText(750+250, 475, "0x1008", "addr3");
makeText(750+250, 575, "0x1004", "addr4");
makeText(750+250, 675, "0x1000", "addr5");
function makeHeap(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"hrec_"+i, // heap rectangle
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
// create heap
makeHeap(1200,100,6,200,100);
makeText(750+690, 80, "0x0218", "haddr0");
makeText(750+690, 180, "0x0214", "haddr1");
makeText(750+690, 280, "0x0210", "haddr2");
makeText(750+690, 380, "0x020C", "haddr3");
makeText(750+690, 480, "0x0208", "haddr4");
makeText(750+690, 580, "0x0204", "haddr5");
// the code rectangle.
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 320,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 470,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect3 = new Konva.Rect({
x: 1450,
y: 650,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: '#ffffff',
width: 250,
height: 150,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
function makeLegendBox(xstart,ystart,color){
var rect = new Konva.Rect({
x: xstart,
y: ystart,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: color,
width: 40,
height: 25,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect);
}
var stackText = new Konva.Text({
x: 820,
y: 35,
id:"stack",
text: "Stack",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var heapText = new Konva.Text({
x: 1270,
y: 35,
id:"heap",
text: "Heap",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 405,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 735,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrow1 = new Konva.Arrow({
points: [880, 148, 1200, 395],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrow2 = new Konva.Arrow({
points: [880, 248, 1200, 595],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
var arrow3 = new Konva.Arrow({
points: [880, 348, 1200, 595],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow3",
fill: 'red',
stroke: 'red',
strokeWidth: 5,
});
/* for the arrow */
var arrowarray2 = [880, 248, 1200, 595];
// move arrow 2 up
function moveArrowUp(){
arrowarray2[3] = arrowarray2[3] - 200;
stage.find('#arrow2').points(arrowarray2);
}
var arrowarray1 = [880, 148, 1200, 395];
// move arrow 1 down
function moveArrowDown(){
arrowarray1[3] = arrowarray1[3] + 200;
stage.find('#arrow1').points(arrowarray1);
}
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
// box for legend
layer.add(rect3);
// legend
makeText(750+690, 650, "legend (for heap)", "legend");
makeText(1490, 695, "memory not allocated", "free");
makeText(1490, 735, "memory allocated", "allocated");
makeLegendBox(1460, 715, '#ddd');
makeLegendBox(1460, 760, '#ecbeb4');
layer.add(stackText);
layer.add(heapText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
}
var code=["1. int * p = new int;",
"2. *p = 17;",
"3. cout << *p << endl;",
"4. int * q;",
"5. q = new int;",
"6. *q = *p;",
"7. *p = 27;",
"8. cout << *p << \" \" << *q << endl;",
"9. int * temp = q;",
"10. q = p;",
"11. p = temp;",
"12. cout << *p << \" \" << *q << endl;",
"13. delete p;",
"14. delete q;",
];
function makeBold(id){
for(let i=1; i<=code.length; i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,60+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
var message=["$",
"",
"",
""];
function updateMessage(msg,i) {
stage.find('#text_msg'+i).text(msg);
}
// draw that $ sign, which is a command line prompt.
makeText(60,480,message[0],'msg0');
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
makeText(650,120,"int * p",'p');
makeText(1120,320,"int",'p_heap');
// changing color to mark it as allocated
stage.find('#hrec_2').fill('#ecbeb4');
// this has to be after makeMemory so that the memory doesn't overwrite this.
makeContent(800,120,"0x020C",'p_value');
makeContent(1280,320,"?",'p_heap_value');
// add the arrow here.
layer.add(arrow1);
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
stage.find('#p_heap_value').text('17');
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
updateMessage("$ 17",0);
makeText(60,500,message[1],'msg1');
updateMessage("$ ",1);
makeText(60,520,message[2],'msg2');
makeText(60,540,message[3],'msg3');
// stage.find('#console_text').text('$ 10 15');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
makeText(650,220,"int * q",'q');
makeContent(800,220,"\t\t\t\t?",'q_value');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
makeText(1120,520,"int",'q_heap');
// changing color to mark it as allocated
stage.find('#hrec_4').fill('#ecbeb4');
stage.find('#q_value').text('0x0204');
makeContent(1280,520,"?",'q_heap_value');
// add the second arrow here.
layer.add(arrow2);
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(pc);
stage.find('#q_heap_value').text('17');
// stage.find('#console_text').text('$ 150 15');
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold(pc);
stage.find('#p_heap_value').text('27');
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(pc);
updateMessage("$ 27 17",1);
updateMessage("$ ",2);
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(pc);
makeText(650,320,"int * temp",'temp');
makeContent(800,320,"0x0204",'temp_value');
// add the 3rd arrow here.
layer.add(arrow3);
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold(pc);
stage.find('#q_value').text('0x020C');
moveArrowUp();
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold(pc);
stage.find('#p_value').text('0x0204');
moveArrowDown();
layer.draw();
pc=pc+1;
}else if(pc == 12){
makeBold(pc);
updateMessage("$ 17 27",2);
updateMessage("$ ",3);
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold(pc);
// changing color to mark it as reclaimed
stage.find('#hrec_4').fill('#ddd');
stage.find('#text_q_heap').text('');
layer.draw();
pc=pc+1;
}else if(pc == 14){
makeBold(pc);
// changing color to mark it as reclaimed
stage.find('#hrec_2').fill('#ddd');
stage.find('#text_p_heap').text('');
layer.draw();
pc=pc+1;
}else if(pc == 15){
alert("End of animation! Refresh the page if you want to re-run the animation.");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dynamic Memory: example 1</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Dynamic Memory: example 1</h1>
<p>This is the animation of example 1. Click the "next step" button to run the animation.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="example1.js"></script>
</body>
</html>

View File

@@ -0,0 +1,560 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let content = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(content);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
// create stack
makeMemory(750,100,6,200,100);
makeText(750+250, 75, "0x1030", "addr0");
makeText(750+250, 175, "0x1028", "addr1");
makeText(750+250, 275, "0x1020", "addr2");
makeText(750+250, 375, "0x1018", "addr3");
makeText(750+250, 475, "0x1010", "addr4");
makeText(750+250, 575, "0x1008", "addr5");
makeText(750+250, 675, "0x1000", "addr6");
function makeHeap(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"hrec_"+i, // heap rectangle
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
// create heap
makeHeap(1200,100,6,200,100);
makeText(1480, 80, "0x0228", "haddr0");
makeText(1480, 180, "0x0220", "haddr1");
makeText(1480, 280, "0x0218", "haddr2");
makeText(1480, 380, "0x0210", "haddr3");
makeText(1480, 480, "0x0208", "haddr4");
makeText(1480, 580, "0x0200", "haddr5");
// the code rectangle.
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 550,
height: 300,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 470,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 550,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect3 = new Konva.Rect({
x: 1450,
y: 650,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: '#ffffff',
width: 250,
height: 150,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
function makeLegendBox(xstart,ystart,color){
var rect = new Konva.Rect({
x: xstart,
y: ystart,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: color,
width: 40,
height: 25,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect);
}
var stackText = new Konva.Text({
x: 820,
y: 35,
id:"stack",
text: "Stack",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var heapText = new Konva.Text({
x: 1270,
y: 35,
id:"heap",
text: "Heap",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 405,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 735,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrow1 = new Konva.Arrow({
points: [880, 248, 1200, 595],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrow2 = new Konva.Arrow({
points: [880, 248, 1200, 505],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
var arrow3 = new Konva.Arrow({
points: [880, 348, 1200, 505],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow3",
fill: 'red',
stroke: 'red',
strokeWidth: 5,
});
/* for the arrow */
var arrowarray2 = [880, 248, 1200, 505];
// move arrow 2 up
function moveArrowUp(){
arrowarray2[3] = arrowarray2[3] - 200;
stage.find('#arrow2').points(arrowarray2);
}
var arrowarray1 = [880, 148, 1200, 305];
// move arrow 1 down
function moveArrowDown(){
arrowarray1[3] = arrowarray1[3] + 200;
stage.find('#arrow1').points(arrowarray1);
}
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
// box for legend
layer.add(rect3);
// legend
makeText(750+690, 650, "legend (for heap)", "legend");
makeText(1490, 695, "memory not allocated", "free");
makeText(1490, 735, "memory allocated", "allocated");
makeLegendBox(1460, 715, '#ddd');
makeLegendBox(1460, 760, '#ecbeb4');
layer.add(stackText);
layer.add(heapText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 550,
padding: 20,
});
}
var code=["0. int main(){",
"1. \t\t\t std::cout << \"Enter the size of the array: \";",
"2. \t\t\t int n, i;",
"3. \t\t\t std::cin >> n;",
"4. \t\t\t double *a = new double[n];",
"5. \t\t\t for (i=0; i<n; ++i) { a[i] = sqrt[i]; }",
"6. \t\t\t for (i=0; i<n; ++i) {",
"7. \t\t\t \t\t\t if (double(int(a[i])) == a[i] )",
"8. \t\t\t \t\t\t \t\t\t std::cout << i << \" is a perfect square \" << std::endl;",
"9. \t\t\t }",
"10. \t delete [] a;",
"11. \t return 0;",
"12. }",
];
function makeBold(id){
for(let i=1; i<=code.length; i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
// make multiple lines bold
function makeBold2(id, len){
for(let i=1; i<=code.length; i++){
if( i<id || i>=(id+len) ){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+i).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,60+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
var message=["$",
"",
"",
"",
""];
function updateMessage(msg,i) {
stage.find('#text_msg'+i).text(msg);
}
// draw that $ sign, which is a command line prompt.
makeText(60,480,message[0],'msg0');
var line1 = new Konva.Line({
points: [750, 150, 950, 150],
stroke: '#343434',
strokeWidth: 5,
});
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
//makeText(1120,320,"int",'p_heap');
// changing color to mark it as allocated
//stage.find('#hrec_2').fill('#ecbeb4');
// this has to be after makeMemory so that the memory doesn't overwrite this.
//makeContent(800,120,"0x020C",'p_value');
//makeContent(1280,320,"?",'p_heap_value');
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
updateMessage("$ Enter the size of the array: ",0);
makeText(60,500,message[1],'msg1');
makeText(60,520,message[2],'msg2');
makeText(60,540,message[3],'msg3');
makeText(60,560,message[4],'msg4');
//stage.find('#p_heap_value').text('17');
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
makeText(650,100,"int n",'n');
makeContent(820,100,"?",'n_value');
layer.add(line1);
makeText(650,150,"int i",'i');
makeContent(820,150,"?",'i_value');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
updateMessage("$ Enter the size of the array: 4 // we pretend someone inputs 4 here",0);
updateMessage("$", 2);
stage.find('#n_value').text('4');
//makeText(650,220,"int * q",'q');
//makeContent(800,220,"\t\t\t\t?",'q_value');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
makeText(650,220,"double *a",'a');
makeText(1070,520,"double [4]",'a_heap');
// changing color to mark it as allocated
stage.find('#hrec_1').fill('#ecbeb4');
stage.find('#hrec_2').fill('#ecbeb4');
stage.find('#hrec_3').fill('#ecbeb4');
stage.find('#hrec_4').fill('#ecbeb4');
stage.find('#q_value').text('0x0204');
makeText(1400, 210, "[3]", "haddr2");
makeText(1400, 310, "[2]", "haddr3");
makeText(1400, 410, "[1]", "haddr4");
makeText(1400, 510, "[0]", "haddr5");
makeContent(1274,220," ?",'q_heap_value3');
makeContent(1274,320," ?",'q_heap_value2');
makeContent(1274,420," ?",'q_heap_value1');
makeContent(1274,520," ?",'q_heap_value0');
makeContent(800,220,"0x0200",'a_value');
// add the 1st arrow here.
layer.add(arrow1);
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(pc);
stage.find('#q_heap_value0').text('0.00');
stage.find('#q_heap_value1').text('1.00');
stage.find('#q_heap_value2').text('1.44');
stage.find('#q_heap_value3').text('1.73');
stage.find('#i_value').text('4');
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold(pc);
stage.find('#i_value').text('0');
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(pc);
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(pc);
updateMessage("$ 0 is a perfect square", 2);
updateMessage("$", 3);
layer.draw();
pc=pc+1;
}else if(pc == 10){ // close curly brace
makeBold(pc);
layer.draw();
pc=pc+1;
}else if(pc == 11){ // open curly brace
makeBold(7);
stage.find('#i_value').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 12){ // if statement
makeBold(8);
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold(9);
updateMessage("$ 1 is a perfect square", 3);
updateMessage("$ ",4);
layer.draw();
pc=pc+1;
}else if(pc == 14){ // close curly brace
makeBold(10);
layer.draw();
pc=pc+1;
}else if(pc == 15){ // open curly brace
makeBold(7);
stage.find('#i_value').text('2');
layer.draw();
pc=pc+1;
}else if(pc == 16){ // if statement
makeBold(8);
layer.draw();
pc=pc+1;
}else if(pc == 17){ // close curly brace
makeBold(10); // skip 9 because if isn't true.
layer.draw();
pc=pc+1;
}else if(pc == 18){ // open curly brace
makeBold(7);
stage.find('#i_value').text('3');
layer.draw();
pc=pc+1;
}else if(pc == 19){ // if statement
makeBold(8);
layer.draw();
pc=pc+1;
}else if(pc == 20){ // close curly brace
makeBold(10); // skip 9 because if isn't true.
layer.draw();
pc=pc+1;
}else if(pc == 21){ // open curl brace, but now i is 4, thus get out of the for loop.
makeBold(7);
stage.find('#i_value').text('4');
layer.draw();
pc=pc+1;
}else if(pc == 22){
makeBold(11);
// changing color to mark it as reclaimed
stage.find('#hrec_1').fill('#ddd');
stage.find('#hrec_2').fill('#ddd');
stage.find('#hrec_3').fill('#ddd');
stage.find('#hrec_4').fill('#ddd');
stage.find('#text_a_heap').text('');
layer.draw();
pc=pc+1;
}else if(pc == 23){
makeBold(12);
layer.draw();
pc=pc+1;
}else if(pc == 24){
alert("End of animation! Refresh the page if you want to re-run the animation.");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dynamic Memory: example 2</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Dynamic Memory: example 2</h1>
<p>This is the animation of example 2. Click the "next step" button to run the animation.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="example2.js"></script>
</body>
</html>

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dynamic Memory: Two Dimensional Arrays Example </title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Dynamic Memory: Two Dimensional Arrays Example</h1>
<p>This is an animation of dynamic allocation of two-dimensional arrays. Click the "next step" button to run the animation. <b>Note</b>: we assume rows is 2 and cols is 3. </p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="two_d_array.js"></script>
</body>
</html>

View File

@@ -0,0 +1,651 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let content = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(content);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
// create stack
makeMemory(750,100,10,200,50);
//makeText(750+250, 75, "0x1030", "addr0");
//makeText(750+250, 175, "0x1028", "addr1");
//makeText(750+250, 275, "0x1020", "addr2");
//makeText(750+250, 375, "0x1018", "addr3");
//makeText(750+250, 475, "0x1010", "addr4");
//makeText(750+250, 575, "0x1008", "addr5");
//makeText(750+250, 675, "0x1000", "addr6");
function makeHeap(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"hrec_"+i, // heap rectangle
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
// create heap
makeHeap(1200,100,12,200,50);
makeText(1480, 74, "0x0258", "haddr0");
makeText(1480, 124, "0x0250", "haddr0");
makeText(1480, 174, "0x0248", "haddr1");
makeText(1480, 224, "0x0240", "haddr0");
makeText(1480, 274, "0x0238", "haddr2");
makeText(1480, 324, "0x0230", "haddr0");
makeText(1480, 374, "0x0228", "haddr3");
makeText(1480, 424, "0x0220", "haddr0");
makeText(1480, 474, "0x0218", "haddr4");
makeText(1480, 524, "0x0210", "haddr0");
makeText(1480, 574, "0x0208", "haddr5");
makeText(1480, 624, "0x0200", "haddr0");
// the code rectangle.
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 250,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 400,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect3 = new Konva.Rect({
x: 1450,
y: 670,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: '#ffffff',
width: 250,
height: 150,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
function makeLegendBox(xstart,ystart,color){
var rect = new Konva.Rect({
x: xstart,
y: ystart,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: color,
width: 40,
height: 25,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect);
}
var stackText = new Konva.Text({
x: 820,
y: 35,
id:"stack",
text: "Stack",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var heapText = new Konva.Text({
x: 1270,
y: 35,
id:"heap",
text: "Heap",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 345,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 635,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrow1 = new Konva.Arrow({
points: [880, 125, 1200, 445],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrow2 = new Konva.Arrow({
points: [1280, 428, 1140, 350, 1200, 295],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
var arrow3 = new Konva.Arrow({
points: [1280, 378, 1140, 450, 1200, 645],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow3",
fill: 'red',
stroke: 'red',
strokeWidth: 5,
});
/* for the arrow */
var arrowarray2 = [880, 248, 1200, 505];
// move arrow 2 up
function moveArrowUp(){
arrowarray2[3] = arrowarray2[3] - 200;
stage.find('#arrow2').points(arrowarray2);
}
var arrowarray1 = [880, 148, 1200, 305];
// move arrow 1 down
function moveArrowDown(){
arrowarray1[3] = arrowarray1[3] + 200;
stage.find('#arrow1').points(arrowarray1);
}
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
// box for legend
layer.add(rect3);
// legend
makeText(750+690, 670, "legend (for heap)", "legend");
makeText(1490, 715, "memory not allocated", "free");
makeText(1490, 755, "memory allocated", "allocated");
makeLegendBox(1460, 735, '#ddd');
makeLegendBox(1460, 780, '#ecbeb4');
layer.add(stackText);
layer.add(heapText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 550,
padding: 20,
});
}
var code=[
"0. double** a = new double* [rows];",
"1. for(int i = 0; i < rows; i++) {",
"2. \t\t\t a[i] = new double[cols];",
"3. \t\t\t for (int j=0; j<cols; j++) {",
"4. \t\t\t \t\t\t a[i][j] = double(i+1) / double(j+1);",
"5. \t\t\t }",
"6. }",
"7. for(int i = 0; i < rows; i++) {",
"8. \t\t\t delete [] a[i];",
"9. }",
"10. delete [] a;",
];
function makeBold(id){
for(let i=1; i<=code.length; i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
// make multiple lines bold
function makeBold2(id, len){
for(let i=1; i<=code.length; i++){
if( i<id || i>=(id+len) ){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+i).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,60+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
var message=["$",
"",
"",
"",
""];
function updateMessage(msg,i) {
stage.find('#text_msg'+i).text(msg);
}
// draw that $ sign, which is a command line prompt.
makeText(60,420,message[0],'msg0');
var line1 = new Konva.Line({
points: [750, 175, 950, 175],
stroke: '#343434',
strokeWidth: 5,
});
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
makeText(600,100,"double ** a",'a');
makeContent(800,100,"0x0220",'a_value');
makeText(1020,400,"double [2]",'a_heap');
// changing color to mark it as allocated
stage.find('#hrec_5').fill('#ecbeb4');
stage.find('#hrec_6').fill('#ecbeb4');
// heap value
makeContent(1262,345,"\t ?",'a_heap_value1');
makeContent(1262,395,"\t ?",'a_heap_value0');
// heap label
makeText(1400, 350, "a[1]", "haddr4");
makeText(1400, 400, "a[0]", "haddr5");
// add the 1st arrow here.
layer.add(arrow1);
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
makeText(650,135,"int i",'i');
makeContent(820,135,"0",'i_value');
layer.add(line1);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
stage.find('#a_heap_value0').text('0x0238');
// changing color to mark it as allocated
stage.find('#hrec_1').fill('#ecbeb4');
stage.find('#hrec_2').fill('#ecbeb4');
stage.find('#hrec_3').fill('#ecbeb4');
// add the 2nd arrow here.
layer.add(arrow2);
// heap label
makeText(1400, 250, "a[0][0]", "a0_haddr0");
makeText(1400, 200, "a[0][1]", "a0_haddr1");
makeText(1400, 150, "a[0][2]", "a0_haddr2");
// heap value
makeContent(1262,145,"\t ?",'a0_heap_value2');
makeContent(1262,195,"\t ?",'a0_heap_value1');
makeContent(1262,245,"\t ?",'a0_heap_value0');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
makeText(650,160,"int j",'j');
makeContent(820,160,"0",'j_value');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
stage.find('#a0_heap_value0').text('1.00');
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(pc);
layer.draw();
pc=pc+1;
}else if(pc == 7){ // inner loop, 2nd iteration, update j first.
makeBold(4);
stage.find('#j_value').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(5);
stage.find('#a0_heap_value1').text('0.50');
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 10){ // inner loop, 3rd iteration, update j first.
makeBold(4);
stage.find('#j_value').text('2');
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold(5);
stage.find('#a0_heap_value2').text('0.33');
layer.draw();
pc=pc+1;
}else if(pc == 12){ // close curly brace of inner loop.
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 13){ // open curly brace
makeBold(4);
stage.find('#j_value').text('3');
layer.draw();
pc=pc+1;
}else if(pc == 14){ // close curly brace of inner loop.
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 15){ // close curly bracket for outter loop.
makeBold(7);
layer.draw();
pc=pc+1;
}else if(pc == 16){ // open curly brace, update i
makeBold(2);
stage.find('#i_value').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 17){
makeBold(3);
stage.find('#a_heap_value1').text('0x0200');
// changing color to mark it as allocated
stage.find('#hrec_8').fill('#ecbeb4');
stage.find('#hrec_9').fill('#ecbeb4');
stage.find('#hrec_10').fill('#ecbeb4');
// add the 3rd arrow here.
layer.add(arrow3);
// heap label
makeText(1400, 600, "a[1][0]", "a1_haddr0");
makeText(1400, 550, "a[1][1]", "a1_haddr1");
makeText(1400, 500, "a[1][2]", "a1_haddr2");
// heap value
makeContent(1262,495,"\t ?",'a1_heap_value2');
makeContent(1262,545,"\t ?",'a1_heap_value1');
makeContent(1262,595,"\t ?",'a1_heap_value0');
layer.draw();
pc=pc+1;
}else if(pc == 18){ // i=1, again start inner loop, reset j to 0. repeat the inner loop one more time.
makeBold(4);
stage.find('#j_value').text('0');
layer.draw();
pc=pc+1;
}else if(pc == 19){
makeBold(5);
stage.find('#a1_heap_value0').text('2.00');
layer.draw();
pc=pc+1;
}else if(pc == 20){
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 21){ // inner loop, 2nd iteration, update j first.
makeBold(4);
stage.find('#j_value').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 22){
makeBold(5);
stage.find('#a1_heap_value1').text('1.00');
layer.draw();
pc=pc+1;
}else if(pc == 23){
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 24){ // inner loop, 3rd iteration, update j first.
makeBold(4);
stage.find('#j_value').text('2');
layer.draw();
pc=pc+1;
}else if(pc == 25){
makeBold(5);
stage.find('#a1_heap_value2').text('0.66');
layer.draw();
pc=pc+1;
}else if(pc == 26){ // close curly brace of inner loop.
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 27){ // open curly brace
makeBold(4);
stage.find('#j_value').text('3');
layer.draw();
pc=pc+1;
}else if(pc == 28){ // close curly brace of inner loop.
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 29){ // close curly bracket for outter loop.
makeBold(7);
layer.draw();
pc=pc+1;
}else if(pc == 30){ // open curly brace, update i, and because i is 2 now, get out of the outter for loop.
makeBold(2);
stage.find('#i_value').text('2');
layer.draw();
pc=pc+1;
}else if(pc == 31){ // close curly brace.
makeBold(7);
layer.draw();
pc=pc+1;
}else if(pc == 32){ // start the next for loop, reset i, reclaim j.
makeBold(8);
stage.find('#i_value').text('0');
stage.find('#j_value').text('');
stage.find('#text_j').text('');
layer.draw();
pc=pc+1;
}else if(pc == 33){ // delete a[0]
makeBold(9);
// changing color to mark it as reclaimed
stage.find('#hrec_1').fill('#ddd');
stage.find('#hrec_2').fill('#ddd');
stage.find('#hrec_3').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 34){ // close curly brace.
makeBold(10);
layer.draw();
pc=pc+1;
}else if(pc == 35){ // 2nd iteration of the for loop, update i.
makeBold(8);
stage.find('#i_value').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 36){ // delete a[1]
makeBold(9);
// changing color to mark it as reclaimed
stage.find('#hrec_8').fill('#ddd');
stage.find('#hrec_9').fill('#ddd');
stage.find('#hrec_10').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 37){ // close curly brace.
makeBold(10);
layer.draw();
pc=pc+1;
}else if(pc == 38){ // update i, and now i is 2, get out of the loop.
makeBold(8);
stage.find('#i_value').text('2');
layer.draw();
pc=pc+1;
}else if(pc == 39){ // close curly brace.
makeBold(10);
layer.draw();
pc=pc+1;
}else if(pc == 40){ // delete a
makeBold(11);
stage.find('#hrec_5').fill('#ddd');
stage.find('#hrec_6').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 41){
alert("End of animation! Refresh the page if you want to re-run the animation.");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Min Heap: Delete a node</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Min Heap: Delete a Node</h1>
<p>This animation shows how to delete a node of value 20 in a Min Heap. Click the "next step" button to run the animation. </p>
<br>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="pop.js"></script>
</body>
</html>

369
animations/heap/pop/pop.js Normal file
View File

@@ -0,0 +1,369 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// Create a layer
var layer = new Konva.Layer();
stage.add(layer);
// Create a function to draw nodes
function drawNode(x, y, label, id) {
var circle = new Konva.Circle({
x: x,
y: y,
id: 'node_'+id,
radius: 40,
fill: 'lightgray',
stroke: 'black',
strokeWidth: 1
});
layer.add(circle);
var text = new Konva.Text({
x: x-5,
y: y-10,
id: 'node_text_'+id,
text: label,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
}
// Draw lines connecting nodes
var line1 = new Konva.Line({
points: [615, 120, 520, 180],
//points: [650, 100, 450, 200, 650, 100, 850, 200],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line2 = new Konva.Line({
points: [685, 120, 780, 180],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow1 = new Konva.Arrow({
points: [925, 200, 1150, 200],
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line3 = new Konva.Line({
//points: [450, 200, 350, 300, 450, 200, 550, 300],
points: [465, 220, 378, 272],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line4 = new Konva.Line({
points: [530, 228, 572, 272],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line5 = new Konva.Line({
// points: [850, 200, 750, 300, 850, 200, 950, 300],
points: [765, 220, 700, 300],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow2 = new Konva.Arrow({
points: [1000, 300, 1150, 300],
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line6 = new Konva.Line({
points: [835, 220, 900, 300],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line7 = new Konva.Line({
// points: [350, 300, 300, 400, 350, 300, 400, 400],
points: [315, 320, 230, 375],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line8 = new Konva.Line({
points: [805, 200, 916, 276],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line9 = new Konva.Line({
points: [950, 300, 900, 400, 950, 300, 1000, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow3 = new Konva.Arrow({
points: [1050, 400, 1150, 400],
pointerLength: 10,
pointerWidth: 10,
id: "arrow3",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
// Create a dotted line
var dottedLine = new Konva.Line({
points: [300, 400, 200, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var dottedLine2 = new Konva.Line({
points: [1000, 400, 1050, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var arrow4 = new Konva.Arrow({
points: [1070, 600, 1150, 600],
pointerLength: 10,
pointerWidth: 10,
id: "arrow4",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var messageBox = new Konva.Rect({
x: 150,
y: 650,
width: 800,
height: 60,
fill: 'lightblue',
stroke: 'black',
strokeWidth: 4
});
var arrow = new Konva.Arrow({
x: messageBox.x() + messageBox.width() / 2,
y: messageBox.y(),
points: [0, 0, 0, -150],
pointerLength: 20,
pointerWidth: 20,
fill: 'black',
stroke: 'black',
strokeWidth: 4
});
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
// make the tree index
makeText(570,80,"0",10);
makeText(420,180,"1",11);
makeText(830,180,"2",12);
makeText(270,280,"3",13);
makeText(520,280,"4",14);
makeText(730,280,"5",15);
makeText(930,280,"6",16);
drawNode(650, 100, '20',0);
layer.add(line1);
layer.add(line2);
drawNode(500, 200, '30',1);
drawNode(800, 200, '60',2);
layer.add(line3);
layer.add(line4);
drawNode(350, 300, '50',3);
drawNode(600, 300, '40',4);
layer.add(line5);
drawNode(700, 300, '70',5);
layer.add(line6);
drawNode(900, 300, '80',6);
layer.add(line8);
line8.hide();
function makeBox(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart+i*w,
y: ystart,
id:"box_"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
}
}
/* this array displays the input string */
makeBox(300,540,8,50,50); // a buffer whose size is 8, the array has 8 elements.
// don't show the last box for now.
stage.find('#box_'+7).hide();
/* for "20, 30, 60, 50, 40, 70, 80" */
makeText(300,540,"20",0);
makeText(350,540,"30",1);
makeText(400,540,"60",2);
makeText(450,540,"50",3);
makeText(500,540,"40",4);
makeText(550,540,"70",5);
makeText(600,540,"80",6);
// make the vector index
makeText(300,600,"0",20);
makeText(350,600,"1",21);
makeText(400,600,"2",22);
makeText(450,600,"3",23);
makeText(500,600,"4",24);
makeText(550,600,"5",25);
makeText(600,600,"6",26);
var msg_box = new Konva.Rect({
x: 1100,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var message=["for each subscript i:",
"the parent, if it exists, is at location ⌊(i 1)/2⌋.",
"the left child, if it exists, is at location 2i + 1.",
"the right child, if it exists, is at location 2i + 2."];
/* draw the message box */
layer.add(msg_box);
makeText(1100,100,message[0],'msg0');
makeText(1100,150,message[1],'msg1');
makeText(1100,200,message[2],'msg2');
makeText(1100,250,message[3],'msg3');
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
// highlight element 7 and element 3
stage.find('#box_'+0).fill('#ff5733');
stage.find('#box_'+6).fill('#ff5733');
stage.find('#node_'+0).fill('#ff5733');
stage.find('#node_'+6).fill('#ff5733');
layer.draw();
pc = pc + 1;
}else if(pc == 2){
// do the numbers swap in the vector
stage.find('#text_'+0).text('80');
// do the numbers swap on the treee
stage.find('#node_text_'+0).text('80');
layer.draw();
pc = pc + 1;
}else if(pc == 3){
stage.find('#text_'+6).hide();
// hide the tree index
stage.find('#text_'+16).hide();
// hide the vector index
stage.find('#text_'+26).hide();
// hide the line
line6.hide();
stage.find('#node_text_'+6).hide();
stage.find('#box_'+6).hide();
stage.find('#node_'+6).hide();
layer.draw();
pc = pc + 1;
}else if(pc == 4){
// highlight element 0 and element 1
stage.find('#box_'+1).fill('#ff5733');
stage.find('#node_'+1).fill('#ff5733');
layer.draw();
pc = pc + 1;
}else if(pc == 5){
// again, do the numbers swap in the vector
stage.find('#text_'+0).text('30');
stage.find('#text_'+1).text('80');
// do the numbers swap on the treee
stage.find('#node_text_'+0).text('30');
stage.find('#node_text_'+1).text('80');
layer.draw();
pc = pc + 1;
}else if(pc == 6){
// highlight element 1 and element 4
stage.find('#box_'+4).fill('#ff5733');
stage.find('#node_'+4).fill('#ff5733');
layer.draw();
pc = pc + 1;
}else if(pc == 7){
// again, do the numbers swap in the vector
stage.find('#text_'+1).text('40');
stage.find('#text_'+4).text('80');
// do the numbers swap on the treee
stage.find('#node_text_'+1).text('40');
stage.find('#node_text_'+4).text('80');
layer.draw();
pc = pc + 1;
}else if(pc == 8){
alert("End of animation! Now the heap is in the right shape. Refresh the page if you want to re-run the animation.");
}
}

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Min Heap: Insert a node</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Min Heap: Insert a Node</h1>
<p>This animation shows how to insert a node of value 10 in a Min Heap. Click the "next step" button to run the animation. </p>
<br>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="push.js"></script>
</body>
</html>

View File

@@ -0,0 +1,374 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// Create a layer
var layer = new Konva.Layer();
stage.add(layer);
// Create a function to draw nodes
function drawNode(x, y, label, id) {
var circle = new Konva.Circle({
x: x,
y: y,
id: 'node_'+id,
radius: 40,
fill: 'lightgray',
stroke: 'black',
strokeWidth: 1
});
layer.add(circle);
var text = new Konva.Text({
x: x-5,
y: y-10,
id: 'node_text_'+id,
text: label,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
}
// Draw lines connecting nodes
var line1 = new Konva.Line({
points: [615, 120, 520, 180],
//points: [650, 100, 450, 200, 650, 100, 850, 200],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line2 = new Konva.Line({
points: [685, 120, 780, 180],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow1 = new Konva.Arrow({
points: [925, 200, 1150, 200],
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line3 = new Konva.Line({
//points: [450, 200, 350, 300, 450, 200, 550, 300],
points: [465, 220, 378, 272],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line4 = new Konva.Line({
points: [530, 228, 572, 272],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line5 = new Konva.Line({
// points: [850, 200, 750, 300, 850, 200, 950, 300],
points: [765, 220, 700, 300],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow2 = new Konva.Arrow({
points: [1000, 300, 1150, 300],
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line6 = new Konva.Line({
points: [835, 220, 900, 300],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line7 = new Konva.Line({
// points: [350, 300, 300, 400, 350, 300, 400, 400],
points: [315, 320, 230, 375],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line8 = new Konva.Line({
points: [805, 200, 916, 276],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line9 = new Konva.Line({
points: [950, 300, 900, 400, 950, 300, 1000, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow3 = new Konva.Arrow({
points: [1050, 400, 1150, 400],
pointerLength: 10,
pointerWidth: 10,
id: "arrow3",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
// Create a dotted line
var dottedLine = new Konva.Line({
points: [300, 400, 200, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var dottedLine2 = new Konva.Line({
points: [1000, 400, 1050, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var arrow4 = new Konva.Arrow({
points: [1070, 600, 1150, 600],
pointerLength: 10,
pointerWidth: 10,
id: "arrow4",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var messageBox = new Konva.Rect({
x: 150,
y: 650,
width: 800,
height: 60,
fill: 'lightblue',
stroke: 'black',
strokeWidth: 4
});
var arrow = new Konva.Arrow({
x: messageBox.x() + messageBox.width() / 2,
y: messageBox.y(),
points: [0, 0, 0, -150],
pointerLength: 20,
pointerWidth: 20,
fill: 'black',
stroke: 'black',
strokeWidth: 4
});
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
// make the tree index
makeText(570,80,"0",0);
makeText(420,180,"1",1);
makeText(830,180,"2",2);
makeText(270,280,"3",3);
makeText(520,280,"4",4);
makeText(730,280,"5",5);
makeText(930,280,"6",6);
drawNode(650, 100, '20',0);
layer.add(line1);
layer.add(line2);
drawNode(500, 200, '30',1);
drawNode(800, 200, '60',2);
layer.add(line3);
layer.add(line4);
drawNode(350, 300, '50',3);
drawNode(600, 300, '40',4);
layer.add(line5);
drawNode(700, 300, '70',5);
layer.add(line6);
drawNode(900, 300, '80',6);
layer.add(line8);
line8.hide();
function makeBox(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart+i*w,
y: ystart,
id:"box_"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
}
}
/* this array displays the input string */
makeBox(300,540,8,50,50); // a buffer whose size is 8, the array has 8 elements.
// don't show the last box for now.
stage.find('#box_'+7).hide();
/* for "20, 30, 60, 50, 40, 70, 80" */
makeText(300,540,"20",10);
makeText(350,540,"30",11);
makeText(400,540,"60",12);
makeText(450,540,"50",13);
makeText(500,540,"40",14);
makeText(550,540,"70",15);
makeText(600,540,"80",16);
// make the vector index
makeText(300,600,"0",1);
makeText(350,600,"1",1);
makeText(400,600,"2",1);
makeText(450,600,"3",1);
makeText(500,600,"4",1);
makeText(550,600,"5",1);
makeText(600,600,"6",1);
var msg_box = new Konva.Rect({
x: 1100,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var message=["for each subscript i:",
"the parent, if it exists, is at location ⌊(i 1)/2⌋.",
"the left child, if it exists, is at location 2i + 1.",
"the right child, if it exists, is at location 2i + 2."];
/* draw the message box */
layer.add(msg_box);
makeText(1100,100,message[0],'msg0');
makeText(1100,150,message[1],'msg1');
makeText(1100,200,message[2],'msg2');
makeText(1100,250,message[3],'msg3');
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
stage.find('#box_'+7).show();
makeText(650,540,"10",17);
makeText(650,600,"7",1);
layer.draw();
pc = pc + 1;
}else if(pc == 2){
drawNode(200, 400, '10', 7);
makeText(120,380,"7",1);
layer.add(line7);
layer.draw();
pc = pc + 1;
}else if(pc == 3){
// highlight element 7 and element 3
stage.find('#box_'+7).fill('#ff5733');
stage.find('#box_'+3).fill('#ff5733');
stage.find('#node_'+7).fill('#ff5733');
stage.find('#node_'+3).fill('#ff5733');
layer.draw();
pc = pc + 1;
}else if(pc == 4){
// do the numbers swap in the vector
stage.find('#text_'+17).text('50');
stage.find('#text_'+13).text('10');
// do the numbers swap on the treee
stage.find('#node_text_'+7).text('50');
stage.find('#node_text_'+3).text('10');
layer.draw();
pc = pc + 1;
}else if(pc == 5){
// highlight element 3 and element 1
stage.find('#box_'+1).fill('#ff5733');
//stage.find('#box_'+3).fill('#ff5733');
stage.find('#node_'+1).fill('#ff5733');
//stage.find('#node_'+3).fill('#ff5733');
layer.draw();
pc = pc + 1;
}else if(pc == 6){
// again, do the numbers swap in the vector
stage.find('#text_'+13).text('30');
stage.find('#text_'+11).text('10');
// do the numbers swap on the treee
stage.find('#node_text_'+3).text('30');
stage.find('#node_text_'+1).text('10');
layer.draw();
pc = pc + 1;
}else if(pc == 7){
// highlight element 1 and element 0
stage.find('#box_'+0).fill('#ff5733');
//stage.find('#box_'+3).fill('#ff5733');
stage.find('#node_'+0).fill('#ff5733');
//stage.find('#node_'+3).fill('#ff5733');
layer.draw();
pc = pc + 1;
}else if(pc == 8){
// again, do the numbers swap in the vector
stage.find('#text_'+11).text('20');
stage.find('#text_'+10).text('10');
// do the numbers swap on the treee
stage.find('#node_text_'+1).text('20');
stage.find('#node_text_'+0).text('10');
layer.draw();
pc = pc + 1;
}else if(pc == 9){
alert("End of animation! Now the heap is in the right shape. Refresh the page if you want to re-run the animation.");
}
}

18223
animations/konva.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,483 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the stack nodes.
var rect2 = new Konva.Rect({
x: 870,
y: 420,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 310,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect2);
// the rectangle which contains the list.
var rect3 = new Konva.Rect({
x: 1050,
y: 420,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 500,
height: 310,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect3);
// create a function to draw stack nodes
function drawStackNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect1);
// name of the pointer
var text1 = new Konva.Text({
x: x - 50,
y: y + 20,
text: label,
id: "node_index_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text1);
}
// create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 40,
height: 50,
});
layer.add(rect1);
let rect2 = new Konva.Rect({
x: x + 40,
y: y,
id:"list_node_pointer_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 80,
height: 50,
});
layer.add(rect2);
var text = new Konva.Text({
x: x + 15,
y: y + 20,
text: label,
id: "list_node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var arrow = new Konva.Arrow({
points: [x+80, y+25, x+150, y+25],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "list_arrow_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
visible: false,
});
layer.add(arrow);
}
var text_null = new Konva.Text({
x: 1605,
y: 475,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_null);
var text_stack = new Konva.Text({
x: 895,
y: 380,
text: "Stack",
id: "node_text_stack",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_stack);
var text_heap = new Konva.Text({
x: 1255,
y: 380,
text: "Heap",
id: "node_text_heap",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_heap);
var rect_console = new Konva.Rect({
x: 150,
y: 400,
id:"console_rect",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_console);
var consoleLabel = new Konva.Text({
x: 280,
y: 635,
id:"console_label",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 140,
y: 400,
id:"console_text",
text: "",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
layer.add(consoleLabel);
layer.add(consoleText);
var message=["$",
"",
"",
"",
""];
function updateMessage(msg,i) {
stage.find('#text_msg'+i).text(msg);
}
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
// draw that $ sign, which is a command line prompt.
makeText(155,420,message[0],'msg0');
var arrow_p = new Konva.Arrow({
points: [1100, 605, 1100, 535],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_p',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
// the node code rectangle.
var rect1 = new Konva.Rect({
x: 150,
y: 30,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 160,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var nodeLabel = new Konva.Text({
x: 280,
y: 235,
id:"node_label",
text: "Node Definition",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
layer.add(nodeLabel);
layer.add(rect1);
// the main code rectangle.
var rect_list = new Konva.Rect({
x: 850,
y: 30,
id:"code_rec_list",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 650,
height: 300,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_list);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 650,
padding: 20,
});
}
var code=[
"0. template <class T>",
"1. class Node {",
"2. public:",
"3. \t\t\t T value;",
"4. \t\t\t Node* next;",
"5. }",
];
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(160,30+(i*20),code[i],i+1);
layer.add(t);
}
var code_list=[
"0. int main() {",
"1. \t\t\t Node<int>* head;",
"2. \t\t\t head = new Node<int>;",
"3. \t\t\t head->value = 6;",
"4. \t\t\t head->next = NULL;",
"5. \t\t\t Node<int>* q = new Node<int>;",
"6. \t\t\t q->value = 8;",
"7. \t\t\t q->next = NULL;",
"8. \t\t\t head->next = q;",
"9. \t\t\t cout << \"1st value: \" << head->value << endl;",
"10. \t\t\tcout << \"2nd value: \" << head->next->value << endl;",
"11. }",
];
function makeBold_list(id){
for(let i=1; i<=code_list.length; i++){
if(i!=id){
// regarding the parentheses, we must add the two numbers first.
stage.find('#line'+(i+100)).fontStyle('normal');
}else{
stage.find('#line'+(i+100)).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code_list.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
// here we add 100 so as to differentiate from the code array.
let t=makeCode(860,30+(i*20),code_list[i],i+1+100);
layer.add(t);
}
// draw the image
layer.draw();
stage.add(layer);
var arrow1 = new Konva.Arrow({
points: [910, 535, 1030, 485, 1075, 485],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrow2 = new Konva.Arrow({
points: [910, 585, 1030, 635, 1235, 585],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.draw();
var targetPts = [1160, 485, 1200, 435, 1600, 485];
// create the animation
var tween = new Konva.Tween({
node: arrow2,
points: targetPts,
duration: 2, // animation duration in seconds
easing: Konva.Easings.Linear
});
var pc=1;
// creating the list.
function nextstep() {
if(pc == 1){
makeBold_list(pc);
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold_list(pc);
drawStackNode(870, 500, 'head', 1);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold_list(pc);
drawListNode(1080, 460, '?', 1);
layer.add(arrow1);
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold_list(pc);
stage.find('#list_node_text_1').text('6');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold_list(pc);
stage.find('#list_arrow_1').points(targetPts);
stage.find('#list_arrow_1').visible('true');
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold_list(pc);
drawStackNode(870, 550, 'q', 2);
drawListNode(1240, 560, '?', 2);
layer.add(arrow2);
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold_list(pc);
stage.find('#list_node_text_2').text('8');
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold_list(pc);
targetPts = [1310, 585, 1350, 600, 1600, 485];
stage.find('#list_arrow_2').points(targetPts);
stage.find('#list_arrow_2').visible('true');
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold_list(pc);
targetPts = [1160, 485, 1200, 555, 1240, 585];
stage.find('#list_arrow_1').points(targetPts);
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold_list(pc);
updateMessage("$ 1st value: 6",0);
makeText(155,440,message[1],'msg1');
updateMessage("$",1);
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold_list(pc);
updateMessage("$ 2nd value: 8",1);
makeText(155,460,message[2],'msg2');
updateMessage("$",2);
layer.draw();
pc=pc+1;
}else if(pc == 12){
makeBold_list(pc);
layer.draw();
pc=pc+1;
}else if(pc == 13){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>List creation</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>List creation</h1>
<p>This animation shows how we implement and create a list. Click the "next step" button to run the animation. </p>
<div id="container"></div>
<script src="creation.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="nextstep()" style="position: absolute; top: 110px; left: 10px;">next step</button>
</body>
</html>

View File

@@ -0,0 +1,431 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the vector.
var rect2 = new Konva.Rect({
x: 70,
y: 360,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 560,
height: 250,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect2);
// the rectangle which contains the list.
var rect3 = new Konva.Rect({
x: 850,
y: 360,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 900,
height: 250,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect3);
// Create a function to draw vector nodes
function drawVecNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect1);
var text = new Konva.Text({
x: x + 45,
y: y + 20,
text: label,
id: "node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var text1 = new Konva.Text({
x: x + 45,
y: y + 60,
text: id - 1,
id: "node_index_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text1);
}
drawVecNode(100, 460, '7', 1);
drawVecNode(200, 460, '5', 2);
drawVecNode(300, 460, '8', 3);
drawVecNode(400, 460, '1', 4);
drawVecNode(500, 460, '9', 5);
// Create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect1);
let rect2 = new Konva.Rect({
x: x+100,
y: y,
id:"list_node_pointer_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 20,
height: 50,
});
layer.add(rect2);
var text = new Konva.Text({
x: x + 45,
y: y + 20,
text: label,
id: "list_node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var arrow = new Konva.Arrow({
points: [x+110, y+25, x+150, y+25],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "list_arrow_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow);
}
drawListNode(900, 460, '7', 1);
drawListNode(1050, 460, '5', 2);
drawListNode(1200, 460, '8', 3);
drawListNode(1350, 460, '1', 4);
drawListNode(1500, 460, '9', 4);
var text_null = new Konva.Text({
x: 1655,
y: 475,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_null);
var text_index = new Konva.Text({
x: 220,
y: 550,
text: "index",
id: "vec_index",
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
// the code rectangle.
var rect1 = new Konva.Rect({
x: 70,
y: 60,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 550,
height: 180,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect1)
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 550,
padding: 20,
});
}
var code=[
"0. void erase_from_vector(unsigned int i, vector<int>& v) {",
"1. \t\t\t for (int index = i; index < v.size()-1; index++) {",
"2. \t\t\t \t\t\t v[index] = v[index+1];",
"3. \t\t\t }",
"4. \t\t\t v.pop_back();",
"5. }",
];
function makeBold(id){
for(let i=1; i<=code.length; i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(80,60+(i*20),code[i],i+1);
layer.add(t);
}
// draw the image
layer.draw();
stage.add(layer);
var pc=1;
// erase 5 from this vector.
function vec_erase_nextstep() {
if(pc == 1){
makeBold(pc);
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
layer.add(text_index);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
// highlight the one we are going to erase.
stage.find('#node_rec_2').fill('#f4d03f');
layer.draw();
pc=pc+1;
}else if(pc == 4){
stage.find('#node_text_2').text('8');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(4);
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(2);
// increment x by 100.
text_index.x(text_index.getX()+100);
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold(3);
// highlight the one we are going to update.
stage.find('#node_rec_3').fill('#f4d03f');
// and restore the previous one.
stage.find('#node_rec_2').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 8){
stage.find('#node_text_3').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(4);
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold(2);
// increment x by 100.
text_index.x(text_index.getX()+100);
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold(3);
// highlight the one we are going to update.
stage.find('#node_rec_4').fill('#f4d03f');
// and restore the previous one.
stage.find('#node_rec_3').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 12){
stage.find('#node_text_4').text('9');
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold(4);
layer.draw();
pc=pc+1;
}else if(pc == 14){
makeBold(2);
// increment x by 100.
text_index.x(text_index.getX()+100);
layer.draw();
pc=pc+1;
}else if(pc == 15){
makeBold(4);
layer.draw();
pc=pc+1;
}else if(pc == 16){
makeBold(5);
text_index.destroy();
// highlight the one we are going to update.
stage.find('#node_rec_5').fill('#f4d03f');
// and restore the previous one.
stage.find('#node_rec_4').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 17){
var shape = stage.find('#node_rec_5');
// let this object disappear in 2 seconds.
shape.to({
opacity: 0,
duration: 2,
});
//stage.find('#node_rec_5').destroy();
shape = stage.find('#node_text_5');
shape.to({
opacity: 0,
duration: 2,
});
//stage.find('#node_text_5').destroy();
shape = stage.find('#node_index_5');
shape.to({
opacity: 0,
duration: 2,
});
//stage.find('#node_index_5').destroy();
layer.draw();
pc=pc+1;
}else if(pc == 18){
makeBold(6);
layer.draw();
pc=pc+1;
}else if(pc == 19){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc=pc+1;
}
}
var targetPoints = [1010, 485, 1100, 585, 1200, 485];
var arrow1 = new Konva.Arrow({
points: [1010, 485, 1030, 485, 1050, 485],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow1);
layer.draw();
var arrow2 = stage.find('#arrow1');
// Create the animation
var tween = new Konva.Tween({
node: arrow2,
points: targetPoints,
duration: 2, // animation duration in seconds
easing: Konva.Easings.Linear
});
var pc2=1;
// erase 5 from this list.
function list_erase_nextstep() {
if(pc2 == 1){
stage.find('#list_arrow_1').destroy();
// start the animation
tween.play();
//layer.add(arrow1);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 2){
var shape = stage.find('#list_arrow_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#list_node_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#list_node_pointer_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#list_node_text_2');
shape.to({
opacity: 0,
duration: 2,
});
layer.draw();
pc2=pc2+1;
}else if(pc2 == 3){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc2=pc2+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>List vs Vector: erase operation</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>List vs Vector: erase operation</h1>
<p>This animation shows why erasing an element in a vector is more expensive than in a list. Click the "next step" button to run the animation. <b>Note:</b> in this animation, we assume we are going to erase the element which has the value 5.</p>
<div id="container"></div>
<script src="erase.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="vec_erase_nextstep()" style="position: absolute; top: 500px; left: 100px;">next step</button>
<button onclick="list_erase_nextstep()" style="position: absolute; top: 500px; left: 900px;">next step</button>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>List: insert operation</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>List: insert operation</h1>
<p>This animation shows the insert operation in List. Click the "next step" button to run the animation. <b>Note:</b> in this animation, we will insert a node in between 5 and 8, and we assume the new node's value (i.e., x) is 4.</p>
<div id="container"></div>
<script src="insert.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="list_insert_nextstep()" style="position: absolute; top: 110px; left: 10px;">next step</button>
</body>
</html>

View File

@@ -0,0 +1,359 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the list.
var rect3 = new Konva.Rect({
x: 250,
y: 360,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 900,
height: 300,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect3);
// Create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect1);
let rect2 = new Konva.Rect({
x: x+100,
y: y,
id:"list_node_pointer_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 20,
height: 50,
});
layer.add(rect2);
// value
var text = new Konva.Text({
x: x + 45,
y: y + 20,
text: label,
id: "list_node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var arrow = new Konva.Arrow({
points: [x+110, y+25, x+150, y+25],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "list_arrow_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow);
}
drawListNode(300, 460, '7', 1);
drawListNode(450, 460, '5', 2);
drawListNode(600, 460, '8', 3);
drawListNode(750, 460, '1', 4);
drawListNode(900, 460, '9', 4);
var text_null = new Konva.Text({
x: 1055,
y: 475,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_null);
var text_itr = new Konva.Text({
x: 235,
y: 640,
text: "itr",
id: 'vec_itr_1',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var itr_arrow = new Konva.Arrow({
points: [250, 625, 250, 555],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'itr_arrow_1',
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var pts = itr_arrow.points();
var text_itr2 = new Konva.Text({
x: 235,
y: 640,
text: "itr2",
id: 'vec_itr_2',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var itr2_arrow = new Konva.Arrow({
points: [250, 625, 250, 555],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'itr_arrow_2',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
var pts2 = itr2_arrow.points();
var text_p = new Konva.Text({
x: 495,
y: 610,
text: "p",
id: 'itr_p',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var arrow_p = new Konva.Arrow({
points: [500, 605, 500, 535],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_p',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
layer.add(text_p);
layer.add(arrow_p);
// for pointer q
var text_q = new Konva.Text({
x: 645,
y: 710,
text: "q",
id: 'itr_q',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var arrow_q = new Konva.Arrow({
points: [650, 705, 650, 635],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_q',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
// the code rectangle.
var rect_list = new Konva.Rect({
x: 250,
y: 60,
id:"code_rec_list",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 650,
height: 250,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_list);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 750,
padding: 20,
});
}
var code_list=[
"0. Node<T> * q = new Node<T>; \t\t\t \t\t\t // create a new node",
"1. q->value = x; \t\t\t \t\t\t \t\t\t \t\t\t // store x in this node",
"2. q->next = p->next; \t\t\t \t\t\t // make its successor be the current successor of p",
"3. p->next = q; \t\t\t \t\t\t \t\t\t \t\t\t // make p's successor be this new node",
];
function makeBold_list(id){
for(let i=1; i<=code_list.length; i++){
if(i!=id){
// regarding the parentheses, we must add the two numbers first.
stage.find('#line'+(i+100)).fontStyle('normal');
}else{
stage.find('#line'+(i+100)).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code_list.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
// here we add 100 so as to differentiate from the code array.
let t=makeCode(260,60+(i*20),code_list[i],i+1+100);
layer.add(t);
}
function increment_itr1() {
text_itr.x(text_itr.getX()+100);
pts[0] = pts[0] + 100;
pts[2] = pts[2] + 100;
itr_arrow.points(pts);
}
function increment_itr2() {
text_itr2.x(text_itr2.getX()+100);
pts2[0] = pts2[0] + 100;
pts2[2] = pts2[2] + 100;
itr2_arrow.points(pts2);
}
// draw the image
layer.draw();
stage.add(layer);
var targetPoints = [1010, 485, 1100, 585, 1200, 485];
var arrow1 = new Konva.Arrow({
points: [1010, 485, 1030, 485, 1050, 485],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow1);
layer.draw();
var arrow2 = stage.find('#arrow1');
// Create the animation
var tween = new Konva.Tween({
node: arrow2,
points: targetPoints,
duration: 2, // animation duration in seconds
easing: Konva.Easings.Linear
});
var pts_p = arrow_p.points();
function increment_p() {
text_p.x(text_p.getX()+160);
pts_p[0] = pts_p[0] + 160;
pts_p[2] = pts_p[2] + 160;
itr2_arrow.points(pts_p);
}
var pc2=1;
// erase 5 from this list.
function list_insert_nextstep() {
if(pc2 == 1){
makeBold_list(1);
drawListNode(600, 560, '?', 6);
layer.add(text_q);
layer.add(arrow_q);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 2){
makeBold_list(2);
stage.find('#list_node_text_6').text('4');
layer.draw();
pc2=pc2+1;
}else if(pc2 == 3){
makeBold_list(3);
targetPoints = [720, 585, 700, 550, 600, 485];
stage.find('#list_arrow_6').points(targetPoints);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 4){
makeBold_list(4);
targetPoints = [560, 485, 565, 530, 600, 585];
stage.find('#list_arrow_2').points(targetPoints);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 5){
makeBold_list(-1);
var shape = stage.find('#arrow_p');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#arrow_q');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#itr_p');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#itr_q');
shape.to({
opacity: 0,
duration: 2,
});
layer.draw();
pc2=pc2+1;
}else if(pc2 == 6){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc2=pc2+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>List vs Vector: erase operation, using iterators</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>List vs Vector: erase operation, using iterators</h1>
<p>This animation shows why erasing an element in a vector is more expensive than in a list. Click the "next step" button to run the animation. <b>Note:</b> in this animation, we assume we are going to erase the element which has the value 5.</p>
<div id="container"></div>
<script src="iterator.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="vec_erase_nextstep()" style="position: absolute; top: 500px; left: 100px;">next step</button>
<button onclick="list_erase_nextstep()" style="position: absolute; top: 500px; left: 900px;">next step</button>
</body>
</html>

View File

@@ -0,0 +1,597 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the vector.
var rect2 = new Konva.Rect({
x: 70,
y: 360,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 650,
height: 350,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect2);
// the rectangle which contains the list.
var rect3 = new Konva.Rect({
x: 850,
y: 360,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 900,
height: 300,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect3);
// Create a function to draw vector nodes
function drawVecNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect1);
var text = new Konva.Text({
x: x + 45,
y: y + 20,
text: label,
id: "node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var text1 = new Konva.Text({
x: x + 45,
y: y + 60,
text: id - 1,
id: "node_index_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text1);
}
drawVecNode(100, 460, '7', 1);
drawVecNode(200, 460, '5', 2);
drawVecNode(300, 460, '8', 3);
drawVecNode(400, 460, '1', 4);
drawVecNode(500, 460, '9', 5);
// Create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
});
layer.add(rect1);
let rect2 = new Konva.Rect({
x: x+100,
y: y,
id:"list_node_pointer_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 20,
height: 50,
});
layer.add(rect2);
var text = new Konva.Text({
x: x + 45,
y: y + 20,
text: label,
id: "list_node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var arrow = new Konva.Arrow({
points: [x+110, y+25, x+150, y+25],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "list_arrow_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow);
}
drawListNode(900, 460, '7', 1);
drawListNode(1050, 460, '5', 2);
drawListNode(1200, 460, '8', 3);
drawListNode(1350, 460, '1', 4);
drawListNode(1500, 460, '9', 4);
var text_null = new Konva.Text({
x: 1655,
y: 475,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_null);
var text_itr = new Konva.Text({
x: 235,
y: 640,
text: "itr",
id: 'vec_itr_1',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var itr_arrow = new Konva.Arrow({
points: [250, 625, 250, 555],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'itr_arrow_1',
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var pts = itr_arrow.points();
var text_itr2 = new Konva.Text({
x: 235,
y: 640,
text: "itr2",
id: 'vec_itr_2',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var itr2_arrow = new Konva.Arrow({
points: [250, 625, 250, 555],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'itr_arrow_2',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
var pts2 = itr2_arrow.points();
var text_p = new Konva.Text({
x: 1100,
y: 610,
text: "p",
id: 'list_itr_p',
fontSize: 26,
fontFamily: 'Calibri',
fill: '#17202a'
});
var arrow_p = new Konva.Arrow({
points: [1100, 605, 1100, 535],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_p',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
// the code rectangle.
var rect1 = new Konva.Rect({
x: 70,
y: 60,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 650,
height: 250,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect1);
// the code rectangle.
var rect_list = new Konva.Rect({
x: 850,
y: 60,
id:"code_rec_list",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 650,
height: 250,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_list);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 650,
padding: 20,
});
}
var code=[
"0. void erase_from_vector(vector<int>::iterator itr, vector<int>& v) {",
"1. \t\t\t vector<int>::iterator itr2 = itr;",
"2. \t\t\t itr2++;",
"3. \t\t\t while (itr2 != v.end()) {",
"4. \t\t\t \t\t\t *itr = *itr2;",
"5. \t\t\t \t\t\t itr++;",
"6. \t\t\t \t\t\t itr2++;",
"7. \t\t\t }",
"8. \t\t\t v.pop_back();",
"9. }",
];
function makeBold(id){
for(let i=1; i<=code.length; i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(80,60+(i*20),code[i],i+1);
layer.add(t);
}
var code_list=[
"0. std::list<int> s;",
"1. std::list<int>::iterator p; // code initializing p is omitted",
"2. p = s.erase(p);",
];
function makeBold_list(id){
for(let i=1; i<=code_list.length; i++){
if(i!=id){
// regarding the parentheses, we must add the two numbers first.
stage.find('#line'+(i+100)).fontStyle('normal');
}else{
stage.find('#line'+(i+100)).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code_list.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
// here we add 100 so as to differentiate from the code array.
let t=makeCode(860,60+(i*20),code_list[i],i+1+100);
layer.add(t);
}
function increment_itr1() {
text_itr.x(text_itr.getX()+100);
pts[0] = pts[0] + 100;
pts[2] = pts[2] + 100;
itr_arrow.points(pts);
}
function increment_itr2() {
text_itr2.x(text_itr2.getX()+100);
pts2[0] = pts2[0] + 100;
pts2[2] = pts2[2] + 100;
itr2_arrow.points(pts2);
}
// draw the image
layer.draw();
stage.add(layer);
var pc=1;
// erase 5 from this vector.
function vec_erase_nextstep() {
if(pc == 1){
makeBold(pc);
layer.add(text_itr);
layer.add(itr_arrow);
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
layer.add(text_itr2);
layer.add(itr2_arrow);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
increment_itr2();
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(4);
// highlight the one we are going to erase.
stage.find('#node_rec_2').fill('#f4d03f');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(5);
stage.find('#node_text_2').text('8');
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(6);
increment_itr1();
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold(7);
increment_itr2();
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(8);
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(4);
// highlight the one we are going to update.
stage.find('#node_rec_3').fill('#f4d03f');
// and restore the previous one.
stage.find('#node_rec_2').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold(5);
stage.find('#node_text_3').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold(6);
increment_itr1();
layer.draw();
pc=pc+1;
}else if(pc == 12){
makeBold(7);
increment_itr2();
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold(8);
layer.draw();
pc=pc+1;
}else if(pc == 14){
makeBold(4);
// highlight the one we are going to update.
stage.find('#node_rec_4').fill('#f4d03f');
// and restore the previous one.
stage.find('#node_rec_3').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 15){
makeBold(5);
stage.find('#node_text_4').text('9');
layer.draw();
pc=pc+1;
}else if(pc == 16){
makeBold(6);
increment_itr1();
layer.draw();
pc=pc+1;
}else if(pc == 17){
makeBold(7);
increment_itr2();
layer.draw();
pc=pc+1;
}else if(pc == 18){
makeBold(8);
layer.draw();
pc=pc+1;
}else if(pc == 19){
makeBold(4);
// highlight the one we are going to update.
stage.find('#node_rec_5').fill('#f4d03f');
// and restore the previous one.
stage.find('#node_rec_4').fill('#ddd');
layer.draw();
pc=pc+1;
}else if(pc == 20){
makeBold(8);
layer.draw();
pc=pc+1;
}else if(pc == 21){
makeBold(9);
layer.draw();
pc=pc+1;
}else if(pc == 22){
var shape = stage.find('#node_rec_5');
// let this object disappear in 2 seconds.
shape.to({
opacity: 0,
duration: 2,
});
//stage.find('#node_rec_5').destroy();
shape = stage.find('#node_text_5');
shape.to({
opacity: 0,
duration: 2,
});
//stage.find('#node_text_5').destroy();
shape = stage.find('#node_index_5');
shape.to({
opacity: 0,
duration: 2,
});
//stage.find('#node_index_5').destroy();
layer.draw();
pc=pc+1;
}else if(pc == 23){
makeBold(10);
layer.draw();
pc=pc+1;
}else if(pc == 24){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc=pc+1;
}
}
var targetPoints = [1010, 485, 1100, 585, 1200, 485];
var arrow1 = new Konva.Arrow({
points: [1010, 485, 1030, 485, 1050, 485],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
layer.add(arrow1);
layer.draw();
var arrow2 = stage.find('#arrow1');
// Create the animation
var tween = new Konva.Tween({
node: arrow2,
points: targetPoints,
duration: 2, // animation duration in seconds
easing: Konva.Easings.Linear
});
var pts_p = arrow_p.points();
function increment_p() {
text_p.x(text_p.getX()+160);
pts_p[0] = pts_p[0] + 160;
pts_p[2] = pts_p[2] + 160;
itr2_arrow.points(pts_p);
}
var pc2=1;
// erase 5 from this list.
function list_erase_nextstep() {
if(pc2 == 1){
makeBold_list(1);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 2){
makeBold_list(2);
layer.add(text_p);
layer.add(arrow_p);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 3){
makeBold_list(3);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 4){
stage.find('#list_arrow_1').destroy();
// start the animation
tween.play();
//layer.add(arrow1);
layer.draw();
pc2=pc2+1;
}else if(pc2 == 5){
makeBold_list(-1);
var shape = stage.find('#list_arrow_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#list_node_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#list_node_pointer_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#list_node_text_2');
shape.to({
opacity: 0,
duration: 2,
});
layer.draw();
pc2=pc2+1;
increment_p();
layer.draw();
}else if(pc2 == 6){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc2=pc2+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>List push_back</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>List push_back</h1>
<p>This animation shows how the push_back() method works in List. Click the "next step" button to run the animation. <b>Note:</b> In this animation, we assume value is 4. </p>
<div id="container"></div>
<script src="push_back.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="nextstep()" style="position: absolute; top: 110px; left: 10px;">next step</button>
</body>
</html>

View File

@@ -0,0 +1,588 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the list, which is also the heap rectangle.
var rect3 = new Konva.Rect({
x: 1350,
y: 220,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 300,
height: 535,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect3);
// create a function to draw stack nodes
function drawStackNode(x, y, label, id, value){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect1);
// name of the pointer
var text1 = new Konva.Text({
x: x - 50,
y: y + 20,
text: label,
id: "node_index_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text1);
// content
var text2 = new Konva.Text({
x: x + 25,
y: y + 20,
text: value,
id: "node_content_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text2);
}
// create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 20,
height: 30,
});
layer.add(rect1);
let rect2 = new Konva.Rect({
x: x + 20,
y: y,
id:"list_node_pointer_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 40,
height: 30,
});
layer.add(rect2);
var text = new Konva.Text({
x: x + 5,
y: y + 5,
text: label,
id: "list_node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var arrow = new Konva.Arrow({
points: [x+40, y+15, x+80, y+15],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "list_arrow_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
visible: false,
});
layer.add(arrow);
}
drawListNode(1360, 230, '7', 1);
drawListNode(1450, 280, '5', 2);
drawListNode(1400, 330, '8', 3);
drawListNode(1450, 380, '1', 4);
stage.find('#list_arrow_1').visible('true');
stage.find('#list_arrow_2').visible('true');
stage.find('#list_arrow_3').visible('true');
stage.find('#list_arrow_4').visible('true');
var targetPts = [1400, 245, 1420, 255, 1450, 295];
stage.find('#list_arrow_1').points(targetPts);
targetPts = [1490, 295, 1450, 318, 1370, 326, 1400, 345];
stage.find('#list_arrow_2').points(targetPts);
targetPts = [1440, 345, 1420, 378, 1450, 395];
stage.find('#list_arrow_3').points(targetPts);
targetPts = [1490, 395, 1475, 420, 1450, 558, 1682, 600];
stage.find('#list_arrow_4').points(targetPts);
var text_null = new Konva.Text({
x: 1685,
y: 575,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
//layer.add(text_null);
var text_stack = new Konva.Text({
x: 295,
y: 380,
text: "Stack",
id: "node_text_stack",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_stack);
var text_heap = new Konva.Text({
x: 855,
y: 380,
text: "Heap",
id: "node_text_heap",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_heap);
var arrow_p = new Konva.Arrow({
points: [1100, 605, 1100, 535],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_p',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
// the node code rectangle.
var rect1 = new Konva.Rect({
x: 10,
y: 30,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 220,
height: 160,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var nodeLabel = new Konva.Text({
x: 25,
y: 235,
id:"node_label",
text: "Node Definition",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
layer.add(nodeLabel);
layer.add(rect1);
function makeCodeBox(x, y){
// the main code rectangle.
var rect_list = new Konva.Rect({
x: x,
y: y,
id:"code_rec_list",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 500,
height: 230,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_list);
}
makeCodeBox(280, 30);
makeCodeBox(280, 280);
makeCodeBox(280, 530);
makeCodeBox(800, 30);
makeCodeBox(800, 280);
makeCodeBox(800, 530);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 480,
padding: 20,
});
}
var code=[
"0. template <class T>",
"1. class Node {",
"2. public:",
"3. \t\t\t T value;",
"4. \t\t\t Node* next;",
"5. }",
];
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(10,30+(i*20),code[i],i+1);
layer.add(t);
}
var code_list=[
"0. void push_back(Node<T>* & head, const T& value) {",
"1. \t\t\t if(head == NULL) {",
"2. \t\t\t \t\t\t Node<T>* tmp = new Node<T>;",
"3. \t\t\t \t\t\t tmp->value = value;",
"4. \t\t\t \t\t\t tmp->next = NULL;",
"5. \t\t\t \t\t\t head = tmp;",
"6. \t\t\t } else {",
"7. \t\t\t \t\t\t push_back(head->next, value);",
"8. \t\t\t }",
"9. }",
];
function makeBold_list(id, box){
for(let i=1; i<=code_list.length; i++){
if(i!=id){
// regarding the parentheses, we must add the two numbers first.
stage.find('#line'+(i+100*box)).fontStyle('normal');
}else{
stage.find('#line'+(i+100*box)).fontStyle('bold');
}
}
}
function makeCodeinBox(x,y,box){
// write the code fragment into the code box.
for (let i=0;i<code_list.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
// here we add 100 so as to differentiate from the code array.
let t=makeCode(x,y+(i*20),code_list[i],i+1+100*box);
layer.add(t);
}
}
makeCodeinBox(290,30,1);
makeCodeinBox(290,280,2);
makeCodeinBox(290,530,3);
makeCodeinBox(810,30,4);
makeCodeinBox(810,280,5);
makeCodeinBox(810,530,6);
// draw the image
drawStackNode(1685, 575, '', 0, 'NULL');
drawStackNode(1370, 50, 'head', 1, ' ');
var arrow1 = new Konva.Arrow({
points: [1420, 75, 1320, 135, 1355, 245],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrow2 = new Konva.Arrow({
points: [1450, 145, 1335, 190, 1340, 455, 1485, 494],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_2",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
// arrow 1 represents head
layer.add(arrow1);
layer.draw();
var pc=1;
// creating the list.
function nextstep() {
if(pc == 1){
makeBold_list(pc, 1);
stage.find('#node_rec_1').fill('plum');
//drawStackNode(270, 550, 'value', 2, '4');
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold_list(pc, 1);
// the node we push front is called node 0.
//drawListNode(600, 560, '?', 0);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold_list(7, 1);
//stage.find('#list_node_text_0').text('4');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold_list(8, 1);
//targetPts = [680, 585, 565, 645, 460, 545, 495, 485];
//stage.find('#list_arrow_0').points(targetPts);
//stage.find('#list_arrow_0').visible('true');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold_list(1, 2);
//targetPts = [1420, 75, 1320, 135, 1450, 295];
//stage.find('#arrow_1').points(targetPts);
stage.find('#list_node_rec_1').fill('yellow');
stage.find('#list_node_pointer_rec_1').fill('yellow');
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold_list(2, 2);
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold_list(7, 2);
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold_list(8, 2);
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold_list(1, 3);
stage.find('#list_node_rec_2').fill('orange');
stage.find('#list_node_pointer_rec_2').fill('orange');
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold_list(2, 3);
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold_list(7, 3);
layer.draw();
pc=pc+1;
}else if(pc == 12){
makeBold_list(8, 3);
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold_list(1, 4);
stage.find('#list_node_rec_3').fill('aqua');
stage.find('#list_node_pointer_rec_3').fill('aqua');
layer.draw();
pc=pc+1;
}else if(pc == 14){
makeBold_list(2, 4);
layer.draw();
pc=pc+1;
}else if(pc == 15){
makeBold_list(7, 4);
layer.draw();
pc=pc+1;
}else if(pc == 16){
makeBold_list(8, 4);
layer.draw();
pc=pc+1;
}else if(pc == 17){
makeBold_list(1, 5);
stage.find('#list_node_rec_4').fill('pink');
stage.find('#list_node_pointer_rec_4').fill('pink');
layer.draw();
pc=pc+1;
}else if(pc == 18){
makeBold_list(2, 5);
layer.draw();
pc=pc+1;
}else if(pc == 19){
makeBold_list(7, 5);
layer.draw();
pc=pc+1;
}else if(pc == 20){
makeBold_list(8, 5);
layer.draw();
pc=pc+1;
}else if(pc == 21){
makeBold_list(1, 6);
stage.find('#node_rec_0').fill('yellowgreen');
//stage.find('#list_node_pointer_rec_5').fill('yellowgreen');
layer.draw();
pc=pc+1;
}else if(pc == 22){
makeBold_list(2, 6);
layer.draw();
pc=pc+1;
}else if(pc == 23){
makeBold_list(3, 6);
drawStackNode(1400, 120, 'tmp', 2, ' ');
// arrow 2 represents tmp
layer.add(arrow2);
drawListNode(1490, 480, '?', 5);
layer.draw();
pc=pc+1;
}else if(pc == 24){
makeBold_list(4, 6);
// setting tmp's value
stage.find('#list_node_text_5').text('4');
layer.draw();
pc=pc+1;
}else if(pc == 25){
makeBold_list(5, 6);
targetPts = [1530, 495, 1540, 530, 1682, 600];
// setting tmp's next to NULL
stage.find('#list_arrow_5').points(targetPts);
stage.find('#list_arrow_5').visible('true');
layer.draw();
pc=pc+1;
}else if(pc == 26){
makeBold_list(6, 6);
// let current head point to the same location as tmp points to.
targetPts = [1490, 395, 1475, 420, 1450, 458, 1492, 495];
stage.find('#list_arrow_4').points(targetPts);
layer.draw();
pc=pc+1;
}else if(pc == 27){
makeBold_list(7, 6);
layer.draw();
pc=pc+1;
}else if(pc == 28){
// tmp goes out of scope
var shape = stage.find('#arrow_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#node_rec_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#node_index_2');
shape.to({
opacity: 0,
duration: 2,
});
makeBold_list(10, 6);
layer.draw();
pc=pc+1;
}else if(pc == 29){
makeBold_list(-1, 6);
layer.draw();
pc=pc+1;
}else if(pc == 30){
makeBold_list(9, 5);
layer.draw();
pc=pc+1;
}else if(pc == 31){
makeBold_list(10, 5);
layer.draw();
pc=pc+1;
}else if(pc == 32){
makeBold_list(-1, 5);
layer.draw();
pc=pc+1;
}else if(pc == 33){
makeBold_list(9, 4);
layer.draw();
pc=pc+1;
}else if(pc == 34){
makeBold_list(10, 4);
layer.draw();
pc=pc+1;
}else if(pc == 35){
makeBold_list(-1, 4);
layer.draw();
pc=pc+1;
}else if(pc == 36){
makeBold_list(9, 3);
layer.draw();
pc=pc+1;
}else if(pc == 37){
makeBold_list(10, 3);
layer.draw();
pc=pc+1;
}else if(pc == 38){
makeBold_list(-1, 3);
layer.draw();
pc=pc+1;
}else if(pc == 39){
makeBold_list(9, 2);
layer.draw();
pc=pc+1;
}else if(pc == 40){
makeBold_list(10, 2);
layer.draw();
pc=pc+1;
}else if(pc == 41){
makeBold_list(-1, 2);
layer.draw();
pc=pc+1;
}else if(pc == 42){
makeBold_list(9, 1);
layer.draw();
pc=pc+1;
}else if(pc == 43){
makeBold_list(10, 1);
layer.draw();
pc=pc+1;
}else if(pc == 44){
makeBold_list(-1, 1);
layer.draw();
pc=pc+1;
}else if(pc == 45){
makeBold_list(2, 3);
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>List push_front</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>List push_front</h1>
<p>This animation shows how the push_front() method works in List. Click the "next step" button to run the animation. <b>Note:</b> In this animation, we only consider the general case where the list is not empty. Also, we assume value is 4. </p>
<div id="container"></div>
<script src="push_front.js"></script>
<!-- we must include the javascript first, and then have this button definition which calls a function defined in the javascript -->
<button onclick="nextstep()" style="position: absolute; top: 110px; left: 10px;">next step</button>
</body>
</html>

View File

@@ -0,0 +1,408 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
// the rectangle which contains the stack nodes.
var rect2 = new Konva.Rect({
x: 270,
y: 420,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 310,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect2);
// the rectangle which contains the list.
var rect3 = new Konva.Rect({
x: 450,
y: 420,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 900,
height: 310,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect3);
// create a function to draw stack nodes
function drawStackNode(x, y, label, id, value){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 100,
height: 50,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect1);
// name of the pointer
var text1 = new Konva.Text({
x: x - 50,
y: y + 20,
text: label,
id: "node_index_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text1);
// content
var text2 = new Konva.Text({
x: x + 45,
y: y + 20,
text: value,
id: "node_content_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text2);
}
// create a function to draw list nodes
function drawListNode(x, y, label, id){
// the rectangle represents list nodes.
let rect1 = new Konva.Rect({
x: x,
y: y,
id:"list_node_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 40,
height: 50,
});
layer.add(rect1);
let rect2 = new Konva.Rect({
x: x + 40,
y: y,
id:"list_node_pointer_rec_" + id,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 80,
height: 50,
});
layer.add(rect2);
var text = new Konva.Text({
x: x + 15,
y: y + 20,
text: label,
id: "list_node_text_" + id,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
var arrow = new Konva.Arrow({
points: [x+80, y+25, x+150, y+25],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "list_arrow_" + id,
fill: 'green',
stroke: 'green',
strokeWidth: 5,
visible: false,
});
layer.add(arrow);
}
drawListNode(500, 460, '7', 1);
drawListNode(650, 460, '5', 2);
drawListNode(800, 460, '8', 3);
drawListNode(950, 460, '1', 4);
drawListNode(1100, 460, '9', 5);
stage.find('#list_arrow_1').visible('true');
stage.find('#list_arrow_2').visible('true');
stage.find('#list_arrow_3').visible('true');
stage.find('#list_arrow_4').visible('true');
stage.find('#list_arrow_5').visible('true');
var targetPts = [1175, 485, 1250, 535, 1400, 585];
stage.find('#list_arrow_5').points(targetPts);
var text_null = new Konva.Text({
x: 1405,
y: 575,
text: "NULL",
id: "node_text_null",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_null);
var text_stack = new Konva.Text({
x: 295,
y: 380,
text: "Stack",
id: "node_text_stack",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_stack);
var text_heap = new Konva.Text({
x: 855,
y: 380,
text: "Heap",
id: "node_text_heap",
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text_heap);
var arrow_p = new Konva.Arrow({
points: [1100, 605, 1100, 535],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: 'arrow_p',
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
// the node code rectangle.
var rect1 = new Konva.Rect({
x: 150,
y: 30,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 160,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var nodeLabel = new Konva.Text({
x: 280,
y: 235,
id:"node_label",
text: "Node Definition",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
layer.add(nodeLabel);
layer.add(rect1);
// the main code rectangle.
var rect_list = new Konva.Rect({
x: 850,
y: 30,
id:"code_rec_list",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 600,
height: 160,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect_list);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 650,
padding: 20,
});
}
var code=[
"0. template <class T>",
"1. class Node {",
"2. public:",
"3. \t\t\t T value;",
"4. \t\t\t Node* next;",
"5. }",
];
// write the code fragment into the code box.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(160,30+(i*20),code[i],i+1);
layer.add(t);
}
var code_list=[
"0. void push_front(Node<T>* & head, const T& value) {",
"1. \t\t\t Node<T>* tmp = new Node<T>;",
"2. \t\t\t tmp->value = value;",
"3. \t\t\t tmp->next = head;",
"4. \t\t\t head = tmp;",
"5. }",
];
function makeBold_list(id){
for(let i=1; i<=code_list.length; i++){
if(i!=id){
// regarding the parentheses, we must add the two numbers first.
stage.find('#line'+(i+100)).fontStyle('normal');
}else{
stage.find('#line'+(i+100)).fontStyle('bold');
}
}
}
// write the code fragment into the code box.
for (let i=0;i<code_list.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
// here we add 100 so as to differentiate from the code array.
let t=makeCode(860,30+(i*20),code_list[i],i+1+100);
layer.add(t);
}
// draw the image
layer.draw();
var arrow1 = new Konva.Arrow({
points: [310, 535, 430, 485, 495, 485],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrow2 = new Konva.Arrow({
points: [310, 630, 430, 655, 595, 585],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrow_2",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var pc=1;
// creating the list.
function nextstep() {
if(pc == 1){
makeBold_list(pc);
drawStackNode(270, 500, 'head', 1, ' ');
drawStackNode(270, 550, 'value', 2, '4');
// arrow 1 represents head
layer.add(arrow1);
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold_list(pc);
drawStackNode(270, 600, 'tmp', 3, ' ');
// the node we push front is called node 0.
drawListNode(600, 560, '?', 0);
// arrow 2 represents tmp
layer.add(arrow2);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold_list(pc);
stage.find('#list_node_text_0').text('4');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold_list(pc);
targetPts = [680, 585, 565, 645, 460, 545, 495, 485];
stage.find('#list_arrow_0').points(targetPts);
stage.find('#list_arrow_0').visible('true');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold_list(pc);
targetPts = [310, 535, 400, 515, 595, 585];
stage.find('#arrow_1').points(targetPts);
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold_list(pc);
var shape = stage.find('#arrow_2');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#node_rec_3');
shape.to({
opacity: 0,
duration: 2,
});
shape = stage.find('#node_index_3');
shape.to({
opacity: 0,
duration: 2,
});
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold_list(pc);
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,286 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'prog'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'cont_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(text);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
makeMemory(800,0,6,200,100);
makeText(800+350, -20, "0x1000", "addr0");
makeText(800+350, 80, "0x1008", "addr2");
makeText(800+350, 180, "0x1010", "addr3");
makeText(800+350, 280, "0x1018", "addr4");
makeText(800+350, 380, "0x1020", "addr5");
makeText(800+350, 480, "0x1028", "addr6");
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"prec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 370,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var memoryText = new Konva.Text({
x: 830,
y: 635,
id:"memory",
text: "Memory",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 305,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 635,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "$",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrowLeft1 = new Konva.Arrow({
points: [925, 250, 1100, 200, 1005, 150],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowright1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
layer.add(memoryText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
}
// hard code here, we assume we only have 8 lines of code.
function makeBold(id){
for(let i=1;i<=8;i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
var code=["1. float x = 15.5;",
"2. float *p;",
"3. p = &x;",
"4. *p = 72; ",
"5. if (x > 20 )",
"6. \t\t cout << \"Bigger\\n\";",
"7. else",
"8. \t\t cout << \"Smaller\\n\"; "];
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,80+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
//t=makeContent(850,220,"0x8",'value2');
//layer.add(t);
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
makeText(650,120,"float x",'x');
// this has to be after makeMemory so that the memory doesn't overwrite this.
makeContent(850,120,"15.5",'value1');
/* update last occurrence of c */
// stage.find('#text_c').text("0");
/* highlight the box for c */
//stage.find('#lastseenbuf_2').fill("#5f9ea0");
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
makeText(650,220,"float *p",'p');
// at first, it's just garbage.
makeContent(850,220,"\ \ \ ?",'value2');
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
// p takes the address of x.
stage.find('#cont_value2').text('0x1008');
// add the arrow here.
layer.add(arrowLeft1);
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
stage.find('#cont_value1').text('72.0');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(pc);
stage.find('#console_text').text('$ Bigger');
layer.draw();
pc=pc+1;
}else if(pc == 7){
alert("End of animation! Refresh the page if you want to re-run the animation.");
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pointers: example 1</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Pointers: example 1</h1>
<p>This is the animation of example 1. Click the "next step" button to run the animation.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="example1.js"></script>
</body>
</html>

View File

@@ -0,0 +1,262 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'prog'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'cont_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(text);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
makeMemory(800,0,6,200,100);
makeText(800+250, -20, "0x1000", "addr0");
makeText(800+250, 80, "0x1008", "addr2");
makeText(800+250, 180, "0x1010", "addr3");
makeText(800+250, 280, "0x1018", "addr4");
makeText(800+250, 380, "0x1020", "addr5");
makeText(800+250, 480, "0x1028", "addr6");
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"prec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 370,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var memoryText = new Konva.Text({
x: 830,
y: 635,
id:"memory",
text: "Memory",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 305,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 635,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "$",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrowLeft1 = new Konva.Arrow({
points: [920, 250, 1100, 200, 1005, 150],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowright1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
layer.add(memoryText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
}
// hard code here, we assume we only have 3 lines of code.
function makeBold(id){
for(let i=1;i<=3;i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
var code=["1. int * p, q;",
"2. float *s, *t;",
"3. *p = 15;"];
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,80+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
t=makeText(650,120,"int *p",'p');
// this has to be after makeMemory so that the memory doesn't overwrite this.
makeContent(870,120,"?",'value1');
makeText(650,220,"int q",'q');
makeContent(870,220,"?",'value2');
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
makeText(650,320,"float *s",'s');
// at first, it's just garbage.
makeContent(870,320,"?",'value3');
makeText(650,420,"float *t",'t');
// at first, it's just garbage.
makeContent(870,420,"?",'value4');
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
layer.draw();
pc=pc+1;
}else if(pc == 4){
alert("p is not initialized!");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pointers: example 2</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Pointers: example 2</h1>
<p>This is the animation of example 2. Click the "next step" button to run the animation. Note: this animation makes an unrealistic assumption, which is it takes 8 bytes to store each of the following: an int object, an int pointer, a float object, a float pointer.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="example2.js"></script>
</body>
</html>

View File

@@ -0,0 +1,309 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'prog'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(text);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
makeMemory(800,0,6,200,100);
makeText(800+350, -20, "0x1000", "addr0");
makeText(800+350, 80, "0x1008", "addr2");
makeText(800+350, 180, "0x1010", "addr3");
makeText(800+350, 280, "0x1018", "addr4");
makeText(800+350, 380, "0x1020", "addr5");
makeText(800+350, 480, "0x1028", "addr6");
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"prec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 370,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var memoryText = new Konva.Text({
x: 830,
y: 635,
id:"memory",
text: "Memory",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 305,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 635,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "$",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrowLeft1 = new Konva.Arrow({
points: [945, 350, 1100, 200, 1005, 150],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowrleft1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrowLeft2 = new Konva.Arrow({
points: [945, 450, 1100, 300, 1005, 250],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowleft2",
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
/* for the arrow */
var arrowarray1 = [945, 450, 1100, 300, 1005, 250];
function moveArrow(){
arrowarray1[5] = arrowarray1[5] - 100;
arrowarray1[3] = arrowarray1[3] - 100;
stage.find('#arrowleft2').points(arrowarray1);
}
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
layer.add(memoryText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
}
// hard code here, we assume we only have 6 lines of code.
function makeBold(id){
for(let i=1;i<=6;i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
var code=["1. float x=5, y=9;",
"2. float *p = &x, *q = &y;",
"3. *p = 17.0;",
"4. *q = *p;",
"5. q = p;",
"6. *q = 13.0;",
];
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,80+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
makeText(650,120,"float x",'x');
// this has to be after makeMemory so that the memory doesn't overwrite this.
makeContent(870,120,"5",'x_value');
makeText(650,220,"float y",'y');
makeContent(870,220,"9",'y_value');
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
makeText(650,320,"float *p",'p');
makeContent(870,320,"0x1008",'p_value');
// add the arrow here.
layer.add(arrowLeft1);
makeText(650,420,"float *q",'q');
makeContent(870,420,"0x1010",'q_value');
// add the second arrow here.
layer.add(arrowLeft2);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
// following pointer p to the address which is pointed to by p, and store 17.0 to that address.
stage.find('#x_value').text('17.0');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
// following pointer p to the address which is pointed to by p, and store 17.0 to that address.
stage.find('#y_value').text('17.0');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
// assign pointer p to q, so now p and q are both pointing to 0x8, which stores variable x.
stage.find('#q_value').text('0x1008');
// move arrow up so that both p and q point to the same address.
moveArrow();
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(pc);
// following pointer q to the address which is pointed to by q, and store 13.0 to that address.
stage.find('#x_value').text('13.0');
layer.draw();
pc=pc+1;
}else if(pc == 7){
alert("End of animation! Refresh the page if you want to re-run the animation!");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pointers: example 3</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Pointers: example 3</h1>
<p>This is the animation of example 3 in which we try to find out what the values of x and y are at the end. Click the "next step" button to run the animation.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="example3.js"></script>
</body>
</html>

View File

@@ -0,0 +1,360 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let content = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(content);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
makeMemory(800,0,6,200,100);
makeText(800+250, -20, "0x1000", "addr0");
makeText(800+250, 80, "0x1008", "addr2");
makeText(800+250, 180, "0x1010", "addr3");
makeText(800+250, 280, "0x1018", "addr4");
makeText(800+250, 380, "0x1020", "addr5");
makeText(800+250, 480, "0x1028", "addr6");
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"prec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 370,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var memoryText = new Konva.Text({
x: 830,
y: 635,
id:"memory",
text: "Memory",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 305,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 635,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrowLeft1 = new Konva.Arrow({
points: [945, 350, 1100, 200, 1005, 150],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowrleft1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrowLeft2 = new Konva.Arrow({
points: [945, 450, 1100, 300, 1005, 250],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowleft2",
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
var arrowLeft3 = new Konva.Arrow({
points: [945, 550, 1100, 400, 1005, 250],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowleft2",
fill: 'red',
stroke: 'red',
strokeWidth: 5,
});
/* for the arrow */
var arrowarray1 = [945, 450, 1100, 300, 1005, 250];
function moveArrow(){
arrowarray1[5] = arrowarray1[5] - 100;
arrowarray1[3] = arrowarray1[3] - 100;
stage.find('#arrowleft2').points(arrowarray1);
}
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
layer.add(memoryText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
}
// hard code here, we assume we only have 9 lines of code.
function makeBold(id){
for(let i=1;i<=9;i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
var code=["1. int x = 10, y = 15;",
"2. int *a = &x;",
"3. cout << x << \" \" << y << endl;",
"4. int *b = &y;",
"5. *a = x * *b;",
"6. cout << x << \" \" << y << endl;",
"7. int *c = b;",
"8. *c = 25;",
"9. cout << x << \" \" << y << endl;",
];
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,60+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
var message=["$",
"",
"",
""];
function updateMessage(msg,i) {
stage.find('#text_msg'+i).text(msg);
}
// draw that $ sign, which is a command line prompt.
makeText(60,400,message[0],'msg0');
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
makeText(650,120,"int x",'x');
// this has to be after makeMemory so that the memory doesn't overwrite this.
makeContent(870,120,"10",'x_value');
makeText(650,220,"int y",'y');
makeContent(870,220,"15",'y_value');
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
makeText(650,320,"int *a",'a');
makeContent(870,320,"0x1008",'a_value');
// add the arrow here.
layer.add(arrowLeft1);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
updateMessage("$ 10 15",0);
makeText(60,420,message[1],'msg1');
updateMessage("$ ",1);
makeText(60,440,message[2],'msg2');
makeText(60,460,message[3],'msg3');
// stage.find('#console_text').text('$ 10 15');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
makeText(650,420,"int *b",'b');
makeContent(870,420,"0x1010",'b_value');
// add the second arrow here.
layer.add(arrowLeft2);
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
// following pointer a to the address which is pointed to by a, and store 150 to that address.
// why 150? because it's x * *b, and *b is y, which is 15, whereas x is 10, and 10*15=150.
stage.find('#x_value').text('150');
layer.draw();
pc=pc+1;
}else if(pc == 6){
makeBold(pc);
updateMessage("$ 150 15",1);
updateMessage("$ ",2);
// stage.find('#console_text').text('$ 150 15');
layer.draw();
pc=pc+1;
}else if(pc == 7){
makeBold(pc);
makeText(650,520,"int *c",'c');
makeContent(870,520,"0x1010",'c_value');
// add the 3rd arrow here.
layer.add(arrowLeft3);
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(pc);
// following pointer c to the address which is pointed to by c, and store 25 to that address.
// and because we assigned b to c, so b and c are now both pointing to the address 0x16, which stores the variable y.
stage.find('#y_value').text('25');
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(pc);
updateMessage("$ 150 25",2);
updateMessage("$ ",3);
// stage.find('#console_text').text('$ 150 25');
layer.draw();
pc=pc+1;
}else if(pc == 10){
alert("End of animation! Refresh the page if you want to re-run the animation.");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pointers: example 4</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Pointers: example 4</h1>
<p>This is the animation of example 4. Click the "next step" button to run the animation.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="example4.js"></script>
</body>
</html>

View File

@@ -0,0 +1,455 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let content = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(content);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
makeMemory(800,0,12,200,50);
makeText(800+350, -20, "0x1000", "addr0");
makeText(800+350, 5, "0x1004", "addr1");
makeText(800+350, 30, "0x1008", "addr2");
makeText(800+350, 80, "0x1010", "addr3");
makeText(800+350, 130, "0x1018", "addr4");
makeText(800+350, 180, "0x1020", "addr5");
makeText(800+350, 230, "0x1028", "addr6");
makeText(800+350, 280, "0x1030", "addr7");
makeText(800+350, 330, "0x1038", "addr8");
makeText(800+350, 380, "0x1040", "addr9");
makeText(800+350, 430, "0x1048", "addr10");
makeText(800+350, 480, "0x1050", "addr11");
makeText(800+350, 530, "0x1058", "addr12");
makeText(800+350, 555, "0x105C", "addr13");
var line1 = new Konva.Line({
points: [800, 25, 1000, 25],
stroke: '#343434',
strokeWidth: 5,
});
layer.add(line1);
var line2 = new Konva.Line({
points: [800, 575, 1000, 575],
stroke: '#343434',
strokeWidth: 5,
});
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"prec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 370,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var memoryText = new Konva.Text({
x: 830,
y: 635,
id:"memory",
text: "Memory",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 305,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 635,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrowLeft1 = new Konva.Arrow({
points: [920, 350, 1100, 200, 1005, 150],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowrleft1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var arrowLeft2 = new Konva.Arrow({
points: [930, 450, 1100, 300, 1005, 250],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowleft2",
fill: 'yellow',
stroke: 'yellow',
strokeWidth: 5,
});
var arrowLeft3 = new Konva.Arrow({
points: [930, 550, 1100, 400, 1005, 250],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowleft2",
fill: 'red',
stroke: 'red',
strokeWidth: 5,
});
/* for the arrow */
var arrowarray1 = [930, 450, 1100, 300, 1005, 250];
function moveArrow(){
arrowarray1[5] = arrowarray1[5] - 100;
arrowarray1[3] = arrowarray1[3] - 100;
stage.find('#arrowleft2').points(arrowarray1);
}
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
layer.add(memoryText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
}
// hard code here, we assume we only have 5 lines of code.
function makeBold(id){
for(let i=1;i<=5;i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
var code=["1. const int n = 10;",
"2. double a[n];",
"3. int i;",
"4. for( i=0; i<n; ++i )",
"5. \t\t a[i] = sqrt( double(i) );",
];
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,80+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
var message=["$",
"",
"",
""];
function updateMessage(msg,i) {
stage.find('#text_msg'+i).text(msg);
}
// draw that $ sign, which is a command line prompt.
makeText(60,400,message[0],'msg0');
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
makeText(650,10,"const int n",'n');
// this has to be after makeMemory so that the memory doesn't overwrite this.
makeContent(870,10,"10",'n_value');
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
makeText(650,50,"double[] a",'a');
makeContent(870,50,"?",'a0_value');
makeContent(870,100,"?",'a1_value');
makeContent(870,150,"?",'a2_value');
makeContent(870,200,"?",'a3_value');
makeContent(870,250,"?",'a4_value');
makeContent(870,300,"?",'a5_value');
makeContent(870,350,"?",'a6_value');
makeContent(870,400,"?",'a7_value');
makeContent(870,450,"?",'a8_value');
makeContent(870,500,"?",'a9_value');
makeText(1050,50,"a[0]",'a0');
makeText(1050,100,"a[1]",'a1');
makeText(1050,150,"a[2]",'a2');
makeText(1050,200,"a[3]",'a3');
makeText(1050,250,"a[4]",'a4');
makeText(1050,300,"a[5]",'a5');
makeText(1050,350,"a[6]",'a6');
makeText(1050,400,"a[7]",'a7');
makeText(1050,450,"a[8]",'a8');
makeText(1050,500,"a[9]",'a9');
// add the arrow here.
//layer.add(arrowLeft1);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
makeText(650,535,"int i",'i');
makeContent(870,535,"?",'i_value');
layer.add(line2);
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
stage.find('#i_value').text('0');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
stage.find('#a0_value').text('0.00');
layer.draw();
pc=pc+1;
}else if(pc == 6){
// because it's a loop, so we just go between line 4 and line 5.
makeBold(4);
stage.find('#i_value').text('1');
layer.draw();
pc=pc+1;
}else if(pc == 7){
// because it's a loop, so we just go between line 4 and line 5.
makeBold(5);
stage.find('#a1_value').text('1.00');
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(4);
stage.find('#i_value').text('2');
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(5);
stage.find('#a2_value').text('1.44'); // sqrt(2)
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold(4);
stage.find('#i_value').text('3');
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold(5);
stage.find('#a3_value').text('1.73'); // sqrt(3)
layer.draw();
pc=pc+1;
}else if(pc == 12){
makeBold(4);
stage.find('#i_value').text('4');
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold(5);
stage.find('#a4_value').text('2.00'); // sqrt(4)
layer.draw();
pc=pc+1;
}else if(pc == 14){
makeBold(4);
stage.find('#i_value').text('5');
layer.draw();
pc=pc+1;
}else if(pc == 15){
makeBold(5);
stage.find('#a5_value').text('2.24'); // sqrt(5)
layer.draw();
pc=pc+1;
}else if(pc == 16){
makeBold(4);
stage.find('#i_value').text('6');
layer.draw();
pc=pc+1;
}else if(pc == 17){
makeBold(5);
stage.find('#a6_value').text('2.45'); // sqrt(6)
layer.draw();
pc=pc+1;
}else if(pc == 18){
makeBold(4);
stage.find('#i_value').text('7');
layer.draw();
pc=pc+1;
}else if(pc == 19){
makeBold(5);
stage.find('#a7_value').text('2.65'); // sqrt(7)
layer.draw();
pc=pc+1;
}else if(pc == 20){
makeBold(4);
stage.find('#i_value').text('8');
layer.draw();
pc=pc+1;
}else if(pc == 21){
makeBold(5);
stage.find('#a8_value').text('2.83'); // sqrt(8)
layer.draw();
pc=pc+1;
}else if(pc == 22){
makeBold(4);
stage.find('#i_value').text('9');
layer.draw();
pc=pc+1;
}else if(pc == 23){
makeBold(5);
stage.find('#a9_value').text('3.00'); // sqrt(9)
layer.draw();
pc=pc+1;
}else if(pc == 24){
makeBold(4);
stage.find('#i_value').text('10');
layer.draw();
pc=pc+1;
}else if(pc == 25){
alert("End of loop! Also end of animation! Refresh the page if you want to re-run the animation.");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Arrays: example 1</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Arrays: example 1</h1>
<p>This is the animation of example 1. Click the "next step" button to run the animation.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="array1.js"></script>
</body>
</html>

View File

@@ -0,0 +1,443 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
var count=0;
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
// align: 'center',
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let content = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(content);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"brec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
makeMemory(800,0,12,200,50);
makeText(800+350, -20, "0x1000", "addr0");
makeText(800+350, 5, "0x1004", "addr1");
makeText(800+350, 30, "0x1008", "addr2");
makeText(800+350, 80, "0x1010", "addr3");
makeText(800+350, 130, "0x1018", "addr4");
makeText(800+350, 180, "0x1020", "addr5");
makeText(800+350, 230, "0x1028", "addr6");
makeText(800+350, 280, "0x1030", "addr7");
makeText(800+350, 330, "0x1038", "addr8");
makeText(800+350, 380, "0x1040", "addr9");
makeText(800+350, 430, "0x1048", "addr10");
makeText(800+350, 480, "0x1050", "addr11");
makeText(800+350, 530, "0x1058", "addr12");
var line1 = new Konva.Line({
points: [800, 25, 1000, 25],
stroke: '#343434',
strokeWidth: 5,
});
layer.add(line1);
var rect1 = new Konva.Rect({
x: 20,
y: 60,
id:"prec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var rect2 = new Konva.Rect({
x: 20,
y: 370,
id:"console",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 220,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var memoryText = new Konva.Text({
x: 830,
y: 635,
id:"memory",
text: "Memory",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var codeLabel = new Konva.Text({
x: 150,
y: 305,
id:"code",
text: "Code",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleLabel = new Konva.Text({
x: 130,
y: 635,
id:"console",
text: "Console",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
var consoleText = new Konva.Text({
x: 60,
y: 400,
id:"console_text",
text: "",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#581845',
});
var arrowLeft1 = new Konva.Arrow({
points: [950, 580, 1100, 400, 1005, 50],
tension: 0.5,
pointerLength: 10,
pointerWidth: 10,
id: "arrowleft1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
/* for the arrow */
var arrowarray1 = [950, 580, 1100, 400, 1005, 50];
// move downwards
function moveArrow(){
arrowarray1[5] = arrowarray1[5] + 50;
arrowarray1[3] = arrowarray1[3] + 50;
stage.find('#arrowleft1').points(arrowarray1);
}
// move downwards
function moveArrow2(){
arrowarray1[5] = arrowarray1[5] + 50;
//arrowarray1[3] = arrowarray1[3] + 10;
stage.find('#arrowleft1').points(arrowarray1);
}
// box for code
layer.add(rect1);
// box for console
layer.add(rect2);
layer.add(memoryText);
layer.add(consoleLabel);
layer.add(codeLabel);
layer.add(consoleText);
function makeCode(x,y,str,id) {
return new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
}
// hard code here, we assume we only have 5 lines of code.
function makeBold(id){
for(let i=1;i<=5;i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+id).fontStyle('bold');
}
}
}
var code=["1. const int n = 10;",
"2. double a[n];",
"3. double *p;",
"4. for( p=a; p<a+n; ++p )",
"5. \t\t *p = sqrt( p-a );",
];
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
let t=makeCode(20,80+(i*20),code[i],i+1);
layer.add(t);
}
// defining the message box
var msg_box = new Konva.Rect({
x: 900,
y: 100,
id:"message_box",
stroke: '#ffa07a',
strokeWidth: 5,
fill: '#ddd',
width: 400,
height: 200,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
// layer.add(msg_box);
var message=["$",
"",
"",
""];
function updateMessage(msg,i) {
stage.find('#text_msg'+i).text(msg);
}
// draw that $ sign, which is a command line prompt.
makeText(60,400,message[0],'msg0');
// add the layer to the stage
stage.add(layer);
// draw the image
layer.draw();
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(pc);
makeText(650,10,"const int n",'n');
// this has to be after makeMemory so that the memory doesn't overwrite this.
makeContent(870,10,"10",'n_value');
layer.draw();
pc=pc+1;
}else if(pc == 2){
makeBold(pc);
makeText(650,50,"double[] a",'a');
makeContent(870,50,"?",'a0_value');
makeContent(870,100,"?",'a1_value');
makeContent(870,150,"?",'a2_value');
makeContent(870,200,"?",'a3_value');
makeContent(870,250,"?",'a4_value');
makeContent(870,300,"?",'a5_value');
makeContent(870,350,"?",'a6_value');
makeContent(870,400,"?",'a7_value');
makeContent(870,450,"?",'a8_value');
makeContent(870,500,"?",'a9_value');
makeText(1050,50,"a[0]",'a0');
makeText(1050,100,"a[1]",'a1');
makeText(1050,150,"a[2]",'a2');
makeText(1050,200,"a[3]",'a3');
makeText(1050,250,"a[4]",'a4');
makeText(1050,300,"a[5]",'a5');
makeText(1050,350,"a[6]",'a6');
makeText(1050,400,"a[7]",'a7');
makeText(1050,450,"a[8]",'a8');
makeText(1050,500,"a[9]",'a9');
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(pc);
makeText(650,550,"double *p",'p');
makeContent(870,550,"?",'p_value');
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(pc);
// add the arrow here.
layer.add(arrowLeft1);
stage.find('#p_value').text('0x1008');
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(pc);
stage.find('#a0_value').text('0.00');
layer.draw();
pc=pc+1;
}else if(pc == 6){
// because it's a loop, so we just go between line 4 and line 5.
makeBold(4);
stage.find('#p_value').text('0x1010');
moveArrow();
layer.draw();
pc=pc+1;
}else if(pc == 7){
// because it's a loop, so we just go between line 4 and line 5.
makeBold(5);
stage.find('#a1_value').text('1.00');
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(4);
stage.find('#p_value').text('0x1018');
moveArrow();
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(5);
stage.find('#a2_value').text('1.44'); // sqrt(2)
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold(4);
stage.find('#p_value').text('0x1020');
moveArrow();
layer.draw();
pc=pc+1;
}else if(pc == 11){
makeBold(5);
stage.find('#a3_value').text('1.73'); // sqrt(3)
layer.draw();
pc=pc+1;
}else if(pc == 12){
makeBold(4);
stage.find('#p_value').text('0x1028');
moveArrow();
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold(5);
stage.find('#a4_value').text('2.00'); // sqrt(4)
layer.draw();
pc=pc+1;
}else if(pc == 14){
makeBold(4);
stage.find('#p_value').text('0x1030');
moveArrow2();
layer.draw();
pc=pc+1;
}else if(pc == 15){
makeBold(5);
stage.find('#a5_value').text('2.24'); // sqrt(5)
layer.draw();
pc=pc+1;
}else if(pc == 16){
makeBold(4);
stage.find('#p_value').text('0x1038');
moveArrow2();
layer.draw();
pc=pc+1;
}else if(pc == 17){
makeBold(5);
stage.find('#a6_value').text('2.45'); // sqrt(6)
layer.draw();
pc=pc+1;
}else if(pc == 18){
makeBold(4);
stage.find('#p_value').text('0x1040');
moveArrow2();
layer.draw();
pc=pc+1;
}else if(pc == 19){
makeBold(5);
stage.find('#a7_value').text('2.65'); // sqrt(7)
layer.draw();
pc=pc+1;
}else if(pc == 20){
makeBold(4);
stage.find('#p_value').text('0x1048');
moveArrow2();
layer.draw();
pc=pc+1;
}else if(pc == 21){
makeBold(5);
stage.find('#a8_value').text('2.83'); // sqrt(8)
layer.draw();
pc=pc+1;
}else if(pc == 22){
makeBold(4);
stage.find('#p_value').text('0x1050');
moveArrow2();
layer.draw();
pc=pc+1;
}else if(pc == 23){
makeBold(5);
stage.find('#a9_value').text('3.00'); // sqrt(9)
layer.draw();
pc=pc+1;
}else if(pc == 24){
makeBold(4);
stage.find('#p_value').text('0x1058');
moveArrow2();
layer.draw();
pc=pc+1;
}else if(pc == 25){
alert("End of loop! Also end of animation! Refresh the page if you want to re-run the animation.");
pc=pc+1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Arrays: example 2</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Arrays: example 2</h1>
<p>This is the animation of example 2. Click the "next step" button to run the animation.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="array2.js"></script>
</body>
</html>

View File

@@ -0,0 +1,608 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// then create layer
var layer = new Konva.Layer();
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
layer.add(text);
}
function makeContent(x,y,str,id) {
let content = new Konva.Text({
x: x,
y: y,
text: str,
id: id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#900C3F',
width: 400,
padding: 20,
});
layer.add(content);
}
function makeMemory(xstart,ystart,bufferSize,w,h) {
for(let i=0;i<bufferSize;i++){
let tr = new Konva.Rect({
x: xstart,
y: ystart+i*h,
id:"stack_rec"+i,
stroke: '#343434',
strokeWidth: 5,
fill: '#ddd',
width: w,
height: h,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
});
layer.add(tr);
} // end of for loop
}
// in this animation, we assume the stack size is fixed.
var stack_size = 18;
// create stack
makeMemory(1050,100,stack_size,200,30);
// the code rectangle.
var rect1 = new Konva.Rect({
x: 20,
y: 10,
id:"code_rec1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 350,
height: 180,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var fact3 = new Konva.Rect({
x: 460,
y: 10,
id:"code_fact4",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 350,
height: 180,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var fact2 = new Konva.Rect({
x: 460,
y: 220,
id:"code_fact3",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 350,
height: 180,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var fact1 = new Konva.Rect({
x: 460,
y: 430,
id:"code_fact2",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 350,
height: 180,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var fact0 = new Konva.Rect({
x: 460,
y: 640,
id:"code_fact1",
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 350,
height: 180,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
var legend = new Konva.Rect({
x: 1350,
y: 270,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: '#ffffff',
width: 360,
height: 350,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
function makeLegendBox(xstart,ystart,color){
var rect = new Konva.Rect({
x: xstart,
y: ystart,
id:"legend_box",
stroke: '#555',
strokeWidth: 5,
fill: color,
width: 40,
height: 25,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.2,
cornerRadius: 10,
});
layer.add(rect);
}
var stackText = new Konva.Text({
x: 1120,
y: 35,
id:"stack",
text: "Stack",
fontSize: 28,
fontFamily: 'Calibri',
fill: '#000000',
});
// box for code
layer.add(rect1);
layer.add(fact3);
layer.add(fact2);
layer.add(fact1);
layer.add(fact0);
layer.add(stackText);
// the large legend box
layer.add(legend);
// the actual legends
makeText(750+690, 270, "legend", "legend");
makeText(1390, 315, "activation record for fact(0)", "AR_0");
makeText(1390, 365, "activation record for fact(1)", "AR_1");
makeText(1390, 415, "activation record for fact(2)", "AR_2");
makeText(1390, 465, "activation record for fact(3)", "AR_3");
makeText(1390, 515, "activation record for fact(4)", "AR_4");
makeLegendBox(1360, 335, '#c4ff33'); // AR 0
makeLegendBox(1360, 385, '#ab33ff'); // AR 1
makeLegendBox(1360, 435, '#3364ff'); // AR 2
makeLegendBox(1360, 485, '#ff5733'); // AR 3
makeLegendBox(1360, 535, '#15925d'); // AR 4
function push_func(n){
x=920;
y=600+(n-4)*90;
id='n_label_' + n;
// make the n label.
makeText(x,y,'int n',id);
x=1120
// make the n value.
id='n_value_' + n;
makeText(x,y,n,id);
x=1060;
y=570+(n-4)*90;
id='return_' + n;
makeText(x,y,"return address",id);
// update color for this stack frame.
if(n == 4){
stage.find('#stack_rec'+(stack_size-1+n-4)).fill('#15925d');
stage.find('#stack_rec'+(stack_size-2+n-4)).fill('#15925d');
}else if(n == 3){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#ff5733');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#ff5733');
}else if(n == 2){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#3364ff');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#3364ff');
}else if(n == 1){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#ab33ff');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#ab33ff');
}else if(n == 0){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#c4ff33');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#c4ff33');
}
}
function push_result(n){
x=920;
y=540+(n-4)*90;
id="result_label_"+n;
// make the result label.
makeText(x,y,'int result',id);
x=1120
id="result_"+n;
// make the result value.
makeText(x,y,'?',id);
if(n == 4){
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#15925d');
}else if(n == 3){
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#ff5733');
}else if(n == 2){
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#3364ff');
}else if(n == 1){
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#ab33ff');
}else if(n == 0){
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#c4ff33');
}
}
function pop_func(n){
stage.find('#text_n_label_'+n).text("");
stage.find('#text_n_value_'+n).text("");
stage.find('#text_return_'+n).text("");
// because level 0 doesn't really define the result variable.
if(n!=0){
stage.find('#text_result_label_'+n).text("");
stage.find('#text_result_'+n).text("");
}
// update color for this stack frame.
if(n == 4){
stage.find('#stack_rec'+(stack_size-1+n-4)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-2+n-4)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#ddd');
}else if(n == 3){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#ddd');
}else if(n == 2){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#ddd');
}else if(n == 1){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-1-2+(n-4)*3)).fill('#ddd');
}else if(n == 0){
stage.find('#stack_rec'+(stack_size-1+(n-4)*3)).fill('#ddd');
stage.find('#stack_rec'+(stack_size-2+(n-4)*3)).fill('#ddd');
}
}
function update_result(n, value){
stage.find('#text_result_'+n).text(value);
}
function makeCode(x,y,str,id) {
let code = new Konva.Text({
x: x,
y: y,
text: str,
id: 'line'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 550,
padding: 20,
});
layer.add(code);
}
var code=["0. int fact(int n){",
"1. \t\t\t if ( n==0 ) {",
"2. \t\t\t \t\t\t return 1;",
"3. \t\t\t } else {",
"4. \t\t\t \t\t\t int result = fact(n-1);",
"5. \t\t\t \t\t\t return n * result;",
"6. \t\t\t }",
"7. }",
];
function makeBold(level, id){
for(let i=(level*100+1); i<=(level*100+code.length); i++){
if(i!=id){
stage.find('#line'+i).fontStyle('normal');
}else{
stage.find('#line'+i).fontStyle('bold');
}
}
}
function makeAllCode(){
// write the code fragment into all 5 code boxes.
for (let i=0;i<code.length;i++){
// the array starts from index 0, but we want ids to be counted from index 1.
makeCode(20,5+(i*20),code[i],i+1+400);
makeCode(470,5+(i*20),code[i],i+1+300);
makeCode(470,210+5+(i*20),code[i],i+1+200);
makeCode(470,210*2+5+(i*20),code[i],i+1+100);
makeCode(470,210*3+5+(i*20),code[i],i+1);
}
}
makeAllCode();
// add the layer to the stage
stage.add(layer);
// only the first line is different, and the first line's id is supposed to be 'line'+1+300
stage.find('#line'+(1+300)).text('0. int fact(3){');
stage.find('#line'+(1+200)).text('0. int fact(2){');
stage.find('#line'+(1+100)).text('0. int fact(1){');
stage.find('#line'+1).text('0. int fact(0){');
var messageBox = new Konva.Rect({
x: 50,
y: 300,
width: 220,
height: 60,
fill: 'lightblue',
stroke: 'black',
strokeWidth: 4
});
var arrow = new Konva.Arrow({
x: messageBox.x() + messageBox.width() / 2,
y: messageBox.y(),
points: [0, 0, 0, -150],
pointerLength: 20,
pointerWidth: 20,
fill: 'black',
stroke: 'black',
strokeWidth: 4
});
var messageText = new Konva.Text({
x: messageBox.x() + 10,
y: messageBox.y() + 20,
text: 'fact(4) returns 24!',
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
// draw the image
layer.draw();
// calculating fact(4), which is 4x3x2x1=24.
var pc=1;
function nextstep() {
if(pc == 1){
makeBold(4, 401);
layer.draw();
pc=pc+1;
}else if(pc == 2){
push_func(4);
layer.draw();
pc=pc+1;
}else if(pc == 3){
makeBold(4, 402);
layer.draw();
pc=pc+1;
}else if(pc == 4){
makeBold(4, 404);
layer.draw();
pc=pc+1;
}else if(pc == 5){
makeBold(4, 405);
push_result(4);
layer.draw();
pc=pc+1;
}else if(pc == 6){
// start fact(3)
makeBold(3, 301);
layer.draw();
pc=pc+1;
}else if(pc == 7){
push_func(3);
layer.draw();
pc=pc+1;
}else if(pc == 8){
makeBold(3, 302);
layer.draw();
pc=pc+1;
}else if(pc == 9){
makeBold(3, 304);
layer.draw();
pc=pc+1;
}else if(pc == 10){
makeBold(3, 305);
push_result(3);
layer.draw();
pc=pc+1;
}else if(pc == 11){
// start fact(2)
makeBold(2, 201);
layer.draw();
pc=pc+1;
}else if(pc == 12){
push_func(2);
layer.draw();
pc=pc+1;
}else if(pc == 13){
makeBold(2, 202);
layer.draw();
pc=pc+1;
}else if(pc == 14){
makeBold(2, 204);
layer.draw();
pc=pc+1;
}else if(pc == 15){
makeBold(2, 205);
push_result(2);
layer.draw();
pc=pc+1;
}else if(pc == 16){
// start fact(1)
makeBold(1, 101);
layer.draw();
pc=pc+1;
}else if(pc == 17){
push_func(1);
layer.draw();
pc=pc+1;
}else if(pc == 18){
makeBold(1, 102);
layer.draw();
pc=pc+1;
}else if(pc == 19){
makeBold(1, 104);
layer.draw();
pc=pc+1;
}else if(pc == 20){
makeBold(1, 105);
push_result(1);
layer.draw();
pc=pc+1;
}else if(pc == 21){
// start fact(0)
makeBold(0, 1);
layer.draw();
pc=pc+1;
}else if(pc == 22){
push_func(0);
layer.draw();
pc=pc+1;
}else if(pc == 23){
makeBold(0, 2);
layer.draw();
pc=pc+1;
}else if(pc == 24){
makeBold(0, 3);
layer.draw();
pc=pc+1;
}else if(pc == 25){
// fact(0) returns
pop_func(0);
// fact(0) is done, no more bold font.
makeBold(0, -1);
layer.draw();
pc=pc+1;
}else if(pc == 26){
// because fact(0) returns 1;
update_result(1,1);
layer.draw();
pc=pc+1;
}else if(pc == 27){
// march on in fact(1).
makeBold(1, 106);
layer.draw();
pc=pc+1;
}else if(pc == 28){
// fact(1) returns
pop_func(1);
// fact(1) is done, no more bold font.
makeBold(1, -1);
layer.draw();
pc=pc+1;
}else if(pc == 29){
// because fact(1) returns 1;
update_result(2,1);
layer.draw();
pc=pc+1;
}else if(pc == 30){
// march on in fact(2).
makeBold(2, 206);
layer.draw();
pc=pc+1;
}else if(pc == 31){
// fact(2) returns
pop_func(2);
// fact(2) is done, no more bold font.
makeBold(2, -1);
layer.draw();
pc=pc+1;
}else if(pc == 32){
// because fact(2) returns 2;
update_result(3, 2);
layer.draw();
pc=pc+1;
}else if(pc == 33){
// march on in fact(3).
makeBold(3, 306);
layer.draw();
pc=pc+1;
}else if(pc == 34){
// fact(3) returns
pop_func(3);
// fact(3) is done, no more bold font.
makeBold(3, -1);
layer.draw();
pc=pc+1;
}else if(pc == 35){
// because fact(3) returns 6;
update_result(4, 6);
layer.draw();
pc=pc+1;
}else if(pc == 36){
// march on in fact(4).
makeBold(4, 406);
layer.draw();
pc=pc+1;
}else if(pc == 37){
// displaying fact(4) results.
layer.add(messageBox);
layer.add(arrow);
layer.add(messageText);
layer.draw();
pc=pc+1;
}else if(pc == 38){
// fact(4) returns
pop_func(4);
layer.draw();
pc=pc+1;
}else if(pc == 39){
// fact(4) is done, no more bold font.
makeBold(4, -1);
layer.draw();
alert("End of animation! Refresh the page if you want to re-run the animation.");
pc=pc+1;
}else if(pc == 40){
// hiding the fact(4) results.
messageText.destroy();
arrow.destroy();
messageBox.destroy();
layer.draw();
// reset the counter.
pc=1;
}
}
/* vim: set ts=4: */

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Recursive Programs: factorial</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Recursive Programs: factorial</h1>
<p>This is the animation of a recursive implementation of the factorial computation. Click the "next step" button to run the animation. <b>Note:</b> we assume the user calls fact(4).</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="factorial.js"></script>
</body>
</html>

View File

@@ -0,0 +1,253 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// Create a layer
var layer = new Konva.Layer();
stage.add(layer);
function makeText(x,y,str,id) {
let text = new Konva.Text({
x: x,
y: y,
text: str,
id: 'text_'+id,
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
layer.add(text);
}
// Create a function to draw nodes
function drawNode(x, y, label) {
var circle = new Konva.Circle({
x: x,
y: y,
radius: 40,
fill: 'lightgray',
stroke: 'black',
strokeWidth: 1
});
layer.add(circle);
var text = new Konva.Text({
x: x - 20,
y: y - 10,
text: label,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
}
// Draw lines connecting nodes
var line = new Konva.Line({
points: [650, 100, 450, 200, 650, 100, 850, 200],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow1 = new Konva.Arrow({
points: [925, 200, 1150, 200],
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line1 = new Konva.Line({
points: [450, 200, 350, 300, 450, 200, 550, 300],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line2 = new Konva.Line({
points: [850, 200, 750, 300, 850, 200, 950, 300],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow2 = new Konva.Arrow({
points: [1000, 300, 1150, 300],
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line3 = new Konva.Line({
points: [350, 300, 300, 400, 350, 300, 400, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line4 = new Konva.Line({
points: [550, 300, 500, 400, 550, 300, 600, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line5 = new Konva.Line({
points: [750, 300, 700, 400, 750, 300, 800, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line6 = new Konva.Line({
points: [950, 300, 900, 400, 950, 300, 1000, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow3 = new Konva.Arrow({
points: [1050, 400, 1150, 400],
pointerLength: 10,
pointerWidth: 10,
id: "arrow3",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
// Create a dotted line
var dottedLine = new Konva.Line({
points: [300, 400, 200, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var dottedLine2 = new Konva.Line({
points: [1000, 400, 1050, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var arrow4 = new Konva.Arrow({
points: [1070, 600, 1150, 600],
pointerLength: 10,
pointerWidth: 10,
id: "arrow4",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var messageBox = new Konva.Rect({
x: 150,
y: 650,
width: 800,
height: 60,
fill: 'lightblue',
stroke: 'black',
strokeWidth: 4
});
var arrow = new Konva.Arrow({
x: messageBox.x() + messageBox.width() / 2,
y: messageBox.y(),
points: [0, 0, 0, -150],
pointerLength: 20,
pointerWidth: 20,
fill: 'black',
stroke: 'black',
strokeWidth: 4
});
var messageText = new Konva.Text({
x: messageBox.x() + 10,
y: messageBox.y() + 20,
text: 'In summary, T(n) = (2^0+2^1+2^2+2^3+...+2^(n-2)) * C = O(2^(n-1)) = O((2^n)/2) = O(2^n)',
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
var pc=1;
function nextstep() {
if(pc == 1){
// Draw nodes
drawNode(650, 100, 'T(n)');
layer.draw();
pc=pc+1;
}else if(pc == 2){
layer.add(line);
drawNode(450, 200, 'T(n-1)');
drawNode(850, 200, 'T(n-2)');
layer.add(arrow1);
makeText(1150,170,"T(n-1)+T(n-2), 1 add operation, and we know 1 is 2^0, thus, time taken: (2^0 * C)",'L1');
layer.draw();
pc=pc+1;
}else if(pc == 3){
layer.add(line1);
layer.add(line2);
drawNode(350, 300, 'T(n-2)');
drawNode(550, 300, 'T(n-3)');
drawNode(750, 300, 'T(n-3)');
drawNode(950, 300, 'T(n-4)');
layer.add(arrow2);
makeText(1150,270,"T(n-2)+T(n-3) and T(n-3)+T(n-4), 2 add operations, and we know 2 is 2^1, thus, time taken: (2^1 * C)",'L2');
layer.draw();
pc=pc+1;
}else if(pc == 4){
layer.add(line3);
layer.add(line4);
layer.add(line5);
layer.add(line6);
layer.add(arrow3);
drawNode(300, 400, 'T(n-3)');
drawNode(400, 400, 'T(n-4)');
drawNode(500, 400, 'T(n-4)');
drawNode(600, 400, 'T(n-5)');
drawNode(700, 400, 'T(n-4)');
drawNode(800, 400, 'T(n-5)');
drawNode(900, 400, 'T(n-5)');
drawNode(1000, 400, 'T(n-6)');
makeText(1150,370,"T(n-3)+T(n-4), T(n-4)+T(n-5), T(n-4)+T(n-5) and T(n-5)+T(n-6), 4 add operations, and we know 4 is 2^2, thus, time taken: (2^2 * C)",'L3');
layer.draw();
pc=pc+1;
}else if(pc == 5){
layer.add(dottedLine);
layer.add(dottedLine2);
drawNode(200, 600, 'T(1)');
layer.add(arrow4);
makeText(1150,570,"2^(n-2) add operations, time taken: (2^(n-2) * C)",'L4');
layer.draw();
pc=pc+1;
}else if(pc == 6){
layer.add(messageBox);
layer.add(messageText);
layer.draw();
pc=pc+1;
}else if(pc == 7){
alert("End of animation! Refresh the page if you want to re-run the animation.");
layer.draw();
pc=pc+1;
}
}

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Recursive Programs: fibonacci</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Recursive Programs: fibonacci</h1>
<p>This animation shows the time complexity of the recursive implementation of the fibonacci computation. Click the "next step" button to run the animation. <b>Note:</b> we assume each add operation takes constant time, and we use C to denote this constant time.</p>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="fibonacci.js"></script>
</body>
</html>

View File

@@ -0,0 +1,405 @@
// Author: Jidong Xiao
// first we need to create a stage
var stage = new Konva.Stage({
container: 'container', // id of container <div>
width: 2000,
height: 1000
});
// Create a layer
var layer = new Konva.Layer();
stage.add(layer);
function makeNULL(x,y) {
let text = new Konva.Text({
x: x,
y: y,
text: 'NULL',
id: 'nullptr',
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000000',
width: 400,
padding: 20,
});
layer.add(text);
}
// Create a function to draw nodes
function drawNode(x, y, label) {
var circle = new Konva.Circle({
x: x,
y: y,
id: 'node_'+label,
radius: 40,
fill: 'lightgray',
stroke: 'black',
strokeWidth: 1
});
layer.add(circle);
var text = new Konva.Text({
x: x-5,
y: y-10,
id: 'node_text_'+label,
text: label,
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
layer.add(text);
}
// Draw lines connecting nodes
var line1 = new Konva.Line({
points: [645, 100, 520, 180],
//points: [650, 100, 450, 200, 650, 100, 850, 200],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line2 = new Konva.Line({
points: [655, 100, 780, 180],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow1 = new Konva.Arrow({
points: [925, 200, 1150, 200],
pointerLength: 10,
pointerWidth: 10,
id: "arrow1",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line3 = new Konva.Line({
//points: [450, 200, 350, 300, 450, 200, 550, 300],
points: [495, 200, 378, 272],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line4 = new Konva.Line({
points: [505, 200, 572, 272],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line5 = new Konva.Line({
// points: [850, 200, 750, 300, 850, 200, 950, 300],
points: [795, 200, 700, 300],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow2 = new Konva.Arrow({
points: [1000, 300, 1150, 300],
pointerLength: 10,
pointerWidth: 10,
id: "arrow2",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var line6 = new Konva.Line({
// points: [350, 300, 300, 400, 350, 300, 400, 400],
points: [345, 300, 200, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line7 = new Konva.Line({
points: [705, 300, 800, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line8 = new Konva.Line({
points: [805, 200, 916, 276],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var line9 = new Konva.Line({
points: [950, 300, 900, 400, 950, 300, 1000, 400],
stroke: 'black',
strokeWidth: 1,
lineCap: 'round',
lineJoin: 'round'
});
var arrow3 = new Konva.Arrow({
points: [1050, 400, 1150, 400],
pointerLength: 10,
pointerWidth: 10,
id: "arrow3",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
// Create a dotted line
var dottedLine = new Konva.Line({
points: [300, 400, 200, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var dottedLine2 = new Konva.Line({
points: [1000, 400, 1050, 600],
stroke: 'black',
strokeWidth: 2,
dash: [5, 5]
});
var arrow4 = new Konva.Arrow({
points: [1070, 600, 1150, 600],
pointerLength: 10,
pointerWidth: 10,
id: "arrow4",
fill: 'green',
stroke: 'green',
strokeWidth: 5,
});
var messageBox = new Konva.Rect({
x: 150,
y: 650,
width: 800,
height: 60,
fill: 'lightblue',
stroke: 'black',
strokeWidth: 4
});
var arrow = new Konva.Arrow({
x: messageBox.x() + messageBox.width() / 2,
y: messageBox.y(),
points: [0, 0, 0, -150],
pointerLength: 20,
pointerWidth: 20,
fill: 'black',
stroke: 'black',
strokeWidth: 4
});
var messageText = new Konva.Text({
x: messageBox.x() + 10,
y: messageBox.y() + 20,
text: 'In summary, T(n) = (2^0+2^1+2^2+2^3+...+2^(n-2)) * C = O(2^(n-1)) = O((2^n)/2) = O(2^n)',
fontSize: 20,
fontFamily: 'Calibri',
fill: 'black'
});
drawNode(650, 100, '5');
layer.add(line1);
layer.add(line2);
drawNode(500, 200, '3');
drawNode(800, 200, '6');
layer.add(line3);
layer.add(line4);
drawNode(350, 300, '2');
drawNode(600, 300, '4');
layer.add(line5);
drawNode(700, 300, '7');
layer.add(line6);
layer.add(line7);
drawNode(200, 400, '1');
drawNode(800, 400, '8');
layer.add(line8);
line8.hide();
layer.draw();
var key;
var old_key = 0;
function start() {
key = document.getElementById('textIn').value;
stage.find('#nullptr').hide();
if(hidden_2==1){
// show line 6
line6.show();
// show 2
stage.find('#node_'+2).show();
stage.find('#node_text_'+2).show();
hidden_2=0;
// reset 1
stage.find('#node_'+1).x(200);
stage.find('#node_'+1).y(400);
stage.find('#node_text_'+1).x(195);
stage.find('#node_text_'+1).y(390);
}
if(hidden_7==1){
// show line 7
line7.show();
// show 7
stage.find('#node_'+7).show();
stage.find('#node_text_'+7).show();
hidden_7=0;
// reset 8
stage.find('#node_'+8).x(800);
stage.find('#node_'+8).y(400);
stage.find('#node_text_'+8).x(795);
stage.find('#node_text_'+8).y(390);
}
if(hidden_6==1){
line5.show();
stage.find('#node_'+6).show();
stage.find('#node_text_'+6).show();
// move 7 and 8 back
stage.find('#node_'+7).x(700);
stage.find('#node_'+7).y(300);
stage.find('#node_text_'+7).x(695);
stage.find('#node_text_'+7).y(290);
stage.find('#node_'+8).x(800);
stage.find('#node_'+8).y(400);
stage.find('#node_text_'+8).x(795);
stage.find('#node_text_'+8).y(390);
line7.show();
line8.hide();
hidden_6=0;
}
if(deleted_3==1){
// swap 3 and 4 back
stage.find('#node_'+3).x(500);
stage.find('#node_'+3).y(200);
stage.find('#node_text_'+3).x(495);
stage.find('#node_text_'+3).y(190);
stage.find('#node_'+4).x(600);
stage.find('#node_'+4).y(300);
stage.find('#node_text_'+4).x(595);
stage.find('#node_text_'+4).y(290);
deleted_3=0;
// reset pc
pc=1;
}
if(old_key == 0){
}else{
// un-highlight the old node.
stage.find('#node_'+old_key).fill("lightgray");
// show the old node
stage.find('#node_'+old_key).show();
stage.find('#node_text_'+old_key).show();
}
// highlight this node.
stage.find('#node_'+key).fill("red");
layer.draw();
old_key = key;
console.log("start");
}
makeNULL(130,390);
var hidden_2=0;
var hidden_6=0;
var hidden_7=0;
var deleted_3=0;
var pc=1;
function nextstep() {
if(key == 1){
// hide this node, and show a NULL pointer.
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
stage.find('#nullptr').x(130);
stage.find('#nullptr').y(390);
stage.find('#nullptr').show();
layer.draw();
}else if(key == 2){
line6.hide();
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
stage.find('#node_'+1).x(350);
stage.find('#node_'+1).y(300);
stage.find('#node_text_'+1).x(345);
stage.find('#node_text_'+1).y(290);
hidden_2=1;
layer.draw();
}else if(key == 3){
if(pc==1){
// swap 3 and 4
stage.find('#node_'+4).x(500);
stage.find('#node_'+4).y(200);
stage.find('#node_text_'+4).x(495);
stage.find('#node_text_'+4).y(190);
stage.find('#node_'+3).x(600);
stage.find('#node_'+3).y(300);
stage.find('#node_text_'+3).x(595);
stage.find('#node_text_'+3).y(290);
deleted_3=1;
layer.draw();
pc = pc + 1;
}else if(pc==2){
// hide this node, and show a NULL pointer.
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
stage.find('#nullptr').x(535);
stage.find('#nullptr').y(260);
stage.find('#nullptr').show();
layer.draw();
pc = pc + 1;
}
}else if(key == 4){
// hide this node, and show a NULL pointer.
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
stage.find('#nullptr').x(535);
stage.find('#nullptr').y(260);
stage.find('#nullptr').show();
layer.draw();
}else if(key == 5){
}else if(key == 6){
line5.hide();
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
// move 7 and 8
stage.find('#node_'+7).x(800);
stage.find('#node_'+7).y(200);
stage.find('#node_text_'+7).x(795);
stage.find('#node_text_'+7).y(190);
stage.find('#node_'+8).x(950);
stage.find('#node_'+8).y(300);
stage.find('#node_text_'+8).x(945);
stage.find('#node_text_'+8).y(290);
line7.hide();
line8.show();
hidden_6=1;
layer.draw();
}else if(key == 7){
line7.hide();
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
stage.find('#node_'+8).x(700);
stage.find('#node_'+8).y(300);
stage.find('#node_text_'+8).x(695);
stage.find('#node_text_'+8).y(290);
hidden_7=1;
layer.draw();
}else if(key == 8){
// hide this node, and show a NULL pointer.
stage.find('#node_'+key).hide();
stage.find('#node_text_'+key).hide();
stage.find('#nullptr').x(770);
stage.find('#nullptr').y(390);
stage.find('#nullptr').show();
layer.draw();
//alert("End of animation! Refresh the page if you want to re-run the animation.");
}
}

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Recursive Program: Delete a Node in a BST</title>
<script src="../../konva.js"></script>
</head>
<body>
<h1>Recursive Program: Delete a Node in a Binary Search Tree</h1>
<p>This animation shows how to delete a node in a binary search tree. Click the "next step" button to run the animation. <b>Note:</b> This animation as of now doesn't support the deletion of node 5.</p>
<label>delete node</label> <input type="text" id="textIn"><button onclick="start()">Start</button>
<br>
<button onclick="nextstep()">next step</button>
<div id="container"></div>
<script src="delete_node.js"></script>
</body>
</html>