如何在D3中的一个页面中更新多个饼图?

时间:2014-03-09 01:09:48

标签: jquery d3.js

我在一个页面中有多个饼图。如何使用单个功能更新它们?这是我到目前为止所做的:

<!DOCTYPE html>
<html>
    <head>
        <title>test</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <style>
            .chart{
                margin: 10px;
                border: 1px solid;                
                height: 100px;
                width: 300px;
            }
        </style>
    </head>
    <body>
        <div class="chart" id="c1"></div>
        <div class="chart" id="c2"></div>
        <div class="chart" id="c3"></div>
        <input type="button" value="update" id="update"/>
        <script src="js/jquery-1.10.2.min.js"></script>
        <script src="js/d3.v3.min.js"></script>
        <script>
            var data1 = [30, 40, 50],
                    data2 = [20, 50, 10],
                    data3 = [10, 10, 10],
                    data4 = [30, 50, 90],
                    data5 = [30, 10, 20],
                    data6 = [10, 60, 20],
                    t = ["yes", "no", "dont know"];
            var createPie = function(div, p, t) {
                var pwidth = $('.chart').width() - 20,
                        pheight = $('.chart').height() - 10,
                        radius = pheight / 2,
                        outerRadius = radius,
                        innerRadius = 10;
                var color = d3.scale.category10();
                var pie = d3.layout.pie().sort(null);
                var arc = d3.svg.arc()
                        .innerRadius(innerRadius)
                        .outerRadius(outerRadius);

                var psvg = d3.select(div)
                        .append("svg")
                        .attr("width", pwidth)
                        .attr("height", pheight)
                        .attr("class", "p");
                var arcs = psvg.selectAll("g.arc")
                        .data(pie(p))
                        .enter()
                        .append("g")
                        .attr("class", "arc")
                        .attr("transform", "translate(" + radius + "," + radius + ")");
                var paths = arcs.append("path")
                        .attr("fill", function(d, i) {
                            return color(i);
                        })
                        .attr("d", arc);
                arcs.append("text")
                        .attr("transform", function(d) {
                            d.innerRadius = radius;
                            return "translate(" + arc.centroid(d) + ")";
                        })
                        .attr("text-anchor", "middle")
                        .text(function(d) {
                            return d.value;
                        })
                        .style("fill", "#fff");
                var legend = psvg.append("g")
                        .attr("class", "legend")
                        .attr("height", 100)
                        .attr("width", 100)
                        .attr('transform', 'translate(-60,10)');
                legend.selectAll('rect')
                        .data(p)
                        .enter()
                        .append("rect")
                        .attr("x", pwidth - 65)
                        .attr("y", function(d, i) {
                            return i * 20;
                        })
                        .attr("width", 10)
                        .attr("height", 10)
                        .style("fill", function(d, i) {
                            return color(i);
                        });
                legend.selectAll('text')
                        .data(p)
                        .enter()
                        .append("text")
                        .attr("x", pwidth - 52)
                        .attr("y", function(d, i) {
                            return i * 20 + 9;
                        })
                        .text(function(d, i) {
                            return t[i];
                        });
            };
            var updatePie = function() {

            }
            $(document).ready(function() {
                createPie('#c1', data1, t);
                createPie('#c2', data2, t);
                createPie('#c3', data3, t);
                $("#update").click(function() {
                    updatePie();
                });
            });
        </script>
    </body>
</html>

我看到了更新examples。但我无法理解如何在更新函数中传递相应饼图的数据数组。

添加了fiidle

2 个答案:

答案 0 :(得分:1)

如果您有多个具有相同布局但数据不同的图表,则可以创建一个<svg><div>个元素,并将它们连接到包含所有数据集的数组。然后,初始化和更新功能都只基于附加数据。因此,更新是一个更新数据并在您选择的图表的每个元素上调用函数的问题。

对于您的示例,这意味着:

//Initialization
var charts = d3.selectAll("div.chart") //pre-existing elements
      .data([{p:data1, t:t}, {p:data2, t:t}, {p:data3, t:t}])
         //note that I have to include the titles within the data object
         //since I can't pass a separate parameter
      .each(createPie);

//The create pie function is changed to take the standard d3 parameters:
var createPie = function(d, i) {
    var div = this;
    var p = d.p; //or you could just use these as needed
    var t = d.t; // (instead of renaming the variables)

    /* and the rest of your code */
}

//An update function would have the same structure
var updatePie = function(d, i) {
    var arcs = d3.select(this).select("svg.p").selectAll("g.arc")
                 .data( pie(d.p) );

    //assuming the only thing that will change is the numbers,
    //and therefore the size of the pie slices:
    arcs.select("path").attr("d", arc);
}

//The update is called after replacing the data on the charts
charts.data([{p:data4, t:t}, {p:data5, t:t}, {p:data6, t:t}])
      .each(updatePie);

通过在整个图表选择上运行初始化和更新函数,而不是在每个元素上运行(即,它们将使用selection.call(update)触发,可以使代码更简洁一些行而不是selection.each(update),然后调用的函数将采用function(selection)而不是function(d,i)的形式。但是上面的内容更接近您现有的初始化代码。

答案 1 :(得分:1)

@ AmeliaBR的解释很有道理(如果我还没有花一些时间在这上面,我可以模仿它)。但是我正在忙着处理它...基本上,我尝试将输入,更新,退出模式应用到原始代码,只需要很少的更改,并且发现很难实现。如果没有足够的时间参与其中,我最终会以严厉的方式将事情放下来并简单地重新构建它们,从而“绕过”这种模式。这是FIDDLE的结果。

我把它放在这里作为答案,因为我确实花了一些时间在它上面,如果你不愿意更改代码的结构,它可能很有用。以下严酷方法的片段:

var updatePie = function (div, p, t) {
    d3.select(div).select("svg").selectAll("g.arc").remove();