How can i disable the animation while dragging the current node in the force simulation in the d3 version 4
Below is the code which is used for drag the node
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function dragstarted(d) {
if (!d3.event.active) force.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) force.alphaTarget(0.3);
// d.fx = null;
//d.fy = null;
}
When i tried to stop the force while in dragged method it doesn't work out.
Please suggest me the best way to stop the animation
Please check this fiddle
It's not exactly clear what you mean by "disable the animation". I suppose that you're talking about the movement of the other nodes... well, that's quite the expected behaviour, since you're reheating the simulation.
A possible solution is setting the fx and fy property of all nodes when the simulation ends:
simulation.on("end", function() {
node.each(function(d) {
d.fx = d.x;
d.fy = d.y;
})
})
Here is your code with that change. Wait until the simulation ends (aprox. 5 seconds) and then drag the nodes:
var nodes = [{
"id": 1,
"name": "server 1"
}, {
"id": 2,
"name": "server 2"
}, {
"id": 3,
"name": "server 3"
}, {
"id": 4,
"name": "server 4"
}, {
"id": 5,
"name": "server 5"
}, {
"id": 6,
"name": "server 6"
}, {
"id": 7,
"name": "server 7"
}, {
"id": 8,
"name": "server 8"
}, {
"id": 9,
"name": "server 9"
}]
var links = [{
source: 1,
target: 2
}, {
source: 1,
target: 3
}, {
source: 1,
target: 4
}, {
source: 2,
target: 5
}, {
source: 2,
target: 6
}, {
source: 3,
target: 7
}, {
source: 5,
target: 8
}, {
source: 6,
target: 9
}, ]
var index = 10;
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;
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));
update();
function update() {
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")
.on("click", click)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("circle")
.attr("r", 2.5)
node.append("title")
.text(function(d) {
return d.id;
});
node.append("text")
.attr("dy", 3)
.text(function(d) {
return d.name;
});
simulation
.nodes(nodes)
.on("tick", ticked)
.on("end", function() {
node.each(function(d) {
d.fx = d.x;
d.fy = d.y;
})
})
simulation.force("link")
.links(links);
}
function click(d) {
nodes.push({
id: index,
name: "server " + index
});
links.push({
source: d.id,
target: index
});
index++;
update();
}
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);
}
.link {
stroke: #aaa;
}
.node {
pointer-events: all;
stroke: none;
stroke-width: 40px;
cursor: pointer;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="400"></svg>
Take a look at this example: http://bl.ocks.org/norrs/2883411 as it seems to accomplish what you are after.
As indicated in the example and the related SO question (D3 force directed graph with drag and drop support to make selected node position fixed when dropped) you will probably be better off creating and using your own drag listener to achieve this specific behaviour.
Its actually very easy. Simply don't define :
.call(d3.drag().on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end))
This is what is controlling the animation part, and yet you find problem in late loading of your graph due to huge data or something then i suggest add a property called .alphaDecay(0.9), this particular thing will decrease the link length thus decreasing your load time of graph.
Related
I have six nodes and i want to link between them , I used forceSimulation to make nodes
so i used "mouseover" and "mouseout" in each node to ensure that when node come closer to another node it means that it will be link with this node , but when i drag node closer to another node that created after it "mouseover" and "mouseout" events are called,
but when i drag node closer to another that presiding it "mouseover" and "mouseout" events are not working
var data = get_data();
var domNode = null;
var selectedNode = null;
var svg =null,simulation,link,node;
function update(){
if(node != null){
node.remove();
}
if (link != null) {
link.remove();
}
svg = d3.select("svg"),
width = +svg.attr('width'),
height = +svg.attr('height'),
svgGroup = svg.append("g");
simulation = d3.forceSimulation()
.force('link', d3.forceLink().id(function (d) {
return d.id;
}).distance(function (d) {
return 50;
}).strength(0.01))
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2));
link = svgGroup
.selectAll('line')
.data(data.links)
.enter().append('line')
.attr('stroke-width', function (d) {
return (d.value * 2);
})
.style('stroke', '#999');
node = svgGroup
.selectAll('circle')
.data(data.nodes)
.enter().append('g')
.attr("class", "node")
.call(d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended));
node.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
node.append("circle")
.attr('class', 'ghostCircle')
.attr("r", 35)
.attr("opacity", 0.3) // change this to zero to hide the target area
.style("fill", "red")
.on("mouseover", function (node) {
overCircle(node);
})
.on("mouseleave", function (node) {
outCircle(node);
});
simulation
.nodes(data.nodes)
.on('tick', ticked)
.force('link')
.links(data.links);
}
update();
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 initiateDrag(d, domNode) {
draggingNode = d;
d3.select(domNode).select('.ghostCircle').attr('pointer-events', 'none');
d3.selectAll('.ghostCircle').attr('class', 'ghostCircle show');
d3.select(domNode).attr('class', 'node activeDrag');
d3.select(domNode).selectAll('.ghostCircle').attr('class', 'ghostCircle');
node.selectAll("g.node").sort(function (a, b) { // select the parent and sort the path's
if (a.id != draggingNode.id) return 1; // a is not the hovered element, send "a" to the back
else return -1; // a is the hovered element, bring "a" to the front
});
if (data.nodes.length > 1) {
nodePaths = node.selectAll("path.link")
.data(data.links, function (d) {
return d.target.id;
}).remove();
nodesExit = node.selectAll("g.node")
.data(data.nodes, function (d) {
return d.id;
}).filter(function (d, i) {
if (d.id == draggingNode.id) {
return false;
}
return true;
}).remove();
}
}
var updateTempConnector = function () {
var data = [];
if (draggingNode !== null && selectedNode !== null) {
// have to flip the source coordinates since we did this for the existing connectors on the original tree
data = [{
source: {
x: draggingNode.x,
y: draggingNode.y
},
target: {
x: selectedNode.x,
y: selectedNode.y
}
}];
}
d3.selectAll(".templink").remove();
var link = node.select(".templink").data(data);
link.exit().remove();
svg.append("path")
.data(data)
.attr("class", "templink")
.attr("d", linkD)
.attr('pointer-events', 'none');
};
var linkD = d3.linkHorizontal()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
})
// drag nodes
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;
domNode = this;
initiateDrag(d, domNode);
updateTempConnector();
ticked();
fix_nodes(d);
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = d.x;
d.fy = d.y;
d3.selectAll('.ghostCircle').attr('class', 'ghostCircle');
d3.select(domNode).attr('class', 'node');
// now restore the mouseover event or we won't be able to drag a 2nd time
d3.select(domNode).select('.ghostCircle').attr('pointer-events', '');
domNode = this;
if (selectedNode) {
var addlink = { "source": data.nodes.indexOf(draggingNode), "target": data.nodes.indexOf(selectedNode), "value": 1 }
// now remove the element from the parent, and insert it into the new elements children
d.fixed = true;
// of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
data.links.push(addlink);
updateTempConnector();
update();
selectedNode = null;
draggingNode = null;
}
}
// Preventing other nodes from moving while dragging one node
function fix_nodes(this_node) {
node.each(function (d) {
if (this_node != d) {
d.fx = d.x;
d.fy = d.y;
}
});
}
var overCircle = function (d) {
selectedNode = d;
updateTempConnector();
};
var outCircle = function (d) {
d3.selectAll(".templink").remove();
selectedNode = null;
updateTempConnector();
};
function get_data() {
var data = {
"nodes": [{
"id": 0,
"name": "A",
"value": 10
},
{
"id": 1,
"name": "B",
"value": 5
},
{
"id": 2,
"name": "C",
"value": 8
},
{
"id": 3,
"name": "D",
"value": 4
},
{
"id": 4,
"name": "E",
"value": 9
},
{
"id": 5,
"name": "F",
"value": 6
}
],
"links": [{
"source": 0,
"target": 1,
"value": 1
},
{
"source": 0,
"target": 2,
"value": 2
},
{
"source": 1,
"target": 2,
"value": 3
},
{
"source": 1,
"target": 3,
"value": 1
}
]
};
return data;
}
.link {
stroke: #ccc;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
.node,
.link {
cursor: pointer;
}
.overlay {
background-color: #EEE;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font-size: 10px;
font-family: sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 4px;
}
.templink {
fill: none;
stroke: red;
stroke-width: 3px;
}
.ghostCircle.show {
display: block;
}
.ghostCircle,
.activeDrag .ghostCircle {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
to another node that presiding it in div , not working
Please advise me what was wrong in the following code.
I want to create foce-directed graph by using D3.js
I cannot find where to correct in the following code.
Please advise me what was wrong in the following code.
I want to create foce-directed graph by using D3.js
I cannot find where to correct in the following code.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 v5 force simulation</title>
</head>
<body>
<svg width="400" height="300"></svg>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var nodesData = [
{id:"Korea", "group": 1},
{id:"USA", "group": 1},
{id:"France", "group": 1},
{id:"UK", "group": 1},
{id:"Japan", "group": 1},
{id:"Turkey", "group": 1},
]
var linksData = [
{ "source": 'Korea', "target": 'USA'},
{ "source": 'UK', "target": 'USA' },
{ "source": 'France', "target": 'Turkey' },
{ "source": 'Korea', "target": 'UK' },
{ "source": 'Japan', "target": 'Turkey' },
{ "source": 'Japan', "target": 'Korea' }
]
var link = d3.select("svg")
.selectAll("line")
.data(linksData)
.enter()
.append("line")
.attr("stroke-width", 1)
.attr("stroke", "black");
var node = d3.select("svg")
.selectAll("circle")
.data(nodesData)
.enter()
.append("circle")
.attr("r", 10)
.attr("fill", "LightSalmon")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var simulation = d3.forceSimulation()
.force("link", d3.forceLink())
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(200, 150));
simulation
.nodes(nodesData)
.on("tick", ticked);
simulation.force("link")
.links(linksData);
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>
I'm trying to figure out a way to space out the nodes in my network graph for my d3.js code. I don't necessarily care about how the shape of the network will be when I load the page since I can just click and drag around the nodes to make any kind of shape I want. But I'm not really sure where I start in trying to space out my nodes. I searched around and nothing I found seems to work for me. Help is very much appreciated.
Here is a picture of what the network looks like when I load the page:
https://i.gyazo.com/919ad4bde39d9fe6a6b6c91548dbcc2f.png
Here is what I'd like for it to look like roughly (again, shape does not really matter, I'm just looking to get a little distance on the inital load):
https://i.gyazo.com/fefa29cf861e204bc83f34cbc2d1a17d.png
(I only have 8 rep so I can't upload pictures sorry)
Here's my code so far:
<!DOCTYPE html>
<style>
.links line {
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
</style>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Group Comments</title>
<script src="http://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<p> Not Ready: Group 6 Comments </p>
<svg width="960" height="600"></svg>
<script>
//fetches the svg
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
//Sets a color scale
var color = d3.scaleOrdinal(d3.schemeCategory20);
var strokeColor = d3.scaleLinear()
.domain([0, 1, 2])
.range(["white", "red", "green"]);
//Creates a force simulation
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))
//reads the JSON file
d3.json("NR6comments.json", function (error, graph) {
if (error) throw error;
//sets up the "links" between the nodes
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) })
.attr("stroke", function (d) { return strokeColor(d.value) });
//sets up the nodes
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 10)
.attr("fill", function (d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
//displays the ID number on a node when hovering over
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>
<p>Likes Chart</p>
</body>
</html>
I would greatly appreciate it if I could get some help with this problem. Thank you!
There are different ways to achieve what you want. The easiest one is setting the strength of your manyBody method. According to the API:
If strength is specified, sets the strength accessor to the specified number or function, re-evaluates the strength accessor for each node, and returns this force. A positive value causes nodes to attract each other, similar to gravity, while a negative value causes nodes to repel each other, similar to electrostatic charge.
Since I don't have access to your data, this is a simplified demo. The first version has no strength, just like your code:
var width = 400;
var height = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var nodes = [{
name: "foo",
color: "blue"
}, {
name: "bar",
color: "green"
}, {
name: "baz",
color: "red"
}, {
name: "foofoo",
color: "yellow"
}, {
name: "foobar",
color: "blue"
}, {
name: "foobaz",
color: "green"
}, {
name: "barfoo",
color: "red"
}, {
name: "barbar",
color: "yellow"
}, {
name: "barbaz",
color: "blue"
}];
var links = [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 2
}, {
"source": 0,
"target": 3
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 4
}, {
"source": 2,
"target": 5
}, {
"source": 3,
"target": 6
}, {
"source": 1,
"target": 7
}, {
"source": 6,
"target": 8
}, {
"source": 0,
"target": 7
}, {
"source": 2,
"target": 6
}, {
"source": 3,
"target": 8
}];
var simulation = d3.forceSimulation()
.force("link", d3.forceLink())
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.selectAll(null)
.data(links)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", 1);
var node = svg.selectAll(null)
.data(nodes)
.enter()
.append("circle")
.attr("r", function(d) {
return d.r = 10;
})
.attr("stroke", "gray")
.attr("stroke-width", "2px")
.attr("fill", function(d) {
return d.color
});
simulation.nodes(nodes);
simulation.force("link")
.links(links);
simulation.on("tick", function() {
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
});
});
<script src="https://d3js.org/d3.v4.min.js"></script>
The second version, however, has the strength set to a negative value:
.force("charge", d3.forceManyBody().strength(-500))
Here it is:
var width = 400;
var height = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var nodes = [{
name: "foo",
color: "blue"
}, {
name: "bar",
color: "green"
}, {
name: "baz",
color: "red"
}, {
name: "foofoo",
color: "yellow"
}, {
name: "foobar",
color: "blue"
}, {
name: "foobaz",
color: "green"
}, {
name: "barfoo",
color: "red"
}, {
name: "barbar",
color: "yellow"
}, {
name: "barbaz",
color: "blue"
}];
var links = [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 2
}, {
"source": 0,
"target": 3
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 4
}, {
"source": 2,
"target": 5
}, {
"source": 3,
"target": 6
}, {
"source": 1,
"target": 7
}, {
"source": 6,
"target": 8
}, {
"source": 0,
"target": 7
}, {
"source": 2,
"target": 6
}, {
"source": 3,
"target": 8
}];
var simulation = d3.forceSimulation()
.force("link", d3.forceLink())
.force("charge", d3.forceManyBody().strength(-500))
.force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.selectAll(null)
.data(links)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", 1);
var node = svg.selectAll(null)
.data(nodes)
.enter()
.append("circle")
.attr("r", function(d) {
return d.r = 10;
})
.attr("stroke", "gray")
.attr("stroke-width", "2px")
.attr("fill", function(d) {
return d.color
});
simulation.nodes(nodes);
simulation.force("link")
.links(links);
simulation.on("tick", function() {
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
});
});
<script src="https://d3js.org/d3.v4.min.js"></script>
I'm new to D3, and am trying to make a graph similar to this example but a few things confuse me. I'm unsure when the example is referring to things built in to D3, or just the data set they are using.
Like here, I'm not sure about the id in d.id. as the example's data looks like this, which makes me think id is from the data. Or does it represent an index value?
"nodes": [
{"id": "Myriel", "group": 1},
{"id": "Napoleon", "group": 1}
],
// etc
"links": [
{"source": "Napoleon", "target": "Myriel", "value": 1},
{"source": "Mlle.Baptistine", "target": "Myriel", "value": 8},
{"source": "Mme.Magloire", "target": "Myriel", "value": 10},
//etc
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; })) <-- where is this from?
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
SO! In my code I get an error repeating thousands of times, 'Uncaught Error: missing: X', where X is the value of the first source in my links array. I can console.log my data and it looks fine, and the elements are rendering to the DOM, but all bunched up to the top left of the SVG. I don't know what is wrong. I guess I have 2 questions.
Could someone clarify about the example id thing?
What does my error mean?
Any help would be appreciated.
My code;
var graph
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
d3.json("./mock.json", function(json) {
var graph = json
console.log(graph);
console.log(graph.nodes);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink(graph.links))
.force("charge", d3.forceManyBody())
.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.id); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) {return d.text });
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;
}
});
Data:
{
"nodes":[
{"reference":5, "year": 0, "text":"The amount of time spent on video gaming is related negatively to academic achievement", "tags":["Academic disturbance"]},
{"reference":5, "year": 0, "text":"Digital addiction ranges from <1% and 38%", "tags":["Addiction"]},
{"reference":58, "year": 0, "text":"Patological video game play impacts negativelly academic achievement", "tags":["Addiction"]},
{"reference":77, "year": 2009, "text":"74% of adults have Internet access at home", "tags":["Adults"]},
{"reference":64, "year": 0, "text":"Apathetic users spend short times on web pages, follow no logical order, and make random selections", "tags":["Apathetic hypertext users3"]},
{"reference":8, "year": 0, "text":"49.8% of sessions are shorter than 5 seconds", "tags":["App usage"]}
],
"links": [
{"source":0,"target":2},
{"source":0,"target":6},
{"source":1,"target":6},
{"source":1,"target":3},
{"source":1,"target":2}
]
}
There are two issues with your code:
The index of 6, see in your links array, is not available in the nodes array. nodes has a length of 6, which means the largest index is 5. This causes an error even with the correct code. I have change 6 to 5 in my working example below, and I believe that is what you want.
Since the links are based on the index, you can simply return the index instead of the ID, i.e. d3.forceLink().id(function(d,i) { return i; }.
Here is the proof-of-function example:
var graph
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var json = {
"nodes": [{
"reference": 5,
"year": 0,
"text": "The amount of time spent on video gaming is related negatively to academic achievement",
"tags": ["Academic disturbance"]
}, {
"reference": 5,
"year": 0,
"text": "Digital addiction ranges from <1% and 38%",
"tags": ["Addiction"]
}, {
"reference": 58,
"year": 0,
"text": "Patological video game play impacts negativelly academic achievement",
"tags": ["Addiction"]
}, {
"reference": 77,
"year": 2009,
"text": "74% of adults have Internet access at home",
"tags": ["Adults"]
}, {
"reference": 64,
"year": 0,
"text": "Apathetic users spend short times on web pages, follow no logical order, and make random selections",
"tags": ["Apathetic hypertext users3"]
}, {
"reference": 8,
"year": 0,
"text": "49.8% of sessions are shorter than 5 seconds",
"tags": ["App usage"]
}],
"links": [{
"source": 0,
"target": 2
}, {
"source": 0,
"target": 5
}, {
"source": 1,
"target": 5
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 2
}
]
};
var graph = json;
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d, i) {
return i;
}))
.force("charge", d3.forceManyBody())
.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.id); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) {
return d.text
});
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: #aaa;
}
.nodes circle {
pointer-events: all;
stroke: none;
stroke-width: 40px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js"></script>
<svg width="500" height="200"></svg>
I am a beginner at d3. One of the diagrams I find particularly helpful and fun is the d3 force diagram. I've been playing around with it, but for some reason I've had a lot of trouble with this particular data set. Specifically, I've been trying forever to get the labels to show up on my d3 force diagram, but it just won't work. Here is my code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
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));
d3.json("links.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 1});
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", function(d){
return 3*d.size;
})
.attr("fill", function(d) { return color(d.id); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("svg:title")
.attr("dx", 12)
.attr("dy", ".35em")
.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>
thanks so much for your help
edit: here is my links.json
{
"nodes": [
{"id": "AK","size": "1.414213562"},
{"id": "AL","size": "1.414213562"},
{"id": "AR","size": "1.414213562"},
{"id": "AZ","size": "2.828427125"}],
"links": [
{"source": "ABC","target": "CO","value": "A"},
{"source": "ABC","target": "CO","value": "A"},
{"source": "ABC","target": "CO","value": "A"},
{"source": "ABC","target": "FL","value": "A"}
}
Added Edit below :
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));
graph = {
"nodes": [
{"id": "AK","size": "1.414213562"},
{"id": "AL","size": "1.414213562"},
{"id": "AR","size": "1.414213562"},
{"id": "AZ","size": "2.828427125"}],
"links": [
{"source": "AK","target": "AL","value": "A"},
{"source": "AL","target": "AZ","value": "A"},
{"source": "AL","target": "AR","value": "A"},
{"source": "AZ","target": "AR","value": "A"}]
};
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return 1});
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", function(d){
return 5;
})
.attr("fill", function(d) { return color(d.id); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("svg:title")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.id });
var labels = svg.append("g")
.attr("class", "label")
.selectAll("text")
.data(graph.nodes)
.enter().append("text")
.attr("dx", 6)
.attr("dy", ".35em")
.style("font-size",10)
.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; });
labels
.attr("x", function(d) { return d.x; })
.attr("y", 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;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="600"></svg>
Original answer :
Your json is not "proper". First of all there is no source named ABC or targets named CO or FL.
Source and target values should be an id from the nodes. You cannot link something that is not defined.
Also you are not using the size and value attribute.
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));
graph = {
"nodes": [
{"id": "AK","size": "1.414213562"},
{"id": "AL","size": "1.414213562"},
{"id": "AR","size": "1.414213562"},
{"id": "AZ","size": "2.828427125"}],
"links": [
{"source": "AK","target": "AL","value": "A"},
{"source": "AL","target": "AZ","value": "A"},
{"source": "AL","target": "AR","value": "A"},
{"source": "AZ","target": "AR","value": "A"}]
};
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return 1});
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", function(d){
return 5;
})
.attr("fill", function(d) { return color(d.id); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("svg:title")
.attr("dx", 12)
.attr("dy", ".35em")
.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;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="600"></svg>