首页 > 解决方案 > d3.js 标签图边[当边值不是数字时]

问题描述

我正在基于此块创建一个图表:http: //bl.ocks.org/jhb/5955887但在我的数据集中,边缘具有字符值而不是数字,我认为这是我问题的根源。edgelabel我想知道代码的哪一部分edgepath需要更新以反映这一点?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Force Layout with labels on edges</title>
    <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <style type="text/css">
    </style>
</head>

<body>

    <script type="text/javascript">

        var w = 1000;
        var h = 600;
        var linkDistance = 200;

        var colors = d3.scale.category10();

        var dataset = {

            nodes: [
                { name: 'A' },
                { name: 'B' },
                { name: 'C' },
                { name: 'D' },
                { name: 'E' },
                { name: 'F' },
                { name: 'G' }
            ],
            edges: [
                { source: 'A', target: 'B' },
                { source: 'A', target: 'C' },
                { source: 'A', target: 'E' },
                { source: 'A', target: 'F' },
                { source: 'B', target: 'C' },
                { source: 'C', target: 'F' },
                { source: 'E', target: 'F' },
                { source: 'E', target: 'D' },
                { source: 'E', target: 'G' }
            ]
            /*
          edges: [
                    { source: 0, target: 1 },
                    { source: 0, target: 2 },
                    { source: 0, target: 4 },
                    { source: 0, target: 5 },
                    { source: 1, target: 2 },
                    { source: 2, target: 5 },
                    { source: 4, target: 5 },
                    { source: 4, target: 3 },
                    { source: 4, target: 6 }
                ]
                */
        };


        var svg = d3.select("body").append("svg").attr({ "width": w, "height": h });

        var force = d3.layout.force()
            .nodes(dataset.nodes)
            .links(dataset.edges)
            .size([w, h])
            .linkDistance([linkDistance])
            .charge([-500])
            .theta(0.1)
            .gravity(0.05)
            .start();



        var edges = svg.selectAll("line")
            .data(dataset.edges)
            .enter()
            .append("line")
            .attr("id", function (d, i) { return 'edge' + i })
            .attr('marker-end', 'url(#arrowhead)')
            .style("stroke", "#ccc")
            .style("pointer-events", "none");

        var nodes = svg.selectAll("circle")
            .data(dataset.nodes)
            .enter()
            .append("circle")
            .attr({ "r": 15 })
            .style("fill", function (d, i) { return colors(i); })
            .call(force.drag)

        var nodelabels = svg.selectAll(".nodelabel")
            .data(dataset.nodes)
            .enter()
            .append("text")
            .attr({
                "x": function (d) { return d.x; },
                "y": function (d) { return d.y; },
                "class": "nodelabel",
                "stroke": "black"
            })
            .text(function (d) { return d.name; });

        var edgepaths = svg.selectAll(".edgepath")
            .data(dataset.edges)
            .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(dataset.edges)
            .enter()
            .append('text')
            .style("pointer-events", "none")
            .attr({
                'class': 'edgelabel',
                'id': function (d, i) { return 'edgelabel' + i },
                'dx': 80,
                'dy': 0,
                'font-size': 10,
                'fill': '#aaa'
            });

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


        force.on("tick", function () {

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

            nodes.attr({
                "cx": function (d) { return d.x; },
                "cy": function (d) { return d.y; }
            });

            nodelabels.attr("x", function (d) { return d.x; })
                .attr("y", function (d) { return d.y; });

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

            edgelabels.attr('transform', function (d, i) {
                if (d.target.x < d.source.x) {
                    bbox = this.getBBox();
                    rx = bbox.x + bbox.width / 2;
                    ry = bbox.y + bbox.height / 2;
                    return 'rotate(180 ' + rx + ' ' + ry + ')';
                }
                else {
                    return 'rotate(0)';
                }
            });
        });

    </script>

</body>

</html>

如您所见,当我切换到注释代码时,这在我取消注释数字边缘时有效

        var dataset = {

            nodes: [
                { name: 'A' },
                { name: 'B' },
                { name: 'C' },
                { name: 'D' },
                { name: 'E' },
                { name: 'F' },
                { name: 'G' }
            ],
            edges: [
                { source: 'A', target: 'B' },
                { source: 'A', target: 'C' },
                { source: 'A', target: 'E' },
                { source: 'A', target: 'F' },
                { source: 'B', target: 'C' },
                { source: 'C', target: 'F' },
                { source: 'E', target: 'F' },
                { source: 'E', target: 'D' },
                { source: 'E', target: 'G' }
            ]
            /*
          edges: [
                    { source: 0, target: 1 },
                    { source: 0, target: 2 },
                    { source: 0, target: 4 },
                    { source: 0, target: 5 },
                    { source: 1, target: 2 },
                    { source: 2, target: 5 },
                    { source: 4, target: 5 },
                    { source: 4, target: 3 },
                    { source: 4, target: 6 }
                ]
                */
        };

任何帮助表示赞赏

标签: d3.js

解决方案


这是片段的工作版本,其中边缘标签文本填充了源节点和目标节点的name属性。

在任何情况下,边缘定义都dataset应该保留数字键,除非代码被迁移到 d3.js v5,在那里可以使用访问器函数在链接定义中使用节点名称。link.id

var w = 1000;
        var h = 600;
        var linkDistance = 200;

        var dataset = {

            nodes: [
                { name: 'A' },
                { name: 'B' },
                { name: 'C' },
                { name: 'D' },
                { name: 'E' },
                { name: 'F' },
                { name: 'G' }
            ],
          edges: [
                    { source: 0, target: 1 },
                    { source: 0, target: 2 },
                    { source: 0, target: 4 },
                    { source: 0, target: 5 },
                    { source: 1, target: 2 },
                    { source: 2, target: 5 },
                    { source: 4, target: 5 },
                    { source: 4, target: 3 },
                    { source: 4, target: 6 }
                ]
        };


        var svg = d3.select("body").append("svg").attr({ "width": w, "height": h });

        var force = d3.layout.force()
            .nodes(dataset.nodes)
            .links(dataset.edges)
            .size([w, h])
            .linkDistance([linkDistance])
            .charge([-500])
            .theta(0.1)
            .gravity(0.05)
            .start();



        var edges = svg.selectAll("line")
            .data(dataset.edges)
            .enter()
            .append("line")
            .attr("id", function (d, i) { return 'edge' + i })
            .style("stroke", "#ccc")
            .style("pointer-events", "none");

        var nodes = svg.selectAll("circle")
            .data(dataset.nodes)
            .enter()
            .append("circle")
            .attr({ "r": 15 })
            .style("fill", "grey")
            .style("stroke", "black")
        .style('stroke-width', 2)
            .call(force.drag)

        var nodelabels = svg.selectAll(".nodelabel")
            .data(dataset.nodes)
            .enter()
            .append("text")
            .attr({
                "x": function (d) { return d.x -5; },
                "y": function (d) { return d.y +5; },
                "class": "nodelabel",
                "stroke": "black"
            })
            .text(function (d) { return d.name; });

        var edgepaths = svg.selectAll(".edgepath")
            .data(dataset.edges)
            .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(dataset.edges)
            .enter()
            .append('text')
            .style("pointer-events", "none")
            .attr({
                'class': 'edgelabel',
                'id': function (d, i) { return 'edgelabel' + i },
                'dx': 80,
                'dy': 0,
                'font-size': 10,
                'fill': '#aaa'
            });

        edgelabels.append('textPath')
      .data(dataset.edges)
            .attr('xlink:href', function (d, i) { return '#edgepath' + i })
            .style("pointer-events", "none")
            .text(function (d, i) { return dataset.edges[i].source.name + ' to ' + dataset.edges[i].target.name });


        force.on("tick", function () {

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

            nodes.attr({
                "cx": function (d) { return d.x; },
                "cy": function (d) { return d.y; }
            });

            nodelabels.attr("x", function (d) { return d.x -5; })
                .attr("y", function (d) { return d.y +5; });

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

            edgelabels.attr('transform', function (d, i) {
                if (d.target.x < d.source.x) {
                    bbox = this.getBBox();
                    rx = bbox.x + bbox.width / 2;
                    ry = bbox.y + bbox.height / 2;
                    return 'rotate(180 ' + rx + ' ' + ry + ')';
                }
                else {
                    return 'rotate(0)';
                }
            });
        });
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Force Layout with labels on edges</title>
    <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <style type="text/css">
    </style>
</head>

<body>

</body>

</html>


推荐阅读