关于javascript:如何从画布上清除图表,以免触发悬停事件?

How to clear a chart from a canvas so that hover events cannot be triggered?

我正在使用Chartjs显示折线图,并且可以正常工作:

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

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

但是,当我尝试更改图表的数据时,就会出现问题。 我通过使用新数据点创建图表的新实例来更新图形,从而重新初始化画布。

这很好。 但是,当我将鼠标悬停在新图表上时,如果碰巧越过了与旧图表上显示的点相对应的特定位置,则仍会触发悬停/标签,并且突然可见旧图表。 当我的鼠标位于该位置时,它仍然可见,而从该点移开时,它消失。 我不希望显示旧图表。 我想将其完全删除。

在加载新画布之前,我已尝试清除画布和现有图表。 喜欢:

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

1
chart.clear();

但是到目前为止,这些方法都没有起作用。 关于如何阻止这种情况的任何想法?


我对此有很大的问题

首先我尝试了.clear(),然后尝试了.destroy(),然后尝试将图表引用设置为null

最终为我解决了这个问题:删除元素,然后将新的重新添加到父容器

我的特定代码(显然有百万种方法可以做到):

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
};


几个小时前我也遇到了同样的问题。

" .clear()"方法实际上清除了画布,但是(显然)它使对象保持活动状态和反应性。

仔细阅读官方文档中的"高级用法"部分,我注意到方法" .destroy()",描述如下:

"Use this to destroy any chart instances that are created. This will
clean up any references stored to the chart object within Chart.js,
along with any associated event listeners attached by Chart.js."

它实际上完成了它声称的功能,并且对我来说效果很好,我建议您尝试一下。


1
2
3
4
5
6
7
8
9
10
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
2
3
document.getElementById("chartContainer").innerHTML = '';
document.getElementById("chartContainer").innerHTML = '<canvas id="myCanvas"></canvas>';
var ctx = document.getElementById("myCanvas").getContext("2d");

我在这里遇到了同样的问题...我尝试使用destroy()和clear()方法,但没有成功。

我以另一种方式解决了它:

HTML:

1
    <canvas id="pieChart" width="300" height="300"></canvas>

Javascript:

1
2
3
4
5
6
var pieChartContent = document.getElementById('pieChartContent');
pieChartContent.innerHTML = '';
$('#pieChartContent').append('<canvas id="pieChart" width="300" height="300"><canvas>');

ctx = $("#pieChart").get(0).getContext("2d");        
var myPieChart = new Chart(ctx).Pie(data, options);

它对我来说很完美……我希望对您有所帮助。


这对我来说很好

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

使用.destroy this可以销毁创建的任何图表实例。这将清除Chart.js中存储到Chart对象的所有引用,以及Chart.js附加的所有关联事件侦听器。必须在画布重新用于新图表之前调用此方法。


我们可以按以下方式更新Chart.js V2.0中的图表数据:

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


使用CanvasJS,这对我来说可以清除图表和其他所有内容,也可能对您有用,因为您可以在其他地方进行每次处理之前完全设置好画布/图表:

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


我也无法使.destroy()正常工作,所以这就是我正在做的事情。 chart_parent div是我要显示画布的位置。我每次都需要调整画布的大小,因此此答案是上述内容的扩展。

HTML:

jQuery的:

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

当您创建一个新的chart.js画布时,这会生成一个隐藏的新iframe,您需要删除画布和旧的iframe。

1
2
3
4
5
$('#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


这对我有用。
在updateChart()的顶部添加对clearChart的调用

1
2
3
4
5
6
7
8
`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;
}`

如果您在带有Typescript的Angular项目中使用chart.js,则可以尝试以下操作;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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>

补充亚当的答案

使用Vanilla JS:

1
2
3
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


2020年的简单编辑:

这对我有用。 通过使其成为窗口所有者,将图表更改为全局图表(将声明从var myChart更改为window myChart)

检查chart变量是否已经初始化为Chart,如果是,则销毁它并创建一个新变量,即使您可以使用相同的名称创建另一个变量。 下面是代码:

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

希望它能起作用!


对我来说,这工作:

1
2
3
4
5
6
7
8
9
\t\tvar in_canvas = document.getElementById('chart_holder');
\t//remove canvas if present
\t\t\twhile (in_canvas.hasChildNodes()) {
\t\t\t\t  in_canvas.removeChild(in_canvas.lastChild);
\t\t\t\t}
\t//insert canvas
\t\t\tvar newDiv = document.createElement('canvas');
\t\t\tin_canvas.appendChild(newDiv);
\t\t\tnewDiv.id ="myChart";


由于销毁类型会销毁"一切",因此,当您真正想要的只是一个"重置数据"时,一种廉价而简单的解决方案。将数据集重置为空数组也可以很好地工作。因此,如果您的数据集带有标签,并且每侧都有一个轴:

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

之后,您可以简单地调用:

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

或者,取决于您是否使用2D数据集:

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

它比完全销毁整个图表/数据集并重建所有内容要轻得多。


我们所做的是,在初始化新图表之前,删除/销毁预览Chart实例(如果已经存在),然后创建一个新图表,例如

1
2
3
4
5
6
if(myGraf != undefined)
    myGraf.destroy();
    myGraf= new Chart(document.getElementById("CanvasID"),
    {
      ...
    }

希望这可以帮助。


对于那些喜欢我的人,使用一个函数来创建多个图形,并且也想对它们进行更新,只有.destroy()函数对我有用,我希望制作一个.update(),看上去更干净,但是.. 这是一个可能有帮助的代码段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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 ...

Chart.js有一个错误:
Chart.controller(instance)在全局属性Chart.instances[]中注册任何新图表,并将其从.destroy()上的此属性中删除。

但是在创建图表时,Chart.js还将._meta属性写入数据集变量:

1
2
3
4
5
6
7
8
9
10
11
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()之后销毁数据集对象。