如何旋转D3图表以使选定的弧线位于底部? [英] How to rotate the D3 chart so that the selected arc is at the bottom?

查看:46
本文介绍了如何旋转D3图表以使选定的弧线位于底部?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试开发一个应用程序,用户可以单击D3饼图并查看与选择有关的信息.如何旋转圆弧,使单击的圆弧位于底部(单击的圆弧的中心应位于底部)?我一直在通过选择弧线组来旋转饼图,但是对于实现该方法的任何想法,我将不胜感激.这是我到目前为止的一些代码.

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.

一种更简单的解决方案是只旋转保存整个饼图的 g ,同时以其他方式旋转所有标签,以使它们保持水平.

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>

这篇关于如何旋转D3图表以使选定的弧线位于底部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆