Come cancellare un grafico da una tela in modo che gli eventi al passaggio del mouse non possano essere attivati?


109

Sto usando Chartjs per visualizzare un grafico a linee e funziona bene:

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

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

Ma il problema si verifica quando provo a modificare i dati per il grafico. Aggiorno il grafico creando una nuova istanza di un grafico con i nuovi punti dati e quindi reinizializzando la tela.

Funziona bene. Tuttavia, quando passo il mouse sul nuovo grafico, se mi capita di passare su posizioni specifiche corrispondenti ai punti visualizzati sul vecchio grafico, il passaggio del mouse / etichetta è ancora attivato e improvvisamente il vecchio grafico è visibile. Rimane visibile mentre il mio mouse si trova in questa posizione e scompare quando si sposta da quel punto. Non voglio che venga visualizzato il vecchio grafico. Voglio rimuoverlo completamente.

Ho provato a cancellare sia l'area di disegno che il grafico esistente prima di caricare quello nuovo. Piace:

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

e

chart.clear();

Ma nessuno di questi ha funzionato finora. Qualche idea su come posso impedire che ciò accada?


18
Amico, questo è esattamente il problema che sto avendo. Il metodo "destroy ()" non funziona e mi fa incazzare.
neaumusic

Posso chiederti come stai accedendo all'oggetto grafico? Ho lo stesso problema, creo un grafico e poi sulla gestione del clic di un pulsante devo distruggerlo, ma è in una funzione completamente diversa e non riesco a trovare un modo per accedere all'oggetto del grafico attraverso la tela o il contesto oggetti.
Matt Williams

È stato aperto un bug per questo problema, vederlo qui. github.com/jtblin/angular-chart.js/issues/187
MDT

Ho avuto questo problema. Soluzione per creare / ricreare stackoverflow.com/a/51882403/1181367
Chris

Risposte:


142

Ho avuto enormi problemi con questo

Prima ho provato, .clear()poi ho provato .destroy()e ho provato a impostare il mio riferimento grafico su null

Cosa ha finalmente risolto il problema per me: eliminare l' <canvas>elemento e quindi riapplicarne uno nuovo <canvas>al contenitore padre


Il mio codice specifico (ovviamente ci sono un milione di modi per farlo):

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
Ha lavorato come un campione. Se qualcuno sa se Chart.js versione 2 risolve questo problema, pubblicalo qui. Mi chiedo se la distruzione sia rotta o se la stiamo usando in modo errato.
TheLettuceMaster

2
Bello! Grazie! Ho appena aggiunto $ ('# risultato-grafico'). Remove (); $ ('# graph-container'). append ('<canvas id = "results-graph"> <canvas>'); prima della creazione del grafico.
Ignacio

.destroy () dovrebbe funzionare bene. In caso contrario, dopo aver chiamato .destroy () per disegnare un nuovo grafico, utilizzare setTimeout ()
Sumeet Kale

questa è l'unica soluzione che ha funzionato per me molte grazie, ma per la larghezza e l'altezza se le hai già impostate in modo corretto dovresti ripristinarle allo stesso valore nella funzione di ripristino
Sandy Elkassar

2
destroy () non è riuscito per me con chartjs 2.8.0 ma la tua soluzione ha funzionato! Nel mio caso l'ho usato solo $('#results-graph').remove(); $('#graph-container').append('<canvas id="results-graph"><canvas>');prima delnew Chart(document.getElementById("myCanvas")
mimi

40

Ho affrontato lo stesso problema poche ore fa.

Il metodo ".clear ()" in realtà cancella la tela, ma (evidentemente) lascia l'oggetto vivo e reattivo.

Leggendo attentamente la documentazione ufficiale , nella sezione "Utilizzo avanzato", ho notato il metodo ".destroy ()", descritto come segue:

"Usalo per distruggere tutte le istanze del grafico che vengono create. Ciò cancellerà tutti i riferimenti memorizzati all'oggetto del grafico all'interno di Chart.js, insieme a tutti i listener di eventi associati allegati da Chart.js."

In realtà fa quello che afferma e ha funzionato bene per me, ti suggerisco di provarlo.


Potresti mostrare un esempio? Ho provato a utilizzare il blocco più volte e non funziona mai. Ricevo sempre un errore che il metodo non esiste.
Ben Hoffman

3
(<ChartInstance> this.chart) .destroy ();
David Dal Busco

2
Questa è la risposta giusta. Per i riferimenti futuri, vedi: stackoverflow.com/questions/40056555/...
ThePhi

29
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});
}

1
questa è la migliore alternativa
RafaSashi

Bene. Grazie
Manjunath Siddappa

11

Questa è l'unica cosa che ha funzionato per me:

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

9

Ho avuto lo stesso problema qui ... Ho provato a usare il metodo destroy () e clear (), ma senza successo.

L'ho risolto nel modo successivo:

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);

Per me funziona perfettamente ... spero che aiuti.


5

Questo ha funzionato molto bene per me

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

Usa .destroy questo per distruggere tutte le istanze del grafico che vengono create. Ciò cancellerà tutti i riferimenti memorizzati all'oggetto del grafico all'interno di Chart.js, insieme a tutti i listener di eventi associati allegati da Chart.js. Questo deve essere chiamato prima che l'area di disegno venga riutilizzata per un nuovo grafico.


In questo modo funziona correttamente per me, sembra che distrugga i callback al passaggio del mouse. Carri armati così tanto !!
Antoine Pointeau

4

Possiamo aggiornare i dati del grafico in Chart.js V2.0 come segue:

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

Sono d'accordo con questa come una soluzione molto migliore - Destroy è selvaggiamente troppo radicale, quando tutto ciò che vogliamo veramente è riavviare semplicemente i "dati".
TS

1

Usando CanvasJS, questo funziona per me cancellare il grafico e tutto il resto, potrebbe funzionare anche per te, garantendoti di impostare completamente la tua tela / grafico prima di ogni elaborazione altrove:

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

per me nessuno dei metodi sopra ha funzionato. Ha funzionato perfettamente. Molte grazie.
principiante

1

Non sono riuscito a far funzionare neanche .destroy (), quindi questo è quello che sto facendo. Il div chart_parent è dove voglio che venga visualizzata la tela. Ho bisogno che la tela venga ridimensionata ogni volta, quindi questa risposta è un'estensione di quella precedente.

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>');


1

Questo ha funzionato per me. Aggiungi una chiamata a clearChart, nella parte superiore del tuo 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;
}`

1

Se stai usando chart.js in un progetto Angular con Typescript, puoi provare quanto segue;

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>

1

Quello che abbiamo fatto è, prima dell'inizializzazione del nuovo grafico, rimuovere / distruggere l'istanza del grafico delle anteprime, se esiste già, quindi creare un nuovo grafico, ad esempio

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

Spero che questo ti aiuti.


1

A complemento della risposta di Adamo

Con 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


1

Modifica semplice per il 2020:

Questo ha funzionato per me. Cambia il grafico in globale rendendolo di proprietà della finestra (Cambia la dichiarazione da var myCharta window myChart)

Controlla se la variabile del grafico è già inizializzata come Grafico, in tal caso, distruggila e creane uno nuovo, anche se puoi crearne un altro con lo stesso nome. Di seguito il codice:

if(window.myChart instanceof Chart)
{
    window.myChart.destroy();
}
var ctx = document.getElementById('myChart').getContext("2d");

Spero funzioni!


1
Grazie mille. Questo funziona per me.
Dante

0

Per me questo ha funzionato:

		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";


0

Chart.js ha un bug: Chart.controller(instance)registra qualsiasi nuovo grafico in una proprietà globale Chart.instances[]e lo elimina da questa proprietà .destroy().

Ma al momento della creazione del grafico Chart.js scrive anche la ._metaproprietà nella variabile del set di dati:

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
   };

e non elimina questa proprietà su destroy().

Se utilizzi il vecchio oggetto del set di dati senza rimuoverlo ._meta property, Chart.js aggiungerà il nuovo set di dati ._metasenza eliminare i dati precedenti. Pertanto, alla reinizializzazione di ogni grafico, l'oggetto del set di dati accumula tutti i dati precedenti.

Per evitare ciò, distruggere l'oggetto dataset dopo la chiamata Chart.destroy().


0

Dal momento che distruggere tipo di distrugge "tutto", una soluzione economica e semplice quando tutto quello che vuoi veramente è semplicemente "resettare i dati". Anche il ripristino dei set di dati su un array vuoto funzionerà perfettamente. Quindi, se hai un set di dati con etichette e un asse su ogni lato:

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

Dopo questo, puoi semplicemente chiamare:

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

oppure, a seconda che tu stia utilizzando un set di dati 2d:

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

Sarà molto più leggero che distruggere completamente l'intero grafico / set di dati e ricostruire tutto.


0

per chi come me usa una funzione per creare più grafici e vuole aggiornare anche loro un blocco, solo la funzione .destroy () ha funzionato per me, mi sarebbe piaciuto fare un .update (), che sembra più pulito ma .. ecco uno snippet di codice che potrebbe essere d'aiuto.

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 ...
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.