【问题标题】:How do I have a specific d3 node be an image in a force directed graph?如何让特定的 d3 节点成为力有向图中的图像?
【发布时间】:2016-11-29 02:26:03
【问题描述】:

我制作了一个与此类似的力有向图。

我希望中间的九英寸钉子节点是一个图像,但其余节点只是圆形。遵循这个answer 似乎并不太难,但我就是无法理解 svg、defs、模式和 d3 的组合。

我的代码是:

      var simulation =
      d3.forceSimulation()
      .force("charge", d3.forceManyBody().strength(-50))
      .force("collide", d3.forceCollide().radius(function (d) { return 15 - d.group}).strength(2).iterations(2))
      .force("link", d3.forceLink().id(function(d, i) { return i;}).distance(20).strength(0.9))
      .force("center", d3.forceCenter(width/2, height/2))
      .force('X', d3.forceX(width/2).strength(0.15)) 
      .force('Y', d3.forceY(height/2).strength(0.15));

  var link = svg.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(graph.links)
    .enter().append("line")

    var defs = svg.append('svg:defs');

    defs.append("svg:pattern")
          .attr("id", "vit-icon")
          .attr("width", 48)
          .attr("height", 48)
          .attr("patternUnits", "userSpaceOnUse")
          .append("svg:image")
          .attr("xlink:href", "http://placekitten.com/g/48/48")
          .attr("width", 48)
          .attr("height", 48)
          .attr("x", width/2)
          .attr("y", height/2)

  var node = svg.append("g")
    .attr("class", "nodes")
    .selectAll("circle")
    .data(graph.nodes)
    .enter().append("circle")
      .attr("id", function(d, i) { return 'c'+i})
      .attr("r", radius)
      .attr("fill", function(d) {
            if(d.group==0) {return "url(#vit-icon)";}
            else {return color(d.group); }
          })
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended));

正如我所说,这在我的脑海中似乎是直截了当的。基本上我认为我想要做的是将图像放在 svg 模式中,然后使用 if 语句告诉我的根节点使用图像 url 而不是填充颜色。

在开发工具中,我可以看到检查图像,它显示了它将占用的蓝色区域,并且我希望它关联的节点具有 'url(#vit-icon)' 作为填充属性。但它没有显示该节点的图像或任何填充。

我做错了什么?或者这是完全错误的方法? 谢谢。

【问题讨论】:

    标签: javascript node.js d3.js svg


    【解决方案1】:

    在您的defs 中,只需更改:

    .attr("x", width/2)
    .attr("y", height/2)
    

    收件人:

    .attr("x", 0)
    .attr("y", 0);
    

    这是一个演示:

    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", "vit-icon")
        .attr("width", 1)
        .attr("height", 1)
        .append("svg:image")
        .attr("xlink:href", "http://66.media.tumblr.com/avatar_1c725152c551_128.png")
        .attr("width", 48)
        .attr("height", 48)
        .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", d=> d.id === 1 ? 24 : 14)
        .style("fill", function(d) {
            if (d.id === 1) {
                return "url(#vit-icon)";
            } else {
                return "teal"
            }
        })
    
    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>

    【讨论】:

    • PS:NIN Trent Reznor。
    • 谢谢,这对我来说几乎可以工作了。您能解释一下为什么要删除“patternUnits”、“userSpaceOnUse”以及将 defs 中的第一个宽度和高度值更改为 1 吗?我无法将图像缩放和居中到节点。
    • 我刚刚删除了那些以使 sn-p 更小。这里重要的是改变xy 的位置。
    • 好的,我想我明白它是如何工作的。对于像我这样的人在未来阅读这篇文章,为了使图像适合节点内部,使我在之前的评论中引用的宽度/高度,两倍于你希望它适合的节点半径的大小。在 Geraldo 的代码中是 48 和 24。哦,我绝对同意 Trent Reznor 是 NiN ......这只是我发现的一个随机示例图:)
    猜你喜欢
    • 2015-07-30
    • 2019-04-23
    • 2013-09-01
    • 2012-11-02
    • 1970-01-01
    • 1970-01-01
    • 2017-11-12
    • 2014-12-05
    • 2012-04-19
    相关资源
    最近更新 更多