Reputation: 1183
I am trying to change this example http://bl.ocks.org/1153292 of force-directed built in d3.js.
I would like to create classes for the circles according to their type in the Json. I will need to use CSS, but I do not know how to change the code to apply it.
This is the code I have modified so far....
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Mobile Patent Suits</title>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?1.29.1"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.geom.js?1.29.1"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.layout.js?1.29.1"></script>
<style type="text/css">
circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
text.shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .8;
}
</style>
</head>
<body>
<script type="text/javascript">
// http://blog.thomsonreuters.com/index.php/mobile-patent-suits-graphic-of-the-day/
var links = [
{source: "t1", target: "hate", type: "green"},
{source: "t1", target: "good", type: "green"},
{source: "t2", target: "hate", type: "green"},
{source: "t3", target: "good", type: "green"},
{source: "t4", target: "good", type: "green"},
{source: "hate", target: "airport", type: "yellow"},
{source: "good", target: "airport", type: "yellow"},
{source: "good", target: "flight", type: "yellow"},
];
var nodes = {};
// Compute the distinct nodes from the links.
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});
var w = 960,
h = 500;
var force = d3.layout.force()
.nodes(d3.values(nodes))
.links(links)
.size([w, h])
.linkDistance(60)
.charge(-300)
.on("tick", tick)
.start();
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
var circle = svg.append("svg:g").selectAll("circle")
.data(force.nodes())
.enter().append("svg:circle")
.attr("r", 6)
.call(force.drag);
var text = svg.append("svg:g").selectAll("g")
.data(force.nodes())
.enter().append("svg:g");
// A copy of the text with a thick white stroke for legibility.
text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.attr("class", "shadow")
.text(function(d) { return d.name; });
text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.name; });
// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});
circle.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
text.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
</script>
</body>
</html>
Could anybody give me a hint? thanks
Upvotes: 1
Views: 5947
Reputation: 74046
You have an array of connections links
. Afterwards you extract the distinct nodes from this array by these lines:
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source} );
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});
At this point you should insert the type
for each node. So, e.g. we could use the class of the link, for this node (in that case, however, only one of all the links for a node determines its class). That would lead to the following code:
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, type: link.type} );
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, type: link.type});
});
No all nodes have a type
attribute and not just a name
.
When creating the circles later on here
var circle = svg.append("svg:g").selectAll("circle")
.data( force.nodes() )
.enter().append("svg:circle")
.attr("r", 6)
.call(force.drag);
we can use that type attribute together with a function that determines each circles class like this:
var circle = svg.append("svg:g").selectAll("circle")
.data( force.nodes() )
.enter().append("svg:circle")
.attr("r", 6)
.attr( 'class', function( d ) { console.log( d ); return d.type; } )
.call(force.drag);
And now all circles with have the respective class.
Note that you probably want to determine the type for each node somehow different, then in this example. So change the above declaration in links.forEach( ... );
accordingly.
Upvotes: 3