I would like to display text in leaf when parent is focused like this: http://i60.tinypic.com/25qxdzt.jpg. Here is my code which display text only when last parent is focused:
var text = svg.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("class", "label")
.style("fill-opacity", function(d) { return d.parent === root ? 1 : 0; })
.style("display", function(d) { return d.children ? null : "none"; })
.text(function(d) { return d.name; });
Related
I have a situation where I want users to browse 3 different data sets using circle pack layout. I am using Bostock's Zoomable circle packing.
I have added 3 options additionally which loads data and creates new nodes. Here chartid is passed from these elements.
function changeDataSet(chartid)
{
console.log(chartid);
//console.log(nodes);
//add new chart data depending on the selected option
if(chartid === "plevels")
{
root = JSON.parse(newKmap_slevels);
focus = root;
nodes = pack.nodes(root);
}
else if (chartid === "pduration")
{
root = JSON.parse(newKmap_sduration);
focus = root;
nodes = pack.nodes(root);
}
else
{
root = JSON.parse(newKmap_stype);
focus = root;
nodes = pack.nodes(root);
}
refresh();
}
Then I have the refresh function, but I am not understnading how to remove existting nodes, and add new ones based on the new data set. Showing some transition animations would be nice also.
Currently I am trying to remove and recreate the initial elements, but the chart goes blank when I do that.
var refresh = function() {
//var nodes = pack.nodes(root);
var duration = 10;
console.log(nodes);
d3.select("#conf_knowledge_map").selectAll("g")
.remove();
svg
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("class", function(d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })
.style("fill", function(d) { return d.children ? color(d.depth) : null; })
.on("click", function(d) {
if (focus !== d) zoom(d), d3.event.stopPropagation();
});
text = svg.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("class", "label")
.style("fill-opacity", function(d) { return d.parent === root ? 1 : 0; })
.style("display", function(d) { return d.parent === root ? "inline" : "none"; })
.text(function(d) {
//console.log(d);
if( d.size )
{
return d.name + ":" + d.size;
}
else
return d.name;
});
}
So my question is how can I remove and then create new nodes on click?
UPDATE
I was able to remove all nodes and add the new nodes based on the new data, but now on click to zoom the layout is all messed up. The transform function is not applied to the new nodes somehow.
var refresh = function() {
svg.selectAll(".node").remove();
svg.selectAll(".label").remove();
var nodes = pack.nodes(root);
focus = root;
circle = svg.selectAll("circle")
.data(nodes)
.enter()
.append("circle")
.attr("class", function(d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })
.attr("r", function(d) { return d.r;})
.attr("cx", function(d) {
console.log(d);
// if(d.depth === 0)
// return 0;
// else
// return d.x - (diameter/2);
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
// .attr("transform", "translate(" + "x" + "," + "y" + ")")
.style("fill", function(d) { return d.children ? color(d.depth) : null; })
.on("click", function(d) {
// d.x = d.x - (diameter/2);
// d.y = d.y - (diameter/2);
if (focus !== d) zoom(d), d3.event.stopPropagation();
});
text = svg.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("class", "label")
.attr("x", function(d) {return d.x - (diameter/2);})
.attr("y", function(d) {return d.y - (diameter/2);})
.style("fill-opacity", function(d) { return d.parent === root ? 1 : 0; })
.style("display", function(d) { return d.parent === root ? "inline" : "none"; })
// .attr("transform", "translate(" + "x" + "," + "y" + ")")
.text(function(d) {
//console.log(d);
if( d.size )
{
return d.name + ":" + d.size;
}
else
return d.name;
});
}
How can I transform the new nodes to be in place and for the zoom to work properly?
UPDATE 2
Now the transform is working properly after attaching 'g' element to the circles, and showing all the nodes and text correctly. The only problem now is that the zoom does not work when I click on the circles!!
circle = svg.selectAll("circle")
.data(nodes)
.enter()
.append("circle")
.attr("class", function(d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })
.attr("r", function(d) { return d.r;})
.attr("cx", function(d) {
if(d.depth === 0)
return 0;
else
return d.x - (diameter/2);
})
.attr("cy", function(d) {
if(d.depth === 0)
return 0;
else
return d.y - (diameter/2);
})
.style("fill", function(d) { return d.children ? color(d.depth) : null;})
.on("click", function(d) {
if (focus !== d) zoom(d); d3.event.stopPropagation();
})
.append("g")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
;
How to make the zoom work??
It so happens that I was making the mistake of simultaneously creating three independent circle pack layouts, with mixed statements one after the other. This was problematic as when you have to select svg sections, different elements were all getting selected and wrongly attached with different events.
So I decided to separate the three implementations and create the three layouts one after the other, only after each one finished. This way I kept the section selection and attaching events etc, separate and then load them as and when required.
I don't really know svg and I want to select the text of this element (and just this element).
var text = svg.selectAll("text")
.data(nodes)
.enter()
.append("text")
.attr("class", "label")
.style("fill-opacity", function(d) { return d.parent === rootZC ? 1 : 0; })
.style("display", function(d) { return d.parent === rootZC ? "inline" : "none"; })
.text(function(d) { return d.name; });
To be clearer, I have some other text in my code and I want to apply a transition on this part and not on the text above.
I apply my transition like this
transition.selectAll("text")
but don't know. (work but remove the other text elements)
Then, how to select well my text? (I tried svg.text but that doesn't work).
Many thanks in advance for your help.
If you want to select this text you create here :
var text = svg.selectAll("text")
.data(nodes)
.enter()
.append("text")
.attr("class", "label")
.style("fill-opacity", function(d) { return d.parent === rootZC ? 1 : 0; })
.style("display", function(d) { return d.parent === rootZC ? "inline" : "none"; })
.text(function(d) { return d.name; });
I would just add a unique class for this text (for example sampleClass) :
.attr('class','label sampleClass'); //adding to the class you already have
Then you can select all elements like so :
var sampleClass = d3.selectAll('.sampleClass');
Then apply the translation like so :
sampleClass.attr('translate', 'transform('+sampleX+','+samplyY')';
So your code would look like :
var text = svg.selectAll("text")
.data(nodes)
.enter()
.append("text")
.attr("class", "label sampleClass")
.style("fill-opacity", function(d) { return d.parent === rootZC ? 1 : 0; })
.style("display", function(d) { return d.parent === rootZC ? "inline" : "none"; })
.text(function(d) { return d.name; });
var sampleClass = d3.selectAll('.sampleClass');
sampleClass.attr('translate', 'transform('+sampleX+','+samplyY')';
Hi so I'm trying to add multiple text elements to a d3 svg g node. However, for the following code, all the first text assignments to a node show up but none of the second text elements appear. Is my approach right? or is there a bug I'm missing
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
// .on("mouseenter",setdatavis)
// .on("mouseleave",setdatainvis);
nodeEnter.append("text")
// .attr("x",0)
// .attr("y",0)
// .append("tspan")
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("y",-10)
.attr("dy", ".35em")
.attr("text-anchor", "end")
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6)
.style("visibility","visible");
// .on("mouseenter", function(){d3.select(this)
// .style("visibility", "hidden")
// .transition()
// ;})
// .on("mouseleave", function(){d3.select(this)
// .style("visibility", "visible")
// .transition()
// ;});
nodeEnter.append("text")
.attr("x",10)
.attr("text-anchor","start")
.attr("y",10)
.attr("dy",".35em")
.text(function(d){return "hi";})
.style("visibility","visible")
.style("fill-opacity",1e-6);
I have a line graph I've made from nested data. The user can pick which keys will be graphed. Each key value has 4 child values associated with it. Every key has the same child value names. Each child value has it's own line. So, if the user picks 2 keys to be graphed, 8 lines will be on the graph. 4 for one key and 4 for the other.
I've made a legend that will display the child name and the pattern of it's line. I would like to be able to click the name of the child value in the legend and all child values with that name will be hidden, even if they have a different key.
Here is how I nested:
var servers = d3.nest()
.key(function (d) { return d.serverName; })
.entries(data)
How I defined lines:
var lineGen = d3.svg.line()
.x(function (d) {
return x(timeFormat.parse(d.metricDate));
})
.y(function (d) {
return y(d.ServerLogon);
})
.interpolate("linear")
var lineGen2 = d3.svg.line()
.x(function (d) {
return x(timeFormat.parse(d.metricDate));
})
.y(function (d) {
return y1(d.Processor);
})
.interpolate("linear");
var lineGen3 = d3.svg.line()
.x(function (d) {
return x(timeFormat.parse(d.metricDate));
})
.y(function (d) {
return y2(d.AdminLogon);
})
.interpolate("linear");
var lineGen4 = d3.svg.line()
.x(function (d) {
return x(timeFormat.parse(d.metricDate));
})
.y(function (d) {
return y3(d.ServerExport);
})
.interpolate("linear");
How I append lines, text and line pattern for legend:
servers.forEach(function (d, i) {
visObjectLoc.append("svg:path")
.attr("class", "line")
.attr("fill", "none")
.attr("stroke-dasharray", ("15, 3"))
.attr("d", lineGen2(d.values))
.attr("id", "Processor")
.style("stroke", function () {
return d.color = color(d.key);
});
visObjectLoc.append("text")
.attr("x", WIDTH / 4)
.attr("y", 34)
.style("text-anchor", "middle")
.style("font-size", "18px")
.text("Processor")
.on("click", function () {
var active = d.active ? false : true,
newOpacity = active ? 0 : 1;
d3.select("#Processor")
.transition().duration(100)
.style("opacity", newOpacity);
d.active = active;
});
visObjectLoc.append("line")
.attr("x1", 455)
.attr("x2", 370)
.attr("y1", 44)
.attr("y2", 44)
.attr("stroke-width", 2)
.attr("stroke", "black")
.attr("stroke-dasharray", ("15, 3"))
});
So far, the onClicks are only hiding the first key's child line. I've tried giving each child line for each server the same ID. I'm thinking I'm not looping through the keys correctly or maybe each line isn't getting the ID it needs. Any suggestions are welcome and appreciated.
IDs are unique. If you want to select a group of things, give them a class. If you could put the project in a JSFiddle I could test it, but it might be as simple as changing the line in the servers.forEach(... in the following way:
.attr("id", "Processor")
to
.attr("class", "Processor")
and then in the onClick callback:
d3.selectAll(".Processor")
.transition().duration(100)
.style("opacity", newOpacity);
...
I am new to D3.js and want to make a treemap like this: http://bl.ocks.org/mbostock/4063582#index.html
What I am going to do is to insert new div into parent nodes.
...
d3.json("flare.json", function(error, root) {
var node = div.datum(root).selectAll(".node")
.data(treemap.nodes)
.enter().append("div")
// parent nodes have class name "first"
.attr("class", function(d) { return d.children ? "node first" : "node"; })
.call(position)
.style("background", function(d) { return d.children ? color(d.name) : null; })
.text(function(d) { return d.children ? null : d.name; });
// my code
var parents = d3.selectAll(".first")
.data(treemap.value(function(d) { return d.size; }).nodes) // ISSUE
.enter().append("div")
.text(function(d) { return d.name; });
d3.selectAll("input").on("change", function change() {
var value = this.value === "count"
? function() { return 1; }
: function(d) { return d.size; };
node
.data(treemap.value(value).nodes)
.transition()
.duration(1500)
.call(position);
});
});
...
But this doesn't work correctly.
HOW CAN I UPDATE ONLY THE PAREENT NODES BY ADDING NEW DIV TO THEM?
Could anybody help me please. Thanks a lot...