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
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
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.
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");
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.
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);