为d3线元素添加标题

时间:2016-12-29 21:01:37

标签: javascript d3.js

我现在正在运行的是通过d3 line元素显示一个根节点和一组节点。我想为该行添加一个标题,因为我已定义它并可以从d.label(在JSON的节点部分)中自由地获取它。我正在使用以下代码:

var width = 500,
    height = 500;
var force = d3.layout.force()
    .size([width, height])
    .charge(-800)

    .linkDistance(d => d.distance)

    .on("tick", tick);

var svg = d3.select("#target").append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("class", "mainsvg");
var link = svg.selectAll(".link"),
    node = svg.selectAll(".node");


d3.json("test.json", function(error, graph) {
  if (error) throw error;

  force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();


  link = link.data(graph.links)
      .enter().append("line")
      .attr("class", "link");


  node = node.data(graph.nodes)
      .enter().append("a")      
    node.append("g")
      .attr("class", "node");    

    node.append("circle")
      .attr("class", "circle")
      .attr("r", function(d) { return d.r })
      .attr("fill", function(d) { return d.color })
      .attr("stroke", function(d){ return d.color });

});

function tick() {

  link.attr("x1", function(d) { return d.source.x; })
      .attr("y1", function(d) { return d.source.y; })
      .attr("x2", function(d) { return d.target.x; })
      .attr("y2", function(d) { return d.target.y; });
  svg.selectAll(".circle").attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });
  svg.selectAll(".text").attr("x", function(d) { return d.x+d.xoffs; })
      .attr("y", function(d) { return d.y+d.yoffs; });

}

现在我尝试以这种方式使用附加到<text>的普通edgepath元素:

var edgepaths = svg.selectAll(".edgepath")
        .data(graph.links)
        .enter()
        .append('path')
        .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
               'class':'edgepath',
               'fill-opacity':0,
               'stroke-opacity':0,
               'fill':'blue',
               'stroke':'red',
               'id':function(d,i) {return 'edgepath'+i}})
        .style("pointer-events", "none");
var edgelabels = svg.selectAll(".edgelabel")
        .data(graph.links)
        .enter()
        .append('text')
        .style("pointer-events", "none")
        .attr({'class':'edgelabel',
               'id':function(d,i){return 'edgelabel'+i},
               'dx':80,
               'dy':10,
               'font-size':10,
               'fill':'black'});

edgelabels.append('textPath')
        .attr('xlink:href',function(d,i) {return '#edgepath'+i})
        .style("pointer-events", "none")
        .text(function(d){return d.label});

然而,我得到的结果充其量是奇怪的。有些标签太靠近,有些标签丢失,但所有标签都放在错误的位置。我如何将它们移动到应有的位置?为了记住一些事情,我正在寻找一种简单的方法来为我已经绘制的路径添加标题,没有别的。所以我尝试过的方法可能太多了,我不确定。

2 个答案:

答案 0 :(得分:1)

text不能是path see this question的孩子path不是容器...... per SVG spec.

最佳做法是首先将g元素作为绑定数据的容器附加到SVG,然后将pathtext元素附加到g,以便他们是兄弟姐妹。然后你可以完全控制相对定位等。

答案 1 :(得分:1)

问题在于dx中的edgelabels,它总是一样的:

'dx': 80,

假设您正在使用带有链接距离的代码(如last question中所述),解决方案很简单:

'dx':function(d){return d.distance/2},

查看演示:

&#13;
&#13;
var nodes = [{
    name: "a"
}, {
    name: "b"
}, {
    name: "c"
}, {
    name: "d"
}, {
    name: "e"
}, {
    name: "f"
}];

var links = [{
    source: 1,
    target: 0,
    distance: 80,
    label: "foo"
}, {
    source: 2,
    target: 0,
    distance: 40,
    label: "bar"
}, {
    source: 3,
    target: 0,
    distance: 180,
    label: "baz"
}, {
    source: 4,
    target: 0,
    distance: 80,
    label: "foobar"
}, {
    source: 5,
    target: 0,
    distance: 90,
    label: "foobaz"
}]

var width = 400
height = 300;

var force = d3.layout.force()
    .nodes(nodes)
    .links(links)
    .size([width, height])
    .linkDistance(d => d.distance)
    .charge(-1000)
    .on("tick", tick)
    .start();

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var link = svg.selectAll(".link")
    .data(force.links())
    .enter().append("line")
    .attr("stroke", "black")
    .attr("class", "link");

var edgepaths = svg.selectAll(".edgepath")
    .data(force.links())
    .enter()
    .append('path')
    .attr({
        'd': function(d) {
            return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y
        },
        'class': 'edgepath',
        'fill-opacity': 0,
        'stroke-opacity': 0,
        'fill': 'blue',
        'stroke': 'red',
        'id': function(d, i) {
            return 'edgepath' + i
        }
    })
    .style("pointer-events", "none");

var edgelabels = svg.selectAll(".edgelabel")
    .data(force.links())
    .enter()
    .append('text')
    .style("pointer-events", "none")
    .attr({
        'class': 'edgelabel',
        'id': function(d, i) {
            return 'edgelabel' + i
        },
        'dx': function(d) {
            return d.distance / 2
        },
        'dy': 10,
        'font-size': 12,
        'fill': 'black'
    });

edgelabels.append('textPath')
    .attr('xlink:href', function(d, i) {
        return '#edgepath' + i
    })
    .style("pointer-events", "none")
    .text(function(d) {
        return d.label
    });

var node = svg.selectAll(".node")
    .data(force.nodes())
    .enter().append("g")
    .attr("class", "node")
    .call(force.drag);

node.append("circle")
    .attr("r", (d, i) => i ? 10 : 16)
    .style("fill", (d, i) => i ? "teal" : "brown");

function tick() {



    link.attr("x1", function(d) {
            return d.source.x;
        })
        .attr("y1", function(d) {
            return d.source.y;
        })
        .attr("x2", function(d) {
            return d.target.x;
        })
        .attr("y2", function(d) {
            return d.target.y;
        });

    node.attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
    });

    edgepaths.attr('d', function(d) {
        var path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
        return path
    });



}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;