// Grab canvas and context. let canvas = document.getElementById('display'); let context = canvas.getContext('2d'); // Declare array to be quite large. let list = new Array(1024); // Flags used to determine if bg or bars need redrawn. let updateBG = true; let updateBars = true; // loopBlock is used to block the program. // It is enabled when simulation is paused or finished. let loopBlock = false; // Setup event listeners for window. function setupCanvas() { // Setup event listeners for load and window resize. window.addEventListener('load', canvasResize); window.addEventListener('resize', canvasResize); } // Initializes the list of 100 random numbers. function initList(len) { for (let i = 0; i < len; i++) list[i] = Math.round(Math.random() * 100); } // This function grabs the width and height of the window // and resizes the canvas in the event of loading or resizing. function canvasResize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; updateBG = true; updateBars = true; } // Finds the largest number in the list. function max(len) { let maximum = list[0]; for (let i = 1; i < len; i++) maximum = list[i] > maximum ? list[i] : maximum; return maximum; } // cmp1 and cmp2 are two indices being compared, make them // negative to mean a switch is happening let cmp1 = 0; let cmp2 = 0; // Plot each index of list[]. function plotBars(len) { let barWidth = canvas.width/len; let barScale = canvas.height/max(len); for (let i = 0; i < len; i++) { let x = i * barWidth; let h = list[i] * barScale; let y = canvas.height - h; context.save(); if (i == cmp1 || i == cmp2) context.fillStyle = '#eafbea'; else if (i == -cmp1 || i == -cmp2) context.fillStyle = '#ea5e5e'; else context.fillStyle = '#1f6650'; context.fillRect(x+1, y, barWidth-2, h); context.fillStyle = 'white'; context.font = "12px Ariel"; context.fillText(list[i], x+4, y+12); context.restore(); } } // Draws the black background. function drawBackground(len) { // Save context to stack. context.save(); context.fillStyle = 'black'; context.fillRect(0, 0, canvas.width, canvas.height); // Pops most recently saved canvas state off stack. context.restore(); context.fillStyle = '#1f6650'; context.font = "30px Ariel"; context.fillText("Bubble Sort, " + len + " numbers", 15, 25); context.fillStyle = 'white'; context.fillText('Comparing - white', 15, 50); context.fillStyle = 'red'; context.fillText('Swapping - red', 15, 75); // Testing buttons: context.fillStyle = 'white'; context.fillRect(15, 90, 30, 30); context.fillRect(50, 90, 30, 30); context.fillStyle = 'black'; context.font = "20px Ariel"; context.fillText("<<", 17, 110); context.fillText(">>", 53, 110); } // These are some variables that flag and alter various parts // of the sort. You may need to add/remove/modify your own // depending on the complexity of your sorting method. let sortStarted = false; let sortFinished = false; let sortIndex = 1; // Sorting function. This example uses bubble sort. function sortStart(len, speed) { // Finished is used to mark when no swaps were done in a sort loop. // Think of it as finishing one sorting loop. let finished = true; // tmp is used as a temporary value when swapping. let tmp; // Flip the sortStarted flag. sortStarted = true; // setInterval() runs once every <sortDelay> let sortLoop = setInterval(function() { // Checks for Pause button and sets loopBlock document.body.onkeyup = function(e){ if(e.keyCode == 32) loopBlock = !loopBlock; } if (loopBlock) { // Paused context.fillStyle = 'red'; context.font = "30px Ariel"; context.fillText("PAUSED", 90, 115); } else { cmp1 = sortIndex; cmp2 = sortIndex+1; // If left > right, swap if (list[sortIndex] < list[sortIndex - 1]) { // Keep setting finished just to be safe. finished = false; // ol-switcharoo tmp = list[sortIndex - 1]; list[sortIndex - 1] = list[sortIndex]; list[sortIndex] = tmp; cmp1 *= -1; cmp2 *= -1; } sortIndex++; // Reached end of list. // If list has been scanned once with no swaps, // sortFinish will be set and sort will end // Otherwise start over from 1. if (sortIndex == len) { sortIndex = 1; if (finished) { sortFinished = true; clearInterval(sortLoop); } else { finished = true; } } } // Flag that bg and bars need redrawn updateBG = true; updateBars = true; // Repeat once every speed ms }, speed); } // Setup initializes the canvas as well as the list of random nums. function setup(len) { setupCanvas(); initList(len); } function loop(len, sortSpeed) { if (!loopBlock) { // If background needs updated, redraw background. if (updateBG) { updateBG = false; drawBackground(len); } // If bars need updated, replot. if (updateBars) { updateBars = false; plotBars(len); } // Starts the sort if it isn't looping already. if (!sortStarted) sortStart(len, sortSpeed); // Checks if sort has completed. Briefly blocks looping while re-initializing the list, sortStarted, and sortFinished variables. if (sortFinished) { loopBlock = true; setTimeout(function() { initList(len); sortStarted = false; sortFinished = false; loopBlock = false; }, 5000); } } } // Main function which runs the setup and holds the main infinite loop. (function main() { // Setup the canvas and list. var numItems = window.prompt("Enter number of items to sort:", "50"); var speed = window.prompt("Delay (in ms) between comparasins:", "10") setup(numItems); (function mainLoop() { loop(numItems, speed); // requestAnimationFrame calls mainLoop infinitely requestAnimationFrame(mainLoop); })(); })();