I have a node with fx/fy parameter on simulation starting. This node is fixed on the correct position. But now I want to define x and y coordinates for one or multiple other nodes (in this example: number 10 in jsfiddle), the purpose is to start the simulation of this "unfixed" nodes on a given position and not 0/0. Why is the node fixed on 0/0?
jsfiddle example: https://jsfiddle.net/6g9howo7/2/
var nodes = [
{
"id" : "1",
"fx" : "225",
"fy" : "225"
},
{
"id" : "2"
},
{
"id" : "3"
},
{
"id" : "4"
},
{
"id" : "5"
},
{
"id" : "6"
},
{
"id" : "7"
},
{
"id" : "8"
},
{
"id" : "9"
},
{
"id" : "10",
"x" : "125",
"y" : "125"
},
{
"id" : "11"
},
{
"id" : "12"
},
{
"id" : "13"
},
{
"id" : "14"
},
{
"id" : "15"
}
]
var links =
[
{
"source" : 1,
"target" : 2
},
{
"source" : 1,
"target" : 3
},
{
"source" : 1,
"target" : 4
},
{
"source" : 1,
"target" : 5
},
{
"source" : 1,
"target" : 6
},
{
"source" : 1,
"target" : 7
},
{
"source" : 1,
"target" : 8
},
{
"source" : 1,
"target" : 9
},
{
"source" : 1,
"target" : 10
},
{
"source" : 10,
"target" : 11
},
{
"source" : 10,
"target" : 12
},
{
"source" : 10,
"target" : 13
},
{
"source" : 10,
"target" : 14
},
{
"source" : 10,
"target" : 15
}
]
var svg = d3.select("svg")
var zoom = d3.zoom()
.on("zoom", zoomed);
//.scaleExtent([1 / 8, 4])
svg
.call(zoom).on("dblclick.zoom", null)
var g = svg.append("g");
function zoomed() {
g.attr("transform", d3.event.transform);
}
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
//.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(function(d) {return d.distance/2;}).strength(1))
.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(10).strength(1))
.force("charge", d3.forceManyBody().strength(-10).distanceMax(100));
//.force("center", d3.forceCenter(1000, 1000));
//.force("y", d3.forceY(500))
//.force("x", d3.forceX(500));
//.force("collide",d3.forceCollide(.5));
//.force("collide",d3.forceCollide( function(d){return d.r + 8 }).iterations(4) );
var link = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke-width", 1 /*function(d) { return Math.sqrt(2); }*/)
.style("stroke", 'red');
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r",3)
// .attr("cx", function(d) { return d.x; })
// .attr("cy", function(d) { return d.y; })
.on("dblclick", dblclick)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) { return d.id; });
simulation.nodes(nodes)
// .alphaDecay(0.5)
.velocityDecay(0.1)
.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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
function dblclick(d) {
d.fx = null;
d.fy = null;
}
function dragstarted(d) {
//if (!d3.event.active) simulation.alphaTarget(0.3).restart();
simulation.restart();
// simulation.alpha -> redémarre la période de simulation
simulation.alpha(1.0);
d.fx = d.x;
d.fy = d.y;
}
//Grid
var grid = 50;
function dragged(d,i) {
//force.stop();
//var grid = 50;
var gx = Math.round(d3.event.x/grid)*grid;
var gy = Math.round(d3.event.y/grid)*grid;
d.fx = gx;
d.fy = gy;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
// console.log(d);
// d.fx = null;
// d.fy = null;
// d.fixed = true;
}
//Grid
var width = 7000;
var height = 7000;
var lineGraph = g.append("g")
.attr("width", width)
.attr("height", height);
// Using for loop to draw multiple horizontal lines
for (var j=grid; j <= width-grid; j=j+grid) {
lineGraph.append("svg:line")
.attr("x1", grid)
.attr("y1", j)
.attr("x2", width-grid)
.attr("y2", j)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
// Using for loop to draw multiple vertical lines
for (var j=grid; j <= height-grid; j=j+grid) {
lineGraph.append("svg:line")
.attr("x1", j)
.attr("y1", grid)
.attr("x2", j)
.attr("y2", height-grid)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
Your approach is correct, setting x
and y
defines the start position. However, they have to be numbers, not strings.
Therefore, instead of:
{
"id": "10",
"x": "125",
"y": "125"
}
It should be:
{
"id": "10",
"x": 125,
"y": 125
}
Here is your code with that change:
var nodes = [{
"id": "1",
"fx": "225",
"fy": "225"
}, {
"id": "2"
}, {
"id": "3"
}, {
"id": "4"
}, {
"id": "5"
}, {
"id": "6"
}, {
"id": "7"
}, {
"id": "8"
}, {
"id": "9"
}, {
"id": "10",
"x": 125,
"y": 125
}, {
"id": "11"
}, {
"id": "12"
}, {
"id": "13"
}, {
"id": "14"
}, {
"id": "15"
}]
var links = [{
"source": 1,
"target": 2
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 4
}, {
"source": 1,
"target": 5
}, {
"source": 1,
"target": 6
}, {
"source": 1,
"target": 7
}, {
"source": 1,
"target": 8
}, {
"source": 1,
"target": 9
}, {
"source": 1,
"target": 10
}, {
"source": 10,
"target": 11
}, {
"source": 10,
"target": 12
}, {
"source": 10,
"target": 13
}, {
"source": 10,
"target": 14
}, {
"source": 10,
"target": 15
}]
var svg = d3.select("svg")
var zoom = d3.zoom()
.on("zoom", zoomed);
//.scaleExtent([1 / 8, 4])
svg
.call(zoom).on("dblclick.zoom", null)
var g = svg.append("g");
function zoomed() {
g.attr("transform", d3.event.transform);
}
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
//.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(function(d) {return d.distance/2;}).strength(1))
.force("link", d3.forceLink().id(function(d) {
return d.id;
}).distance(10).strength(1))
.force("charge", d3.forceManyBody().strength(-10).distanceMax(100));
//.force("center", d3.forceCenter(1000, 1000));
//.force("y", d3.forceY(500))
//.force("x", d3.forceX(500));
//.force("collide",d3.forceCollide(.5));
//.force("collide",d3.forceCollide( function(d){return d.r + 8 }).iterations(4) );
var link = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke-width", 1 /*function(d) { return Math.sqrt(2); }*/ )
.style("stroke", 'red');
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 3)
// .attr("cx", function(d) { return d.x; })
// .attr("cy", function(d) { return d.y; })
.on("dblclick", dblclick)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) {
return d.id;
});
simulation.nodes(nodes)
// .alphaDecay(0.5)
.velocityDecay(0.1)
.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("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
}
function dblclick(d) {
d.fx = null;
d.fy = null;
}
function dragstarted(d) {
//if (!d3.event.active) simulation.alphaTarget(0.3).restart();
simulation.restart();
// simulation.alpha -> redémarre la période de simulation
simulation.alpha(1.0);
d.fx = d.x;
d.fy = d.y;
}
//Grid
var grid = 50;
function dragged(d, i) {
//force.stop();
//var grid = 50;
var gx = Math.round(d3.event.x / grid) * grid;
var gy = Math.round(d3.event.y / grid) * grid;
d.fx = gx;
d.fy = gy;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
// console.log(d);
// d.fx = null;
// d.fy = null;
// d.fixed = true;
}
//Grid
var width = 7000;
var height = 7000;
var lineGraph = g.append("g")
.attr("width", width)
.attr("height", height);
// Using for loop to draw multiple horizontal lines
for (var j = grid; j <= width - grid; j = j + grid) {
lineGraph.append("svg:line")
.attr("x1", grid)
.attr("y1", j)
.attr("x2", width - grid)
.attr("y2", j)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
// Using for loop to draw multiple vertical lines
for (var j = grid; j <= height - grid; j = j + grid) {
lineGraph.append("svg:line")
.attr("x1", j)
.attr("y1", grid)
.attr("x2", j)
.attr("y2", height - grid)
.style("stroke", "rgb(119,119,119)")
.style("stroke-width", 1);
};
html {
width: 100%;
height: 100%;
}
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
display: flex;
font-family: sans-serif;
font-size: 75%;
}
/* SVG styles */
svg {
flex-basis: 100%;
}
.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>
<svg></svg>
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