销毁chart.js条形图以在同一<canvas>中重绘其他图形

时间:2016-10-15 07:53:54

标签: javascript canvas graph chart.js

我正在使用 Chart.js 库来绘制条形图,它工作正常,但现在我要销毁条形图并在同一画布中制作折线图。我试过这两种方法来清除画布:

%
第二种方式:

var grapharea = document.getElementById("barChart").getContext("2d");

grapharea.destroy();

var myNewChart = new Chart(grapharea, { type: 'radar', data: barData, options: barOptions });

我称之为正确吗? OnButtonClick我调用这个使用相同画布的函数。

18 个答案:

答案 0 :(得分:67)

为了能够在同一画布上绘制另一个图表,使用的正确方法是.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中的1}}元素。然后我将这个新创建的div用于新图表。如果您遇到过可能与当前图表之前占据画布的图表有关的奇怪行为,也应考虑这种方法。

答案 1 :(得分:21)

每次图表调用后删除画布,这对我有用

$("canvas#chartreport").remove();
$("div.chartreport").append('<canvas id="chartreport" class="animated fadeIn" height="150"></canvas>');
var ctx = document.getElementById("chartreport").getContext("2d");
chartreport= new Chart(ctx, { .... });

答案 2 :(得分:2)

对于 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();
});

答案 3 :(得分:2)

2020年的简单修改:

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

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

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

希望它能起作用!

答案 4 :(得分:1)

截至目前,我正在使用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);

答案 5 :(得分:1)

您可以测试

 $('#canvas').replaceWith($('<canvas id="canvas" height="320px"></canvas>'));

;)

答案 6 :(得分:1)

这是我在为给定的画布 ID 创建新图表之前销毁 ChartJS 图表的策略。这有点蛮力,但可以完成工作。

我创建了一个对象,用于跟踪从画布 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 对象。

答案 7 :(得分:0)

我不知道我花了多少小时来处理这个问题。

假设您的 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);
  .
  .
}

答案 8 :(得分:0)

如果您在一页上有很多图表,那么构建数据结构来保存现有图表的列表是很复杂的。在 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);

答案 9 :(得分:0)

对我来说,它似乎与核心 javascript 的工作方式如下(假设图表最小 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);
    }

答案 10 :(得分:0)

我设法找到了一个解决方案,它可以与 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 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);
}

它就像一个魅力。

答案 11 :(得分:0)

我遇到了同样的问题,我删除了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)

答案 12 :(得分:0)

这将解决您的图表在多次ajax调用中多次更新时变慢的问题:

只需在启动图表之前添加以下代码:

    $('.chartjs-size-monitor').each(function(){
      $(this).remove();
    })
    var grapharea = document.getElementById("barChart").getContext("2d");

答案 13 :(得分:0)

创建一个全局对象:

window['chart-' + chartId] = new Chart(...);

访问并销毁以进行重绘:

if ( window['chart-' + chartId] != undefined ) {
    window['chart-' + chartId].destroy();
}

答案 14 :(得分:0)

我总是只使用1个图形/页面。 Destroy()解决了问题。

 if (
        window.myLine !== undefined
        &&
        window.myLine !== null
    ) {
        window.myLine.destroy();
    }

    window.myLine = new Chart(graphCanvasCtx, config);

答案 15 :(得分:0)

也许有更好的方法,但是没有答案适合我。

df.col.str.rsplit(".",1).str[0]

我的HTML部分是

document.querySelector("#chartReport").innerHTML = '<canvas id="myChart"></canvas>';

答案 16 :(得分:0)

为了解决此问题,我使用了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 

}

答案 17 :(得分:-1)

这对我有用

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