var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click)
.on("mouseover",function (d){
if(d.name=="Purchased"){
jQuery.getJSON("RequestHandler?usercommand=jsoncompany&subcommand=propCount&useraction=d3Tree_frm&mgmtId="+d.id+"&type="+d.name, function(json){
var count=JSON.stringify(json.prop_purchased_count);
result="Purchased Property :"+count;
});
}
var g = d3.select(this);
var info = g.append("text")
.classed('info', true)
.attr('x', 30)
.attr('y', 30)
.text(result);
})
.on("mouseout", function() {
d3.select(this).select('text.info').remove();
});
i am using above code to display basic tooltip on mouse over of a node. The problem is that when i move from one node to another tooltip value is not updated quickely it show me previous value .if i move my cursor little bit and move again to that node then only it shows me correct value of that node.
How to resolve that issue?
Related
I'm trying to implement the general update pattern in D3, to allow me to update existing elements before entering new ones.
This code works and generates the elements I want:
var nodes = nodeGroup.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y +")";
})
Now I want to change the code to store the update selection and modify some attributes before retrieving the enter selection.
But when I make this simple change, nothing gets appended any more:
var nodes = nodeGroup.selectAll(".node")
.data(root.descendants())
nodes.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y +")";
})
Why don't these two pieces of code behave identically?
I'm trying to find the problem with the drag behavior setup that I have in my program, because it seems like the drag won't even activate. I'm using http://jsfiddle.net/da37B/317/ as the reference code for my program.
Here's the relevant code:
vis.selectAll(".nodes")
.data(nodes)
.enter().append("circle")
.attr("class", "nodes")
.attr("cx", function (d) {
return xRange(d.x);
})
.attr("cy", function (d) {
return yRange(d.y);
})
.attr("r", "10px")
.attr("fill", "black")
.attr("transform", "translate(" + p.x + "," + p.y + ")")
.call(drag); <------
// Define drag beavior
var drag = d3.behavior.drag()
.on("drag", dragmove);
function dragmove(d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
}
And here's the full code: https://jsfiddle.net/4o5pch1q/1/
The reason you don't see any effect is that you have an error in your jsfiddle. Please check the console for such obvious things in the future.
Once the obvious error is fixed (including moving the definition of drag up so that it's defined before it's being used), the only thing that remains is to tell D3 how to get the origin of the element being dragged (otherwise the circle "jumps" on drag):
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("drag", dragmove);
Complete demo here.
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 managed to create a bubble chart which works fine when it is a single dataset. But something goes wrong if I need to update it with other datasets. Please help me with my update function at http://jsfiddle.net/9jL64/.
function changebubble(root)
{
var node = svg.selectAll(".node")
.data(bubble.nodes(classes(root))
.filter(function(d) { return !d.children; }));
node.enter()
.append("g")
.attr("class", "node")
.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; });
node.select("circle")
.transition()
.duration(1000)
.attr("r", function(d) { return d.r; })
.style("fill", function(d,i) { return color(i); });
node.transition().attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("circle")
.attr("r", function (d) { return d.r; })
.style("fill", function (d, i) { return color(i); });
node.exit()
.remove();
// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root)
{
var classes = [];
function recurse(name, node) {
if (node.children)
node.children.forEach(function(child) { recurse(node.name, child); });
else
classes.push({packageName: name, className: node.name, value: node.size});
}
recurse(null, root);
return {children: classes};
}
This is the classic case when you need to capture the enter selection on the svg:g group element in order to apply the enter/update/exit pattern correctly. But, to keep object constancy, and so that your labels still point to the right elements, you also need to key your data based on some data property of interest (d.className, which is generated from d.name).
Here is the main segment of your revised bubble update function:
var node = svg.selectAll(".node")
.data(
bubble.nodes(classes(root)).filter(function (d){return !d.children;}),
function(d) {return d.className} // key data based on className to keep object constancy
);
// capture the enter selection
var nodeEnter = node.enter()
.append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
// re-use enter selection for circles
nodeEnter
.append("circle")
.attr("r", function (d) {return d.r;})
.style("fill", function (d, i) {return color(i);})
// re-use enter selection for titles
nodeEnter
.append("title")
.text(function (d) {
return d.className + ": " + format(d.value);
});
The complete FIDDLE is here.
I also blogged on the matter of applying the enter/update/exit pattern to svg:g elements, if you are interested.
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);