Como limpar um gráfico de uma tela para que os eventos de foco não possam ser acionados?


109

Estou usando Chartjs para exibir um gráfico de linha e isso funciona bem:

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

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

Mas o problema ocorre quando tento alterar os dados do Chart. Eu atualizo o gráfico criando uma nova instância de um Gráfico com os novos pontos de dados e, assim, reinicializando a tela.

Isso funciona bem. No entanto, quando passo o mouse sobre o novo gráfico, se acontecer de eu passar por locais específicos correspondentes a pontos exibidos no gráfico antigo, o foco / rótulo ainda é acionado e de repente o gráfico antigo fica visível. Ele permanece visível enquanto meu mouse está neste local e desaparece quando me movo para fora desse ponto. Não quero que o gráfico antigo seja exibido. Eu quero removê-lo completamente.

Tentei limpar a tela e o gráfico existente antes de carregar o novo. Gostar:

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

e

chart.clear();

Mas nada disso funcionou até agora. Alguma ideia de como posso impedir que isso aconteça?


18
Cara, esse é exatamente o problema que estou tendo. O método "destroy ()" não funciona e está me irritando.
neaumusic

Posso perguntar como você está obtendo acesso ao objeto gráfico? Estou tendo o mesmo problema, crio um gráfico e, ao lidar com um clique de botão, preciso destruí-lo, mas está em uma função totalmente diferente e não consigo encontrar uma maneira de acessar o objeto de gráfico através da tela ou contexto objetos.
Matt Williams

Há um bug aberto para este problema, veja-o aqui. github.com/jtblin/angular-chart.js/issues/187
MDT de

Tive esse problema. Solução para criar / recriar stackoverflow.com/a/51882403/1181367
Chris

Respostas:


142

Eu tive grandes problemas com isso

Primeiro tentei .clear()depois tentei.destroy() e tentei definir minha referência de gráfico como nula

O que finalmente resolveu o problema para mim: excluir o <canvas>elemento e, em seguida, reaplicar um novo <canvas>ao contêiner pai


Meu código específico (obviamente, há um milhão de maneiras de fazer isso):

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
Trabalhou como um campeão. Se alguém souber se o Chart.js versão 2 corrige isso, poste aqui. Eu me pergunto se o destroy está quebrado ou se o estamos usando incorretamente.
TheLettuceMaster de

2
Agradável! Obrigado! Acabei de adicionar $ ('# gráfico de resultados'). Remove (); $ ('# graph-container'). append ('<canvas id = "results-graph"> <canvas>'); antes da criação do gráfico.
Ignacio

.destroy () deve funcionar bem. Se não, depois de chamar .destroy () para desenhar um novo gráfico, use setTimeout ()
Sumeet Kale

essa é a única solução que funcionou para mim, muito obrigado, mas para a largura e altura se você já os definiu fixos, você deve redefini-los para o mesmo valor na função de redefinição
Sandy Elkassar

2
destroy () falhou para mim com chartjs 2.8.0, mas sua solução funcionou! No meu caso, usei apenas $('#results-graph').remove(); $('#graph-container').append('<canvas id="results-graph"><canvas>');antes donew Chart(document.getElementById("myCanvas")
mimi

40

Eu enfrentei o mesmo problema algumas horas atrás.

O método ".clear ()" realmente limpa a tela, mas (evidentemente) deixa o objeto vivo e reativo.

Lendo com atenção a documentação oficial , na seção "Uso avançado", percebi o método ".destroy ()", descrito a seguir:

"Use isso para destruir quaisquer instâncias de gráfico que sejam criadas. Isso limpará todas as referências armazenadas ao objeto de gráfico em Chart.js, junto com quaisquer ouvintes de eventos associados anexados por Chart.js."

Ele realmente faz o que afirma e tem funcionado bem para mim, sugiro que você experimente.


Você poderia dar um exemplo? Tentei usar o bloqueio várias vezes e nunca funciona. Sempre recebo um erro informando que o método não existe.
Ben Hoffman

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

2
Este é o anszwer certo. Para referências futuras, consulte: 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
esta é a melhor alternativa
RafaSashi

Um bom. Obrigado
Manjunath Siddappa

11

Esta é a única coisa que funcionou para mim:

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

9

Eu tive o mesmo problema aqui ... Tentei usar os métodos destroy () e clear (), mas sem sucesso.

Eu resolvi isso da próxima maneira:

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

Funciona perfeitamente para mim ... Espero que ajude.


5

Isso funcionou muito bem para mim

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

Use .destroy para destruir todas as instâncias de gráfico criadas. Isso limpará todas as referências armazenadas no objeto gráfico em Chart.js, junto com quaisquer ouvintes de eventos associados anexados por Chart.js. Deve ser chamado antes que a tela seja reutilizada para um novo gráfico.


Dessa forma, funciona corretamente para mim, parece que destrói os callbacks do hover. Tanques soo much !!
Antoine Pointeau

4

Podemos atualizar os dados do gráfico no Chart.js V2.0 da seguinte maneira:

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

Eu concordo com isso como sendo uma solução muito melhor - Destroy é radical demais, quando tudo o que realmente queremos é apenas reiniciar os "dados".
TS

1

Usando o CanvasJS, isso funciona para mim, limpar o gráfico e tudo o mais pode funcionar para você também, garantindo que você configure sua tela / gráfico totalmente antes de cada processamento em outro lugar:

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

para mim nenhum dos métodos acima funcionou. Funcionou perfeitamente. Muito obrigado.
iniciante em

1

Eu também não consegui fazer .destroy () funcionar, então é isso que estou fazendo. O div chart_parent é onde eu quero que a tela apareça. Preciso que a tela seja redimensionada a cada vez, portanto, esta resposta é uma extensão da anterior.

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

Isso funcionou para mim. Adicione uma chamada para clearChart, no topo de seu 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 você estiver usando chart.js em um projeto Angular com Typescript, você pode tentar o seguinte;

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

O que fizemos é, antes da inicialização do novo gráfico, remover / destruir a instância do gráfico de visualizações, se já existir, em seguida, criar um novo gráfico, por exemplo

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

Espero que isto ajude.


1

Complementando a resposta de Adam

Com 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

Edição simples para 2020:

Isso funcionou para mim. Altere o gráfico para global tornando-o proprietário da janela (alterar a declaração de var myChartpara window myChart)

Verifique se a variável do gráfico já está inicializada como Gráfico, em caso afirmativo, destrua-a e crie uma nova, mesmo que você possa criar outra com o mesmo nome. Abaixo está o código:

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

Espero que funcione!


1
Muito obrigado. Isso funciona para mim.
Dante

0

Para mim, funcionou:

		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 tem um bug: Chart.controller(instance)registra qualquer novo gráfico em uma propriedade global Chart.instances[]e o exclui desta propriedade em.destroy() .

Mas, na criação do gráfico, Chart.js também escreve ._meta propriedade na variável do conjunto de dados:

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 não exclui esta propriedade em destroy() .

Se você usar seu objeto de conjunto de dados antigo sem remover ._meta property , Chart.js adicionará novo conjunto de dados a._meta sem excluir os dados anteriores. Portanto, na reinicialização de cada gráfico, o objeto do conjunto de dados acumula todos os dados anteriores.

Para evitar isso, destrua o objeto do conjunto de dados após a chamada Chart.destroy().


0

Já que destruir meio que destrói "tudo", uma solução simples e barata quando tudo o que você realmente quer é apenas "redefinir os dados". Redefinir seus conjuntos de dados para um array vazio funcionará perfeitamente bem também. Portanto, se você tiver um conjunto de dados com rótulos e um eixo em cada lado:

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

Depois disso, você pode simplesmente ligar para:

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

ou, dependendo se você está usando um conjunto de dados 2D:

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

Será muito mais leve do que destruir completamente seu gráfico / conjunto de dados e reconstruir tudo.


0

para quem gosta de mim usa uma função para criar vários gráficos e quer atualizá-los um bloco também, só a função .destroy () funcionou para mim, gostaria de fazer um .update (), que parece mais limpo, mas .. . aqui está um trecho de código que pode ajudar.

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 ...
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.