d3.js强制定向图 - 为节点使用图像而不是圆圈

时间:2016-11-29 19:24:30

标签: javascript d3.js d3-force-directed

我正在尝试使用d3.js可视化动态网络拓扑。到目前为止,我可以通过将圆圈作为节点来使其工作,但我必须为不同的节点类型放置不同的自定义图像。

我目前的代码是这样的:

 node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(jsonTry.nodes)
.enter().append("circle")
    .attr("r", 10)
    .attr("fill", function(d) { return color(d.group); })
    .call(d3.drag()
        .subject(dragsubject)
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended));

首先,我想将图像放到所有节点上,看看它是如何工作的,如下所示:

node = svg.append("g")
.attr("class", "nodes")
.data(graph.nodes)

node.append("svg:image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);

它似乎没有这样工作,因为我只能看到链接,节点就消失了。我找到了一些使用d3 v3的例子,但是目前我正在使用d3 v4并且想要相应地实现它(因为我遇到了不包含在v3中的forceLink()问题)

提前致谢。

1 个答案:

答案 0 :(得分:1)

如果您将<image>追加到<g>,您的方法就会奏效。但是,您要将<image>附加到<circle>元素,这不起作用。

您有两种解决方案:

  1. image附加到群组,而不是圈子;
  2. 保留您的圈子,但请使用def

    var defs = svg.append('svg:defs');
    
    defs.append("svg:pattern")
        .attr("id", "myPattern")
        .attr("width", 1)
        .attr("height", 1)
        .append("svg:image")
        .attr("xlink:href", "https://github.com/favicon.ico")
        .attr("width", 16)
        .attr("height", 16)
        .attr("x", 0)
        .attr("y", 0);
    
  3. 这是一个演示:

    var nodes = [{
        "id": 1,
    }, {
        "id": 2,
    }, {
        "id": 3,
    }, {
        "id": 4,
    }, {
        "id": 5,
    }, {
        "id": 6,
    }, {
        "id": 7,
    }, {
        "id": 8,
    }];
    
    var links = [{
        source: 1,
        target: 2
    }, {
        source: 1,
        target: 3
    }, {
        source: 1,
        target: 4
    }, {
        source: 2,
        target: 5
    }, {
        source: 2,
        target: 6
    }, {
        source: 1,
        target: 7
    }, {
        source: 7,
        target: 8
    }];
    
    var index = 10;
    var svg = d3.select("svg"),
        width = +svg.attr("width"),
        height = +svg.attr("height"),
        node,
        link;
    
    var defs = svg.append('svg:defs');
    
    defs.append("svg:pattern")
        .attr("id", "myPattern")
        .attr("width", 1)
        .attr("height", 1)
        .append("svg:image")
        .attr("xlink:href", "https://github.com/favicon.ico")
        .attr("width", 16)
        .attr("height", 16)
        .attr("x", 0)
        .attr("y", 0);
    
    var simulation = d3.forceSimulation()
        .force("link", d3.forceLink().id(function(d) {
            return d.id;
        }).distance(100))
        .force("collide", d3.forceCollide(50))
        .force("charge", d3.forceManyBody())
        .force("center", d3.forceCenter(width / 2, height / 2));
    
    link = svg.selectAll(".link")
        .data(links, function(d) {
            return d.target.id;
        })
    
    link = link.enter()
        .append("line")
        .attr("class", "link");
    
    node = svg.selectAll(".node")
        .data(nodes, function(d) {
            return d.id;
        })
    
    node = node.enter()
        .append("g")
        .attr("class", "node")
        .call(d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended));
    
    node.append("circle")
        .attr("r", 10)
        .style("fill", "url(#myPattern)")
    
    simulation
        .nodes(nodes)
        .on("tick", ticked);
    
    simulation.force("link")
        .links(links);
    
    
    function ticked() {
        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 + ")";
            });
    }
    
    function dragstarted(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart()
    }
    
    function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
    }
    
    function dragended(d) {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = undefined;
        d.fy = undefined;
    }
    .link {
      stroke: #aaa;
    }
    
    .node {
      pointer-events: all;
      stroke: none;
      stroke-width: 40px;
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg width="500" height="300"></svg>