How to clear a chart from a canvas so that hover e

2020-01-25 13:14发布

问题:

I'm using Chartjs to display a Line Chart and this works fine:

// get line chart canvas
var targetCanvas = document.getElementById('chartCanvas').getContext('2d');

// draw line chart
var chart = new Chart(targetCanvas).Line(chartData);

But the problem occurs when I try to change the data for the Chart. I update the graph by creating a new instance of a Chart with the new data points, and thus reinitializing the canvas.

This works fine. However, when I hover over the new chart, if I happen to go over specific locations corresponding to points displayed on the old chart, the hover/label is still triggered and suddenly the old chart is visible. It remains visible while my mouse is at this location and disappears when move off that point. I don't want the old chart to display. I want to remove it completely.

I've tried to clear both the canvas and the existing chart before loading the new one. Like:

targetCanvas.clearRect(0,0, targetCanvas.canvas.width, targetCanvas.canvas.height);

and

chart.clear();

But none of these have worked so far. Any ideas about how I can stop this from happening?

回答1:

I had huge problems with this

First I tried .clear() then I tried .destroy() and I tried setting my chart reference to null

What finally fixed the issue for me: deleting the <canvas> element and then reappending a new <canvas> to the parent container


My specific code (obviously there's a million ways to do this):

var resetCanvas = function(){
  $('#results-graph').remove(); // this is my <canvas> element
  $('#graph-container').append('<canvas id="results-graph"><canvas>');
  canvas = document.querySelector('#results-graph');
  ctx = canvas.getContext('2d');
  ctx.canvas.width = $('#graph').width(); // resize to parent width
  ctx.canvas.height = $('#graph').height(); // resize to parent height
  var x = canvas.width/2;
  var y = canvas.height/2;
  ctx.font = '10pt Verdana';
  ctx.textAlign = 'center';
  ctx.fillText('This text is centered on the canvas', x, y);
};


回答2:

I have faced the same problem few hours ago.

The ".clear()" method actually clears the canvas, but (evidently) it leaves the object alive and reactive.

Reading carefully the official documentation, in the "Advanced usage" section, I have noticed the method ".destroy()", described as follows:

"Use this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js."

It actually does what it claims and it has worked fine for me, I suggest you to give it a try.



回答3:

var myPieChart=null;

function drawChart(objChart,data){
    if(myPieChart!=null){
        myPieChart.destroy();
    }
    // Get the context of the canvas element we want to select
    var ctx = objChart.getContext("2d");
    myPieChart = new Chart(ctx).Pie(data, {animateScale: true});
}


回答4:

This is the only thing that worked for me:

document.getElementById("chartContainer").innerHTML = '&nbsp;';
document.getElementById("chartContainer").innerHTML = '<canvas id="myCanvas"></canvas>';
var ctx = document.getElementById("myCanvas").getContext("2d");


回答5:

I had the same problem here... I tried to use destroy() and clear() method, but without success.

I resolved it the next way:

HTML:

<div id="pieChartContent">
    <canvas id="pieChart" width="300" height="300"></canvas>
</div>

Javascript:

var pieChartContent = document.getElementById('pieChartContent');
pieChartContent.innerHTML = '&nbsp;';
$('#pieChartContent').append('<canvas id="pieChart" width="300" height="300"><canvas>');

ctx = $("#pieChart").get(0).getContext("2d");        
var myPieChart = new Chart(ctx).Pie(data, options);

It works perfect to me... I hope that It helps.



回答6:

This worked very well for me

    var ctx = $("#mycanvas");
     var LineGraph = new Chart(ctx, {
        type: 'line',
        data: chartdata});
        LineGraph.destroy();

Use .destroy this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js. This must be called before the canvas is reused for a new chart.



回答7:

We can update the chart data in Chart.js V2.0 as follows:

var myChart = new Chart(ctx, data);
myChart.config.data = new_data;
myChart.update();


回答8:

Using CanvasJS, this works for me clearing chart and everything else, might work for you as well, granting you set your canvas/chart up fully before each processing elsewhere:

var myDiv= document.getElementById("my_chart_container{0}";
myDiv.innerHTML = "";


回答9:

I couldn't get .destroy() to work either so this is what I'm doing. The chart_parent div is where I want the canvas to show up. I need the canvas to resize each time, so this answer is an extension of the above one.

HTML:

<div class="main_section" > <div id="chart_parent"></div> <div id="legend"></div> </div>

JQuery:

  $('#chart').remove(); // this is my <canvas> element
  $('#chart_parent').append('<label for = "chart">Total<br /><canvas class="chart" id="chart" width='+$('#chart_parent').width()+'><canvas></label>');


回答10:

When you create one new chart.js canvas, this generate one new iframe hidden, you need delete the canvas and the olds iframes.

$('#canvasChart').remove(); 
$('iframe.chartjs-hidden-iframe').remove(); 
$('#graph-container').append('<canvas id="canvasChart"><canvas>'); 
var ctx = document.getElementById("canvasChart"); 
var myChart = new Chart(ctx, { blablabla });

reference: https://github.com/zebus3d/javascript/blob/master/chartJS_filtering_with_checkboxs.html



回答11:

This worked for me. Add a call to clearChart, at the top oF your updateChart()

`function clearChart() {
    event.preventDefault();
    var parent = document.getElementById('parent-canvas');
    var child = document.getElementById('myChart');          
    parent.removeChild(child);            
    parent.innerHTML ='<canvas id="myChart" width="350" height="99" ></canvas>';             
    return;
}`


回答12:

If you are using chart.js in an Angular project with Typescript, the you can try the following;

Import the library:
    import { Chart } from 'chart.js';

In your Component Class declare the variable and define a method:

  chart: Chart;

  drawGraph(): void {
    if (this.chart) {
      this.chart.destroy();
    }

    this.chart = new Chart('myChart', {
       .........
    });
  }


In HTML Template:
<canvas id="myChart"></canvas>


回答13:

For me this worked:

		var in_canvas = document.getElementById('chart_holder');
	//remove canvas if present
			while (in_canvas.hasChildNodes()) {
				  in_canvas.removeChild(in_canvas.lastChild);
				} 
	//insert canvas
			var newDiv = document.createElement('canvas');
			in_canvas.appendChild(newDiv);
			newDiv.id = "myChart";



回答14:

Chart.js has a bug: Chart.controller(instance) registers any new chart in a global property Chart.instances[] and deletes it from this property on .destroy().

But at chart creation Chart.js also writes ._meta property to dataset variable:

var meta = dataset._meta[me.id];
if (!meta) {
   meta = dataset._meta[me.id] = {
       type: null,
       data: [],
       dataset: null,
       controller: null,
       hidden: null,     // See isDatasetVisible() comment
       xAxisID: null,
       yAxisID: null
   };

and it doesn't delete this property on destroy().

If you use your old dataset object without removing ._meta property, Chart.js will add new dataset to ._meta without deletion previous data. Thus, at each chart's re-initialization your dataset object accumulates all previous data.

In order to avoid this, destroy dataset object after calling Chart.destroy().



回答15:

Since destroy kind of destroys "everything", a cheap and simple solution when all you really want is to just "reset the data". Resetting your datasets to an empty array will work perfectly fine as well. So, if you have a dataset with labels, and an axis on each side:

window.myLine2.data.labels = [];
window.myLine2.data.datasets[0].data = [];
window.myLine2.data.datasets[1].data = [];

After this, you can simply call:

window.myLine2.data.labels.push(x);
window.myLine2.data.datasets[0].data.push(y);

or, depending whether you're using a 2d dataset:

window.myLine2.data.datasets[0].data.push({ x: x, y: y});

It'll be a lot more lightweight than completely destroying your whole chart/dataset, and rebuilding everything.



回答16:

What we did is, before initialization of new chart, remove/destroy the previews Chart instance, if exist already, then create a new chart, for example

if(myGraf != undefined)
    myGraf.destroy();
    myGraf= new Chart(document.getElementById("CanvasID"),
    { 
      ...
    }

Hope this helps.



回答17:

for those who like me use a function to create several graphics and want to update them a block too, only the function .destroy() worked for me, I would have liked to make an .update(), which seems cleaner but ... here is a code snippet that may help.

var SNS_Chart = {};

// IF LABELS IS EMPTY (after update my datas)
if( labels.length != 0 ){

      if( Object.entries(SNS_Chart).length != 0 ){

            array_items_datas.forEach(function(for_item, k_arr){
                SNS_Chart[''+for_item+''].destroy();
            });

       }

       // LOOP OVER ARRAY_ITEMS
       array_items_datas.forEach(function(for_item, k_arr){

             // chart
             OPTIONS.title.text = array_str[k_arr];
             var elem = document.getElementById(for_item);
             SNS_Chart[''+for_item+''] = new Chart(elem, {
                 type: 'doughnut',
                 data: {
                     labels: labels[''+for_item+''],
                     datasets: [{
                        // label: '',
                        backgroundColor: [
                            '#5b9aa0',
                            '#c6bcb6',
                            '#eeac99',
                            '#a79e84',
                            '#dbceb0',
                            '#8ca3a3',
                            '#82b74b',
                            '#454140',
                            '#c1502e',
                            '#bd5734'
                        ],
                        borderColor: '#757575',
                        borderWidth : 2,
                        // hoverBackgroundColor : '#616161',
                        data: datas[''+for_item+''],
                     }]
                 },
                 options: OPTIONS

             });
             // chart
       });
       // END LOOP ARRAY_ITEMS

  }
 // END IF LABELS IS EMPTY ...


回答18:

Complementing Adam's Answer

With Vanilla JS:

document.getElementById("results-graph").remove(); //canvas
div = document.querySelector("#graph-container"); //canvas parent element
div.insertAdjacentHTML("afterbegin", "<canvas id='results-graph'></canvas>"); //adding the canvas again