0x10f2c
0x10f2c

Reputation: 15

I am trying to use canvas to visualize sort algorithm in javascript?

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

Answers (2)

trincot
trincot

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

Asaf
Asaf

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:

  1. Draw array
  2. Wait 300 milliseconds
  3. Draw array
  4. Wait 300 milliseconds
  5. Etc...

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

Related Questions