¿Cómo borrar un gráfico de un lienzo para que los eventos de desplazamiento no se puedan activar?


109

Estoy usando Chartjs para mostrar un gráfico de líneas y esto funciona bien:

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

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

Pero el problema ocurre cuando trato de cambiar los datos del gráfico. Actualizo el gráfico creando una nueva instancia de un gráfico con los nuevos puntos de datos y, por lo tanto, reinicializo el lienzo.

Esto funciona bien. Sin embargo, cuando coloco el cursor sobre el nuevo gráfico, si paso por encima de ubicaciones específicas correspondientes a los puntos que se muestran en el gráfico anterior, el cursor / etiqueta todavía se activa y, de repente, el gráfico anterior es visible. Permanece visible mientras mi mouse está en esta ubicación y desaparece cuando me muevo de ese punto. No quiero que se muestre el gráfico antiguo. Quiero eliminarlo por completo.

Intenté borrar tanto el lienzo como el gráfico existente antes de cargar el nuevo. Me gusta:

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

y

chart.clear();

Pero ninguno de estos ha funcionado hasta ahora. ¿Alguna idea sobre cómo puedo evitar que esto suceda?


18
Amigo, este es exactamente el problema que tengo. El método "destroy ()" no funciona y me está cabreando.
neaumusic

¿Puedo preguntar cómo está obteniendo acceso al objeto gráfico? Tengo el mismo problema, creo un gráfico y luego, al manejar un botón, necesito destruirlo, pero tiene una función completamente diferente y no puedo encontrar una manera de acceder al objeto del gráfico a través del lienzo o el contexto. objetos.
Matt Williams

Hay un error abierto para este problema, véalo aquí. github.com/jtblin/angular-chart.js/issues/187
MDT

Tuve este problema. Solución para crear / recrear stackoverflow.com/a/51882403/1181367
Chris

Respuestas:


142

Tuve grandes problemas con esto

Primero lo intenté, .clear()luego lo intenté .destroy()e intenté establecer la referencia de mi gráfico en nulo

Lo que finalmente solucionó el problema para mí: eliminar el <canvas>elemento y luego volver a agregar uno nuevo <canvas>al contenedor principal


Mi código específico (obviamente hay un millón de formas de hacer esto):

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
Trabajó como un campeón. Si alguien sabe si Chart.js versión 2 soluciona esto, publíquelo aquí. Me pregunto si destruir está roto o si lo estamos usando incorrectamente.
TheLettuceMaster

2
¡Agradable! ¡Gracias! Acabo de agregar $ ('# results-graph'). Remove (); $ ('# graph-container'). append ('<canvas id = "results-graph"> <canvas>'); antes de la creación del gráfico.
Ignacio

.destroy () debería funcionar bien. Si no es así, después de llamar a .destroy () para dibujar un nuevo gráfico, use setTimeout ()
Sumeet Kale

Esa es la única solución que funcionó para mí, muchas gracias, pero para el ancho y la altura, si ya los fijaste, debes restablecerlos al mismo valor en la función de reinicio
Sandy Elkassar

2
destruir () me falló con chartjs 2.8.0 pero su solución simplemente funcionó! En mi caso, solo usé $('#results-graph').remove(); $('#graph-container').append('<canvas id="results-graph"><canvas>');antes delnew Chart(document.getElementById("myCanvas")
mimi

40

Me he enfrentado al mismo problema hace unas horas.

El método ".clear ()" en realidad borra el lienzo, pero (evidentemente) deja el objeto vivo y reactivo.

Leyendo detenidamente la documentación oficial , en la sección "Uso avanzado", he notado el método ".destroy ()", descrito a continuación:

"Use esto para destruir cualquier instancia de gráfico que se cree. Esto limpiará cualquier referencia almacenada al objeto de gráfico dentro de Chart.js, junto con cualquier detector de eventos asociado adjunto por Chart.js".

De hecho, hace lo que dice y me ha funcionado bien, te sugiero que lo pruebes.


¿Podría mostrarnos un ejemplo? He intentado usar el bloqueo varias veces y nunca funciona. Siempre recibo un error de que el método no existe.
Ben Hoffman

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

2
Esta es la respuesta correcta. Para futuras referencias, 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 es la mejor alternativa
RafaSashi

Buena. Gracias
Manjunath Siddappa

11

Esto es lo único que funcionó para mí:

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

9

Tuve el mismo problema aquí ... Traté de usar el método destroy () y clear (), pero sin éxito.

Lo resolví de la siguiente manera:

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 perfecto para mí ... Espero que ayude.


5

Esto funcionó muy bien para mi

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

Use .destroy this para destruir cualquier instancia de gráfico que se cree. Esto limpiará cualquier referencia almacenada al objeto de gráfico dentro de Chart.js, junto con cualquier detector de eventos asociado adjunto por Chart.js. Esto se debe llamar antes de que el lienzo se reutilice para un nuevo gráfico.


De esta manera funciona correctamente para mí, parece que destruye las devoluciones de llamada flotantes. ¡¡Tanques tanto !!
Antoine Pointeau

4

Podemos actualizar los datos del gráfico en Chart.js V2.0 de la siguiente manera:

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

Estoy de acuerdo con esto como una solución mucho mejor: Destroy es demasiado radical, cuando todo lo que realmente queremos es simplemente reiniciar los "datos".
TS

1

Al usar CanvasJS, esto me funciona al borrar el gráfico y todo lo demás, también podría funcionar para usted, ya que le permite configurar su lienzo / gráfico completamente antes de cada procesamiento en otro lugar:

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

para mí ninguno de los métodos anteriores funcionó. Esto funcionó perfectamente. Muchas gracias.
principiante

1

Tampoco pude hacer que .destroy () funcione, así que esto es lo que estoy haciendo. El div chart_parent es donde quiero que aparezca el lienzo. Necesito que el lienzo cambie de tamaño cada vez, por lo que esta respuesta es una extensión de la 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

Esto funcionó para mí. Agregue una llamada a clearChart, en la parte superior de su 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

Si está utilizando chart.js en un proyecto Angular con Typescript, puede probar lo siguiente;

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

Lo que hicimos fue, antes de la inicialización de un nuevo gráfico, eliminar / destruir las vistas previas de la instancia del Gráfico, si ya existe, luego crear un nuevo gráfico, por ejemplo

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

Espero que esto ayude.


1

Complementando la respuesta de Adam

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

Edición simple para 2020:

Esto funcionó para mí. Cambie el gráfico a global haciéndolo propiedad de la ventana (cambie la declaración de var myCharta window myChart)

Compruebe si la variable del gráfico ya está inicializada como Gráfico, de ser así, destrúyala y cree una nueva, incluso puede crear otra con el mismo nombre. A continuación se muestra el código:

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

¡Espero que funcione!


1
Muchas gracias. Esto funciona para mi.
Dante

0

Para mí esto funcionó:

		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 tiene un error: Chart.controller(instance)registra cualquier gráfico nuevo en una propiedad global Chart.instances[]y lo elimina de esta propiedad en .destroy().

Pero en la creación del gráfico, Chart.js también escribe la ._metapropiedad en la variable del conjunto de datos:

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

y no elimina esta propiedad en destroy().

Si usa su antiguo objeto de conjunto de datos sin eliminarlo ._meta property, Chart.js agregará un nuevo conjunto de datos ._metasin eliminar los datos anteriores. Por lo tanto, en la reinicialización de cada gráfico, su objeto de conjunto de datos acumula todos los datos anteriores.

Para evitar esto, destruya el objeto del conjunto de datos después de llamar Chart.destroy().


0

Dado que destruir destruye "todo", una solución barata y simple cuando todo lo que realmente quieres es simplemente "restablecer los datos". Restablecer sus conjuntos de datos a una matriz vacía también funcionará perfectamente. Entonces, si tiene un conjunto de datos con etiquetas y un eje en cada lado:

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

Después de esto, simplemente puede llamar:

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

o, dependiendo de si está utilizando un conjunto de datos 2d:

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

Será mucho más liviano que destruir completamente todo su gráfico / conjunto de datos y reconstruir todo.


0

para aquellos que como yo usan una función para crear varios gráficos y quieren actualizarlos también en un bloque, solo la función .destroy () funcionó para mí, me hubiera gustado hacer un .update (), que parece más limpio pero .. .Aquí hay un fragmento de código que puede ayudar.

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 ...
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.