Search code examples
javascriptchart.jsinsertion-sort

Chart.js update() method only works once in the end instead of updating every iteration


function insertSort(inputArray = myChart.data.datasets[0].data) {
    let inputArrayLength = inputArray.length;
    let outerIndex = 1;
    let innerIndex = 0;
    while(outerIndex<inputArrayLength) {
        innerIndex = outerIndex - 1;
        temp = outerIndex;
        while(innerIndex>=0){
            if (inputArray[temp]<inputArray[innerIndex]){
                inputArray[innerIndex] = [inputArray[temp], inputArray[temp] = inputArray[innerIndex]][0];
                temp = innerIndex;
                innerIndex--;
            } else {
                innerIndex--;
            }
        }
        sleep(1000);
        console.log('Intermediate result is: ', inputArray);
        myChart.data.datasets[0].data = inputArray;
        myChart.update();
        outerIndex++;
    }
    console.log('Final result is: ', inputArray);
    return true;
}
function sleep(milliseconds) {
  console.log('going in sleep');
  const date = Date.now();
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
  console.log('out of sleep');
}
let ctx = document.getElementById('myChart').getContext('2d');
let randomArray = Array.from({length: 10}, () => Math.floor(Math.random() * 10+1));
let myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange', 'Blue', 'Blue', 'Blue', 'Blue'],
        datasets: [{
            label: '# of Votes',
            data: randomArray,
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(54, 162, 235, 0.2)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        }
    }
});
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>
    <button type="button" onclick="insertSort()">StartSorting</button>
    <canvas id="myChart" width="400" height="400">
    </canvas>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js"></script>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

I have built a simple insertion sort algorithm in JavaScript, which sorts an array of ten random integers from the smallest to the largest.

  • The result is visualised by using Chart.js library, ten bars of different heights are sorted and updated from the shortest to the tallest.

What I want to achieve now is: visualise each step of this sorting process. I introduced a sleep() function which basically delays the code execution and right after this sleep() function, I call myChart.update() to update the bars. But the result is not what I expected, it turned out that all bars were only updated once by the end of this code execution instead of being updated whenever a sorting step is completed.

Can anyone help? My code can be executed by C&P as a HTML file and run it in Chrome browser. Click startSorting button to have it sorted, and some simple debugging messages are available in the developer console.


Solution

  • Your code blocks the UI, hence the console log messages and the updated chart can only be shown once its execution has completed (see https://stackoverflow.com/a/32316972/2358409).

    Instead of using your own sleep function, you better use setTimeout in order to schedule individual work portions. Below runnable code illustrates how this could work while the function insertSort was simplified and no longer does what it originally did.

    function insertSort(inputArray = myChart.data.datasets[0].data) {
        let inputArrayLength = inputArray.length;
        let outerIndex = 1;
        while(outerIndex<inputArrayLength) {
            setTimeout(() => {           
               myChart.data.datasets[0].data = Array.from({length: 10}, () => Math.floor(Math.random() * 10+1));
               console.log('Intermediate result is: ', myChart.data.datasets[0].data.join(', '));
               myChart.update();
            }, 1000 * outerIndex);
            outerIndex++;
        }
        console.log('Final result is: ', inputArray.join(', '));
        return true;
    }
    
    let ctx = document.getElementById('myChart').getContext('2d');
    let randomArray = Array.from({length: 10}, () => Math.floor(Math.random() * 10+1));
    let myChart = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange', 'Blue', 'Blue', 'Blue', 'Blue'],
            datasets: [{
                label: '# of Votes',
                data: randomArray,
                backgroundColor: [
                    'rgba(255, 99, 132, 0.2)',
                    'rgba(54, 162, 235, 0.2)',
                    'rgba(255, 206, 86, 0.2)',
                    'rgba(75, 192, 192, 0.2)',
                    'rgba(153, 102, 255, 0.2)',
                    'rgba(54, 162, 235, 0.2)',
                    'rgba(54, 162, 235, 0.2)',
                    'rgba(54, 162, 235, 0.2)',
                    'rgba(54, 162, 235, 0.2)',
                    'rgba(54, 162, 235, 0.2)'
                ],
                borderWidth: 1
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: true
                    }
                }]
            }
        }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js"></script>
    <button type="button" onclick="insertSort()">StartSorting</button>
    <canvas id="myChart" height="100">