如何只使用一个d3.json().就可以使用多个不同的柱状图?

pnwntuvh  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(155)

要在一个.js文件中创建多个图表而不出现变量名问题,一种方法是将它们封装在不同的函数中,然后在文件的末尾调用它们,如下图所示:

function barchart2() {
    //your amazing chart code here
}

function barchart2() {
    //your amazing chart code here
}

function barchart3() {
    //your amazing chart code here
}

//plot charts
barchart1();
barchart2();
barchart3();

当你这样做的时候,你会发现图表中有很多重复,编程中最重要的原则之一是不要重复自己(DRY),主要是如果你在团队中工作,并且不想在维护和开发代码的时候发疯的话。
下面您可以看到一个示例,其中的一部分代码与所有其他图表相同,位于文件的开头,因此可重复用于所有图表。

//set the dimensions and margins of the svg for ALL charts and maps
const MARGIN = {top: 16, right: 0, bottom: 32, left: 64},
    WIDTH  = 640 - MARGIN.left - MARGIN.right,
    HEIGHT = 320 - MARGIN.top - MARGIN.bottom;

//set scales for ALL barcharts
const X = d3.scaleBand()
    .range([0, WIDTH])
    .paddingInner(0.04)
    .paddingOuter(0.02);

const Y = d3.scaleLinear()
    .range([HEIGHT, 0]);

//the above part is common for ALL charts, goes outside the function in the beginning of the file

但奇怪的是,所有图表都从同一个数据源接收数据,那么我们怎么能只调用一次数据,而不需要对每个数据重复一遍又一遍的承诺呢?

function barchart1() {

    //get data
    d3.json("data.json").then(function(data) { //this part is the same in all 3 charts except for a small part (see comment below)
        //format data
        data.forEach(function(d) {
            d.votes = Number(d.votes);
            d.tt_votes = Number(d.tt_votes);
        });

        const selectedData = [...new Map(data.map(item => [item['code'], item]))
            .values()]
            .sort((a, b) => d3.ascending(a.code, b.code)); //sort list by code

        //plot chart on page first load
        update(data); //calls update function

        let dropdown = d3.select("#select1") //THIS ONLY LINE IS NOT THE SAME IN THE DIFFERENT CHARTS

        //add the options to the dropdown
        dropdown
            .selectAll('myOptions')
            .data(selectedData)
            .enter()
            .append("option")
            .text(function (d) { return d.state_name; }) //text showed in the options
            .attr("value", function (d) { return d.state_code; }) //value of each option
            .property("selected", function(d) { //select state_code === 33 as default
                return d.state_code === 33;
            });

        //calls update function to plot the chart the first time page is load
        update(data);
    })
    
    function update(data){
        //update code goes here
        ...
    }
}

function barchart2() {
    //here the same excepted for let dropdown = d3.select("#select2")
}

function barchart3() {
    //here the same excepted for let dropdown = d3.select("#select3")
}

//plot charts
barchart1();
barchart2();
barchart3();

为了更清楚和简单,我们可以只集中在这一部分找到一个解决方案(这是所有图表的基本和共同点):

//get data
    d3.json("data.json").then(function(data) { //this part is the same in all 3 charts except for a small part (see comment below)
        //format data
        data.forEach(function(d) {
            d.votes = Number(d.votes);
            d.tt_votes = Number(d.tt_votes);
        });

        //calls update function to plot the chart the first time page is load
        update(data);
    })

我试着剪切d3.json("data.json").then(function(data) { etc.,把它放在一个函数中,然后调用这个函数,但是这不起作用,因为我们不能到达内部函数result var。它总是未定义的。这个案例有什么线索吗?

1l5u6lss

1l5u6lss1#

JS的作用域是词法上的,因此如果在promise的作用域中定义函数,则可以使用data参数。

d3.json("data.json").then(function(data) {
    /// you can do data prep and make scales here
    function barchart1() {
    // you can refer to data now
    }
    function barchart2() {
    // you can refer to data now
    }

    barchart1();
    barchart2();

})

相关问题