Как очистить диаграмму от холста, чтобы не запускались события зависания?


109

Я использую Chartjs для отображения линейной диаграммы, и это отлично работает:

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

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

Но проблема возникает, когда я пытаюсь изменить данные для диаграммы. Я обновляю график, создавая новый экземпляр диаграммы с новыми точками данных и, таким образом, повторно инициализируя холст.

Это прекрасно работает. Однако при наведении указателя мыши на новую диаграмму, если мне случится пройти по определенным местам, соответствующим точкам, отображаемым на старой диаграмме, наведение / метка по-прежнему срабатывает, и внезапно становится видна старая диаграмма. Он остается видимым, пока моя мышь находится в этом месте, и исчезает при выходе из этой точки. Я не хочу, чтобы отображалась старая диаграмма. Я хочу удалить его полностью.

Я попытался очистить холст и существующую диаграмму перед загрузкой новой. Подобно:

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

и

chart.clear();

Но пока ничего из этого не сработало. Есть идеи о том, как я могу остановить это?


18
Чувак, это как раз та проблема, с которой я столкнулся. Метод "destroy ()" не работает и меня бесит.
neaumusic

Могу я спросить, как вы получаете доступ к объекту диаграммы? У меня та же проблема, я создаю диаграмму, а затем при обработке нажатия кнопки мне нужно ее уничтожить, но это совершенно другая функция, и я не могу найти способ доступа к объекту диаграммы через холст или контекст объекты.
Мэтт Уильямс

Для этой проблемы обнаружена ошибка, см. Здесь. github.com/jtblin/angular-chart.js/issues/187
MDT

Была эта проблема. Решение для создания / воссоздания stackoverflow.com/a/51882403/1181367
Крис,

Ответы:


143

У меня были огромные проблемы с этим

Сначала я попробовал, .clear()потом попробовал, .destroy()и попытался установить ссылку на диаграмму на null

Что окончательно <canvas>устранило проблему для меня: удаление элемента и повторное добавление нового <canvas>в родительский контейнер


Мой конкретный код (очевидно, есть миллион способов сделать это):

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
Работал как чемпион. Если кто-нибудь знает, исправляет ли это Chart.js версии 2, опубликуйте его здесь. Интересно, сломано ли уничтожение или мы его неправильно используем.
TheLettuceMaster

2
Ницца! Спасибо! Я только что добавил $ ('# results-graph'). Remove (); $ ('# граф-контейнер'). append ('<canvas id = "results-graph"> <canvas>'); перед созданием диаграммы.
Игнасио

.destroy () должен работать нормально. Если это не так, после вызова .destroy () для рисования нового графика используйте setTimeout ()
Sumeet Kale

это единственное решение сработало для меня, большое спасибо, но для ширины и высоты, если вы уже установили их фиксированными, вы должны сбросить их на то же значение в функции сброса
Сэнди Элкассар,

2
destroy () не удалось для меня с chartjs 2.8.0, но ваше решение просто сработало! В моем случае я использовал только $('#results-graph').remove(); $('#graph-container').append('<canvas id="results-graph"><canvas>');доnew Chart(document.getElementById("myCanvas")
mimi

40

Несколько часов назад я столкнулся с той же проблемой.

Метод ".clear ()" фактически очищает холст, но (очевидно) оставляет объект живым и реактивным.

Внимательно читая официальную документацию , в разделе «Расширенное использование» я заметил метод «.destroy ()», описанный следующим образом:

«Используйте это для уничтожения любых созданных экземпляров диаграммы. Это очистит все ссылки, хранящиеся в объекте диаграммы в Chart.js, вместе со всеми связанными прослушивателями событий, прикрепленными Chart.js».

Он действительно делает то, что заявляет, и у меня он отлично сработал, я предлагаю вам попробовать.


Не могли бы вы показать пример? Я несколько раз пытался использовать блокировку, но она не работает. У меня всегда появляется ошибка, что метода не существует.
Бен Хоффман

3
(<ChartInstance> this.chart) .destroy ();
Дэвид Дал Буско,

2
Это правильный ответ. Для будущих ссылок см .: 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
это лучшая альтернатива
RafaSashi

Хороший. Спасибо
Манджунатх Сиддаппа

11

Это единственное, что у меня сработало:

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

9

У меня была такая же проблема ... Я пытался использовать методы destroy () и clear (), но безуспешно.

Я решил это следующим образом:

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

У меня это работает идеально ... Я надеюсь, что это поможет.


5

Это очень хорошо сработало для меня

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

Используйте .destroy, чтобы уничтожить все созданные экземпляры диаграммы. Это очистит все ссылки, хранящиеся в объекте диаграммы в Chart.js, вместе со всеми связанными прослушивателями событий, прикрепленными Chart.js. Это необходимо вызвать перед повторным использованием холста для новой диаграммы.


Этот способ работает для меня правильно, похоже, он уничтожает обратные вызовы при наведении. Таких танков !!
Antoine Pointeau

4

Мы можем обновить данные диаграммы в Chart.js V2.0 следующим образом:

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

Я согласен с этим как с гораздо лучшим решением - Destroy слишком радикален, когда все, что нам действительно нужно, это просто перезапустить «данные».
TS

1

Используя CanvasJS, это работает для меня, очищая диаграмму, и все остальное, может работать и для вас, предоставляя вам полностью настраивать свой холст / диаграмму перед каждой обработкой в ​​другом месте:

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

для меня ни один из вышеперечисленных методов не работал. Это сработало отлично. Большое спасибо.
новичок

1

Я не мог заставить работать .destroy (), так что я делаю это. Я хочу, чтобы холст отображался в div chart_parent. Мне нужно, чтобы размер холста менялся каждый раз, поэтому этот ответ является продолжением предыдущего.

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

Когда вы создаете один новый холст chart.js, это создает один новый скрытый iframe, вам нужно удалить холст и старые iframe.

$('#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 });

ссылка: https://github.com/zebus3d/javascript/blob/master/chartJS_filtering_with_checkboxs.html


1

Это сработало для меня. Добавьте вызов clearChart в верхней части 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

Если вы используете chart.js в проекте Angular с Typescript, вы можете попробовать следующее:

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

Что мы сделали, так это перед инициализацией новой диаграммы удалили / уничтожили экземпляр диаграммы предварительного просмотра, если он уже существует, затем создали новую диаграмму, например

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

Надеюсь это поможет.


1

Дополняя ответ Адама

С 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

Простое редактирование для 2020 года:

Это сработало для меня. Измените диаграмму на глобальную, сделав ее владельцем окна (измените декларацию с var myChartна window myChart)

Проверьте, инициализирована ли уже переменная диаграммы как Chart, если да, уничтожьте ее и создайте новую, даже если вы можете создать другую с тем же именем. Ниже приведен код:

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

Надеюсь, что это работает!


1
Огромное спасибо. У меня это работает.
Данте

0

Для меня это сработало:

		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 есть ошибка: Chart.controller(instance)любая новая диаграмма регистрируется в глобальном свойстве Chart.instances[]и удаляется из этого свойства .destroy().

Но при создании диаграммы Chart.js также записывает ._metaсвойство в переменную набора данных:

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

и это свойство не удаляется destroy().

Если вы используете свой старый объект набора данных, не удаляя его ._meta property, Chart.js добавит новый набор данных в._meta предыдущие данные. Таким образом, при каждой повторной инициализации диаграммы ваш объект набора данных накапливает все предыдущие данные.

Чтобы этого избежать, уничтожьте объект набора данных после вызова Chart.destroy().


0

Поскольку уничтожение уничтожает «все», дешевое и простое решение, когда все, что вам действительно нужно, это просто «сбросить данные». Сброс ваших наборов данных на пустой массив также будет работать нормально. Итак, если у вас есть набор данных с метками и осью с каждой стороны:

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

После этого вы можете просто позвонить:

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

или, в зависимости от того, используете ли вы 2-мерный набор данных:

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

Это будет намного легче, чем полностью уничтожить всю вашу диаграмму / набор данных и восстановить все.


0

для тех, кто вроде меня использует функцию для создания нескольких графиков и хочет обновить их тоже блоком, у меня работала только функция .destroy (), я бы хотел создать .update (), который кажется более чистым, но ... . вот фрагмент кода, который может помочь.

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 ...

0

Сначала поместите диаграмму в какую-либо переменную, затем запишите ее в следующий раз перед запуском

# Проверяем, существует ли объект myChart, а затем искажаем его

    if($scope.myChart) {
      $scope.myChart.destroy();
    }

    $scope.myChart  = new Chart(targetCanvas
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.