D3 - 在DOM元素之间绘制路径

时间:2016-07-01 16:30:16

标签: javascript d3.js svg

我正在创建一个平行坐标图表。每个圈子都是一个特定的品牌,每个品牌在每一栏都有一个圈子:

enter image description here

当用户盘旋在一个圆圈上时,我想绘制一条将该圆圈连接到同一品牌的其他三个圆圈的路径。问题是圆圈的X位置是随机的,所以我必须使用圆圈修改的cx值(而不是数据)来绘制线条。

方便的是,我将所有四个品牌圈分组在他们自己的g元素中:

<g class="line-group">
    <circle r="5" cx="340.48700997553686" cy="0" data-brand="Brand X"></circle>
    <circle r="5" cx="916.9181438059958" cy="59.347826086956466" data-brand="Brand X"></circle>
    <circle r="5" cx="1589.2772695723352" cy="229.1306884480747" data-brand="Brand X"></circle>
    <circle r="5" cx="2272.275506967826" cy="0" data-brand="Brand X"></circle>
</g>

我可以抓取元素,并以d3.line()喜欢的方式对坐标进行分组,但它会使一条线连接每个点。

var line = d3.svg.line()
               .interpolate('basis');

var circles = d3.selectAll('.line-group').selectAll('circle'),
          circleCoords = [];

      circles.forEach( function(d) {
        console.log(circles);
        for ( i = 0; i < d.length; i++ ) {
          var cx = d3.select(d[i]).attr('cx'),
              cy = d3.select(d[i]).attr('cy');

          circleCoords.push([cx, cy]);
        }
      });

      lineGroup.append('path')
             .attr({
               'd' : line( circleCoords )
             });

我如何构建这个以便我可以获取每个圆群的cx和cy值(g.line-group中同一品牌的四个圆圈)?

我可能必须制作一个自定义的d属性,类似这样的(伪代码):

path.attr('d', function(d) { 
                  return 'M ' + /* cx of circle 1 */ + ' ' + /* cy of circle 1 */ + 
                    ' L ' + /* cx of circle 2 */ + ' ' + /* cy of circle 2 */ + 
                    ' L ' + /* cx of circle 3 */ + ' ' + /* cy of circle 3 */ + 
                    ' L ' + /* cx of circle 4 */ + ' ' + /* cy of circle 4 */ + ' Z';
                })

我相信所有的碎片都在那里,我似乎无法找到一种正确的方法。如果有人有任何想法,我们将不胜感激!

修改:添加了行定义。

1 个答案:

答案 0 :(得分:2)

你的选择错误(我看不到你的行定义,不要忘记它):

var svg = d3.selectAll("svg")
var circles = svg.selectAll('.line-group').selectAll("circle"),
// or var circles = svg.selectAll('.line-group > circle'),

          circleCoords = [];

      circles.forEach( function(d) {
        for ( i = 0; i < d.length; i++ ) {
          var cx = d3.select(d[i]).attr('cx'),
              cy = d3.select(d[i]).attr('cy');

          circleCoords.push([cx, cy]);
        }
        console.log(circleCoords);  
      });

      var line = d3.svg.line()

      svg.append('path')
             .attr({
               'd' : line( circleCoords )
             });

Here the working code

别忘了款式。 您需要识别每个'.line-group'或D3将选择所有'.line-group'类,可以添加id属性.-

在您的情况下,您有多个“品牌”,如下所示:

<svg>
<g class="line-group">
    <circle r="5" cx="10" cy="110" data-brand="Brand-X"></circle>
    <circle r="5" cx="30" cy="120" data-brand="Brand-X"></circle>
    <circle r="5" cx="150" cy="30" data-brand="Brand-X"></circle>
    <circle r="5" cx="290" cy="40" data-brand="Brand-X"></circle>
</g>

<g class="line-group">
    <circle r="5" cx="10" cy="10" data-brand="Brand-Y"></circle>
    <circle r="5" cx="30" cy="20" data-brand="Brand-Y"></circle>
    <circle r="5" cx="150" cy="130" data-brand="Brand-Y"></circle>
    <circle r="5" cx="290" cy="140" data-brand="Brand-Y"></circle>
</g>
</svg>

你需要重构你的代码:

var svg = d3.selectAll("svg")
var circles = svg.selectAll('.line-group').selectAll("circle"),
          circleCoords = [];
var line = d3.svg.line()

// circles.length give you .line-group's count or brand's count:

   for (j=0; j<circles.length; j++) {
       circles[j].forEach( function(d) {     // forEach brand draw a line
          var cx = d.getAttribute('cx'),
              cy = d.getAttribute('cy');
          circleCoords.push([cx, cy]);
       })
       svg.append('path')
          .attr({ 'd' : line( circleCoords )  })
          .attr("id","id_"+j);
       circleCoords = [];
   };

Here's the working code