【问题标题】:how to align text and labels in D3如何在 D3 中对齐文本和标签
【发布时间】:2021-05-31 11:55:56
【问题描述】:

我正在尝试制作一个看起来像这样的自定义 SVG。

到目前为止,我已经得到了这个。

所有数据都是动态的,所以我试图弄清楚如何使用半径来设置 x/y 轴。我有一个例子

const w = 400,
  h = 400,
  r = 160;

const STREAMS = [{
  label: 'Emissions',
  isSelected: true,
  yAxis: -40
}, {
  label: 'Energy Produced',
  isSelected: false,
  yAxis: -20
}, {
  label: 'Energy Consumed',
  isSelected: false,
  yAxis: 0
}, {
  label: 'Intensity',
  isSelected: false,
  yAxis: 20
}]

const SUB_STREAMS = [{
  value: 0.15,
  label: 'Total',
  isSelected: true
}, {
  value: 0.2,
  label: 'CO2',
  isSelected: false
}, {
  value: 0.25,
  label: 'Methane',
  isSelected: false
}, {
  value: 0.30,
  label: 'N2O',
  isSelected: false
}, {
  value: 0.35,
  label: 'Other',
  isSelected: false
}];

const svg = d3.select("#foo")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

const g = svg.append("g")
  .attr("transform", "translate(" + [w / 2, h / 2] + ")");

g.append("circle")
  .attr("r", r)
  .style("fill", "none")
  .style("stroke", "black");

const points = g.selectAll(null)
  .data(SUB_STREAMS)
  .enter()
  .append("circle")
  .attr('stroke', 'dodgerblue')
  .attr('stroke-width', 1)
  .style("fill", function(d) {
    return d.isSelected ? 'dodgerblue' : 'white'
  })
  .attr("r", 12)
  .attr("cx", function(d) {
    return r * Math.cos(d.value * Math.PI * 2 - Math.PI / 2)
  })
  .attr("cy", function(d) {
    return r * Math.sin(d.value * Math.PI * 2 - Math.PI / 2)
  })

points.on("click", function(d) {
  console.log(d)
})

g.selectAll(null)
  .data(SUB_STREAMS)
  .enter()
  .append('text')
  .style('cursor', 'pointer')
  .style('fill', 'black')
  .attr('text-anchor', 'right')
  .attr('font-size', '1.3em')
  .attr('dx', (d) => r * Math.cos(d.value * Math.PI * 2 - Math.PI / 2))
  .attr('dy', (d) => r * Math.sin(d.value * Math.PI * 2 - Math.PI / 2))
  .text((d) => d.label)

const text = g
  .selectAll('path')
  .data(STREAMS)
  .enter()
  .append("text")
  .attr("text-anchor", "left")
  .attr('font-size', '1em')
  .attr("y", function(d, a) {
    return d.yAxis
  })

  .text((d) => d.label);

text.on("click", function(d) {
  console.log(d)
})


var arc = d3.symbol().type(d3.symbolTriangle)
var line = g.selectAll('path')
  .data(STREAMS)
  .enter()
  .append('path')
  .attr('d', arc)
  .attr('fill', 'red')
  .attr('stroke', '#000')
  .attr('stroke-width', 1)
  .attr('transform', function(d) {
    return `translate(-10,${d.yAxis - 5}) rotate(210)`;
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="foo" />

【问题讨论】:

    标签: javascript html svg d3.js


    【解决方案1】:

    相应地设置dominant-baseline(例如central),并将文本移动圆圈的大小,加上一点填充。

    这是您的代码进行了这些更改:

    const w = 500,
      h = 400,
      r = 160;
    
    const STREAMS = [{
      label: 'Emissions',
      isSelected: true,
      yAxis: -40
    }, {
      label: 'Energy Produced',
      isSelected: false,
      yAxis: -20
    }, {
      label: 'Energy Consumed',
      isSelected: false,
      yAxis: 0
    }, {
      label: 'Intensity',
      isSelected: false,
      yAxis: 20
    }]
    
    const SUB_STREAMS = [{
      value: 0.15,
      label: 'Total',
      isSelected: true
    }, {
      value: 0.2,
      label: 'CO2',
      isSelected: false
    }, {
      value: 0.25,
      label: 'Methane',
      isSelected: false
    }, {
      value: 0.30,
      label: 'N2O',
      isSelected: false
    }, {
      value: 0.35,
      label: 'Other',
      isSelected: false
    }];
    
    const svg = d3.select("#foo")
      .append("svg")
      .attr("width", w)
      .attr("height", h);
    
    const g = svg.append("g")
      .attr("transform", "translate(" + [w / 2, h / 2] + ")");
    
    g.append("circle")
      .attr("r", r)
      .style("fill", "none")
      .style("stroke", "black");
    
    const points = g.selectAll(null)
      .data(SUB_STREAMS)
      .enter()
      .append("circle")
      .attr('stroke', 'dodgerblue')
      .attr('stroke-width', 1)
      .style("fill", function(d) {
        return d.isSelected ? 'dodgerblue' : 'white'
      })
      .attr("r", 12)
      .attr("cx", function(d) {
        return r * Math.cos(d.value * Math.PI * 2 - Math.PI / 2)
      })
      .attr("cy", function(d) {
        return r * Math.sin(d.value * Math.PI * 2 - Math.PI / 2)
      })
    
    points.on("click", function(d) {
      console.log(d)
    })
    
    g.selectAll(null)
      .data(SUB_STREAMS)
      .enter()
      .append('text')
      .style('cursor', 'pointer')
      .style('fill', 'black')
      .attr('text-anchor', 'right')
      .attr('font-size', '1.3em')
      .attr('dx', (d) => 14 + r * Math.cos(d.value * Math.PI * 2 - Math.PI / 2))
      .attr('dy', (d) => r * Math.sin(d.value * Math.PI * 2 - Math.PI / 2))
      .text((d) => d.label)
    
    const text = g
      .selectAll('path')
      .data(STREAMS)
      .enter()
      .append("text")
      .attr("text-anchor", "left")
      .attr('font-size', '1em')
      .attr("y", function(d, a) {
        return d.yAxis - 5
      })
      .text((d) => d.label);
    
    text.on("click", function(d) {
      console.log(d)
    })
    
    
    var arc = d3.symbol().type(d3.symbolTriangle)
    var line = g.selectAll('path')
      .data(STREAMS)
      .enter()
      .append('path')
      .attr('d', arc)
      .attr('fill', 'red')
      .attr('stroke', '#000')
      .attr('stroke-width', 1)
      .attr('transform', function(d) {
        return `translate(-10,${d.yAxis - 5}) rotate(210)`;
      });
    text {
      dominant-baseline: central;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div id="foo" />

    【讨论】:

    • 太棒了!有没有办法使用半径或其他东西动态设置yAxis?
    • @texas697 我不确定你在问什么,你能解释一下吗?顺便说一句,text-anchor 中没有rightleft
    • 圆圈内的列表。您在硬编码数组 STREAMS 中看到了我的 -40、-20、0、20。可以做得更好吗?该数组将是动态的,有时会有 2、4 或 5 个以上的列表项。我希望他们居中
    • @texas697 我明白了。一个简单的解决方案是根据中心点按索引向下平移包含文本和符号的组,并按数组长度向上平移。要获得适当的答案,我建议您将此作为新问题发布。
    • 如果您有时间,我可以在其他一些帖子上使用您的帮助
    猜你喜欢
    • 2017-04-08
    • 2010-12-22
    • 2016-09-06
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-16
    相关资源
    最近更新 更多