Tooltips for nested circles in D3 circle pack layout - javascript

I'm banging my head here. I want to display tooltips for the leaf nodes in a structure such as Zoomable Pack Layout. The leaf nodes are the brown ones. If I used the standard code for tooltips:
vis.selectAll("circle")
.data(nodes)
.enter()
.append("svg:circle")
.attr("class", function(d) {
return d.children ? "parent" : "child";
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.r;
})
.on("click", function(d) {
zoom(node == d ? root : d);
})
.append("svg:title")
.text("test"); \\ Browser uses this for tooltips
I get tooltips on the primary circles but not on the leaf nodes. I tried:
.append("svg:title")
.text(function(d) {
if(d.size){return 'test';}
});
...hoping that by returning something only when a varaible contained by leaf nodes is present may prevent the parent nodes from showing a tooltip but I'm afraid all it did was allow a hidden tooltip taht silently prevents anything from displaying.
Any thoughts? I figure I either need to stack the svg:circles so that the leaf nodes are in front of the others or attach svg:titles only to the leaf nodes but I'm not sure how to do that.
Here is a fiddle of the tooltips:
Fiddle

The problem is in fact not the code, but the CSS that prevents the leaf node circles from receiving pointer events. Simply remove
circle.child {
pointer-events: none;
}
and it works fine. Complete example here.

Related

bubble chart color by parent class

I am looking at the Bubble Chart by Mike Bostock: http://bl.ocks.org/mbostock/4063530 that uses circle packing. I would like to however, be able to color the circles by the name of the containing class.
I am trying it in JSBin here: http://jsbin.com/qoveguvopu/edit?css,js,output
My fault is here:
node.append("circle")
.attr("r", function(d) { return d.r; })
.style("fill", function(d) {return color(d.data.name);});
Thanks!
Kind of like this:
You can get the data bound to the parent...
d.parent.data.name
... and color the circles according to it, first checking if a parent exists:
node.append("circle")
.attr("r", function(d) {
return d.r;
})
.style("fill", function(d) {
if (d.parent) {
return color(d.parent.data.name)
};
});
Here is your updated Bin: http://jsbin.com/ruyegidopo/1/edit

D3 circle pack - Adding labels to nodes

While I've seen this question asked a few times, I'm having a bit trouble implementing. What I'd like to do is have the label attribute centered within each circle (as mentioned here). I believe I'd be adding the text attribute to:
canvas.selectAll('circles')
.data(nodes)
.enter()
.append('svg:circle')
.attr('cx', function (d) {
return d.x;
})
.attr('cy', function (d) {
return d.y;
})
.attr('r', function (d) {
return d.r;
})
.attr('fill', function (d) {
return d.color;
});
But am confused on why the instructions they gave in the previous example I linked to doesn't work with the setup I currently have. I believe it's the pack option that could be throwing me off (about the difference between the two), but any further examples would be a huge help. Thanks!
Update
Thanks for the answers/suggestions, I updated the Codepen with my progress (as I needed two lines of data; should have clarified) which seems to be working well. Now this is packing into a circle - at the end of the day, I'd love for this to be packed in the actual #canvas width/height (which is a rectangle). I saw this treemap example - would that be what I'm going for here?
Demo of what I have so far
Perhaps the confusion is that you can't add labels to the circle selection (because in SVG, a circle element can't contain a text element). You need to either make a g element that contains both circle and text, or a separate selection for the text, e.g.:
canvas.selectAll('text')
.data(nodes)
.enter()
.append('svg:text')
.attr('x', function (d) {
return d.x;
})
.attr('y', function (d) {
return d.y;
})
// sets the horizontal alignment to the middle
.attr('text-anchor', "middle")
// sets the vertical alignment to the middle of the line
.attr('dy', '0.35em')
.text(function(d) {
return d.label;
});
See the updated demo: http://codepen.io/anon/pen/djebv

D3.js Force Layout: Dynamically added node doesn't move with rest of graph

I'm working on building a molecule creator in D3 using the original example created by Mike Bostock: http://bl.ocks.org/mbostock/3037015
I'm using a force layout just like in the example. My problem is when I add a new Node/atom dynamically, it doesn't move with the rest of the graph. I've read other questions and implemented everything that is suggested and have made sure that I'm following the proper update/join procedure that D3 requires and yet still the added carbon refuses to move with the rest of the graph.
Here is my update/create function:
function buildMolecule () {
// Update link data
link = link.data(links);
// Create new links
link.enter().append("g")
.attr("class", "link")
.each(function(d) {
d3.select(this)
.insert("line", ".node")
.style("stroke-width", function(d) { return (d.bond * 2 - 1) * 2 + "px"; });
d3.select(this)
.filter(function(d) { return d.bond > 1; }).append("line")
.attr("class", "separator");
d3.select(this)
.on("click", bondClicked);
});
// Delete removed links
link.exit().remove();
// Update node data
node = node.data(nodes);
// Create new nodes
node.enter().append("g")
.attr("class", "node")
.on("click", atomClicked)
.each(function(d) {
console.log('d:', d);
// Add node circle
d3.select(this)
.append("circle")
.attr("r", function(d) { return radius(d.size); })
.style("fill", function(d) { return color(d.atom); });
// Add atom symbol
d3.select(this)
.append("text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.atom; });
d3.select(this).call(force.drag);
});
// Delete removed nodes
node.exit().remove();
force.start();
}
JsFiddle: http://jsfiddle.net/2dPMF/1/
Any help would be greatly appreciated!
You're modifying the data structures of the nodes and links beyond adding and deleting nodes, which messes up the force layout. I'm talking about these lines in particular.
function bigBang () {
links = links.concat(linksList);
nodes = nodes.concat(nodesList);
buildMolecule();
}
The first two lines in that function are what I'm talking about. Working jsfiddle here.

How to display names next to bubbles in d3js motion chart

In Mike Bostocks example http://bost.ocks.org/mike/nations/ there is so much data that putting the names of the countries there would make it chaotic, but for a smaller project I would like to display it.
I found this in the source:
var dot = svg.append("g")
.attr("class", "dots")
.selectAll(".dot")
.data(interpolateData(2004))
.enter().append("circle")
.attr("class", "dot")
.style("fill", function(d) { return color(d); })
.text(function(d) { return d.name; })
.call(position)
.sort(order);
dot.append("title")
.text(function(d) { return d.name; });
But somehow a title never shows up. Does anybody have an idea, how to display the name, next to the bubble?
As the other answer suggests, you need to group your elements together. In addition, you need to append a text element -- the title element only displays as a tooltip in SVG. The code you're looking for would look something like this.
var dot = svg.append("g")
.attr("class", "dots")
.selectAll(".dot")
.data(interpolateData(2004))
.enter()
.append("g")
.attr("class", "dot")
.call(position)
.sort(order);
dot.append("circle")
.style("fill", function(d) { return color(d); });
dot.append("text")
.attr("y", 10)
.text(function(d) { return d.name; });
In the call to position, you would need to set the transform attribute. You may have to adjust the coordinates of the text element.
Unfortunately grouping the text and circles together will not help in this case. The bubbles are moved by changing their position attributes (cx and cy), but elements do not have x and y positions to move. They can only be moved with a transform-translate. See: https://www.dashingd3js.com/svg-group-element-and-d3js
Your options here are:
1) rewrite the position function to calculate the position difference (change in x and change in y) between the elements current position and its new position and apply that to the . THIS WOULD BE VERY DIFFICULT.
or 2) Write a parallel set of instructions to setup and move the tags. Something like:
var tag = svg.append("g")
.attr("class", "tag")
.selectAll(".tag")
.data(interpolateData(2004))
.enter().append("text")
.attr("class", "tag")
.attr("text-anchor", "left")
.style("fill", function(d) { return color(d); })
.text(function(d) { return d.name; })
.call(tagposition)
.sort(order);
You will need a separate tagposition function since text needs 'x' and 'y' instead of 'cx', 'cy', and 'r' attributes. Don't forget to update the "displayYear" function to change the tag positions as well. You will probably want to offset the text from the bubbles, but making sure the text does not overlap is a much more complicated problem: http://bl.ocks.org/thudfactor/6688739
PS- I called them tags since 'label' already means something in that example.
you have to wrap the circle element and text together , it should look like
<country>
<circle ></circle>
<text></text>
</country>

adding labels to node in d3.js

I am a newbie in d3.js
I am trying to add labels to my nodes.
But whatever I tried is not working..
My code is here:
http://jsfiddle.net/Ymtg5/1/
Its a mash up between http://bl.ocks.org/christophermanning/4208494
and force directed graphs.
Basically I am reading a json file and creating the said graph.
Now I want to add labels to node exactly like http://bl.ocks.org/mbostock/950642
I tried adding these lines
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
But its not working.
Any help. suggestions..
Thanks
Most probably the problem is that your JSON classes don't have a "name".
Right, this was not the problem
The relevant part of your code is as follows:
var node = svg.selectAll("path.node")
.data(nodes)
.enter().append("path").attr("class", "node")
.style("fill", function(d) { return fill(d.value); })
.style("stroke", function(d) { return d3.rgb(fill(d.value)).darker(); })
.call(force.drag);
// HERE should go node manipulation to add the text
force
.nodes(nodes)
.links(links)
.on("tick", tick)
.start();
function tick() {
//node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; );
node.attr("d", function(d) { return clip({"type":"F {"type":"Point","coordin...
link.attr("d", function(d) { return clip({"type":"Feature","geometry":{ ...
I have inserted a comment line where your node manipulation should go, if you want to add labels to the nodes. You are doing that inside the tick function (well, I think you are trying to do it there, the code isn't in the fiddle), and that function should be only for manipulation of the attr of the nodes. The place to create the text and append it to the node is outside of the function.

Categories