D3绕圆形饼图绘制线条

时间:2020-03-20 13:53:55

标签: javascript d3.js

给出一个带有圆弧的饼图,我想在每个圆弧的中心点附加直线以遵循路径。我目前可以在路径上正确地附加线条,但不能适当地倾斜它们。我在饼图周围有一组圆,需要将这些线放置在圆的下方,在第一个圆与下一个圆之间的中点处。这是我要执行的操作的大致图像,线条应在圆弧的中心,但在圆的下方,并沿着圆弧的路径。 D3 lines around a pie chart

这是我当前使用代码获得的结果。我正在尝试使深黑色线条跟随与您在中心看到的浅灰色线条相似的旋转。

enter image description here

const startAngle = (-45 * Math.PI) / 180;
const endAngle = (-45 * Math.PI) / 180 + 2 * Math.PI;
const width = 500;
const height = Math.min(width, 500);
const viewBox = [-width / 2, -height / 2, width, height];

const svg = d3
    .select("#canvas")
    .append("svg")
    .attr("viewBox", viewBox);

function drawGridDonut(svg, innerFactor, outerFactor) {
  const radius = Math.min(width, height) / 2;
  const graph = new Array(6); // 6 equal sections

  const gridPie = d3
    .pie()
    .startAngle(startAngle)
    .endAngle(endAngle)
    .sort(null)
    .value(1);

  const arc = d3
    .arc()
    .innerRadius(radius * innerFactor)
    .outerRadius(radius * outerFactor);

  // base path + arc
  svg
    .append("g")
    .attr("class", "grid")
    .selectAll("path")
    .data(gridPie(graph))
    .join("path")
    .attr("stroke-width", 1)
    .attr("fill", "none")
    .attr("d", arc);

  // border lines
  svg
    .selectAll(".grid")
    // border lines, 1 = dark border, 0 = light border
    .data(gridPie([1, 0, 1, 0, 1, 0]))
    .append("line")
    .attr("x1", 0)
    .attr("y1", 0)
    .attr(
      "y2",
      d =>
        Math.sin(d.startAngle - Math.PI / 2) *
        (radius - (d.data === 1 ? 0 : 75.5))
    )
    .attr(
      "x2",
      d =>
        Math.cos(d.startAngle - Math.PI / 2) *
        (radius - (d.data === 1 ? 0 : 75.5))
    )
    .attr("stroke", d => (d.data === 0 ? "#C8C8C8" : "#000"))
    .attr("stroke-width", "0.1");


  // dots for overuse + benefits
  svg
    .selectAll(".dot")
    .data(gridPie([...Array(12)]))
    .enter()
    .append("circle")
    .attr('class', '.dot')
    .attr("cx", d => arc.centroid(d)[0])
    .attr("cy", d => arc.centroid(d)[1])
    .attr("r", 1)
    .style("fill", "#C8C8C8");

// this is where the lines are being made
  svg
      .selectAll('.hash')
      .data(gridPie([...Array(12)]))
      .enter()
      .append('line')
      .attr('class', '.hash')
      .attr('d', arc)
      .attr("x1", (d) => arc.centroid(d)[0] - d.startAngle)
      .attr("y1", (d) => arc.centroid(d)[1] - d.startAngle)
      .attr('x2', d =>  arc.centroid(d)[0] + d.endAngle )
      .attr('y2', d => arc.centroid(d)[1] + d.endAngle)
      .attr('width', 10)
      .attr('height', 4)
      .attr("stroke", "black")
      .attr('transform', (d) => 'rotate(180)')

}

for (let i = 0; i < 6; i++) {
  drawGridDonut(svg, 0.9 - 0.04, 0.9 + 0.002)
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="canvas"></div>

1 个答案:

答案 0 :(得分:0)

我通过在饼的中心到顶部绘制一条线,然后添加破折号数组(对内外圆弧进行微调以标记安全空间)来解决此问题。

function drawHyphen(svg, innerFactor, outerFactor, dashPercent) {
  const radius = Math.min(width, height) / 2;

  const gridPie = d3
    .pie()
    .startAngle(startAngle)
    .endAngle(endAngle)
    .sort(null)
    .value(1);

  svg
  .selectAll('.line')
  .data(gridPie([...Array(12)]))
  .enter()
  .append("line")
  .attr('class', (d, i) => `line${i}`)
  .attr(
    "y1",
    d =>
      Math.sin((d.startAngle) - Math.PI / 4) * radius * innerFactor
  )
  .attr(
    "x1",
    d =>
      Math.cos((d.startAngle) - Math.PI / 4) * radius * innerFactor
  )
  .attr(
    "y2",
    d =>
      Math.sin((d.startAngle) - Math.PI / 4) * radius / outerFactor
  )
  .attr(
    "x2",
    d =>
      Math.cos((d.startAngle) - Math.PI / 4) * radius / outerFactor
  )
  .attr("stroke", "#EEEEEE")
  .attr("stroke-dasharray", `0.5, ${dashPercent}`)
  .attr("stroke-width", 4)
}

然后,我需要多次调用该函数,并将externalFactor设置为安全空间的阈值。

let outerArc = 1 - 0.051
 drawHyphen(svg, outerArc - 0.835, outerArc - 2.3, "1.9%")