销毁 chart.js 条形图以重绘同一 <canvas> 中的其他图表
Posted
技术标签:
【中文标题】销毁 chart.js 条形图以重绘同一 <canvas> 中的其他图表【英文标题】:Destroy chart.js bar graph to redraw other graph in same <canvas> 【发布时间】:2017-02-24 16:13:58 【问题描述】:我正在使用 Chart.js 库来绘制 条形图,它工作正常,但现在我想销毁 条形图 strong> 并在同一个 canvas 中制作 折线图。我试过这两种方法来清除画布:
var grapharea = document.getElementById("barChart").getContext("2d");
grapharea.destroy();
var myNewChart = new Chart(grapharea, type: 'radar', data: barData, options: barOptions );
第二种方式:
var grapharea = document.getElementById("barChart").getContext("2d");
grapharea.clear();
var myNewChart = new Chart(grapharea, type: 'radar', data: barData, options: barOptions );
我说的对吗? OnButtonClick 我调用这个函数,它使用相同的画布。
【问题讨论】:
重复问题:***.com/questions/24815851/… 【参考方案1】:从...更改新图表变量
var yourChart= new Chart(ctx1).Line(barChartData1, animation: false);
到
window.yourChart= new Chart(ctx1).Line(barChartData1, animation: false);
然后
if(window.yourChart!= null)
window.yourChart.destroy();
var doc1 = document.getElementById("stockPrice");
var ctx1 = doc1.getContext("2d");
window.yourChart = new Chart(ctx1).Bar(barChartData1, animation: false);
【讨论】:
【参考方案2】:对于给定的画布 ID,这是我在创建新图表之前销毁 ChartJS 图表的策略。这有点蛮力,但可以完成工作。
我创建了一个对象 chartsByCanvasId
,它跟踪从画布 id 到关联 ChartJS 对象的映射,我将在创建新对象之前检查该对象是否存在要销毁的任何现有 ChartJS 对象。
看这里:
// Helper object and functions
const chartsByCanvasId = ;
const destroyChartIfNecessary = (canvasId) =>
if (chartsByCanvasId[canvasId])
chartsByCanvasId[canvasId].destroy();
const registerNewChart = (canvasId, chart) =>
chartsByCanvasId[canvasId] = chart;
那么,如果图表存在,这就是你如何销毁图表
destroyChartIfNecessary(canvasId);
const myChart = new Chart(ctx, config);
registerNewChart(canvasId, myChart);
请注意,创建图表后,我们会立即将其“注册”到registerNewChart()
。这个注册步骤很重要,因为这就是destroyChartIfNecessary()
知道给定画布 id 已经存在 ChartJS 对象的方式。
这个策略的好处在于,即使您的页面上有很多图表,它也能工作,因为它通过画布 ID 跟踪 ChartJS 对象。
【讨论】:
【参考方案3】: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();
//-- 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 中。
【讨论】:
这会对未定义的元素进行 fab 检查。真正符合 OOP!【参考方案4】:我不知道我花了多少时间来处理这个问题。
假设您的 html 包含该内容
<div id="soner" class="card-body customerDonutChart">
<canvas id="customerDonutChart" style="min-height: 250px; height: 250px; max-height: 250px; max-width: 100%;"></canvas>
</div>
注意解决问题所必需的<div id="soner"
部分。
function myChartJsCaller()
document.getElementById("soner").innerHTML = '<canvas id="customerDonutChart" style="min-height: 250px; height: 250px; max-height: 250px; max-width: 100%;"></canvas>';
// here is important, your ctx = blabla must be below after changing innerHTML
let ctx = document.getElementById(selector);
.
.
【讨论】:
【参考方案5】:如果您在一页上有很多图表,那么构建数据结构来保存现有图表的列表会很复杂。在 chart.js 3.5.0 中更容易测试图表画布是否已被使用。不需要单独的数据结构:
// Chart may previously have been shown or not, so the chart may need creating or updating.
// Vue messes with the DOM, so you can't just "update" the chart as per the docs.
var canv = this.$refs['canvas'];
const oldChart = Chart.getChart(canv);
if (typeof oldChart !== 'undefined')
oldChart.destroy();
new Chart(canv.getContext('2d'), this.config);
【讨论】:
【参考方案6】:这适用于我的角度
removeHTML()
let chart = <HTMLCanvasElement>document.getElementById("myChart");
let chart2 = <HTMLCanvasElement>document.getElementById("myChart2");
if(chart)
chart.remove()
if(chart2)
chart2.remove()
ngOnDestroy(): void
this.removeHTML();
【讨论】:
尝试根据上下文回答。【参考方案7】:对我来说,它似乎与核心 javascript 一起工作如下(假设图表 min js 已经加载):
const data =
labels : graphDataLabels,
datasets: [
label: 'Sentiment Intensity Distribution',
data: dataValues, //[300, 50, 100],
backgroundColor: [
"#0D5265",
"#32DAC8",
"#FF8300"
],
hoverOffset: 4
]
;
const config =
type: 'pie',
data: data
;
var ctx = document.getElementById('pieChart').getContext('2d');
if(ctx.pieChart)
pieChart = null;
else
pieChart = new Chart(ctx, config);
【讨论】:
【参考方案8】:我设法找到了一个与 destroy 方法一起使用的解决方案,并允许重复使用画布而不删除和重新创建它,同时它消耗的资源更少。
首先,将var chart声明为全局并创建一个布尔值来检查js是否加载
var chart;
var graphScriptLoaded = false;
下一部分很好,因为它只在需要图表时加载js,节省了加载页面的时间,同时它可以让你了解它是否是第一次执行与否。
//load graph just when needed and destry existing istances
if (!Boolean(graphScriptLoaded))
loadScript('https://cdn.jsdelivr.net/npm/chart.js@2.8.0', function()
graphScriptLoaded = true;
chart=graphs_init(i_arr, spent_arr);
);
else
chart.destroy();
chart=graphs_init(i_arr, spent_arr);
然后,在创建图表的函数中,只需返回图表 var
var chart = new Chart(ctx,
[.....]
);
return chart;
函数“loadscript”是自定义的,基于这个答案: How do I include a JavaScript file in another JavaScript file?
这里是:
function loadScript(url, callback)
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState) //IE
script.onreadystatechange = function()
if (script.readyState == "loaded" || script.readyState == "complete")
script.onreadystatechange = null;
callback();
;
else //Others
script.onload = function()
callback();
;
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
它就像一个魅力。
【讨论】:
【参考方案9】:我遇到了同样的问题,我已经删除了 canvas 元素并重新创建了 canvas 元素,然后再次延迟渲染。
var element = document.getElementById("canvasId");
element.parentNode.removeChild(element);
var canv = document.createElement("canvas");
canv.setAttribute("id","canvasId");
canv.style.height = "20vw"; // give height and width as per the requirement
canv.style.width = "20vw";
setTimeout(()=>
var grapharea = document.getElementById("canvasId").getContext("2d");
,500)
【讨论】:
【参考方案10】:这将解决图表在多个 ajax 调用中多次更新时变慢的问题:
只需在启动图表之前添加此代码:
$('.chartjs-size-monitor').each(function()
$(this).remove();
)
var grapharea = document.getElementById("barChart").getContext("2d");
【讨论】:
【参考方案11】:创建一个全局对象:
window['chart-' + chartId] = new Chart(...);
通过重绘访问和销毁进程:
if ( window['chart-' + chartId] != undefined )
window['chart-' + chartId].destroy();
【讨论】:
【参考方案12】:2020 年的简单编辑:
这对我有用。通过使其拥有窗口将图表更改为全局(将声明从 var myChart
更改为 window myChart
)
检查图表变量是否已经初始化为Chart,如果是,则销毁它并创建一个新的,即使你可以创建另一个同名的变量。下面是代码:
if(window.myChart instanceof Chart)
window.myChart.destroy();
var ctx = document.getElementById('myChart').getContext("2d");
希望它有效!
【讨论】:
这必须是唯一正确的选项。你不应该在没有先检查有什么东西要破坏的情况下打电话给destroy()
。此外,明确检查 instanceof Chart
是正确的。我之前一直在检查“未定义”,它在某些情况下可能会导致问题。【参考方案13】:
对于 ChartJS v2.x,您可以使用 update() 更新图表数据,而无需显式销毁和创建画布。
var chart_ctx = document.getElementById("chart").getContext("2d");
var chart = new Chart(chart_ctx,
type: "pie",
data: ,
options:
);
$.ajax(
...
).done(function (response)
chart.data = response;
chart.update();
);
【讨论】:
如果变量已被覆盖或不再使用,是否有办法检索图表实例? @RahulHindocha 如果您无权访问您的变量,您可以通过查看Chart.instances
对象重新访问实例。从这里你可以做Chart.instances[key].destroy()
或Chart.instances[key].update()
。【参考方案14】:
我总是只使用 1 个图表/页面。 Destroy() 解决了问题。
if (
window.myLine !== undefined
&&
window.myLine !== null
)
window.myLine.destroy();
window.myLine = new Chart(graphCanvasCtx, config);
【讨论】:
【参考方案15】:你可以测试一下
$('#canvas').replaceWith($('<canvas id="canvas" ></canvas>'));
;)
【讨论】:
【参考方案16】:也许有更好的方法,但没有适合我的答案。
document.querySelector("#chartReport").innerHTML = '<canvas id="myChart"></canvas>';
我的 HTML 部分是
<div class="col-md-6 col-md-offset-3">
<div id="chartReport">
<canvas id="myChart"></canvas>
</div>
</div>
【讨论】:
你的解决方案对我有用,而不是其他人建议使用 jquery 删除和附加 非常感谢!我尝试了很多答案,但只有这个答案可以完美地工作,没有故障数据 你是个传奇人物。 最快、最好、最简单的解决方法 简单的解决方法,谢谢??【参考方案17】:为了解决这个问题,我使用了 jQuery 的 add()
和 remove()
方法来清除画布。我正在删除组件,在再次绘制它之前,我使用 jQuery 的 append()
方法再次使用相同的 id 附加画布。
redraw()
$("#myChart").remove();// removing previous canvas element
//change the data values or add new values for new graph
$("#chart_box").after("<canvas id='myChart'></canvas>");
// again adding a new canvas element with same id
generateGraph();// calling the main graph generating function
【讨论】:
【参考方案18】:我现在使用的是 Chart.js 2.7.2。在我的应用程序中,我正在创建多个图表,并且需要一种方法来访问它们以正确“替换”它们的数据并修复悬停时显示的“旧图表”。我试过的答案都没有正确。
这是一种使用一个或多个图表来管理此问题的方法:
在全局中存储图表
var charts=[]; // global
创建图表功能
function createChart(id, type, labels, data)
// for multiple datasets
var datasets=[];
data.forEach(function(set)
datasets.push(
label: set.label,
data: set.data
);
);
var config =
type: type,
data:
labels: labels,
datasets: datasets
;
if(typeof charts[id] == "undefined") // see if passed id exists
// doesn't, so create it
charts[id]= new (function()
this.ctx=$(id); // canvas el
this.chart=new Chart(this.ctx, config);
)();
console.log('created chart '+charts[id].chart.canvas.id);
else
charts[id].chart.destroy(); // "destroy" the "old chart"
charts[id].chart=new Chart(charts[id].ctx, config); // create the chart with same id and el
console.log('replaced chart '+charts[id].chart.canvas.id);
// just to see all instances
Chart.helpers.each(Chart.instances, function(instance)
console.log('found instance '+instance.chart.canvas.id)
)
对于您的每个画布元素,例如:
<canvas id="thiscanvasid"></canvas>
使用函数创建/替换图表
createChart('#thiscanvasid', 'bar', json.labels, json.datasets);
【讨论】:
【参考方案19】:每次图表调用后删除画布,这对我有用
$("canvas#chartreport").remove();
$("div.chartreport").append('<canvas id="chartreport" class="animated fadeIn" ></canvas>');
var ctx = document.getElementById("chartreport").getContext("2d");
chartreport= new Chart(ctx, .... );
【讨论】:
这是个好主意,在 vanilla js 中document.getElementById( "sector-chart" ).remove(); let canvas = document.createElement('canvas'); canvas.setAttribute('id','chart'); canvas.setAttribute('width','300'); canvas.setAttribute('height','100'); document.querySelector('#chart-container').appendChild(canvas);
这非常有效,特别是如果你有你的 JS 文件来在不同的文件上绘制图形。【参考方案20】:
为了能够在同一画布上绘制另一个图表,正确的使用方法是.destroy()
。您必须在先前创建的图表对象上调用它。您也可以对两个图表使用相同的变量。
var grapharea = document.getElementById("barChart").getContext("2d");
var myChart = new Chart(grapharea, type: 'bar', data: barData, options: barOptions );
myChart.destroy();
myChart = new Chart(grapharea, type: 'radar', data: barData, options: barOptions );
直接来自docs (under Prototype Methods):
.destroy()
使用它来销毁任何已创建的图表实例。这将清除存储在 Chart.js 中的图表对象的所有引用,以及 Chart.js 附加的任何关联事件侦听器。这必须在画布重新用于新图表之前调用。
// Example from the docs
var myLineChart = new Chart(ctx, config);
// Destroys a specific chart instance
myLineChart.destroy();
它明确指出必须先调用此方法,然后才能将画布重新用于新图表。
.clear()
稍后在同一部分中也提到了“将清除图表画布。在动画帧之间广泛用于内部,但您可能会发现它很有用。”调用此方法后,图表将保持活动状态,因此如果您想将画布重用于全新的图表,则无需调用此方法。
说实话,在像你这样的情况下,我经常使用容器 div
来包装我的 canvas
,并且每当我需要创建新图表时,我都会在其中放置一个新的 canvas
元素div
。然后我将这个新创建的canvas
用于新图表。如果您遇到奇怪的行为,可能与图表在当前图表之前占据画布有关,请记住这种方法。
【讨论】:
谢谢,但是如何知道一个图表是存在还是被破坏了呢?typeof myChart === undefined
有效吗?
回复 João Pimentel Ferreira - 将图表声明为变量,然后编写一个条件来检查它是否存在。 if (myChart) myChart.destroy();
这种方法对我不起作用。 destroy 方法什么也没做。
伙计,非常感谢。你节省了我的时间。我使用了使用 div 的解决方法,因为调用 destroy 没有帮助。以上是关于销毁 chart.js 条形图以重绘同一 <canvas> 中的其他图表的主要内容,如果未能解决你的问题,请参考以下文章