d3.js 强制定向图 - 使用图像而不是圆作为节点
d3.js Force Directed Graph - Using Images instead of Circles for the Nodes
我正在尝试使用 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 并希望相应地实现它(因为我遇到了 forceLink() 未包含在 v3 中的问题)
提前致谢。
如果您将 <image>
附加到 <g>
,您的方法就会奏效。但是,您将 <image>
附加到 <circle>
元素,这是行不通的。
你有两个解决方案:
- 将
image
附加到组中,而不是圆圈中;
保留您的圈子,但使用 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);
这是一个演示:
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>
我正在尝试使用 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 并希望相应地实现它(因为我遇到了 forceLink() 未包含在 v3 中的问题)
提前致谢。
如果您将 <image>
附加到 <g>
,您的方法就会奏效。但是,您将 <image>
附加到 <circle>
元素,这是行不通的。
你有两个解决方案:
- 将
image
附加到组中,而不是圆圈中; 保留您的圈子,但使用
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);
这是一个演示:
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>