D3js蜂巢图:如何标记节点?

3
我第一次尝试使用D3js Hive图表,并且在理解如何将标签放置在每个轴上的节点旁边方面遇到了困难。请参见我的fiddle,链接如下: http://jsfiddle.net/NovasTaylor/jgkqoasm/#base 使用这段代码,我可以将每个节点的标签放置在其正确的轴上。但是标签(名称)不靠近其相应的节点。我需要哪些代码才能将标签位置调整到节点旁边?
nodes.append("text")
    .attr("class", "text")
    .text(function(d) {return d.name;})
    // Following is needed to place E,F on the vertical axis toward the top
    // of the graph (group=3)
    .attr("y", function(d) { 
        if (d.group === 3) {
            return -radius(d.y);
        } else {
            return radius(d.y);
        }
    })
    .attr("transform", function(d) {
        if (d.group !== 3) {
            return "rotate(" + (degrees(angle(d.group)) - 90) + ")";
        }
    })

任何帮助都将不胜感激!
祝好,
Tim
2个回答

1
你应该应用与节点 circle 元素相同的变换:旋转 degrees(angle(d.x)) 度并将 x 位置设置为 radius(d.y)。此外,我建议将文本包装在一个 g 中,然后使用这些属性定位该 g,然后附加一个 text 并将其逆时针旋转以使文本处于正确的位置:
nodes.append("g")
  .attr("class", "text")
  .attr("transform", function(d) { 
    var t = "rotate(" + degrees(angle(d.x)) + ")";
    t += "translate(" + radius(d.y) + ",0)";
    return t; 
  })
  .append("text")
  .attr("transform", function(d) { 
    var t = "rotate(" + -degrees(angle(d.x)) + ")";
    return t; 
  })
  .text(function(d) {return d.name;})

完整的工作代码:

var width = 960,
    height = 500,
    innerRadius = 40,
    outerRadius = 240;
var angle = d3.scale.ordinal().domain(d3.range(4)).rangePoints([0, 2 * Math.PI]),
    radius = d3.scale.linear().range([innerRadius, outerRadius]),
    color = d3.scale.category10().domain(d3.range(20));
var nodes = [
    {name:"A", group:1, x: 0, y: .1},
    {name:"B", group:1, x: 0, y: .9},
    {name:"C", group:2, x: 1, y: .2},
    {name:"D", group:2, x: 1, y: .3},
    {name:"E", group:3, x: 2, y: .1},
    {name:"F", group:3, x: 2, y: .8}
];
var links = [
    {source: nodes[0], target: nodes[2]},
    {source: nodes[1], target: nodes[3]},
    {source: nodes[2], target: nodes[4]},
    {source: nodes[2], target: nodes[5]},
    {source: nodes[3], target: nodes[5]},
    {source: nodes[4], target: nodes[0]},
    {source: nodes[5], target: nodes[1]}
];
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.selectAll(".axis")
   .data(d3.range(3))
  .enter().append("line")
    .attr("class", "axis")
    .attr("transform", function(d) { return "rotate(" + degrees(angle(d)) + ")"; })
    .attr("x1", radius.range()[0])
    .attr("x2", radius.range()[1]);

svg.selectAll(".link")
    .data(links)
  .enter().append("path")
    .attr("class", "link")
    .attr("d", d3.hive.link()
    .angle(function(d) { return angle(d.x); })
    .radius(function(d) { return radius(d.y); }))
    .style("stroke", function(d) { return color(d.source.x); });
var nodes = svg.selectAll("g.node")
    .data(nodes, function (d) {
        return d.name;
    }); 
nodes.enter()
     .append("g");
nodes.append("circle")
    .attr("class", "node")
    .attr("transform", function(d) { return "rotate(" + degrees(angle(d.x)) + ")"; })
    .attr("cx", function(d) { return radius(d.y); })
    .attr("r", 5)
    .style("fill", function(d) { return color(d.x); });
// Append name as label to each node  
nodes.append("g")
    .attr("class", "text")
 .attr("transform", function(d) { 
     var t = "rotate(" + degrees(angle(d.x)) + ")";
     t += "translate(" + radius(d.y) + ",0)";
     return t; 
 })
 .append("text")
    .attr("transform", function(d) { 
     var t = "rotate(" + -degrees(angle(d.x)) + ")";
     return t; 
 })
    .text(function(d) {return d.name;})
 

function degrees(radians) {
  return radians / Math.PI * 180 - 90;
}
.link {
    fill: none;
    stroke-width: 1.5px;
}
.axis, .node {
    stroke: #000;
    stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="http://d3js.org/d3.hive.v0.min.js"></script>


1

我认为将圆圈和文本放在一个组中会更容易。这样就不需要额外计算文本位置。

var nodes = svg.selectAll("g.node")
    .data(nodes, function(d) {
        return d.name;
    });

var group = nodes.enter()
    .append("g")
    .attr("transform", function(d) {
        return "rotate(" + degrees(angle(d.x)) + ")";
    });
group.append("circle")
    .attr("class", "node")
    .attr("cx", function(d) {
        return radius(d.y);
    })
    .attr("r", 5)
    .style("fill", function(d) {
        return color(d.x);
    });
// Append name as label to each node  
group.append("text")
    .attr("class", "text")
    .attr("dy", "1.2em")
    .text(function(d) {
        return d.name;
    })
    .attr("x", function(d, i) {
        return radius(d.y);
    });

var width = 960,
    height = 500,
    innerRadius = 40,
    outerRadius = 240;
var angle = d3.scale.ordinal().domain(d3.range(4)).rangePoints([0, 2 * Math.PI]),
    radius = d3.scale.linear().range([innerRadius, outerRadius]),
    color = d3.scale.category10().domain(d3.range(20));
var nodes = [{
    name: "A",
    group: 1,
    x: 0,
    y: .1
}, {
    name: "B",
    group: 1,
    x: 0,
    y: .9
}, {
    name: "C",
    group: 2,
    x: 1,
    y: .2
}, {
    name: "D",
    group: 2,
    x: 1,
    y: .3
}, {
    name: "E",
    group: 3,
    x: 2,
    y: .1
}, {
    name: "F",
    group: 3,
    x: 2,
    y: .8
}];
var links = [{
    source: nodes[0],
    target: nodes[2]
}, {
    source: nodes[1],
    target: nodes[3]
}, {
    source: nodes[2],
    target: nodes[4]
}, {
    source: nodes[2],
    target: nodes[5]
}, {
    source: nodes[3],
    target: nodes[5]
}, {
    source: nodes[4],
    target: nodes[0]
}, {
    source: nodes[5],
    target: nodes[1]
}];
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.selectAll(".axis")
    .data(d3.range(3))
    .enter().append("line")
    .attr("class", "axis")
    .attr("transform", function(d) {
        return "rotate(" + degrees(angle(d)) + ")";
    })
    .attr("x1", radius.range()[0])
    .attr("x2", radius.range()[1]);

svg.selectAll(".link")
    .data(links)
    .enter().append("path")
    .attr("class", "link")
    .attr("d", d3.hive.link()
        .angle(function(d) {
            return angle(d.x);
        })
        .radius(function(d) {
            return radius(d.y);
        }))
    .style("stroke", function(d) {
        return color(d.source.x);
    });

var nodes = svg.selectAll("g.node")
    .data(nodes, function(d) {
        return d.name;
    });

var group = nodes.enter()
    .append("g")
    .attr("transform", function(d) {
        return "rotate(" + degrees(angle(d.x)) + ")";
    });
group.append("circle")
    .attr("class", "node")
    .attr("cx", function(d) {
        return radius(d.y);
    })
    .attr("r", 5)
    .style("fill", function(d) {
        return color(d.x);
    });
// Append name as label to each node  
group.append("text")
    .attr("class", "text")
    .attr("dy", "1.2em")
    .text(function(d) {
        return d.name;
    })
    .attr("x", function(d, i) {
        return radius(d.y);
    });

function degrees(radians) {
    return radians / Math.PI * 180 - 90;
}
.link {
  fill: none;
  stroke-width: 1.5px;
}
.axis,
.node {
  stroke: #000;
  stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="http://d3js.org/d3.hive.v0.min.js"></script>


你说得没错,这样更简洁。但是使用你的方法,你还应该通过 translate 来定位组,这样就不需要在圆形上使用冗余的 cx 属性和在文本上使用 x 属性了。 - Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接