d3js:如何在弧线末端放置圆圈

3

我正尝试在d3js中创建甜甜圈图表,其中每个弧的末端都有一个圆。

圆的边缘必须适配于弧的边缘。

我尝试通过附加圆和包含标记的圆来实现,但均未成功。

尝试附加标记似乎是最接近所需解决方案的方法,但我无法控制标记溢出弧的边缘。

代码:

var data = [
  {
    name: "punti",
    count: 3,
    color: "#fff000"
  },
  {
    name: "max",
    count: 7,
    color: "#f8b70a"
  }
];
var totalCount = data.reduce((acc, el) => el.count + acc, 0);
var image_width = 32;
var image_height = 32;
var width = 540,
  height = 540,
  radius = 200,
  outerRadius = radius - 10,
  innerRadius = 100;
var cornerRadius = innerRadius;
var markerRadius = (outerRadius - innerRadius) / 2;
var arc = d3
  .arc()
  .outerRadius(outerRadius)
  .innerRadius(innerRadius)
  .cornerRadius(cornerRadius);

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

var svg = d3
  .select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var pieData = pie(data);
var g = svg
  .selectAll(".arc")
  .data(pieData)
  .enter()
  .append("g");

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

var marker = svg
  .append("defs")
  .append("marker")
  .attr("id", "endmarker")
  .attr("overflow", "visible")
  .append("circle")
  .attr("cy", 0)
  .attr("cx", 0)
  .attr("r", markerRadius)
  .attr("fill", "red");
g.attr("marker-end", "url(#endmarker)");

g
  .append("circle")
  .attr("cx", function(d) {
    let path = d3.select(this.parentNode);
    var x = arc.centroid(d)[0];
    return x;
  })
  .attr("cy", function(d) {
    var y = arc.centroid(d)[1];
    console.log(d3.select(this).attr("cx"));
    return y;
  })
  .attr("fill", d => d.data.color)
  .attr("stroke", "black")
  .attr("r", (outerRadius - innerRadius) / 2);

这里是codepen链接

感谢任何愿意帮助的人!


你能放一张你想要的最终结果的图片吗? - Coola
1个回答

3
假设您想要输出结果如下: enter image description here 我在Mike Bostock的代码块中找到了一些代码,用于向圆弧角添加圆形
我为您调整了以下代码,其中包含相当复杂的数学运算。
var cornerRadius = (outerRadius - innerRadius)/2;
svg.append("g")
    .style("stroke", "#555")
    .style("fill", "none")
    .attr("class", "corner")
  .selectAll("circle")
    .data(d3.merge(pieData.map(function(d) {
      return [
        {angle: d.startAngle + d.padAngle / 2, radius: outerRadius - cornerRadius, start: +1},
        {angle:   d.endAngle - d.padAngle / 2, radius: outerRadius - cornerRadius, start: -1},
      ];
    })))
  .enter().append("circle")
    .attr("cx", function(d) { return d.start * cornerRadius * Math.cos(d.angle) + Math.sqrt(d.radius * d.radius - cornerRadius * cornerRadius) * Math.sin(d.angle); })
    .attr("cy", function(d) { return d.start * cornerRadius * Math.sin(d.angle) - Math.sqrt(d.radius * d.radius - cornerRadius * cornerRadius) * Math.cos(d.angle); })
    .attr("r", cornerRadius);

完整代码段显示输出:

<div id="chart"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.min.js"></script>
<script>
var data = [
  {
    name: "punti",
    count: 3,
    color: "#fff000"
  },
  {
    name: "max",
    count: 7,
    color: "#f8b70a"
  },
];
var totalCount = data.reduce((acc, el) => el.count + acc, 0);
var image_width = 32;
var image_height = 32;
var width = 540,
  height = 540,
  radius = 200,
  outerRadius = radius - 10,
  innerRadius = 100;
var cornerRadius = innerRadius;
var markerRadius = (outerRadius - innerRadius) / 2;
var arc = d3
  .arc()
  .outerRadius(outerRadius)
  .innerRadius(innerRadius)
  .cornerRadius(cornerRadius);

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

var svg = d3
  .select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var pieData = pie(data);
var g = svg
  .selectAll(".arc")
  .data(pieData)
  .enter()
  .append("g");

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

var cornerRadius = (outerRadius - innerRadius)/2;
svg.append("g")
    .style("stroke", "#555")
    .style("fill", "none")
    .attr("class", "corner")
  .selectAll("circle")
    .data(d3.merge(pieData.map(function(d) {
      return [
        {angle: d.startAngle + d.padAngle / 2, radius: outerRadius - cornerRadius, start: +1},
        {angle:   d.endAngle - d.padAngle / 2, radius: outerRadius - cornerRadius, start: -1},
      ];
    })))
  .enter().append("circle")
    .attr("cx", function(d) { return d.start * cornerRadius * Math.cos(d.angle) + Math.sqrt(d.radius * d.radius - cornerRadius * cornerRadius) * Math.sin(d.angle); })
    .attr("cy", function(d) { return d.start * cornerRadius * Math.sin(d.angle) - Math.sqrt(d.radius * d.radius - cornerRadius * cornerRadius) * Math.cos(d.angle); })
    .attr("r", cornerRadius);
  
  
</script>


1
谢谢,这正是我需要实现的。非常感谢。 - lbrutti
太棒了。很高兴它是你想要的,我不完全确定那是否是你想要的结果。 - Coola

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接