在D3中以编程方式为节点分配形状

时间:2017-03-16 23:02:32

标签: javascript d3.js

我正在尝试根据节点值分配形状。我的代码类似于:

// some variables from the UI
var anodezoom = d3.select("#nodezoom").property("value");
var asize = d3.select("#ona").property("value");
var acolor = d3.select("#color").property("value");
var ameasure = d3.select("#shape").property("value");
// build, resize, recolor and reshape the nodes
nodes = svg.selectAll('.node')
   .data(graph.nodes.filter(function (d) {
       return d.degree > 0;
   }))
   .enter()
   .append(function (d) {
       shaping(ameasure, d);
   })
   .attr('class', 'node')
   .attr('r', function (d) {
       return resizing(anodezoom, asize, d);
   })
   .style('fill', function (d) {
       return coloring(acolor, d);
   })
   .style('stroke', function (d) {
       return coloring(acolor, d);
   })
   .call(force.drag);

我得到的错误是:

TypeError: Argument 1 ('node') to Node.appendChild must be an instance of Node

发生这种情况是因为我在整形函数中返回一个节点对象失败,即:

function shaping(ashape, anode) {
    var shape = null;
    if (ashape === "gender") {
        if (anode.gender === "M") {
            shape = d3.svg.symbolTypes[0];
        } else if (anode.gender === "F") {
            shape = d3.svg.symbolTypes[1];
        } else {
            shape = d3.svg.symbolTypes[2];
        }
    return shape;
 };

我基本上会返回一个字符串,这听起来不错,因为它是合法的:

.append('circle')

但是它没有用,所以有没有办法返回一个Node对象,并在shape()函数中分配了正确的形状?

修改

我已将代码更改为:

nodes = svg.selectAll('path')
                    .data(graph.nodes.filter(function (d) {
                        return d.degree > 0;
                    }))
                    .enter()
                    .append('path')
                    .attr('d', d3.svg.symbol().type(function (d) {
                        return shaping(ashape, d);
                    }))
                    .attr('class', 'node')
                    .attr('r', function (d) {
                        return resizing(anodezoom, asize, d);
                    })
                    .style('fill', function (d) {
                        return coloring(acolor, d);
                    })
                    .style('stroke', function (d) {
                        return coloring(acolor, d);
                    })
                    .call(force.drag);

但是当链接按预期显示时,所有节点都在左上角,几乎看不到......我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

在设置路径数据时,您需要追加路径而不是d3形状,然后指定形状:

.append('path')
.attr('d', function(d) { return d3.symbol().type( /* shape */ ) });

以下是使用形状序数比例(var shape = d3.scaleOrdinal(d3.symbols);)的简单示例:

 .append('path')   
 .attr("d", d3.symbol().type( function(d) { return shape(d.group);} ) )

它在此block中实现。这个答案是用d3v4,d3v3代码会有点不同。两者的代码在下面的最小示例中进行了比较:

D3V3:

var svg = d3.select('body')
  .append('svg');

svg.selectAll('path')
  .data(d3.range(6))
  .enter()
    .append('path')
    .attr('transform',function(d,i) { return 'translate('+(i * 30 + 30) + ',20)'; })
    .attr('d',d3.svg.symbol()
                .type(function(d,i){ return d3.svg.symbolTypes[i]; })
                .size(function(d,i){ return i * 30 + 30; })
         )
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

d3v4:

var svg = d3.select('body').append('svg').attr('width',400).attr('height',200);

svg.selectAll('.symbol')
   .data(d3.range(6))
   .enter()
   .append('path')
   .attr('transform',function(d,i) { return 'translate('+(i*30+30)+','+30+')';})
   .attr('d',d3.symbol()
           .type(function(d,i){ return d3.symbols[i];})
           .size(function(d,i){ return i * 30 + 30; })
   )
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js"></script>