D3.js - How to change position of labels on zoom - javascript

I have a zoom function which works perfectly fine for circles, but not for labels.
svgEnter.attr('transform', 'translate(' + d3.event.translate + ')scale(' + d3.event.scale + ')');
How to "attach" labels to circle, so it follows parent when users scroll or zoom?
Here is an example fiddle: http://jsfiddle.net/seveneleven/z4m5c06a/1/

In case if anyone wondering: plain text nodes is the way to go.
var ne = node.enter()
.append('a')
.attr('class', function(d) {
return d.style + '-bubble-node';
})
.attr('alt', function(d) {
return '#' + (encodeURIComponent(idValue(d)));
})
.call(force.drag)
.call(connectEvents);
ne.append('text')
.text(function(d) {
return d.name
});
ne.append('circle')
.attr('r', function(d) {
return rScale(rValue(d));
});

Related

How to enable text selection in a D3.js-SVG that has zoom enabled?

I'm new with D3 and I going crazy with this detail: I'm building a graph which is a Bubble graph with some labels inside, and I would like to enable users to be able to select the textual labels of the bubbles. I mean, in the traditional way, as if they are highlighting any other text in a webpage.
By default, the graph allows users to select the text in the bubbles, but if I enable the zoom, I can no longer select the texts. I enabled the zoom by:
var svg = d3
.select(this.domSelector)
.append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "bubble")
.call(d3.behavior.zoom().on("zoom", function () {
svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
}))
I tried to temporally disable this effect by preventing it if the user is clicking any element byt the background. This is to say:
.call(d3.behavior.zoom().on("zoom", (evt) => {
if(d3.event.sourceEvent.target.tagName.toLocaleLowerCase() == "svg"){
svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}
else svg.on('.zoom', null); }))
But the behaviour is the same: I can not select the text. Any idea?
https://jsfiddle.net/gal007/e2gsvkLt/
You can assign mousedown event to the text element with d3.event.stopPropagation(). Would be something like that:
generateBubbleNames(nodes){
var maxCharacters = 10;
var labels = nodes.selectAll("text.label")
.data(function(d) { return [d]; });
labels.enter().append("text")
.attr({
"class": "label",
dy: "0.35em"
})
.style("text-anchor", "middle")
.style("font-size", function(d) { return d.r / 3; })
.text(function(d) {
return d[0]
})
.on("mousedown", function(){
d3.event.stopPropagation();
})
}
Here's a working example:
JsFiddle

Add labels to nodes in Hobbelt's "Group/Bundle Nodes" D3 force layout example?

I adapted Ger Hobbelt's excellent example of group/bundle nodes
https://gist.github.com/GerHobbelt/3071239
as a JSFiddle here:
https://jsfiddle.net/NovasTaylor/tco2fkad/
The display demonstrates both collapsible nodes and regions (hulls).
The one tweak that eludes me is how to add labels to expanded nodes. I have successfully added labels to nodes in my other force network diagrams using code similar to:
nodes.append("text")
.attr("class", "nodetext")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) {
// d.name is a label for the node, present in the JSON source
return d.name;
});
Is anyone familiar enough with Ger's example to guide me in the right direction?
On enter, instead of appending circle append a g with a circle and a text. Then re-factor a bit to fix the movement of the g instead of the circle. Finally, append write out the .text() only if the node has a name (meaning it's a leaf):
node = nodeg.selectAll("g.node").data(net.nodes, nodeid);
node.exit().remove();
var onEnter = node.enter();
var g = onEnter
.append("g")
.attr("class", function(d) { return "node" + (d.size?"":" leaf"); })
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
g.append("circle")
// if (d.size) -- d.size > 0 when d is a group node.
.attr("r", function(d) { return d.size ? d.size + dr : dr+1; })
.style("fill", function(d) { return fill(d.group); })
.on("click", function(d) {
expand[d.group] = !expand[d.group];
init();
});
g.append("text")
.attr("fill","black")
.text(function(d,i){
if (d['name']){
return d['name'];
}
});
And refactored tick to use g instead of circle:
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
Updated fiddle.

How to add a text label to a polyline edge in D3.js

I had to use polyline to draw the edges because I needed straight line edges with arrow markers in the middle. (As suggested in Display an arrow head in the middle of D3 force layout link).
I also need to add labels to the edges(Something like this http://jsfiddle.net/bc4um7pc/).
From what I understand, textPath is used to add text labels to a path. How to adapt this for polyline edges. textPath doesnt seem to work with polyline. How do I make this work?
var path = svg.append("svg:g").selectAll("path");
path = path.data(force.links(), function(d,i) {return d.source.id + "-" + d.target.id; });
path.enter()
.append("polyline")
.attr("class", function(d) { return "link " + d.type; })
.attr("id",function(d,i) { return "linkId_" + i; })
.attr("marker-mid", function(d) { return "url(#" + d.type + ")"; });
var linktext = svg.append("svg:g").selectAll(".linklabelholder");
linktext = linktext.data(force.links())
.enter().append("g").attr("class", "linklabelholder")
.append("text")
.attr("class", "linklabel")
.style("font-size", "13px")
.attr("x", "50")
.attr("y", "-20")
.attr("text-anchor", "start")
.style("fill","#000")
.append("textPath")
.attr("xlink:href",function(d,i) { return "#linkId_" + i;})
.text( "test");

How to get D3 Tree link text to transition smoothly?

Visualization Goal: Build a D3 Tree that has text at, both, nodes and links, and that transitions cleanly, when nodes are selected/deselected.
Problem: While I can get link text, called "predicates," to show up along the centroid of all link paths, I can't seem to get them to transition in and out "smoothly."
Question: Can someone please help me please help me clean up the code and better understand how tree "link" transitions are behaving so I understand the theory behind the code?
Visualization and Source Location: http://bl.ocks.org/Guerino1/raw/ed80661daf8e5fa89b85/
The existing code looks as follows...
var linkTextItems = vis.selectAll("g.linkText")
.data(tree.links(nodes), function(d) { return d.target.id; })
var linkTextEnter = linkTextItems.enter().append("svg:g")
.attr("class", "linkText")
.attr("transform", function(d) { return "translate(" + (d.target.y + 20) + "," + (getCenterX(d)) + ")"; });
// Add Predicate text to each link path
linkTextEnter.append("svg:foreignObject")
.attr("width", "120")
.attr("height", "40")
.append("xhtml:body")
.attr("xmlns", "http://www.w3.org/1999/xhtml")
.html(function(d){ return "<p>" + (linksByIdHash[d.source.id + ":" + d.target.id].predicate) + "</p>"; });
// Transition nodes to their new position.
//var linkTextUpdate = linkTextItems.transition()
//.duration(duration)
//.attr("transform", function(d) { return "translate(" + d.source.x + "," + d.source.y + ")"; })
//linkTextUpdate.select("linkText")
//.style("fill-opacity", 1);
// Transition exiting linkText to the new position of the parents.
var linkTextExit = linkTextItems.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.source.y + 20 + "," + (getCenterX(d)) + ")"; })
.remove();
linkTextExit.select("linkText")
.style("fill-opacity", 1e-6);
function getCenterX(d) {
var xS = d.source.x;
var xT = d.target.x;
if(xS == xT)
{ return (xS - (xS - xT)/2); }
else if(xS > xT)
{return (xS - (xS - xT)/2); }
else
{ return (xT - (xT - xS)/2); }
}
Some Symptoms...
When link text transitions in or out, it's choppy / not smooth
When a branch is collapse, link text doesn't transition to appropriate path centroids
My frustration is that I feel like I'm very close but that I'm missing something very simple/basic. Any help is greatly appreciate.

Used Arc.centroid to plot circles - but text do no go along with it why?

I've used arc.Centroid to try to plot my circles on the arcs with labels. However, the labels do not stay with it?
force.on("tick", function() {
text.attr("x", function(d) { return d.x + 6; })
.attr("y", function(d) { return d.y + 4; });
node.attr("transform", function(d,i) {
return "translate(" + arc[i].centroid(d) + ")"; })
});
I have attempted to put centroid & arc[i] instead of the x & y. How can I put my circles with text? http://jsfiddle.net/xwZjN/20/
Also say if I were to have more json data, would I be able to restrict the plots only going into each section e.g. each section being a category?
Any help would be great. I think the solution may be similar to this - http://jsfiddle.net/nrabinowitz/GQDUS/
It seems that the force layout is not the right choice for your application. Try to group your symbol and text in a g element and place them at the calculated coordinates. See updated fiddle without force layout: http://jsfiddle.net/xwZjN/26/
var node = svg.selectAll("g.node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d,i) {
return "translate(" + arc[i].centroid() + ")";
});
node.append("path")
.attr("d", d3.svg.symbol().type(function(d) { return d.type; }))
// change (0,0) for exact symbol placement
.attr("transform", "translate(0,0)")
.style("fill", "blue" );
node.append("text")
.text(function(d) { return d.Name; })
// shift text in nice position
.attr("x", 10)
.attr("y", 5);

Categories

Resources