D3.js饼图..选择时可以切片移动吗?

时间:2014-10-07 10:53:34

标签: javascript d3.js charts pie-chart

只是想知道是否可以用d3做这样的事情?

http://jsfiddle.net/8T7Ew/

当您点击某个饼图切片时,切片会单击?

到目前为止创建饼图只是想知道我是否可以添加此功能

<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  font: 10px sans-serif;
}

.arc path {
  stroke: #fff;
}

</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var width = 960,
    height = 500,
    radius = Math.min(width, height) / 2;

var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

var arc = d3.svg.arc()
    .outerRadius(radius - 10)
    .innerRadius(0);

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.population; });

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

d3.csv("data.csv", function(error, data) {

  data.forEach(function(d) {
    d.population = +d.population;
  });

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

  g.append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color(d.data.age); });

  g.append("text")
      .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
      .attr("dy", ".35em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.data.age; });

});

</script>

数据来自csv文件。

由于

3 个答案:

答案 0 :(得分:11)

您可以增加饼图的圆弧半径以突出显示。 JSFiddle

var arcOver = d3.svg.arc()
    .outerRadius(r + 10);

g.append("path")
   .attr("d", arc)
   .style("fill", function(d) { return color(d.data.age); })
   .on("mouseenter", function(d) {
        d3.select(this)
           .attr("stroke","white")
           .transition()
           .duration(1000)
           .attr("d", arcOver)             
           .attr("stroke-width",6);
    })
    .on("mouseleave", function(d) {
        d3.select(this).transition()            
           .attr("d", arc)
           .attr("stroke","none");
    });

答案 1 :(得分:2)

我更喜欢更改 Radius 而不是笔画,因为它可以为您提供流畅,更好的动画......

使用这样的函数:

function pathEnter() {
  t = d3.select(this);
  t.transition()
  .attr('d', pathIn);
}

运行以下代码以查看互动:

&#13;
&#13;
<!DOCTYPE html>
<meta charset="utf-8">
<style>
  .arc text {
    font: 10px sans-serif;
    text-anchor: middle;
  }
  
  .arc path {
    stroke: #fff;
  }
</style>
<svg width="520" height="280"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
  var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height"),
    radius = Math.min(width, height) / 2 - 20,
    g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


  var color = d3.scaleOrdinal(d3.schemeCategory10);

  var pie = d3.pie()
    .sort(null)
    .value(function(d) {
      return d.population;
    });

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

  var pathIn = d3.arc()
    .outerRadius(radius + 6)
    .innerRadius(0);


  function pathEnter() {
    t = d3.select(this);
    t.transition()
      .attr('d', pathIn);
  }

  function pathOut() {
    t = d3.select(this);
    t.transition()
      .attr('d', path);
  }

  var label = d3.arc()
    .outerRadius(radius - 40)
    .innerRadius(radius - 40);


  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'
    },
  ];

  data.population = +data.population;

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


  arc.append("path")
    .attr("d", path)
    .on('mouseenter', pathEnter)
    .on('mouseout', pathOut)
    .attr("fill", function(d) {
      return color(d.data.age);
    });

  arc.append("text")
    .attr("transform", function(d) {
      return "translate(" + label.centroid(d) + ")";
    })
    .attr("dy", "0.35em")
    .text(function(d) {
      return d.data.age;
    });
</script>
&#13;
&#13;
&#13;

答案 2 :(得分:2)

使用属性 transform =&#34; translate(x,y)&#34; 可以实际移动每个切片。

http://jsfiddle.net/qkHK6/3306/

以@Gilsha的答案为基础(我知道这个问题已经过时了,但我认为我已将此答案用于存档目的)...

g.append("path")
    .attr("d", arc)
    .attr("opacity", "1.0")
    .on("mouseenter", function (d) {
        var arcOver = d3.arc()
            .outerRadius(radius).innerRadius(0).startAngle(d.startAngle + 0.01).endAngle(d.endAngle - 0.01);
        var transformText = getTranslate(d.startAngle + 0.01, d.endAngle - 0.01, 20);

        d3.select(this)
            .attr("d", arcOver)
            .transition()
            .duration(200).ease(d3.easeBack)
            .attr("transform", transformText)
            .attr("style", "fill: rgb(102, 102, 102)");
    })
    .on("mouseleave", function (d) {
        d3.select(this)
            .attr("d", arc)
            .transition().ease(d3.easeBack)
            .duration(600)
            .attr("transform", "translate(0,0)")
            .attr("style", "fill: " + color(d.data));
    })
    .style("fill", function (d) { return color(d.data); });

同样 d3.arc()来自版本4.

以下助手方法:

getTranslate = function (startAngle, endAngle, distance) {
    var xTranslate, yTranslate;
    var startQ = getQuadrant(startAngle);
    var endQ = getQuadrant(endAngle);

//Assume there are 7 possibilities since last slice always ends at Tau or 12 o'clock when doing a d.endAngle
    switch (true) {
        case (startQ == 1 && endQ == 1):
            xTranslate = distance * 0.5;
            yTranslate = distance * -1.5;
            break;
        case (startQ == 1 && endQ == 4):
            xTranslate = distance * 1.5;
            yTranslate = distance * 0.5;
            break;
        case (startQ == 4 && endQ == 4):
            xTranslate = distance * 0.5;
            yTranslate = distance * 1.5;
            break;
        case (startQ == 4 && endQ == 3):
            xTranslate = distance * -0.5;
            yTranslate = distance * 1.5;
            break;
        case (startQ == 3 && endQ == 3):
            xTranslate = distance * -1.5;
            yTranslate = distance * 0.5;
            break;
        case (startQ == 3 && endQ == 2):
            xTranslate = distance * -1.5;
            yTranslate = distance * -0.5;
            break;
        case (startQ == 2 && endQ == 2):
            xTranslate = distance * -0.5;
            yTranslate = distance * -1.5;
            break;
    }

    return "translate(" + xTranslate + "," + yTranslate + ")";
}

getQuadrant = function (angle) {
    switch (true) {
        case angle < (Math.PI * 0.5):
            return 1;
            break;
        case angle >= (Math.PI * 1.5):
            return 2;
            break;
        case ((Math.PI < angle) && angle <= (Math.PI * 1.5)):
            return 3;
            break;
        default:
            return 4;
    }
}