Reputation: 15
For fun I am trying to visualize a sorting algorithm, but I have run into an issue.
I tried to call the draw function in the sort method but the browser locks up and renders only the final sorted array. How can I visualize every process of sorting?
var CANVAS_WIDTH = window.innerWidth;
var CANVAS_HEIGHT = window.innerHeight;
var canvas = document.querySelector('canvas')
var context = canvas.getContext('2d');
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;
context.fillStyle = 'red';
context.fillRect(0,0, CANVAS_WIDTH, CANVAS_WIDTH);
function draw(array){
context.save();
context.clearRect(0, 0, canvas.width, canvas.height);
context.strokeStyle = 'white';
context.beginPath();
context.moveTo(0, canvas.height-100);
context.lineTo(canvas.width, canvas.height-100);
context.stroke();
context.restore();
context.fillStyle = 'white';
for(let i = 0; i < array.length; i++){
context.fillRect(100 + 7*i,canvas.height-100,5,-5 * array[i]);
}
}
let array = []
for(let i = 0; i < 100; i++){
array.push(100-i);
}
function bubble_Sort(arr){
let ticks = 0;
const speed = 50;
let size = arr.length;
for(let i = 0; i < size; i++){
ticks++;
for(let j = 0; j < size - 1; j++){
draw(array);
if (arr[j] > arr[j+1]){
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
draw(array);
array = bubble_Sort(array)
Upvotes: 0
Views: 358
Reputation: 350725
You can use async
await
for that: that way you don't have to touch (much) your existing code. Just make the bubble_Sort function asynchronous with the keyword async
, and add an await delay()
in the loop. The delay
function should then be a function that returns a promise that resolves within a short delay.
As a side note, you can speed up your bubble sort a bit. The inner loop should not revisit the part of the array that is already sorted. Each time the outer loop makes a cycle, a value arrives at its final spot at the righter end of the array, so the inner loop can stop before reaching that position.
You can also save a bit on the drawing: only call draw
when you perform a swap, as there is no use in drawing the same situation twice.
Here is your code with those adaptations:
// Utility function:
let delay = ms => new Promise(resolve => setTimeout(resolve, ms));
// Make the main function async
async function bubble_Sort(arr){
// Move the initial call of draw here
draw(array);
await delay(5); // <---- asynchronous delay of a few milliseconds
let size = arr.length;
for(let i = 0; i < size; i++){
for(let j = 0; j < size - 1 - i; j++){ // optimised algo a bit!
if (arr[j] > arr[j+1]){
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
// Only draw when something changed
draw(array);
await delay(5); // <---- asynchronous delay of a few milliseconds
}
}
}
return arr;
}
function draw(array) { // Just simplified it for this demo. Nothing essential.
context.clearRect(0, 0, canvas.width, canvas.height);
for(let i = 0; i < array.length; i++){
context.fillRect(10 + 7*i,canvas.height-20,5,-array[i]);
}
}
var CANVAS_WIDTH = window.innerWidth - 10;
var CANVAS_HEIGHT = window.innerHeight - 70;
var canvas = document.querySelector('canvas')
var context = canvas.getContext('2d');
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;
context.fillStyle = 'red';
let array = [...Array(80).keys()].reverse();
// skip a draw call here, and
// Don't assign to array, since bubble_Sort now returns a promise
bubble_Sort(array).then(sorted => console.log(...sorted));
<canvas></canvas>
Upvotes: 1
Reputation: 1564
You are missing setTimeout
, you need set a timeout between each change of your array so you can actually see the change. Currently all your changes are happen, but too fast to see :)
It gonna be something like:
You need to wrap draw function with setTimeout
, you will need to specify a number for the timeout duration, there you need to do somethink like: 300 * index
.
Also, I can see you already got a speed
variable, but you didnt use it..
Upvotes: 0