ChartJS 在循环中初始化多个图表

0pizxfdo  于 2022-12-13  发布在  Chart.js
关注(0)|答案(1)|浏览(144)

在我的页面上,我想显示通过 AJAX 加载的多个图表。所以我得到了类似如下的html:

<h4>Chart 1</h4>
<canvas data-type="bar" data-labels='["Label 1", "Label 2"]' data-data='[10,20]'></canvas>
<h4>Chart 2</h4>
<canvas data-type="pie" data-labels='["Label 3", "Label 4"]' data-data='[30,40]'></canvas>

正如您所看到的,图表可以是不同的类型,我有一个对象保存每种类型的图表的所有配置

const chartConfigs = {
    bar: {
        type: 'bar',
        data: {
          labels: [],
          datasets: [{
            data: [],
            pointRadius: 2,
            backgroundColor: '',
            maxBarThickness: 50
          }]
        },
        options: {
            legend: {
                display: false
            },
            scales: barScalesOptions
        }
    },
    pie: {
        type: 'pie',
        data: {
            labels: [],
            datasets: [{
                data: [],
                backgroundColor: ['#84c267', '#c9556a'],
                borderWidth: 0
            }],
        },
        options: {
            legend: {
          labels: {
            fontColor: '#CCC',
          }
        },
            aspectRatio: 1,
            responsive: true
        }
    }
}

然后我循环遍历所有的画布来初始化它们。

container.querySelectorAll('canvas').forEach(canv => {
    const chartOptions = chartConfigs[canv.dataset.type];
    chartOptions.data.datasets[0].data = JSON.parse(canv.dataset.data);
    if(canv.dataset.labels != undefined)
        chartOptions.data.labels = JSON.parse(canv.dataset.labels);

    console.log(JSON.stringify(chartOptions));
    new Chart(canv, chartOptions);
});

但问题是所有的图表都呈现相同的-标签和数据。我假设这是因为chartOptions是一个通过引用复制的。这是一个非常困难的任务来做一个深复制,因为这是一个嵌套的对象,我还需要在其中的函数。但即使我以某种方式做了这个任务,这将是一个内存管理噩梦,因为有很多图表在页面上。
如果你以前做过类似的事情,请分享一个更好的方法。

rjzwgtxy

rjzwgtxy1#

一个 * 快速的解决方案 * 是克隆对象的所需部分,使用方便的函数JSON.parseJSON.stringify,这很容易,并确保它打破了所有的引用(如mentioned on mdn)。

container.querySelectorAll('canvas').forEach(canv => {
    const chartOptions = JSON.parse(JSON.stringify(chartConfigs[canv.dataset.type]));
    chartOptions.data.datasets[0].data = JSON.parse(canv.dataset.data);
    if(canv.dataset.labels != undefined){
        chartOptions.data.labels = JSON.parse(canv.dataset.labels);

    console.log(JSON.stringify(chartOptions));
    new Chart(canv, chartOptions);
});

因为我看不到对象chartOptions中的任何函数,所以序列化和反序列化应该没有问题吧?

更新,对于具有函数的对象 (针对您的特定情况)

我看到两个简单的选择,
1.只从基对象中提取函数并传递当前对象
1.或者如果你不想改变chartConfigs对象,就使用prototype函数calllink to documentation)。换句话说,把函数调用改为:

// clone
const chartOptions = JSON.parse(JSON.stringify(chartConfigs[canv.dataset.type]));
...
let id = 1;
let value = 100;

// call the function
chartConfigs[chartOptions.typ].testFunction.call(chartOptions, id, value);
...
  • (如果testFunction是一个函数,具有2个参数(idvalue))*

不是很性感,但是一个快速的解决方案,将需要很少的代码修改.

相关问题