Zoom for graph in D3 - javascript

I have javascript code that draws a graph using data stored in json file.
<!DOCTYPE html xmlns:xlink="http://www.w3.org/1999/xlink">
<meta charset="utf-8">
<style>
// style here
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<div id="animviz"></div>
<script>
var vv = window,
w = vv.innerWidth,
h = vv.innerHeight;
var x = d3.scale.linear()
.domain([0, w])
.range([0, w]);
var y = d3.scale.linear()
.domain([0, h])
.range([h, 0]);
var svg = d3.select("#animviz")
.append("svg")
.attr("width", w)
.attr("height", h)
.append("g")
var color = d3.scale.category10();
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.size([w, h]);
d3.json("post000.json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
var myMouseoverFunction = function() {
var circle = d3.select(this);
circle.transition().duration(100)
.attr("r", 20 )
node.append("title")
.text(function(d) { return d.name});
}
var myMouseoutFunction = function() {
var circle = d3.select(this);
circle.transition().duration(500)
.attr("r", 10 );
}
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 10)
.attr("transform", transform)
.style("fill", function(d) { return color(d.group); })
.call(force.drag)
.on("mouseover", myMouseoverFunction)
.on("mouseout", myMouseoutFunction);
force.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>
</body>
However I can't zoom in or out this graph in a browser. I planned to use similar example from documentation; however, in my case I load data from post000.json using d3.json that is asynchronous and I'm not sure how I can access this data when it's loaded to pass it as input to zoom function.
How can I draw a graph that I can zoom in with data stored in json?

Here is code that works for me:
<!DOCTYPE html xmlns:xlink="http://www.w3.org/1999/xlink">
<meta charset="utf-8">
<style>
// style here
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<div id="animviz"></div>
<script>
d3.json("post000.json", function(error, graph) {
var vv = window,
w = vv.innerWidth,
h = vv.innerHeight;
var svg = d3.select("#animviz")
.append("svg")
.attr("width", w)
.attr("height", h)
.append("g")
.call(d3.behavior.zoom().scaleExtent([0, 8]).on("zoom", zoom))
.append("g");
var color = d3.scale.category10();
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.size([w, h]);
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.attr("transform", function(d) { return "translate(" + d + ")"; });
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
var myMouseoverFunction = function() {
var circle = d3.select(this);
circle.transition().duration(100)
.attr("r", 20 )
node.append("title")
.text(function(d) { return d.name});
}
var myMouseoutFunction = function() {
var circle = d3.select(this);
circle.transition().duration(500)
.attr("r", 10 );
}
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 10)
.style("fill", function(d) { return color(d.group); })
.call(force.drag)
.on("mouseover", myMouseoverFunction)
.on("mouseout", myMouseoutFunction);
force.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>
</body>

Related

How to wrap text in force layout d3 with long labels?

I am trying to wrap text which is parsed from a json response into my application.
I have two svg elements : rect and text. I want to find a way where I can wrap my svg text such that it fits in the rectangle.
( Picture Force layout with text labels and rectangles )
This is the link to the original project in which I have made modifications
Visualizing Reddit Discussions
setupGraph();
function setupGraph() {
$(".network").empty();
names = {};
nodecolor = {};
force = d3.layout.force()
.charge(-500)
.linkDistance(20)
.size([width, height]);
nodes = force.nodes(),
links = force.links();
force.on("tick", function() {
svg.selectAll("line.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;
});
svg.selectAll("rect.node")
.attr("x", function(d) {
return d.x - d.curWidth / 2;
})
.attr("y", function(d) {
return d.y - d.curHeight / 2;
});
svg.selectAll("text.node")
.attr("x", function(d) {
return d.x - d.curWidth / 2 + 8;
})
.attr("y", function(d) {
return d.y - d.curHeight / 2 + 20;
});
});
d3.select("svg").remove();
svg = d3.select("#chart").append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("class", "network");
}
function updateNetwork() {
var link = svg.selectAll("line.link")
.data(links, function(d) {
return d.source.id + "-" + d.target.id;
});
link.enter().insert("svg:line", "text.node", "rect.node")
.attr("class", "link")
.style("stroke-width", function(d) {
return 2;
})
.style("stroke", "gray")
.style("opacity", 0.1);
var node = svg.selectAll("rect.node")
.data(nodes, function(d) {
return d.id;
});
var node = svg.selectAll("text.node")
.data(nodes, function(d) {
return d.id;
});
var nodeEnter = node.enter().append("svg:rect")
.attr("class", "node")
.call(force.drag)
.attr("width", function(d) {
return d.curWidth;
})
.attr("height", function(d) {
return d.curHeight;
})
.style("opacity", 1.0)
.on("mouseover", displayTooltip)
.on("mousemove", moveTooltip)
.on("mouseout", removeTooltip)
.on("mouseover", function(d) {
d3.select(this).transition().attr("height", 100).attr("width", 100); //.style("fill", "red");
})
.call(force.drag)
var nodeEnterr = node.enter().append("svg:text")
.attr("class", "node")
.text(function(d) {
return d.name + ": " + d.body
})
.call(force.drag)
.style("opacity", 1.0)
.on("mouseover", displayTooltip)
.on("mousemove", moveTooltip)
.on("mouseout", removeTooltip)
.call(force.drag)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to add a dynamic legend to a D3 force directed graph in Apex?

I built in Apex a D3 force graph basically like http://bl.ocks.org/mbostock/1093130 or http://bl.ocks.org/mbostock/4062045. The difference is, that I pull my data with an Application Process from a address table from the database. It works just fine.
The colors of the nodes are defined by the address type (like Contact, Payment Office, Licensees, ...). Now I want to add a legend on the side of the page with the different colors the graph is using and the connected address type.
Do I do that in the Page Attributes in the CSS Inline Part, or do I have to add something in the D3 graph JavaScript code.
Here is my code:
var graph;
function get_chart_data() {
var get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=AddressData',$v('pFlowStepId'));
var data_all = get.get();
var obj = eval ("(" + data_all + ")");
return obj;
}
function showChart2() {
graph = get_chart_data();
var width = 1000,
height = 800;
var color = d3.scale.category20();
var force = d3.layout.force()
.gravity(0)
.charge(-400)
.linkDistance(90)
.size([width, height]);
var svg = d3.select("#chart2").append("svg")
.attr("width", width)
.attr("height", height);
var nodeById = d3.map();
graph.nodes.forEach(function(node) {
nodeById.set(node.id, node);
});
graph.links.forEach(function(link) {
link.source = nodeById.get(link.source);
link.target = nodeById.get(link.target);
});
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 8)
.style("fill", function(d) { return color(d.type); })
node.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function(d) { return d.first_name; });
force.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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
};
I hope I explained it well enough for you to understand it.
Guess what, I just solved my own question :)
I added a code in the JavaScript part of the Page Attributes at the end of the function showChart2(), but still in it.
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
And here is the full working code:
var graph;
function get_chart_data() {
var get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=AddressData',$v('pFlowStepId'));
var data_all = get.get();
var obj = eval ("(" + data_all + ")");
return obj;
}
function showChart2() {
graph = get_chart_data();
var width = 1000,
height = 800;
var color = d3.scale.category20();
var force = d3.layout.force()
.gravity(0)
.charge(-400)
.linkDistance(90)
.size([width, height]);
var svg = d3.select("#chart2").append("svg")
.attr("width", width)
.attr("height", height);
var nodeById = d3.map();
graph.nodes.forEach(function(node) {
nodeById.set(node.id, node);
});
graph.links.forEach(function(link) {
link.source = nodeById.get(link.source);
link.target = nodeById.get(link.target);
});
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 8)
.style("fill", function(d) { return color(d.type); })
node.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function(d) { return d.first_name; });
force.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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
};
I never thought I could answer my own question, but it works ;)
I hope it helps somebody else too...

Labels and images for D3 nodes incorrectly show at top left of screen

I'm able to get images and labels to show for the nodes, but they show at the top left of the screen.
Nodes show up in the correct position when I use this
.enter().append("circle")
Labels and node images show at the top left (incorrect) when I use this:
.enter().append("g")
This works with append "circle" (commented out in the code below):
When I comment out append circle and use append "g" (in order to use node images and labels) the images and labels all show up near (0,0) instead of near the node:
Also, what exactly is append "g"? Where is the documentation to find out what's possible with append "g"?
Here is all the code:
<script>
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size(\[width, height\]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var graph = getData();
var nodeMap = {};
graph.nodes.forEach(function(d) { nodeMap\[d.name\] = d; });
graph.links.forEach(function(l) {
l.source = nodeMap\[l.source\];
l.target = nodeMap\[l.target\];
})
force.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke", function(d) {
return d.line_color;
})
.style("stroke-width", function(d) {
return Math.sqrt(d.value)+1;
});
var node = svg.selectAll(".node")
.data(graph.nodes)
// .enter().append("circle")
// .attr("class", "node")
// .attr("r", 10)
// .style("fill", function(d) { return d.fill_color; })
// .call(force.drag);
.enter().append("g")
.attr("class", "node")
.attr("r", 15)
.style("fill", function(d) { return d.fill_color; })
.on("click", function(d){
alert("You clicked on node " + d.name);
})
.call(force.drag);
node.append("title")
.text(function(d) { return d.label; });
node.append("image")
.attr("xlink:href", function(d) { return d.image_url })
.attr("x", -8)
.attr("y", -8)
.attr("width", 26)
.attr("height", 26);
node.append("text")
.attr("dx", function(d) {
if (d.image_url == "/profile.png"){
return 100;
}
else{
return 16;
}
})
.attr("dy", function(d) {
if (d.image_url == "/profile.png"){
return 100;
}
else{
return ".35em";
}
})
// .attr("dy", ".35em")
.text(function(d) { return d.name });
force.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; });
});
function getData() {
return {
"nodes":\[
{"name":"user1","image_url":"http://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/103px-Wikipedia-logo-v2.svg.png","fill_color":"blue","text_color":"black"},
{"name":"user2","image_url":"http://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/103px-Wikipedia-logo-v2.svg.png","fill_color":"blue","text_color":"black"},
{"name":"user3","image_url":"http://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/103px-Wikipedia-logo-v2.svg.png","fill_color":"blue","text_color":"black"},
{"name":"tag1","image_url":"","fill_color":"blue","text_color":"black"},
{"name":"tag2","image_url":"","fill_color":"blue","text_color":"black"},
{"name":"tag3","image_url":"","fill_color":"blue","text_color":"black"}
\],
"links":\[
{"source":"tag1","target":"user1","value":1,"line_color":"green"},
{"source":"tag2","target":"user1","value":1,"line_color":"green"},
{"source":"tag3","target":"user1","value":1,"line_color":"green"},
{"source":"tag1","target":"user2","value":1,"line_color":"green"},
{"source":"tag2","target":"user2","value":1,"line_color":"green"}
\]
};
}
</script>
With .append("g") you insert a SVG Group Element.
The problem is, that you try to apply attributes that are for circles, like the radius with .attr("r",15), to the group element.
You have to use circles if you want to draw a circle. Group elements do not have any shape. They are used to group elements like circles.
A solution would be to append the g element and transform it to the location of the node. I updated your code in the following snippet. I used the group elements and added the circle, image and text inside the group elements.
Moreover I removed the backslashes before each angular bracket and set the title to the field name instead of label.
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var graph = getData();
var nodeMap = {};
graph.nodes.forEach(function(d) { nodeMap[d.name] = d; });
graph.links.forEach(function(l) {
l.source = nodeMap[l.source];
l.target = nodeMap[l.target];
})
force.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter()
.append("line")
.attr("class", "link")
.style("stroke", function(d) {
return d.line_color;
})
.style("stroke-width", function(d) {
return Math.sqrt(d.value)+1;
});
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter()
.append("g")
.attr("transform", function(d){return "translate("+d.x+","+d.y+")"})
.call(force.drag);
node.append("circle")
.attr("class", "node")
.attr("r", 15)
.style("fill", function(d) { return d.fill_color; })
.on("click", function(d){
alert("You clicked on node " + d.name);
});
node.append("title")
.text(function(d) { return d.name; });
node.append("image")
.attr("xlink:href", function(d) { return d.image_url })
.attr("x", -8)
.attr("y", -8)
.attr("width", 26)
.attr("height", 26);
node.append("text")
.attr("dx", function(d) {
if (d.image_url == "/profile.png"){
return 100;
}
else{
return 16;
}
})
.attr("dy", function(d) {
if (d.image_url == "/profile.png"){
return 100;
}
else{
return ".35em";
}
})
// .attr("dy", ".35em")
.text(function(d) { return d.name });
force.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("transform", function(d){return "translate("+d.x+","+d.y+")"});
});
function getData() {
return {
"nodes":[
{"name":"user1","image_url":"http://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/103px-Wikipedia-logo-v2.svg.png","fill_color":"blue","text_color":"black"},
{"name":"user2","image_url":"http://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/103px-Wikipedia-logo-v2.svg.png","fill_color":"blue","text_color":"black"},
{"name":"user3","image_url":"http://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/103px-Wikipedia-logo-v2.svg.png","fill_color":"blue","text_color":"black"},
{"name":"tag1","image_url":"","fill_color":"blue","text_color":"black"},
{"name":"tag2","image_url":"","fill_color":"blue","text_color":"black"},
{"name":"tag3","image_url":"","fill_color":"blue","text_color":"black"}
],
"links":[
{"source":"tag1","target":"user1","value":1,"line_color":"green"},
{"source":"tag2","target":"user1","value":1,"line_color":"green"},
{"source":"tag3","target":"user1","value":1,"line_color":"green"},
{"source":"tag1","target":"user2","value":1,"line_color":"green"},
{"source":"tag2","target":"user2","value":1,"line_color":"green"}
]
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

d3.js: Drag is disabled when use zoom with force layout

I have seen this question: Is there a way to zoom into a D3 force layout graph?
But I got some unexpected behaivor from my graph - after few drags or zoom or pan all nodes just freezes and drag stop working.
I created this fiddle: http://jsfiddle.net/7gpweae9/9/
SO asked for code, so here is main part:
var svg = d3.select("#graph")
.append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-event", "all")
.append("svg:g")
.call(d3.behavior.zoom().on("zoom", zoom))
.append("svg:g");
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr('fill', 'white');
var link = svg.selectAll(".link");
var node = svg.selectAll(".node");
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([width,height])
.linkDistance(100)
.charge(-400)
.start();
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(drag);
node.append("circle")
.attr("class", "node-circle")
.attr("r", 12);
node.append("text")
.attr("x", 12)
.attr("y", ".35em")
.text(function(d) { return d.word; });
link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");
force.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("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
function zoom() {
svg.attr("transform",
"translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("x", d.x = d3.event.x).attr("y", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
Perhaps I missed something, I never used d3 before.
UPD: It seems that freezing occurs after a certain period of time.
I replaced d3.layout.force() to force.drag() and now it works almost fine.
var nodes;
var links;
prepareData();
var graph = document.querySelectorAll("#graph")[0];
var height = 500;
var width = 500;
var svg = d3.select("#graph").append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-event", "all")
.append("svg:g")
.call(d3.behavior.zoom().on("zoom", zoom))
.append("svg:g");
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr('fill', 'white');
var link = svg.selectAll(".link");
var node = svg.selectAll(".node");
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([width,height])
.linkDistance(100)
.charge(-400)
.start();
var drag = force.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(drag);
node.append("circle")
.attr("class", "node-circle")
.attr("r", 12);
node.append("text")
.attr("x", 12)
.attr("y", ".35em")
.text(function(d) { return d.word; });
link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");
force.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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
}
function dragged(d) {
d3.select(this).attr("x", d.x = d3.event.x).attr("y", d.y = d3.event.y);
}
function prepareData() {
nodes = [{"index":0,"word":"edit"},{"index":1,"word":"course","sentences":[29859]},{"index":2,"word":"needs","sentences":[29859]},{"index":3,"word":"fit","sentences":[29859]},{"index":4,"word":"slides","sentences":[29859]},{"index":5,"word":"print","sentences":[29859]},{"index":6,"word":"can","sentences":[29859]}];
links = [{"source":0,"target":1},{"source":0,"target":2},{"source":0,"target":3},{"source":0,"target":4},{"source":0,"target":5},{"source":0,"target":6}]
}
svg {
border: 1px solid black;
}
.link {
stroke: #000;
stroke-width: 1px;
}
.node-circle {
cursor: move;
fill: #ccc;
stroke: #000;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<div id="graph"></div>
</body>
You had to make your drag variable a function and change d3.behaviour.drag to force.drag :
function drag(){
return force.drag()
// .origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
}
Ive updated your fiddle
Working JSFIDDLE : http://jsfiddle.net/7gpweae9/15/

Labels / text on the nodes of a D3 force directed graph

I still not understanding why the code bellow does not display its labels / text...
I have defined the css and set the attribute like the title when the move is over the node:
Json:
{
"nodes":[
{"name":"t1","group":1},
{"name":"t2","group":1},
{"name":"t3","group":1},
{"name":"t4","group":1},
{"name":"hate","group":2},
{"name":"good","group":2},
{"name":"aiport","group":3},
{"name":"flight","group":3}
],
"links":[
{"source":0,"target":4,"value":4},
{"source":0,"target":5,"value":4},
{"source":1,"target":4,"value":4},
{"source":2,"target":5,"value":4},
{"source":3,"target":5,"value":4},
{"source":4,"target":6,"value":4},
{"source":5,"target":6,"value":4},
{"source":5,"target":7,"value":4}
]
}
Code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
fill: #555;
stroke: #999;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 1024,
height = 768;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("data.json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll("line.link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll("circle.node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
node.append("text")
.text(function(d) { return d.name; });
force.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>
</body>
</html>
You are adding the text element inside the circle element - try running your code and have a look at the svg with the DOM inspector. I'm not sure text is allowed there. Instead add the text elements separately - like another rendering of the nodes:
var texts = svg.selectAll("text.label")
.data(graph.nodes)
.enter().append("text")
.attr("class", "label")
.attr("fill", "black")
.text(function(d) { return d.name; });
force.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; });
texts.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
Another option would be to add both circle and text elements inside a g container element as shown below:
var container = svg.selectAll("g.node").data(graph.nodes).enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
}).call(force.drag);
container.append("circle")
.attr("r", 5)
.style("fill", color);
container.append("text")
.style("text-anchor", "middle")
.text(function (d) {
return d.name;
});
Here you can play with a working jsfiddle:
http://jsfiddle.net/vfu78/16/

Categories