Add text on links using D3.js - javascript

I want to write relations between 2 nodes on the links that connect them. This is my code, I do not know why he did not work. Can you help me ?
Thanks a lot.
PS: Sorry for my english.
d3.json("links.json", function(json) {
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter()
.append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.weight); })
.style("stroke", function(d) { return color(d.group); });
link.append("path")
.attr("fill", "none")
.attr("stroke", "#333S")
.attr("stroke-width", "1.5px");
link.append("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial")
.attr("transform", function(d) {
return "translate(" +
((d.source.x + d.target.y)/2) + "," +
((d.source.x + d.target.y)/2) + ")";
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
console.log(d.relation);
return d.relation;
});
});
This is a links.json example :
{
"nodes":[{"name":"Gaillard Ruzé","group":0},{"name":"Guillaume Budé,Gulielmus Budaeus","group":1}],
"links":[{"source":0,"target":1,"weight":1,"group":15,"relation":"est dédicataire de"}]
}

Related

How can I position text inside bubble chart?

Using d3.js v3, I've made this bubble chart:
d3.json(JSON_URL, function(data) {
data = JSON.parse(data)
var nodes = pack.nodes(data);
var node = canvas.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function (d) { return "translate(" + d.x + ","+ d.y + ")" ;});
node.append("circle")
.attr("r", function(d) {return d.r; })
.attr("fill", function (d, i) {return d.children ? "#fff" : color(i)})
.attr("opacity", 0.25)
.attr("stroke-width", "2");
node.append("text")
.text(function(d) {return d.children ? "" : d.name ;})
.attr("text-anchor", "middle")
.attr("class", "nodetext")
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;})
.on("click", function(d) { window.open("https://twitter.com/hashtag/" + d.name.trim() + "\?src=hash"); })
.on("mouseover", function(d) {
d3.select(this).attr("r", 10).style("fill", "#2f4cff");
d3.select(this).style("cursor", "pointer");
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 5.5).style("fill", "#000");
});
//problem here
node.append("text")
.text(function(d) {return d.children ? "" : d.value ;})
.attr("text-anchor", "middle")
.attr("class", "nodevalue")
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;});
}) ;
It's all well, expect the fact that the texts for d.value overlap the texts of d.name, while I want them to come under the d.name. The result should be something like this:
I tried to tweak the nodevalue class but it did not affect the positioning of texts.
How can I acheive this?
You can use the y attribute to position vertically your text. Your code is a bit hard to test because we don't have access to your json, so blindly the code for the text part would be :
node.append("text")
.text(function(d) {return d.children ? "" : d.name ;})
.attr("text-anchor", "middle")
.attr("class", "nodetext")
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;})
.on("click", function(d) { window.open("https://twitter.com/hashtag/" + d.name.trim() + "\?src=hash"); })
.on("mouseover", function(d) {
d3.select(this).attr("r", 10).style("fill", "#2f4cff");
d3.select(this).style("cursor", "pointer");
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 5.5).style("fill", "#000");
});
node.append("text")
.text(function(d) {return d.children ? "" : d.value ;})
.attr("text-anchor", "middle")
.attr("class", "nodevalue")
.attr("y", 15) // adding y attribute to offset vertically your text
.attr("data-classname", function(d) {return d.className;})
.attr("style", function(d) {return "font-size:" + d.r/4;});

D3 node update - how to select a specific text element among multiple ones?

Let's say I got this code for fading in nodes:
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
})
.on("click", collapse);
nodeEnter.append("rect")
.attr("class", "rect")
.attr("width", 170)
.attr("height", 80)
.attr("x", -85)
.attr("y", -80)
.attr("opacity", 0)
.style("fill", "#989898")
.style("stroke", "#65737e");
nodeEnter.append("text")
.attr("class", "title")
.attr("x", -80)
.attr("y", -70)
.attr("opacity", 0)
.attr("fill", "black")
.attr("dy", ".71em")
.text(function (d) {
return d.title;
});
nodeEnter.append("text")
.attr("class", "name")
.attr("x", -80)
.attr("y", -70)
.attr("opacity", 0)
.attr("fill", "black")
.attr("dy", "1.86em")
.text(function (d) {
return d.firstName + " " + d.lastName;
});
And will be updated like this:
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
nodeUpdate.select("rect")
.attr("width", 170)
.attr("height", 80)
.attr("x", -85)
.attr("y", -80)
.attr("opacity", 1)
.style("fill", "#989898")
.style("stroke", "#65737e");
nodeUpdate.select("text")
.attr("class", "title")
.attr("x", -80)
.attr("y", -70)
.attr("opacity", 1)
.attr("fill", "black")
.attr("dy", ".71em")
.text(function (d) {
return d.title;
});
nodeUpdate.select("text")
.attr("class", "name")
.attr("x", -80)
.attr("y", -70)
.attr("opacity", 1)
.attr("fill", "black")
.attr("dy", "1.86em")
.text(function (d) {
return d.firstName + " " + d.lastName;
});
My problem is now that I append multiple text elements (title and name) on a single node, but only the last one selected will be shown, as the other ones seem overwritten, since I don't select a specific text element. I tried both saving every element in a variable when appending, as well as selecting them by class, but none of these options did work. Does anyone have a solution for this?
The problem is that you have multiple text elements that need to be dealt with separately, but you're not distinguishing between them in the selectors. You can do that easily by using the classes that you've assigned to them, i.e. instead of
.select("text")
you would do
.select("text.title")
and
.select("text.name")

D3.js network graph using force-directed layout and rectangles for nodes

I'm trying to modify Mike's Force-Directed Graph example to use rectangles instead of circles as nodes. Also, I want text inside the rectangle.
I have rectangles showing up with text correctly, however they're not attached to the links, and they do not move.
Here's a codepen link: http://codepen.io/anon/pen/gpgWaz
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);
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("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.call(force.drag);
node.append("rect")
.attr("class", "node")
.attr("width", 100)
.attr("height", 35)
.style("fill", function(d) {
return color(d.group);
})
.style("stroke", "black")
.style("stroke-width", "1px");
node.append("text")
.text(function(d) {
return d.name;
})
.style("font-size", "12px")
.attr("dy", "1em");
node.append("title")
.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("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
});
});
Update
Thanks to Lars's comment, and his codepen it works now.
Updates I made to my code:
Add transform illustrated by Lars
Changed links to connect at the center of rectangles
Added rounded corners to rectangles
Gave the text a slight margin indentation
Changed to use window width/height
Here my new codepen: http://codepen.io/anon/pen/bdgREd
var width = window.innerWidth,
height = window.innerHeight,
nodeWidth = 100,
nodeHeight = 35;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-1500)
.linkDistance(100)
.friction(0.5)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
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("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.call(force.drag);
node.append("rect")
.attr("class", "node")
.attr("width", nodeWidth)
.attr("height", nodeHeight)
.attr("rx", 5)
.attr("ry", 5)
.style("fill", function(d) {
return color(d.group);
})
.style("stroke", "black")
.style("stroke-width", "1px");
node.append("text")
.attr("x", 5)
.attr("y", 2)
.text(function(d) {
return d.name;
})
.style("font-size", "12px")
.attr("dy", "1em");
node.append("title")
.text(function(d) {
return d.name;
});
force.on("tick", function() {
link.attr("x1", function(d) {
return d.source.x + (nodeWidth / 2);
})
.attr("y1", function(d) {
return d.source.y + (nodeHeight / 2);
})
.attr("x2", function(d) {
return d.target.x + (nodeWidth / 2);
})
.attr("y2", function(d) {
return d.target.y + (nodeHeight / 2);
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
You're setting the x and y attributes on the g elements to change their positions -- this won't do anything. You need to set the transform attribute instead, like you're doing when adding the g elements. So your tick handler function would contain
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
instead of
node.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
});
Complete demo here.

d3.js force-collapsible with labels

Actually I've integrated collapsible feature inside bounded force directed graph. But when I tried to put a label on each node, I got unexpected output.
I used bellow code to append labels on node:
node.enter().append("text")
.attr("class","node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.on("click",click)
.text(function(d){return d.name})
.call(force.drag);
And below code I've written inside a tick function:
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
What I might be doing wrong?
I need to append the g tag and then circle and text:
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.on("click", click)
.call(force.drag);
nodeEnter.append("circle")
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 8.5; });
nodeEnter.append("text")
.attr("dy", ".35em")
.text(function(d) { return d.name; });
node.select("circle")
.style("fill", color);

JS D3 textPath isn't displayed

i have the code below and wonder, why the textpath isn't displayed? Can anyone help?
var areas = svg.append("g").selectAll("path")
.data(chord.groups)
.enter().append("path")
.style("fill", function(d) { return fill(d.index); })
.style("stroke", function(d) { return fill(d.index); })
.attr("class", "bar")
.attr("id", function(d, i) { return "group" + i; })
.attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius))
.on("mouseover", fade(.1))
.on("mouseout", fade(1));
svg.selectAll(".bar").append("text")
.style("font-size", "10px")
.attr("fill", "black")
.append("textPath")
.attr("x", 8)
.attr("dy", ".35em")
.style("fill", "#ff00ff")
.attr("xlink:href", function(d, i) { return "#group" + i; })
.text("Textexample");
Thank you very much!
Benjamin

Categories

Resources