代码之家  ›  专栏  ›  技术社区  ›  VELFR

如何将标签添加到D3弦图上的弧组arc.centroid()?

  •  2
  • VELFR  · 技术社区  · 6 年前

    所以,最近我开始尝试使用 D3 library here's the pen

    var parentSelector = '#con1'
    var width = '100vh'
    var height = '100vh'
    var cssid = 'chord1'
    var cssclass = 'svgChord'
    var labels = ['a', 'b', 'c', 'd', 'e']
    var data = [[11, 21, 31, 41, 51], [12, 22, 32, 42, 52], [13, 23, 33, 43, 53], [14, 24, 34, 44, 54], [15, 25, 35, 45, 55]]
    var colors = ['#ddffdd', '#fd8b43', '#00922c', '#ffffff', '#F0d064']
    var getWidth = function () { return document.querySelector('#' + cssid + '.' + cssclass).clientWidth }
    var getHeight = function () { return document.querySelector('#' + cssid + '.' + cssclass).clientHeight }
    var svg = d3.select(parentSelector)
      .append('svg:svg')
      .attr('width', width)
      .attr('height', height)
      .attr('class', cssclass)
      .attr('id', cssid)
      .attr('viewBox', '0,0,' + getWidth() + ',' + getHeight())
    var outerRadius = Math.min(getWidth(), getHeight()) * 0.5 - 40
    var innerRadius = outerRadius - 30
    var colorsMap = d3.scaleOrdinal().range(colors)
    var arc = d3.arc()
      .innerRadius(innerRadius)
      .outerRadius(outerRadius)
    var chord = d3.chord()
      .padAngle(0.05)
      .sortSubgroups(d3.descending)
    var ribbon = d3.ribbon()
      .radius(innerRadius)
    var g = svg.append('g')
      .attr('transform', 'translate(' + getWidth() / 2 + ',' + getHeight() / 2 + ')')
      .datum(chord(data))
    var groups = g.append('g')
      .attr('class', 'groups')
    var group = groups.selectAll('g')
      .data(function (chords) { return chords.groups })
      .enter()
      .append('g')
      .attr('class', 'group')
    var arcSvg = group.append('path')
      .attr('class', 'arc')
      .attr('d', arc)
      .style('fill', function (d) { return colorsMap(d.index) })
      .style('stroke', function (d) { return d3.rgb(colorsMap(d.index)).darker() })
    group.append('text')
    // .attr('x', function (d) { return arc.centroid()[d.index][0] }) // doesn't work
    // .attr('y', function (d) { return arc.centroid()[d.index][1] }) // doesn't work
      .attr('class', 'group-label')
      .text(function (d) { return labels[d.index] })
    var ribbons = g.append('g')
      .attr('class', 'ribbons')
      .selectAll('path')
      .data(function (d) { return d })
      .enter()
      .append('path')
      .attr('d', ribbon)
      .style('fill', function (d) { return colorsMap(d.target.index) })
      .style('stroke', function (d) { return d3.rgb(colorsMap(d.target.index)).darker() })
    g.groups text.group-label {
      font: 11px sans-serif;
      pointer-events: none;
      z-index: 100000;
      font-size: 30px;
      font-weight: 700;
    }
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <div class="container" id="con1"></div>

    现在我需要添加一些信息,使它更有用。但由于某些原因,我无法实现添加标签组扇区各自的中心点使用 arc.centroid() 1 , 2 , 3 4 , 5 弧形心() anything_else.centroid()

    :如何更改代码以获得所需的结果-在每个svg弧的质心上绘制svg文本?

    1 回复  |  直到 6 年前
        1
  •  2
  •   i alarmed alien    6 年前

    问题出在你试图计算弧形心的方法上;您需要指定开始和结束角度,然后以适当的形式输出结果。最简单的方法是使用变换,因此只计算一次质心位置,而不是分别计算x和y:

    group.append('text')
    .attr('transform', function (d) {
      return 'translate(' +
        arc.startAngle(d.startAngle)
        .endAngle(d.endAngle)
        .centroid() // this is an array, so will automatically be printed out as x,y
         + ')'
    })
    

    这会使标签大致处于正确的位置,但您可以通过稍微向下平移字母(文本基线当前位于质心点,因此向下移动文本0.35em会使文本的垂直中心更靠近中间)并使用 text-anchor: middle :

    group.append('text')
    .attr('transform', function (d) {
      return 'translate(' +
        arc.startAngle(d.startAngle)
        .endAngle(d.endAngle)
        .centroid() // this is an array, so will automatically be printed out as x,y
         + ')'
     })
    .attr('dy', '.35em')
    .attr('text-anchor', 'middle')
    .attr('class', 'group-label')
    .text(function (d) { return labels[d.index] })
    

    var parentSelector = '#con1'
    var width = '100vh'
    var height = '100vh'
    var cssid = 'chord1'
    var cssclass = 'svgChord'
    var labels = ['a', 'b', 'c', 'd', 'e']
    var data = [[11, 21, 31, 41, 51], [12, 22, 32, 42, 52], [13, 23, 33, 43, 53], [14, 24, 34, 44, 54], [15, 25, 35, 45, 55]]
    var colors = ['#ddffdd', '#fd8b43', '#00922c', '#ffffff', '#F0d064']
    var getWidth = function () { return document.querySelector('#' + cssid + '.' + cssclass).clientWidth }
    var getHeight = function () { return document.querySelector('#' + cssid + '.' + cssclass).clientHeight }
    var svg = d3.select(parentSelector)
      .append('svg:svg')
      .attr('width', width)
      .attr('height', height)
      .attr('class', cssclass)
      .attr('id', cssid)
      .attr('viewBox', '0,0,' + getWidth() + ',' + getHeight())
    var outerRadius = Math.min(getWidth(), getHeight()) * 0.5 - 40
    var innerRadius = outerRadius - 30
    var colorsMap = d3.scaleOrdinal().range(colors)
    var arc = d3.arc()
      .innerRadius(innerRadius)
      .outerRadius(outerRadius)
    var chord = d3.chord()
      .padAngle(0.05)
      .sortSubgroups(d3.descending)
    var ribbon = d3.ribbon()
      .radius(innerRadius)
    var g = svg.append('g')
      .attr('transform', 'translate(' + getWidth() / 2 + ',' + getHeight() / 2 + ')')
      .datum(chord(data))
    var groups = g.append('g')
      .attr('class', 'groups')
    var group = groups.selectAll('g')
      .data(function (chords) { return chords.groups })
      .enter()
      .append('g')
      .attr('class', 'group')
    var arcSvg = group.append('path')
      .attr('class', 'arc')
      .attr('d', arc)
      .style('fill', function (d) { return colorsMap(d.index) })
      .style('stroke', function (d) { return d3.rgb(colorsMap(d.index)).darker() })
    group.append('text')
      .attr('dy', '.35em')
      .attr('transform', function (d) {
        return 'translate('
        + arc
          .startAngle(d.startAngle)
          .endAngle(d.endAngle)
          .centroid() + ')'
      })
      .attr('class', 'group-label')
      .attr('text-anchor', 'middle')
      .text(function (d) { return labels[d.index] })
    
    var ribbons = g.append('g')
      .attr('class', 'ribbons')
      .selectAll('path')
      .data(function (d) { return d })
      .enter()
      .append('path')
      .attr('d', ribbon)
      .style('fill', function (d) { return colorsMap(d.target.index) })
      .style('stroke', function (d) { return d3.rgb(colorsMap(d.target.index)).darker() })
    g.groups text.group-label {
      font: 11px sans-serif;
      pointer-events: none;
      z-index: 100000;
      font-size: 30px;
      font-weight: 700;
    }
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <div class="container" id="con1"></div>