如何在向下钻取饼图中添加额外的级别

  • 本文关键字:添加 钻取 d3.js drilldown
  • 更新时间 :
  • 英文 :


我有一个使用 d3.js 的很好的向下钻取图表,但我想添加一个(或多个)更深的级别。

我可以看到如何有一个级别 0(开始状态)和一个级别 1(单击更深),但我似乎无法弄清楚如何将其实现到级别 2 状态(两次向下单击)。

有人可以告诉我怎么做吗?到目前为止,我已经有了这个:https://jsfiddle.net/yLsg841u/5/

<script type="text/javascript">
var salesData;
var chartInnerDiv = '<div class="innerCont" style="overflow: auto;top:100px; left: 400px; height:91% ; Width:100% ;position: relative;overflow: hidden;"/>';
var truncLengh = 30;
$(document).ready(function () {
    Plot();
});
function Plot() {
    TransformChartData(chartData, chartOptions, 0);
    BuildPie("chart", chartData, chartOptions, 0)
}
function BuildPie(id, chartData, options, level) {
    var xVarName;
    var divisionRatio = 2.5;
    var legendoffset = (level == 0) ? 0 : -40;
    d3.selectAll("#" + id + " .innerCont").remove();
    $("#" + id).append(chartInnerDiv);
    chart = d3.select("#" + id + " .innerCont");
    var yVarName = options[0].yaxis;
    width = $(chart[0]).outerWidth(),
    height = $(chart[0]).outerHeight(),
    radius = Math.min(width, height) / divisionRatio;
    if (level == 1) {
        xVarName = options[0].xaxisl1;
    }
    else {
        xVarName = options[0].xaxis;
    }
    var rcolor = d3.scale.ordinal().range(runningColors);
    arc = d3.svg.arc()
            .outerRadius(radius)
            .innerRadius(radius - 200);
    var arcOver = d3.svg.arc().outerRadius(radius + 20).innerRadius(radius - 180);
    chart = chart
            .append("svg")  //append svg element inside #chart
            .attr("width", width)    //set width
            .attr("height", height)  //set height
            .append("g")
            .attr("transform", "translate(" + (width / divisionRatio) + "," + ((height / divisionRatio) + 30) + ")");
    var pie = d3.layout.pie()
                .sort(null)
                .value(function (d) {
                    return d.Total;
                });
    var g = chart.selectAll(".arc")
                .data(pie(runningData))
                .enter().append("g")
                .attr("class", "arc");
    var count = 0;
    var path = g.append("path")
                .attr("d", arc)
                .attr("id", function (d) { return "arc-" + (count++); })
                .style("opacity", function (d) {
                    return d.data["op"];
                });
    path.on("mouseenter", function (d) {
        d3.select(this)
            .attr("stroke", "white")
            .transition()
            .duration(200)
            .attr("d", arcOver)
            .attr("stroke-width", 1);
    })
     .on("mouseleave", function (d) {
         d3.select(this).transition()
             .duration(200)
             .attr("d", arc)
             .attr("stroke", "none");
     })
     .on("click", function (d) {
         if (this._listenToEvents) {
             // Reset inmediatelly
             d3.select(this).attr("transform", "translate(0,0)")
             // Change level on click if no transition has started
             path.each(function () {
                 this._listenToEvents = false;
             });
         }
         d3.selectAll("#" + id + " svg").remove();
         if (level == 1) {
             TransformChartData(chartData, options, 0, d.data[xVarName]);
             BuildPie(id, chartData, options, 0);
         }
         else {
             var nonSortedChart = chartData.sort(function (a, b) {
                 return parseFloat(b[options[0].yaxis]) - parseFloat(a[options[0].yaxis]);
             });
             TransformChartData(nonSortedChart, options, 1, d.data[xVarName]);
             BuildPie(id, nonSortedChart, options, 1);
         }
     });
    path.append("svg:title")
    .text(function (d) {
        return d.data["title"] + " (" + d.data[yVarName] + ")";
    });
    path.style("fill", function (d) {
        return rcolor(d.data[xVarName]);
    })
     .transition().duration(1000).attrTween("d", tweenIn).each("end", function () {
         this._listenToEvents = true;
     });

    g.append("text")
     .attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
     .attr("dy", ".35em")
     .style("text-anchor", "middle")
     .style("opacity", 1)
     .text(function (d) {
         return d.data[yVarName];
     });
    count = 0;
    var legend = chart.selectAll(".legend")
        .data(runningData).enter()
        .append("g").attr("class", "legend")
        .attr("legend-id", function (d) {
            return count++;
        })
        .attr("transform", function (d, i) {
            return "translate(15," + (parseInt("-" + (runningData.length * 10)) + i * 28 + legendoffset) + ")";
        })
        .style("cursor", "pointer")
        .on("click", function () {
            var oarc = d3.select("#" + id + " #arc-" + $(this).attr("legend-id"));
            oarc.style("opacity", 0.3)
            .attr("stroke", "white")
            .transition()
            .duration(200)
            .attr("d", arcOver)
            .attr("stroke-width", 1);
            setTimeout(function () {
                oarc.style("opacity", function (d) {
                    return d.data["op"];
                })
               .attr("d", arc)
               .transition()
               .duration(200)
               .attr("stroke", "none");
            }, 1000);
        });
    var leg = legend.append("rect");
    leg.attr("x", width / 2)
        .attr("width", 18).attr("height", 18)
        .style("fill", function (d) {
            return rcolor(d[yVarName]);
        })
        .style("opacity", function (d) {
            return d["op"];
        });
    legend.append("text").attr("x", (width / 2) - 5)
        .attr("y", 9).attr("dy", ".35em")
        .style("text-anchor", "end").text(function (d) {
            return d.caption;
        });
    leg.append("svg:title")
    .text(function (d) {
        return d["title"] + " (" + d[yVarName] + ")";
    });
    function tweenOut(data) {
        data.startAngle = data.endAngle = (2 * Math.PI);
        var interpolation = d3.interpolate(this._current, data);
        this._current = interpolation(0);
        return function (t) {
            return arc(interpolation(t));
        };
    }
    function tweenIn(data) {
        var interpolation = d3.interpolate({ startAngle: 0, endAngle: 0 }, data);
        this._current = interpolation(0);
        return function (t) {
            return arc(interpolation(t));
        };
    }
}
function TransformChartData(chartData, opts, level, filter) {
    var result = [];
    var resultColors = [];
    var counter = 0;
    var hasMatch;
    var xVarName;
    var yVarName = opts[0].yaxis;
    if (level == 1) {
        xVarName = opts[0].xaxisl1;
        for (var i in chartData) {
            hasMatch = false;
            for (var index = 0; index < result.length; ++index) {
                var data = result[index];
                if ((data[xVarName] == chartData[i][xVarName]) && (chartData[i][opts[0].xaxis]) == filter) {
                    result[index][yVarName] = result[index][yVarName] + chartData[i][yVarName];
                    hasMatch = true;
                    break;
                }
            }
            if ((hasMatch == false) && ((chartData[i][opts[0].xaxis]) == filter)) {
                if (result.length < 9) {
                    ditem = {}
                    ditem[xVarName] = chartData[i][xVarName];
                    ditem[yVarName] = chartData[i][yVarName];
                    ditem["caption"] = chartData[i][xVarName].substring(0, 10) + '...';
                    ditem["title"] = chartData[i][xVarName];
                    ditem["op"] = 1.0 - parseFloat("0." + (result.length));
                    result.push(ditem);
                    resultColors[counter] = opts[0].color[0][chartData[i][opts[0].xaxis]];
                    counter += 1;
                }
            }
        }
    }
    else {
        xVarName = opts[0].xaxis;
        for (var i in chartData) {
            hasMatch = false;
            for (var index = 0; index < result.length; ++index) {
                var data = result[index];
                if (data[xVarName] == chartData[i][xVarName]) {
                    result[index][yVarName] = result[index][yVarName] + chartData[i][yVarName];
                    hasMatch = true;
                    break;
                }
            }
            if (hasMatch == false) {
                ditem = {};
                ditem[xVarName] = chartData[i][xVarName];
                ditem[yVarName] = chartData[i][yVarName];
                ditem["caption"] = opts[0].captions != undefined ? opts[0].captions[0][chartData[i][xVarName]] : "";
                ditem["title"] = opts[0].captions != undefined ? opts[0].captions[0][chartData[i][xVarName]] : "";
                ditem["op"] = 1;
                result.push(ditem);
                resultColors[counter] = opts[0].color != undefined ? opts[0].color[0][chartData[i][xVarName]] : "";
                counter += 1;
            }
        }
    }

    runningData = result;
    runningColors = resultColors;
    return;
}
chartOptions = [{
    "captions": [{ "INDIA": "INDIA", "CANADA": "CANADA", "USA": "USA" }],
    "color": [{ "INDIA": "#FFA500", "CANADA": "#0070C0", "USA": "#ff0000" }],
    "xaxis": "Country",
    "xaxisl1": "Model",
    "yaxis": "Total"
}]
var chartData = [
    {
        "Country": "USA",
        "Model": "Model 1",
        "Total": 487
    },
    {
        "Country": "USA",
        "Model": "Model 2",
        "Total": 185
    },
    {
        "Country": "USA",
        "Model": "Model 3",
        "Total": 140
    },
    {
        "Country": "USA",
        "Model": "Model 4",
        "Total": 108
    },
    {
        "Country": "USA",
        "Model": "Model 5",
        "Total": 26
    },
    {
        "Country": "USA",
        "Model": "Model 6",
        "Total": 106
    },
    {
        "Country": "USA",
        "Model": "Model 7",
        "Total": 27
    },
    {
        "Country": "USA",
        "Model": "Model 8",
        "Total": 44
    },
    {
        "Country": "USA",
        "Model": "Model 9",
        "Total": 96
    },
    {
        "Country": "INDIA",
        "Model": "Model 1",
        "Total": 411
    },
    {
        "Country": "INDIA",
        "Model": "Model 2",
        "Total": 33
    },
    {
        "Country": "INDIA",
        "Model": "Model 3",
        "Total": 32
    },
    {
        "Country": "INDIA",
        "Model": "Model 4",
        "Total": 29
    },
    {
        "Country": "INDIA",
        "Model": "Model 5",
        "Total": 29
    },
    {
        "Country": "CANADA",
        "Model": "Model 1",
        "Total": 7
    },
    {
        "Country": "CANADA",
        "Model": "Model 2",
        "Total": 20
    },
    {
        "Country": "CANADA",
        "Model": "Model 3",
        "Total": 232
    },
    {
        "Country": "CANADA",
        "Model": "Model 4",
        "Total": 117
    }
];

我尝试添加一个级别。首先,确保您有其他级别的 json 数据其次,在chartOptions中提及第二级名称为"xaxisl2":"YourLevelName"最后,为 (level==2) 添加 else if 语句,如下所示:

 TransformChartData(nonSortedChart, options, 2, d.data[xVarName]);
 BuildPie(id, nonSortedChart, options, 2);

其中 xVarName=opts[0].xaxisl2;

最新更新