Reputation: 341
I am trying to get in touch with the D3v6. Functions which I used to work with D3v4 seems obsolete now or are in need of different constructor. Anyway I am trying to add a node during a simple click event. addNode()
The ID is generator by the length of the array + 1, further I pushing the element to the array and create/merge the new node. Afterwards the simulation is restarted and the alpha heated. Still no clue why I get such a result as shown. Its like the nodes freeze and the links are moving instead.
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>D3v6 v.0.0.1</title>
<!-- call external d3.js framework -->
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<style>
circle {
fill: whitesmoke;
stroke: white;
stroke-width: 2px
}
line {
stroke: black;
}
svg {
background-color: rgb(220, 220, 220);
}
</style>
<body>
<div id="content">
<svg> </svg>
</div>
<script src="https://d3js.org/d3.v6.js"></script>
<script>
var width = window.innerWidth, height = window.innerHeight
var graph = {
"nodes": [
{ "id": 1 },
{ "id": 2 },
{ "id": 3 },
{ "id": 4 },
{ "id": 5 }
],
"links": [
{ "source": 1, "target": 2 },
{ "source": 2, "target": 3 },
{ "source": 3, "target": 4 },
{ "source": 4, "target": 5 },
{ "source": 5, "target": 1 }
]
}
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
}))
.append("g")
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(100))
.force('charge', d3.forceManyBody().strength(-400))
.force('center', d3.forceCenter(width / 2, height / 2))
var link = svg.selectAll(".link")
.data(graph.links)
.enter()
.append("line")
var node = svg.selectAll(".nodes")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 20)
.on("click", addNode)
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded)
)
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("transform", function (d) { return "translate(" + d.x + ", " + d.y + ")"; });
}
function dragStarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged (event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragEnded(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = undefined;
d.fy = undefined;
}
function addNode(d) {
var newID = graph.nodes.length + 1
graph.nodes.push({"id": newID})
node = svg.selectAll(".nodes")
.append("circle")
.attr("r", 20)
.merge(node)
simulation.nodes(graph.nodes);
simulation.force("link").links(graph.links);
//reheat the simulation
simulation.alpha(0.3).restart()
}
</script>
</body>
</html>
Upvotes: 0
Views: 1163
Reputation: 38151
You're not enter items correctly - you don't have an enter statement. You also don't have any elements with class node
, so your initial selection is empty, you want to select circle
s (or apply a class to them). Try:
node = svg.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 20)
.merge(node)
The nodes are unbound, so they'll float away. Also, a drag is a long click, so you can't drag a node without creating a new one as is.
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>D3v6 v.0.0.1</title>
<!-- call external d3.js framework -->
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<style>
circle {
fill: whitesmoke;
stroke: white;
stroke-width: 2px
}
line {
stroke: black;
}
svg {
background-color: rgb(220, 220, 220);
}
</style>
<body>
<div id="content">
<svg> </svg>
</div>
<script src="https://d3js.org/d3.v6.js"></script>
<script>
var width = window.innerWidth, height = window.innerHeight
var graph = {
"nodes": [
{ "id": 1 },
{ "id": 2 },
{ "id": 3 },
{ "id": 4 },
{ "id": 5 }
],
"links": [
{ "source": 1, "target": 2 },
{ "source": 2, "target": 3 },
{ "source": 3, "target": 4 },
{ "source": 4, "target": 5 },
{ "source": 5, "target": 1 }
]
}
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
}))
.append("g")
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(100))
.force('charge', d3.forceManyBody().strength(-400))
.force('center', d3.forceCenter(width / 2, height / 2))
var link = svg.selectAll(".link")
.data(graph.links)
.enter()
.append("line")
var node = svg.selectAll(".nodes")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 20)
.on("click", addNode)
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded)
)
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("transform", function (d) { return "translate(" + d.x + ", " + d.y + ")"; });
}
function dragStarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged (event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragEnded(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = undefined;
d.fy = undefined;
}
function addNode(d) {
var newID = graph.nodes.length + 1
graph.nodes.push({"id": newID})
node = svg.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 20)
.merge(node)
simulation.nodes(graph.nodes);
simulation.force("link").links(graph.links);
//reheat the simulation
simulation.alpha(0.3).restart()
}
</script>
</body>
</html>
Upvotes: 1