3

I show a chart with chart.js and when a user hovers over it a tooltip is displayed. This works fine.

However, I want to add option that users can un-check data-points. I did and this is done correct, but the tooltip-functionality remembers both the new and the old data. So if you hover over the chart it flickers between old and new.

When I make a custom tooltip and place a console.log of the data-oject I can see that it just loads several data-objects in.

Is there a way to make sure the old data is truly forgotten?

See the fiddle https://jsfiddle.net/CorneelDragon/s0udzwv3/27/ or see code below (It works at the start, but when you uncheck things the tooltip makes it erratic):

<script 
src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js'></script>`
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>`
<div id="slct2">"beh"</div>
<table id="table1"  border=1></table>
<!-- bar chart canvas element -->
<canvas id="myChart" width="200" height="50"></canvas>
<script type="text/javascript">
</script>

and the javascript:

test_labels = ["meh", "beh", "yeh"]
score = [4,3.8,5]
var s2 = document.getElementById("slct2");
s2.innerHTML = "";
for (var test in test_labels) {
    if (test_labels.hasOwnProperty(test)) {
        var pair = test_labels[test] + score[test];
        var checkbox = document.createElement("input");
        checkbox.type = "checkbox";
        checkbox.name = "test_filter";
        checkbox.value = pair;
        checkbox.checked = true;
        s2.appendChild(checkbox);
        var label = document.createElement('label');
        label.htmlFor = pair;
        label.appendChild(document.createTextNode(pair));
        s2.appendChild(label);
        s2.appendChild(document.createElement("br"));    
    }
}

function fillCanvas (test_labels, score) {
  var ctx = document.getElementById("myChart").getContext('2d');
  ctx.innerHTML = "";

  var myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels : ["test_month"]
      },
  });

  setTimeout(function () {

     for (test in test_labels){
        myChart.data.datasets.push({
          backgroundColor: 'rgb(228,26,28)',
          label: test_labels[test],
          data: [score[test]]
        });
      }

    myChart.update();

  }, 1000);

}
fillCanvas(test_labels, score);

var filter_magic = function(e) {

        test_selected = []
        var table1 = document.getElementById("table1");
        table1.innerHTML = "";
        jQuery('input[type="checkbox"][name="test_filter"]').each(function() {
            if (jQuery(this).is(':checked')) {
              var tr = document.createElement('tr');
              tr.innerHTML = this.value;
              table1.appendChild(tr);
              test_selected.push(this.value);
            }
          })
        fillCanvas(test_selected, score);
        }     
jQuery('input[type="checkbox"][name="test_filter"]').on('change', filter_magic);
filter_magic();  
CorneeldH
  • 593
  • 1
  • 8
  • 21

1 Answers1

5

This is not the right way to update a chart, in your code every time you are updating the chart you are creating a new instance of the chart as well without destroying the previous instance and that is why you can see the old value on hover.

One solution would be if you want to create a new chart every time then store your chart in a global variable and whenever checkbox is toggled then check if the chart is stored in the variable, destroy it then create a new one.

See the below code or fiddle -> https://jsfiddle.net/s0udzwv3/31/

test_labels = ["meh", "beh", "yeh"]
score = [4,3.8,5]
var s2 = document.getElementById("slct2");
s2.innerHTML = "";
for (var test in test_labels) {
    if (test_labels.hasOwnProperty(test)) {
        var pair = test_labels[test] + score[test];
        var checkbox = document.createElement("input");
        checkbox.type = "checkbox";
        checkbox.name = "test_filter";
        checkbox.value = pair;
        checkbox.checked = true;
        s2.appendChild(checkbox);
        var label = document.createElement('label');
        label.htmlFor = pair;
        label.appendChild(document.createTextNode(pair));
        s2.appendChild(label);
        s2.appendChild(document.createElement("br"));    
    }
}
var myChart;

function fillCanvas (test_labels, score) {  
  var ctx = document.getElementById("myChart").getContext('2d');
  ctx.innerHTML = "";

  if(myChart)
  {
    myChart.destroy();
  }

  myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels : ["test_month"]
      },
  });

  setTimeout(function () {
     for (test in test_labels){
        myChart.data.datasets.push({
          backgroundColor: 'rgb(228,26,28)',
          label: test_labels[test],
          data: [score[test]]
        });
      }

    myChart.update();

  }, 1000);
}

fillCanvas(test_labels, score);

var filter_magic = function(e) {

        test_selected = []
        var table1 = document.getElementById("table1");
        table1.innerHTML = "";
        jQuery('input[type="checkbox"][name="test_filter"]').each(function() {
            if (jQuery(this).is(':checked')) {
              var tr = document.createElement('tr');
              tr.innerHTML = this.value;
              table1.appendChild(tr);
              test_selected.push(this.value);
            }
          })
        fillCanvas(test_selected, score);
        }     
jQuery('input[type="checkbox"][name="test_filter"]').on('change', filter_magic);
filter_magic();  

And the another recommended way would load the chart only once with the new Chart and every time for the checkbox toggle just push new datasets and call the chart.update() method stored in a global variable.

Kunal Khivensara
  • 1,619
  • 14
  • 21
  • Thanks, funny additional thing it the code is that at the start fillCanvas is called twice (also in filter_magic). The result that in your fiddle the data gets pushed twice ;-) Anyway, definitely more optimization needed in the code, thanks for the pointers! – CorneeldH Nov 19 '18 at 19:47
  • Works perfectly. Thanks – Rohit Singh Apr 18 '20 at 03:16