Problem Description
Draw a Force-Directed Graph with d3.js Official examples
But in the official example, the width and height of the SVG element are set to pixels, that is, the SVG can not adapt.
In order to make the SVG adaptive, it is natural to set the width and height of the SVG element as a percentage.
<svg width="100%" height="100%"></svg>
It's still an official example, but it's not on the website.
Problem Location
Using chrome for debugging: It was found that the height and width of the svg element were both 0.
Look at the source code of the web page and find that all the coordinates of the nodes are 0, then it is possible that the problem lies in the js code:
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
The problem is that the center of the force-oriented graph is 0_width, height = 0_width and height errors in obtaining svg
Solve the problem
The svg is generated dynamically by js, and then the real width and height of the page svg are obtained
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
</style>
<!--Added a div element-->
<div id="knowledgeGraph" style="height:600px">
<#-- SVG will be generated here.>
</div>
<script src="https://cdn.bootcss.com/d3/4.8.0/d3.js"></script>
<script>
var w = "100%";
var presvg = d3.select("#knowledgeGraph");
//Generate svgy elements
presvg.append("svg")
.attr(":xmlns:svg", "http://www.w3.org/2000/svg")
.attr("id","shownSVG")
.style("width", w)
.style("height", h)
.attr("class", "thumbnail");
var svg = d3.select("svg");
//Get the actual width and height of svg. Notice that both svg.attr("width") and svg.attr("height") in the original example return 0.
var width = $("#shownSVG").width();
var height = $("#shownSVG").height();
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json("1.json", function(error, graph) {
if (error) throw error;
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) { return d.id; });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
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 = null;
d.fy = null;
}
</script>
key point
It is not necessary to generate svg dynamically. The key point is to get the true width and height of svg elements correctly.
Therefore, we must get the svg elements of the page, and then get the real width and height.
That is to say,
var svg = d3.select("#shownSVG");
var width = $("#shownSVG").width();
var height = $("#shownSVG").height();
Related links: https://stackoverflow.com/questions/31854267/get-pixel-width-of-d3-js-svg-element-after-its-created-with-width-as-percentage