如何从画布中清除图表以便无法触发悬停事件?
Posted
技术标签:
【中文标题】如何从画布中清除图表以便无法触发悬停事件?【英文标题】:How to clear a chart from a canvas so that hover events cannot be triggered? 【发布时间】:2014-09-09 01:14:08 【问题描述】:我正在使用 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();
但到目前为止,这些都没有奏效。关于如何阻止这种情况发生的任何想法?
【问题讨论】:
老兄,这正是我遇到的问题。 “destroy()”方法不起作用,这让我很生气。 请问您是如何访问图表对象的?我遇到了同样的问题,我创建了一个图表,然后在处理按钮单击时我需要销毁它,但它在一个完全不同的函数中,我找不到通过画布或上下文访问图表对象的方法对象。 有一个针对此问题的错误打开,请在此处查看。 github.com/jtblin/angular-chart.js/issues/187 有这个问题。创建/重新创建***.com/a/51882403/1181367的解决方案 【参考方案1】:我遇到了很大的问题
首先我尝试了.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);
;
【讨论】:
像冠军一样工作。如果有人知道 Chart.js 版本 2 是否修复了这个问题,请在此处发布。我想知道destroy是坏了还是我们使用不正确。 不错!谢谢!我刚刚添加了 $('#results-graph').remove(); $('#graph-container').append(' .destroy() 应该可以正常工作。如果没有,在调用 .destroy() 绘制新图表后,使用 setTimeout() 这是唯一对我有用的解决方案,非常感谢,但是对于宽度和高度,如果你已经将它们设置为固定,你应该在重置函数中将它们重置为相同的值 destroy() 使用 chartjs 2.8.0 对我来说失败了,但您的解决方案刚刚奏效!就我而言,我只在new Chart(document.getElementById("myCanvas")
之前使用了 $('#results-graph').remove(); $('#graph-container').append('<canvas id="results-graph"><canvas>');
【参考方案2】:
几个小时前我也遇到过同样的问题。
“.clear()”方法实际上清除了画布,但(显然)它使对象保持活跃和反应。
仔细阅读the official documentation,在“高级用法”部分,我注意到方法“.destroy()”,描述如下:
"使用它来销毁任何已创建的图表实例。这将 清理存储在 Chart.js 中的图表对象的所有引用, 以及 Chart.js 附加的任何关联事件侦听器。”
它确实做到了它声称的效果,对我来说效果很好,我建议你试一试。
【讨论】:
你能举个例子吗?我曾尝试多次使用阻塞,但它从来没有用过。我总是收到该方法不存在的错误。 (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);
【讨论】:
这是最好的选择 好一个。谢谢【参考方案4】:这是唯一对我有用的东西:
document.getElementById("chartContainer").innerhtml = ' ';
document.getElementById("chartContainer").innerHTML = '<canvas id="myCanvas"></canvas>';
var ctx = document.getElementById("myCanvas").getContext("2d");
【讨论】:
【参考方案5】:我在这里遇到了同样的问题...我尝试使用 destroy() 和 clear() 方法,但没有成功。
我用下一个方法解决了:
HTML:
<div id="pieChartContent">
<canvas id="pieChart" ></canvas>
</div>
var pieChartContent = document.getElementById('pieChartContent');
pieChartContent.innerHTML = ' ';
$('#pieChartContent').append('<canvas id="pieChart" ><canvas>');
ctx = $("#pieChart").get(0).getContext("2d");
var myPieChart = new Chart(ctx).Pie(data, options);
它对我来说很完美......我希望它会有所帮助。
【讨论】:
【参考方案6】:我们可以在 Chart.js V2.0 中更新图表数据如下:
var myChart = new Chart(ctx, data);
myChart.config.data = new_data;
myChart.update();
【讨论】:
我同意这是一个更好的解决方案 - Destroy 过于激进,而我们真正想要的只是重新启动“数据”。 谢谢哥们!!这就是我需要的。投票赞成!【参考方案7】:这对我来说效果很好
var ctx = $("#mycanvas");
var LineGraph = new Chart(ctx,
type: 'line',
data: chartdata);
LineGraph.destroy();
使用 .destroy 来销毁任何已创建的图表实例。这将清除存储在 Chart.js 中的图表对象的所有引用,以及 Chart.js 附加的任何关联事件侦听器。这必须在画布重新用于新图表之前调用。
【讨论】:
这种方式对我来说可以正常工作,看起来它破坏了悬停回调。坦克这么多!【参考方案8】:2020 年的简单编辑:
这对我有用。通过使其拥有窗口来将图表更改为全局(将声明从 var myChart
更改为 window myChart
)
检查图表变量是否已经被初始化为Chart,如果是,则销毁它并创建一个新的,即使你可以创建另一个同名的变量。下面是代码:
if(window.myChart instanceof Chart)
window.myChart.destroy();
var ctx = document.getElementById('myChart').getContext("2d");
希望它有效!
【讨论】:
【参考方案9】:补充亚当的答案
使用香草 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
【讨论】:
【参考方案10】:最好使用 Chart.js 的特定功能来初步检查现有图表实例,然后执行 destroy 或 clear 以便重用相同的 canvas 元素来呈现另一个图表,而不是处理 HTML JS 中的元素。
ChartJs 的getChart(key) - 从给定的键中查找图表实例。
如果键是字符串,则将其解释为图表的 Canvas 元素的 ID。 键也可以是 CanvasRenderingContext2D 或 HTMLDOMElement。注意:如果没有找到图表,这将返回 undefined。如果找到图表的实例,则表明该图表必须是先前创建的。
// JS - Destroy exiting Chart Instance to reuse <canvas> element
let chartStatus = Chart.getChart("myChart"); // <canvas> id
if (chartStatus != undefined)
chartStatus.destroy();
//(or)
// chartStatus.clear();
//-- End of chart destroy
var chartCanvas = $('#myChart'); //<canvas> id
chartInstance = new Chart(chartCanvas,
type: 'line',
data: data
);
<!-- HTML -Line Graph - Chart.js -->
<div class="container-fluid" id="chartContainer">
<canvas id="myChart" > </canvas>
</div>
这种方法将使您免于从 JS 内部删除 - 创建 - 将 Canvas 元素附加到 DIV 中。
【讨论】:
【参考方案11】:使用 CanvasJS,这适用于我清除图表和其他所有内容,也可能适用于您,允许您在其他地方的每个处理之前完全设置您的画布/图表:
var myDiv= document.getElementById("my_chart_container0";
myDiv.innerHTML = "";
【讨论】:
对我来说,上述方法都不起作用。这非常有效。非常感谢。【参考方案12】:我也无法让 .destroy() 工作,所以这就是我正在做的事情。 chart_parent div 是我希望画布出现的地方。我需要每次调整画布大小,所以这个答案是上述答案的扩展。
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>');
【讨论】:
【参考方案13】:当您创建一个新的 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
【讨论】:
【参考方案14】:这对我有用。 在您的 updateChart() 顶部添加对 clearChart 的调用
`function clearChart()
event.preventDefault();
var parent = document.getElementById('parent-canvas');
var child = document.getElementById('myChart');
parent.removeChild(child);
parent.innerHTML ='<canvas id="myChart" ></canvas>';
return;
`
【讨论】:
【参考方案15】:如果您在带有 Typescript 的 Angular 项目中使用 chart.js,您可以尝试以下方法;
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>
【讨论】:
【参考方案16】:我们所做的是,在初始化新图表之前,删除/销毁预览图表实例,如果已经存在,则创建一个新图表,例如
if(myGraf != undefined)
myGraf.destroy();
myGraf= new Chart(document.getElementById("CanvasID"),
...
希望这会有所帮助。
【讨论】:
【参考方案17】:首先将图表放入某个变量中,然后在下次初始化之前对其进行历史记录
#检查myChart对象是否存在然后扭曲它
if($scope.myChart)
$scope.myChart.destroy();
$scope.myChart = new Chart(targetCanvas
【讨论】:
【参考方案18】:您应该将图表保存为变量。 在全局范围内,如果它是纯 javascript,或者作为一个类属性,如果它是 Angular。
然后你就可以使用这个引用来调用destroy()。
纯 Javascript:
var chart;
function startChart()
// Code for chart initialization
chart = new Chart(...); // Replace ... with your chart parameters
function destroyChart()
chart.destroy();
角度:
export class MyComponent
chart;
constructor()
// Your constructor code goes here
ngOnInit()
// Probably you'll start your chart here
// Code for chart initialization
this.chart = new Chart(...); // Replace ... with your chart parameters
destroyChart()
this.chart.destroy();
【讨论】:
【参考方案19】:对我来说这很有效:
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";
【讨论】:
【参考方案20】: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()
后销毁数据集对象。
【讨论】:
【参考方案21】:由于破坏类型会破坏“一切”,因此当您真正想要的只是“重置数据”时,这是一种廉价而简单的解决方案。将数据集重置为空数组也可以正常工作。因此,如果您有一个带有标签的数据集,并且每边都有一个轴:
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);
或者,取决于您是否使用二维数据集:
window.myLine2.data.datasets[0].data.push( x: x, y: y);
这将比完全破坏整个图表/数据集并重建所有内容要轻巧得多。
【讨论】:
【参考方案22】:对于那些像我一样使用函数创建多个图形并想更新它们的块的人,只有函数 .destroy() 对我有用,我想制作一个看起来更干净的 .update()但是...这里有一个可能有帮助的代码 sn-p。
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 ...
【讨论】:
【参考方案23】:在创建图表之前声明let doughnut = null
const doughnutDriverStatsChartCanvas = $('#dougnautChartDriverStats').get(0).getContext('2d')
const doughnutOptionsDriverStats =
maintainAspectRatio: false,
responsive: true,
let doughnut = null
doughnut = new Chart(doughnutDriverStatsChartCanvas,
type: 'doughnut',
data: doughnutChartDriverStats,
options: doughnutOptionsDriverStats
)
【讨论】:
以上是关于如何从画布中清除图表以便无法触发悬停事件?的主要内容,如果未能解决你的问题,请参考以下文章