Jak wyczyścić wykres z płótna, aby nie wywoływać zdarzeń najechania kursorem?


109

Używam Chartjs do wyświetlania wykresu liniowego i to działa dobrze:

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

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

Ale problem pojawia się, gdy próbuję zmienić dane wykresu. Aktualizuję wykres, tworząc nową instancję wykresu z nowymi punktami danych, a tym samym ponownie inicjując płótno.

To działa dobrze. Jednak gdy najeżdżam kursorem na nowy wykres, jeśli zdarzy mi się przejść przez określone lokalizacje odpowiadające punktom wyświetlanym na starym wykresie, wskaźnik myszy / etykieta jest nadal wyzwalany i nagle stary wykres jest widoczny. Pozostaje widoczny, gdy moja mysz znajduje się w tym miejscu, i znika, gdy odejdzie od tego punktu. Nie chcę, aby wyświetlał się stary wykres. Chcę go całkowicie usunąć.

Próbowałem wyczyścić płótno i istniejący wykres przed załadowaniem nowego. Lubić:

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

i

chart.clear();

Ale żadne z nich do tej pory nie zadziałało. Jakieś pomysły, jak mogę temu zapobiec?


18
Stary, to jest dokładnie ten problem, który mam. Metoda „zniszcz ()” nie działa i wkurza mnie.
neaumusic

Czy mogę zapytać, jak uzyskujesz dostęp do obiektu wykresu? Mam ten sam problem, tworzę wykres, a następnie przy obsłudze kliknięcia przycisku muszę go zniszczyć, ale ma on zupełnie inną funkcję i nie mogę znaleźć sposobu na dostęp do obiektu wykresu przez płótno lub kontekst obiekty.
Matt Williams

Istnieje błąd związany z tym problemem, zobacz go tutaj. github.com/jtblin/angular-chart.js/issues/187
MDT

Miałem ten problem. Rozwiązanie do tworzenia / ponownego tworzenia stackoverflow.com/a/51882403/1181367
Chris

Odpowiedzi:


143

Miałem z tym ogromne problemy

Najpierw spróbowałem, .clear()potem spróbowałem .destroy()i próbowałem ustawić moje odniesienie wykresu na zero

Co ostatecznie rozwiązało problem: usunięcie <canvas>elementu, a następnie ponowne dołączenie nowego <canvas>do kontenera nadrzędnego


Mój konkretny kod (oczywiście jest na to milion sposobów):

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
Pracował jak mistrz. Jeśli ktoś wie, czy Chart.js wersja 2 to naprawi, opublikuj to tutaj. Zastanawiam się, czy niszczenie jest zepsute, czy też używamy go nieprawidłowo.
TheLettuceMaster

2
Miły! Dzięki! Właśnie dodałem $ ('# wykres wyników'). Remove (); $ ('# graph-container'). append ('<canvas id = "results-graph"> <canvas>'); przed utworzeniem wykresu.
Ignacio

.destroy () powinno działać dobrze. Jeśli tak się nie stanie, po wywołaniu .destroy () w celu narysowania nowego wykresu użyj setTimeout ()
Sumeet Kale

to jedyne rozwiązanie zadziałało u mnie wielkie dzięki ale dla szerokości i wysokości jeśli już ustawiłeś je na stałe powinieneś zresetować je do tej samej wartości w funkcji resetu
Sandy Elkassar

2
Zniszczenie () nie powiodło się w przypadku chartjs 2.8.0, ale Twoje rozwiązanie właśnie zadziałało! W moim przypadku użyłem tylko $('#results-graph').remove(); $('#graph-container').append('<canvas id="results-graph"><canvas>');przednew Chart(document.getElementById("myCanvas")
mimi

40

Kilka godzin temu miałem ten sam problem.

Metoda „.clear ()” faktycznie czyści kanwę, ale (ewidentnie) pozostawia obiekt żywy i reaktywny.

Czytając uważnie oficjalną dokumentację , w sekcji „Zaawansowane użycie” zauważyłem metodę „.destroy ()”, opisaną w następujący sposób:

„Użyj tego, aby zniszczyć wszelkie utworzone instancje wykresów. Spowoduje to wyczyszczenie wszelkich odniesień przechowywanych do obiektu wykresu w Chart.js, wraz ze wszystkimi powiązanymi odbiornikami zdarzeń dołączonymi przez Chart.js.”

W rzeczywistości robi to, co twierdzi i działa dobrze dla mnie, proponuję spróbować.


Czy mógłbyś pokazać przykład? Wielokrotnie próbowałem użyć blokowania i nigdy nie działa. Zawsze otrzymuję błąd, że metoda nie istnieje.
Ben Hoffman

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

2
To jest właściwa odpowiedź. Aby zapoznać się z przyszłymi referencjami, zobacz: 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
to najlepsza alternatywa
RafaSashi

Dobry. Dzięki
Manjunath Siddappa

11

To jedyna rzecz, która zadziałała dla mnie:

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

9

Miałem tutaj ten sam problem ... Próbowałem użyć metody zniszcz () i wyczyść (), ale bez powodzenia.

Rozwiązałem to w następujący sposób:

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

U mnie działa idealnie ... Mam nadzieję, że to pomaga.


5

To działało bardzo dobrze dla mnie

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

Użyj .destroy this, aby zniszczyć wszelkie utworzone instancje wykresów. Spowoduje to wyczyszczenie wszelkich odniesień przechowywanych do obiektu wykresu w Chart.js, wraz ze wszystkimi powiązanymi detektorami zdarzeń dołączonymi przez Chart.js. Należy to wywołać, zanim płótno zostanie ponownie użyte dla nowego wykresu.


W ten sposób działa poprawnie dla mnie, wygląda na to, że niszczy wywołania zwrotne w dymku. Czołgi tak dużo !!
Antoine Pointeau

4

Możemy zaktualizować dane wykresu w Chart.js V2.0 w następujący sposób:

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

Zgadzam się z tym, że jest to znacznie lepsze rozwiązanie - Destroy jest szalenie zbyt radykalne, kiedy wszystko, czego naprawdę chcemy, to po prostu ponownie uruchomić "dane".
TS

1

Korzystając z CanvasJS, działa to dla mnie, usuwając wykres i wszystko inne, może również działać dla Ciebie, zapewniając pełne ustawienie płótna / wykresu przed każdym przetwarzaniem w innym miejscu:

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

u mnie żadna z powyższych metod nie zadziałała. To działało doskonale. Wielkie dzięki.
początkujący

1

Nie mogłem też zmusić .destroy () do działania, więc to właśnie robię. Element div chart_parent jest miejscem, w którym ma się wyświetlać płótno. Za każdym razem potrzebuję zmiany rozmiaru płótna, więc ta odpowiedź jest rozszerzeniem powyższej.

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

To zadziałało dla mnie. Dodaj wywołanie do clearChart, na górze twojego 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

Jeśli używasz chart.js w projekcie Angular z Typescript, możesz wypróbować następujące rozwiązania;

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

To, co zrobiliśmy, to przed inicjalizacją nowego wykresu, usunięcie / zniszczenie podglądu Wystąpienie wykresu, jeśli już istnieje, a następnie utworzenie nowego wykresu, na przykład

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

Mam nadzieję że to pomoże.


1

Uzupełnienie odpowiedzi Adama

Z 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

Prosta edycja na rok 2020:

To zadziałało dla mnie. Zmień wykres na globalny, ustawiając go jako własność okna (Zmień deklarację z var myChartna window myChart)

Sprawdź, czy zmienna wykresu jest już zainicjowana jako Wykres, jeśli tak, zniszcz ją i utwórz nową, nawet jeśli możesz utworzyć inną o tej samej nazwie. Poniżej kod:

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

Mam nadzieję, że to działa!


1
Dziękuję bardzo. To działa dla mnie.
Dante

0

U mnie to zadziałało:

		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 ma błąd: Chart.controller(instance)rejestruje każdy nowy wykres we właściwości globalnej Chart.instances[]i usuwa go z tej właściwości w dniu .destroy().

Ale przy tworzeniu wykresu Chart.js zapisuje również ._metawłaściwość do zmiennej zestawu danych:

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

i nie usuwa tej właściwości w dniu destroy().

Jeśli użyjesz starego obiektu zestawu danych bez usuwania ._meta property, Chart.js doda nowy zestaw danych ._metabez usuwania poprzednich danych. W ten sposób przy ponownej inicjalizacji każdego wykresu obiekt zestawu danych gromadzi wszystkie poprzednie dane.

Aby tego uniknąć, po wywołaniu należy zniszczyć obiekt zestawu danych Chart.destroy().


0

Ponieważ niszczenie niszczy „wszystko”, tanim i prostym rozwiązaniem jest tylko „zresetowanie danych”. Zresetowanie zestawów danych do pustej tablicy również będzie działać idealnie. Jeśli więc masz zbiór danych z etykietami i osiami po każdej stronie:

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

Następnie możesz po prostu zadzwonić:

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

lub, w zależności od tego, czy korzystasz z zestawu danych 2D:

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

Będzie to o wiele lżejsze niż całkowite zniszczenie całego wykresu / zbioru danych i odbudowanie wszystkiego.


0

dla tych, którzy tak jak ja używają funkcji do tworzenia kilku grafik i chcą je również zaktualizować blok, tylko funkcja .destroy () działała dla mnie, chciałbym zrobić .update (), który wydaje się czystszy, ale ... . oto fragment kodu, który może pomóc.

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 ...
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.