Comment effacer un graphique d'un canevas afin que les événements de survol ne puissent pas être déclenchés?


109

J'utilise Chartjs pour afficher un graphique en courbes et cela fonctionne bien:

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

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

Mais le problème se produit lorsque j'essaie de modifier les données du graphique. Je mets à jour le graphique en créant une nouvelle instance d'un graphique avec les nouveaux points de données, et en réinitialisant ainsi le canevas.

Cela fonctionne très bien. Cependant, lorsque je survole le nouveau graphique, s'il m'arrive de passer par des emplacements spécifiques correspondant aux points affichés sur l'ancien graphique, le survol / l'étiquette est toujours déclenché et soudainement l'ancien graphique est visible. Il reste visible tant que ma souris est à cet endroit et disparaît lorsque je quitte ce point. Je ne veux pas que l'ancien graphique s'affiche. Je veux le supprimer complètement.

J'ai essayé d'effacer à la fois le canevas et le graphique existant avant de charger le nouveau. Comme:

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

et

chart.clear();

Mais aucun de ceux-ci n'a fonctionné jusqu'à présent. Des idées sur la façon dont je peux empêcher cela de se produire?


18
Mec, c'est exactement le problème que j'ai. La méthode "destroy ()" ne fonctionne pas et ça me fait chier.
neaumusic

Puis-je vous demander comment vous accédez à l'objet graphique? J'ai le même problème, je crée un graphique, puis sur la manipulation d'un bouton, cliquez sur je dois le détruire, mais c'est dans une fonction entièrement différente et je ne trouve pas de moyen d'accéder à l'objet graphique via le canevas ou le contexte objets.
Matt Williams

Il y a un bug ouvert pour ce problème, voyez-le ici. github.com/jtblin/angular-chart.js/issues/187
MDT

Eu ce problème. Solution pour créer / recréer stackoverflow.com/a/51882403/1181367
Chris

Réponses:


143

J'ai eu d'énormes problèmes avec ça

J'ai d'abord essayé, .clear()puis j'ai essayé .destroy()et j'ai essayé de définir ma référence de graphique sur null

Ce qui a finalement résolu le problème pour moi: supprimer l' <canvas>élément, puis en réappliquer un nouveau <canvas>au conteneur parent


Mon code spécifique (il y a évidemment un million de façons de le faire):

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
A travaillé comme un champion. Si quelqu'un sait si la version 2 de Chart.js résout ce problème, postez-le ici. Je me demande si destroy est cassé ou si nous ne l'utilisons pas correctement.
TheLettuceMaster

2
Agréable! Merci! Je viens d'ajouter $ ('# results-graph'). Remove (); $ ('# graph-container'). append ('<canvas id = "results-graph"> <canvas>'); avant la création du graphique.
Ignacio

.destroy () devrait fonctionner correctement. Si ce n'est pas le cas, après avoir appelé .destroy () pour dessiner un nouveau graphique, utilisez setTimeout ()
Sumeet Kale

c'est la seule solution qui a fonctionné pour moi, merci beaucoup, mais pour la largeur et la hauteur si vous les avez déjà réglées, vous devez les réinitialiser à la même valeur dans la fonction de réinitialisation
Sandy Elkassar

2
destroy () a échoué pour moi avec chartjs 2.8.0 mais votre solution a fonctionné! Dans mon cas, je n'ai utilisé $('#results-graph').remove(); $('#graph-container').append('<canvas id="results-graph"><canvas>');qu'avant lenew Chart(document.getElementById("myCanvas")
mimi

40

J'ai été confronté au même problème il y a quelques heures.

La méthode ".clear ()" efface réellement la toile, mais (évidemment) elle laisse l'objet vivant et réactif.

En lisant attentivement la documentation officielle , dans la section "Utilisation avancée", j'ai remarqué la méthode ".destroy ()", décrite comme suit:

"Utilisez ceci pour détruire toutes les instances de graphique créées. Cela nettoiera toutes les références stockées à l'objet de graphique dans Chart.js, ainsi que tous les écouteurs d'événements associés attachés par Chart.js."

Il fait ce qu'il prétend et cela a bien fonctionné pour moi, je vous suggère de l'essayer.


Pouvez-vous montrer un exemple? J'ai essayé d'utiliser le blocage plusieurs fois et cela ne fonctionne jamais. Je reçois toujours une erreur indiquant que la méthode n'existe pas.
Ben Hoffman

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

2
C'est la bonne réponse. Pour de futures références, voir: 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
c'est la meilleure alternative
RafaSashi

Bon. Merci
Manjunath Siddappa

11

C'est la seule chose qui a fonctionné pour moi:

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

9

J'ai eu le même problème ici ... J'ai essayé d'utiliser les méthodes destroy () et clear (), mais sans succès.

Je l'ai résolu de la manière suivante:

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

Cela fonctionne parfaitement pour moi ... J'espère que cela aide.


5

Cela a très bien fonctionné pour moi

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

Utilisez .destroy this pour détruire toutes les instances de graphique créées. Cela nettoiera toutes les références stockées à l'objet graphique dans Chart.js, ainsi que tous les écouteurs d'événements associés attachés par Chart.js. Cela doit être appelé avant que le canevas ne soit réutilisé pour un nouveau graphique.


Cela fonctionne correctement pour moi, il semble que cela détruit les rappels de survol. Des chars tellement !!
Antoine Pointeau

4

Nous pouvons mettre à jour les données du graphique dans Chart.js V2.0 comme suit:

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

Je suis d'accord avec cela comme étant une bien meilleure solution - Destroy est extrêmement radical, alors que tout ce que nous voulons vraiment, c'est simplement redémarrer les "données".
TS

1

En utilisant CanvasJS, cela fonctionne pour moi, effacer le graphique et tout le reste, cela pourrait également fonctionner pour vous, vous permettant de configurer complètement votre canevas / graphique avant chaque traitement ailleurs:

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

pour moi, aucune des méthodes ci-dessus n'a fonctionné. Cela a parfaitement fonctionné. Merci beaucoup.
débutant le

1

Je n'ai pas pu faire fonctionner .destroy () non plus, c'est ce que je fais. Le div chart_parent est l'endroit où je veux que le canevas apparaisse. J'ai besoin de redimensionner la toile à chaque fois, donc cette réponse est une extension de celle ci-dessus.

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

Lorsque vous créez un nouveau canevas chart.js, cela génère un nouvel iframe caché, vous devez supprimer le canevas et les anciens 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 });

référence: https://github.com/zebus3d/javascript/blob/master/chartJS_filtering_with_checkboxs.html


1

Cela a fonctionné pour moi. Ajoutez un appel à clearChart, en haut de votre 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 vous utilisez chart.js dans un projet Angular avec Typescript, vous pouvez essayer ce qui suit;

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

Ce que nous avons fait est, avant l'initialisation du nouveau graphique, de supprimer / détruire l'instance de graphique des aperçus, si elle existe déjà, puis de créer un nouveau graphique, par exemple

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

J'espère que cela t'aides.


1

Compléter la réponse d'Adam

Avec 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

Modification simple pour 2020:

Cela a fonctionné pour moi. Changer le graphique en global en le rendant propriétaire de la fenêtre (changer la déclaration de var myChartà window myChart)

Vérifiez si la variable de graphique est déjà initialisée en tant que graphique, si c'est le cas, détruisez-la et créez-en une nouvelle, même si vous pouvez en créer une autre sur le même nom. Voici le code:

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

Esperons que ça marche!


1
Merci beaucoup. Cela fonctionne pour moi.
Dante

0

Pour moi, cela a fonctionné:

		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 a un bogue: Chart.controller(instance)enregistre tout nouveau graphique dans une propriété globale Chart.instances[]et le supprime de cette propriété le .destroy().

Mais lors de la création du graphique, Chart.js écrit également la ._metapropriété dans la variable du jeu de données:

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

et il ne supprime pas cette propriété sur destroy().

Si vous utilisez votre ancien objet de jeu de données sans supprimer ._meta property, Chart.js ajoutera un nouvel ensemble de données ._metasans supprimer les données précédentes. Ainsi, lors de la réinitialisation de chaque graphique, votre objet de jeu de données accumule toutes les données précédentes.

Afin d'éviter cela, détruisez l'objet de l'ensemble de données après l'appel Chart.destroy().


0

Puisque détruire détruit en quelque sorte «tout», une solution simple et bon marché quand tout ce que vous voulez vraiment est de simplement «réinitialiser les données». La réinitialisation de vos ensembles de données dans un tableau vide fonctionnera également parfaitement. Donc, si vous avez un jeu de données avec des étiquettes et un axe de chaque côté:

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

Après cela, vous pouvez simplement appeler:

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

ou, selon que vous utilisez un jeu de données 2D:

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

Ce sera beaucoup plus léger que de détruire complètement l'ensemble de votre graphique / ensemble de données et de tout reconstruire.


0

pour ceux qui comme moi utilisent une fonction pour créer plusieurs graphiques et veulent aussi mettre à jour un bloc, seule la fonction .destroy () a fonctionné pour moi, j'aurais aimé faire un .update (), qui semble plus propre mais .. . voici un extrait de code qui peut vous aider.

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 ...
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.