0

So my problem is that when I'm cyclically updating canvas element in my HTML with line chart created by Chart.js library I'm getting bunch of detached HTMLCanvasElements. I noticed this when I was fixing some memory leaks in my code which earlier lead my webpage to crash(chrome gave "aw snap" error page). I was able to fix most of the memory leaks but this one is still bothering me and I am helpless because of not knowing why this is happening..

I have canvas elements in my HTML code like this:

<div class="kuvaaja"><canvas id="etaisyyskuvaaja"></canvas></div>
<div class="kuvaaja"><canvas id="etaisyyskuvaaja2"></canvas></div>
<div class="kuvaaja"><canvas id="etaisyyskuvaaja3"></canvas></div>
<div class="kuvaaja"><canvas id="etaisyyskuvaaja4"></canvas></div>

And this is how I fetch those elements in my JavaScript (in window.onload function):

pohjacanvas = document.getElementById("etaisyyskuvaaja");
pohjacanvas2 = document.getElementById("etaisyyskuvaaja2");
pohjacanvas3 = document.getElementById("etaisyyskuvaaja3");
pohjacanvas4 = document.getElementById("etaisyyskuvaaja4");

Then I start cyclic updating of those canvases with(also inside window.onload):

paivitysvali = setInterval(haeetaisyysmittaukset, 1000);
painepaivitys = setInterval(haepainemittaukset, 1000);

And in these functions I first fetch data from database like this (haepainemittaukset() is similar to this one just different data is fetched):

function haeetaisyysmittaukset() {
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            etaisyys = [];
            ajat = [];
            var mittaukset = JSON.parse(xmlhttp.response);
            for (var i = 0; i < mittaukset.length; i++) {
                etaisyys.push(mittaukset[i]["etaisyys"]);
                ajat.push(mittaukset[i]["timestamp"]);
            }
            if (paivitysbitti == 1) {
                etaisyys.reverse();
                ajat.reverse();
                luokuvaaja2(pohjacanvas, etaisyys, ajat);
                luokuvaaja2(pohjacanvas4, etaisyys, ajat);
            }

        }
    }
    xmlhttp.open("POST", "haeetaisyysmittaukset.php", true);
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xmlhttp.send("limit=" + mittausmaara);
}

After data is fetched in global arrays (etaisyys[] and ajat[]) I call luokuvaaja2() function with the canvas I want to update and these data arrays. And this is the phase where problem starts at least I think so.. Here is how I am trying to implement this update of canvas:

function luokuvaaja2(pohja, data, ajat) {
    pohja.height = 400;
    pohja.width = 700;
    myChart = new Chart(pohja, {
        type: 'line',
        data: {
            labels: ajat,
            datasets: [{
                data: data,
                label: "Etaisyys",
                borderColor: "blue",
                fill: false
            }
            ]
        },
        options: {
            animation: {
                duration: 0, // general animation time
            },
            hover: {
                animationDuration: 0, // duration of animations when hovering an item
            },
            title: {
                display: true,
                text: 'Etaisyysmittaus'
            },
            scales: {
                yAxes: [{
                    ticks: {
                        min: 0,
                        max: 6000
                    }
                }]
            }
        }
    });

}

So what I think that I'm doing here is setting canvas height and width, after that I create new chart in the same canvas where old one was(or am I?). However it looks like that there is something wrong and my current code is creating bunch of detached canvas elements but I can't understand why and where this is exactly happening? So now memory footprint of my page is slowly increasing after every cycle (canvas update).

Here is also snapshot of memory distribution: memory distribution In this memory distribution there are many detached canvas elements all pointing to those canvases(pohjacanvas, pohjacanvas2, pohjacanvas3, pohjacanvas4).

Tvak
  • 13
  • 7

1 Answers1

0

You should keep track (in an array, for example) of your charts previously created, then when the new data is fetched from the server, you need to retrieve the chart to update, update its data and/or options, and then call

chart.update();

to refresh the chart. In this case you won't create new charts at each update. You may find more details in the Chart.js docs.

Alberto
  • 674
  • 13
  • 25
  • Awesome thanks! With chart.update() I was able to update my old charts and get rid of pile of old charts. In Chart.js docs there were examples where data were push and pulled but it's also possible to change data in datasets directly like shown in this [thread](https://stackoverflow.com/questions/17354163/dynamically-update-values-of-a-chartjs-chart) – Tvak Jul 05 '18 at 13:03