简体   繁体   中英

How to rotate the D3 chart so that the selected arc is at the bottom?

I am trying to develop an application where users can click on the D3 pie chart and see information which relates to the selection. How can I rotate the arc's so that the clicked arc comes to the bottom (the centre of the arc clicked on should be at the bottom)? I have been playing around with rotating the pie by selecting the arc group but I would appreciate any idea on how to achieve this. Here is some code I have so far.

 var self = this;
    var instanceId = Math.floor(Math.random() * 100000);

    var margin = {
        top: 5,
        right: 15,
        bottom: 50,
        left: 20
    };

    self.width = this.htmlElement.parentElement.parentElement.offsetWidth - margin.right - margin.left;
    self.height =   window.innerHeight / 3 ;
    self.curAngle = 0;

    self.svgParent.html("<h4 style='color:green;'>Sponsors </h4><br>");

    // Update data for the chart
    self.updateChartData = function () {

        if(!self.svg) {
            this.svg = this.svgParent
                .classed("svg-container", true)
                .append("svg")
                .attr("preserveAspectRatio", "xMinYMin meet")
                .attr("viewBox", "0 0 " + this.width + " " + this.height)
                .append("g")
                .classed("svg-content-responsive", true);
                //.attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")");
        }

        var svgg = this.svg
          .append("g")
          .classed("svg-content-responsive", true)
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        self.svg.selectAll(".arctext").remove();
        self.svg.selectAll(".pie-widget-total-label").remove();

        var pie = d3.pie().sort(sort)(self.selectedData.map(function (d: any) {
            return d.count;
        }));

        var path = d3.arc()
            .outerRadius(radius)
            .innerRadius(radius / 2);

        var outsideLabel = d3.arc()
            .outerRadius(radius * 0.9)
            .innerRadius(radius * 0.9);

        var middleLabel = d3.arc()
            .outerRadius(radius * 0.75)
            .innerRadius(radius * 0.75);

        var insideLabel = d3.arc()
            .outerRadius(radius * 0.6)
            .innerRadius(radius * 0.6);

        var g = self.svg
            .attr("width", self.width + margin.left + margin.right)
            .attr("height", self.height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");

        var defs = g.append("defs");

        var lightGradients = defs.selectAll(".arc")
            .data(pie)
            .enter()
            .append("radialGradient")
            .attr("id", function (d: any) {
                return "lightGradient-" + instanceId + "-" + d.index;
            })
            .attr("gradientUnits", "userSpaceOnUse")
            .attr("cx", "0")
            .attr("cy", "0")
            .attr("r", "120%");

        var darkGradients = defs.selectAll(".arc")
            .data(pie)
            .enter()
            .append("radialGradient")
            .attr("id", function (d: any) {
                return "darkGradient-" + instanceId + "-" + d.index;
            })
            .attr("gradientUnits", "userSpaceOnUse")
            .attr("cx", "0")
            .attr("cy", "0")
            .attr("r", "120%");

        lightGradients.append("stop")
            .attr("offset", "0%")
            .attr("style", function (d: any) {
                return "stop-color: " + d3.color(color(d.index)) + ";";
            });

        lightGradients.append("stop")
            .attr("offset", "100%")
            .attr("style", function (d: any) {
                return "stop-color: black;";
            });

        darkGradients.append("stop")
            .attr("offset", "0%")
            .attr("style", function (d: any) {
                return "stop-color: " + d3.color(color(d.index)).darker(0.5) + ";";
            });

        darkGradients.append("stop")
            .attr("offset", "100%")
            .attr("style", function (d: any) {
                return "stop-color: black;";
            });

        self.tooltip = d3.select("body")
            .append("div")
            .attr("class", "pie-widget-tooltip")
            .style("opacity", 0);

        self.arc = g.selectAll(".arc")
            .data(pie)
            .enter()
            .append("g")
            .attr("class", "arc");

        var arcpath = self.arc.append("path")
            .attr("id", function (d: any) {
                return d.index;
            })
            .attr("d", path)
            .attr("stroke", "white")
            .attr("stroke-width", "2px")
            .attr("fill", function (d: any) {
                return "url(#lightGradient-" + instanceId + "-" + d.index + ")";
            })
            .on("click", function (d: any) {
                console.log("About to send::::" + getStudyLabel(d.index));
                self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
                self.showDialog();
                self.rotateChart();
             })

            .transition()
            .duration(function(d:any, i:any) {
                return i * 800;
            })
            .attrTween('d', function(d:any) {
                var i = d3.interpolate(d.startAngle + 0.1, d.endAngle);
                return function (t: any) {
                    d.endAngle = i(t);
                    return path(d);
                }
            });

        function arcTween(a: any) {
            var i = d3.interpolate(this._current, a);
            this._current = i(0);
            return function(t: any) {
                return path(i(t));
            };
        }

        var gtext = self.svg
            .append("g")
            .attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");

        var arctext = gtext.selectAll(".arctext")
            .data(pie)
            .enter()
            .append("g")
            .attr("class", "arctext");

        var primaryLabelText = arctext.append("text")
          .on("click", function (d: any) {
            console.log("About to send::::" + getStudyLabel(d.index));
            self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
            self.showDialog();
          })
            .transition()
            .duration(750)
            .attr("transform", function (d: any) {
                return "translate(" + middleLabel.centroid(d) + ")";
            })
            .attr("dy", "-0.75em")
            .attr("font-family", "sans-serif")
            .attr("font-size", "15px")
            .attr("class", "sponsor-pie-widget-label")
            .text(function (d: any) {
                if (d.endAngle - d.startAngle < 0.3) {
                    return "";
                } else {
                    return getStudyLabel(d.index);
                }
            });

        var secondaryLabelText = arctext.append("text")
          .on("click", function (d: any) {
            console.log("About to send::::" + getStudyLabel(d.index));
            self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
            self.showDialog();
          })
            .transition()
            .duration(750)
            .attr("transform", function (d: any) {
                return "translate(" + middleLabel.centroid(d) + ")";
            })
            .attr("dy", "0.75em")
            .attr("font-family", "sans-serif")
            .attr("font-size", "10px")
            .attr("class", "sponsor-pie-widget-label")
            .text(function (d: any) {
                if (d.endAngle - d.startAngle < 0.3) {
                    return "";
                } else {
                    return getPatientsLabel(d.index);
                }
            });

        var n = 0;
        for (var i = 0; i < self.selectedData.length; i++) {
            n = n + this.selectedData[i]["count"];
        }
        var total = self.svg
            .append("g")
            .attr("transform", "translate(" + (self.width / 2 - 20 ) + "," + self.height / 2 + ")")
        total.append("text")
            .attr("class", "pie-widget-total-label")
            .text("Total\r\n" + n);
    }.bind(self);


    self.showDialog = function() {
        this.router.navigateByUrl('/myRouteName');
    }.bind(self);

    self.rotateChart = function() {
      self.arc.attr("transform", "rotate(-45)");
    }.bind(self);

You could rotate the arcs by changing their start/end angles as appropriate, but this would be more complex than needed.

A simpler solution would be to just rotate a g that holds the entire pie chart, at the same time, rotate any labels the other way so they remain level.

I've just used the canonical pie chart from this block as an example:

 var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), radius = Math.min(width, height) / 2, g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]); var data = [ {age:"<5", population: 2704659},{age:"5-13", population: 4499890},{age:"14-17", population: 2159981},{age:"18-24", population: 3853788},{age:"25-44", population: 14106543},{age:"45-64", population: 8819342},{age:"≥65", population: 612463} ] var pie = d3.pie() .sort(null) .value(function(d) { return d.population; }); var path = d3.arc() .outerRadius(radius - 10) .innerRadius(0); var label = d3.arc() .outerRadius(radius - 40) .innerRadius(radius - 40); var arc = g.selectAll(".arc") .data(pie(data)) .enter().append("g") .attr("class", "arc"); arc.append("path") .attr("d", path) .attr("fill", function(d) { return color(d.data.age); }) .on("click",function(d) { // The amount we need to rotate: var rotate = 180-(d.startAngle + d.endAngle)/2 / Math.PI * 180; // Transition the pie chart g.transition() .attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + rotate + ")") .duration(1000); // Τransition the labels: text.transition() .attr("transform", function(dd) { return "translate(" + label.centroid(dd) + ") rotate(" + (-rotate) + ")"; }) .duration(1000); }); var text = arc.append("text") .attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; }) .attr("dy", "0.35em") .text(function(d) { return d.data.age; }); 
 .arc text { font: 10px sans-serif; text-anchor: middle; } .arc path { stroke: #fff; } 
 <svg width="960" height="500"></svg> <script src="https://d3js.org/d3.v4.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM