I am new to D3 and try to learn force layout. I want to change the link distance between nodes and maintain the origin shape. I find that after I change the distance of the links, the layout was changed.
Figure one is the original layout, then I changed the link distance with code distance([150])
(at line 80) to make the nodes further, but the layout changes out of my expectation.
I expected it the layout will grow up with keeping the shape as same as original, but the layout changes a lot. I am not sure about the meaning of link distance now. Can anyone help? Thank you! My code on codepen
By its very definition, a force directed chart is dynamic: you cannot previously set the nodes' position, or expect that the nodes will fall in a given position.
D3 force simulation has so many parameters that a minor change in one of them can make the layout completely different. That's actually expected.
So, in your case, there is nothing strange here. You can try a few different solutions. In my opinion, the one that keeps (approximately) the structure you want with a bigger separation between the nodes is using forceCollide
, setting a different radius for the central node (the orange one):
.force('collide', d3.forceCollide(function(d){
return d.id === "j" ? 100 : 50
}));
Here is the updated CodePen: https://codepen.io/anon/pen/xJgYmP?editors=0010
And here the same code in the Stack snippet:
graph = {
nodes: [{
id: 'a',
group: 1
},
{
id: 'b',
group: 1
},
{
id: 'c',
group: 1
},
{
id: 'd',
group: 2
},
{
id: 'e',
group: 2
},
{
id: 'f',
group: 2
},
{
id: 'g',
group: 3
},
{
id: 'h',
group: 3
},
{
id: 'i',
group: 3
},
{
id: 'j',
group: 4
}
],
links: [{
source: 'a',
target: 'b',
value: 2
},
{
source: 'a',
target: 'c',
value: 2
},
{
source: 'b',
target: 'c',
value: 1
},
{
source: 'd',
target: 'e',
value: 2
},
{
source: 'd',
target: 'f',
value: 2
},
{
source: 'e',
target: 'f',
value: 1
},
{
source: 'g',
target: 'h',
value: 1
},
{
source: 'g',
target: 'i',
value: 2
},
{
source: 'i',
target: 'h',
value: 2
},
{
source: 'a',
target: 'j',
value: 2
},
{
source: 'b',
target: 'j',
value: 1
},
{
source: 'c',
target: 'j',
value: 1
},
{
source: 'd',
target: 'j',
value: 1
},
{
source: 'e',
target: 'j',
value: 1
},
{
source: 'f',
target: 'j',
value: 1
},
{
source: 'g',
target: 'j',
value: 1
},
{
source: 'h',
target: 'j',
value: 2
},
{
source: 'i',
target: 'j',
value: 2
},
]
}
var graph = this.graph
var svg = d3.select('svg')
var width = +svg.attr('width')
var 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('collide', d3.forceCollide(function(d) {
return d.id === "j" ? 100 : 50
}))
.force('center', d3.forceCenter(width / 2, height / 2))
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
}
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div class="container">
<svg width="960" height="600"></svg>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With