As a follow up question of D3.js change width of container after it is drawn I create the rectangles that fits the text length, I want to link the rectangles from bottom. But I'm stuck in getting the width of rectangle when I draw the link.
This is the js code:
var rectW = 140, rectH = 40;
// Declare the nodes.
var node = draw.selectAll('g.node')
.data(nodes, function(d) { return d.id; });
// Enter the nodes.
var nodeLabel = node.enter().append('g')
.attr('transform', function(d) { return 'translate(' + source.x0 + ',' + source.y0 + ')'; });
var nodeRect = nodeLabel.append('rect')
.attr('width', rectW)
.attr('height', rectH);
var nodeText = nodeLabel.append('text')
.attr('x', rectW / 2)
.attr('y', rectH / 2)
.text(function (d) { return d.name; });
// This arranges the width of the rectangles
nodeRect.attr("width", function() {
return this.nextSibling.getComputedTextLength() + 20;
})
// This repositions texts to be at the center of the rectangle
nodeText.attr('x', function() {
return (this.getComputedTextLength() + 20) /2;
})
Next,I'd like to link the nodeRects. Linking the top left corner is ugly, so I adjust a bit:
link.attr('d', function (d) {
var sourceX = d.source.x + 0.5*d.source.getComputedTextlength() + 10,
sourceY = (d.source.y > d.target.y)? d.source.y: (d.source.y + rectH),
targetX = d.target.x + 0.5*d.target.getComputedTextlength() +10,
targetY = (d.source.y >= d.target.y)? (d.target.y + rectH) : d.target.y;
It returns error. Is there a way that I can get access to the target rect and source rect's textlength or width?
I find an answer by myself. d.source.width doesn't work because it is not defined.
Change
nodeRect.attr("width", function() {
return this.nextSibling.getComputedTextLength() + 20;
})
to
nodeRect.attr("width", function(d) {
d.width = this.nextSibling.getComputedTextLength() + 20;
return d.width;
})
Then use d.source.width works well.
Related
If you see the existing code, https://jsfiddle.net/sheilak/9wvmL8q8 when the graph is loaded for first time links that connecting the parent and child node are from border of parent node but once its collapsed and expanded, you can see same links are from center of parent node. i don't want to link to be from center of the parent node.
code
var width = 960,
height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.size([width, height])
//gravity(0.2)
.linkDistance(height / 6)
.charge(function(node) {
if (node.type !== 'ORG') return -2000;
return -30;
});
// build the arrow.
svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", function(d) {
return d;
})
.attr("viewBox", "0 -5 10 10")
.attr("refX", 12)
.attr("refY", 0)
.attr("markerWidth", 9)
.attr("markerHeight", 5)
.attr("orient", "auto")
.attr("class", "arrow")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var json = dataset;
var edges = [];
json.edges.forEach(function(e) {
var sourceNode = json.nodes.filter(function(n) {
return n.id === e.from;
})[0],
targetNode = json.nodes.filter(function(n) {
return n.id === e.to;
})[0];
edges.push({
source: sourceNode,
target: targetNode,
value: e.Value
});
});
for(var i = 0; i < json.nodes.length; i++) {
json.nodes[i].collapsing = 0;
json.nodes[i].collapsed = false;
}
var link = svg.selectAll(".link");
var node = svg.selectAll(".node");
force.on("tick", function() {
// make sure the nodes do not overlap the arrows
link.attr("d", function(d) {
// Total difference in x and y from source to target
diffX = d.target.x - d.source.x;
diffY = d.target.y - d.source.y;
// Length of path from center of source node to center of target node
pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY));
// x and y distances from center to outside edge of target node
offsetX = (diffX * d.target.radius) / pathLength;
offsetY = (diffY * d.target.radius) / pathLength;
return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
update();
function update(){
var nodes = json.nodes.filter(function(d) {
return d.collapsing == 0;
});
var links = edges.filter(function(d) {
return d.source.collapsing == 0 && d.target.collapsing == 0;
});
force
.nodes(nodes)
.links(links)
.start();
link = link.data(links)
link.exit().remove();
link.enter().append("path")
.attr("class", "link")
.attr("marker-end", "url(#end)");
node = node.data(nodes);
node.exit().remove();
node.enter().append("g")
.attr("class", function(d) {
return "node " + d.type
});
node.append("circle")
.attr("class", "circle")
.attr("r", function(d) {
d.radius = 30;
return d.radius
}); // return a radius for path to use
node.append("text")
.attr("x", 0)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("class", "text")
.text(function(d) {
return d.type
});
// On node hover, examine the links to see if their
// source or target properties match the hovered node.
node.on('mouseover', function(d) {
link.attr('class', function(l) {
if (d === l.source || d === l.target)
return "link active";
else
return "link inactive";
});
});
// Set the stroke width back to normal when mouse leaves the node.
node.on('mouseout', function() {
link.attr('class', "link");
})
.on('click', click);
function click(d) {
if (!d3.event.defaultPrevented) {
var inc = d.collapsed ? -1 : 1;
recurse(d);
function recurse(sourceNode){
//check if link is from this node, and if so, collapse
edges.forEach(function(l) {
if (l.source.id === sourceNode.id){
l.target.collapsing += inc;
recurse(l.target);
}
});
}
d.collapsed = !d.collapsed;
}
update();
}
}
There are two simple ways to address this that require little modification of your existing code.
The first is half done as the target of each link is already offset when you define your path data:
return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
});
You could extend this to offset from the source node quite easily, just add the offsets to sourceX and sourceY as here. This way it doesn't matter if the nodes are above or under the links because they don't overlap. (There might be slight overlap, so you could add a pixel or two to the offsets to account for link width).
The second option is possibly easier in d3v4+, as it features selection.raise() (docs). This method raises the selected item to the top of the SVG (as the last child of the parent element). The is equivalent to:
this.parentNode.appendChild(this);
In your click function, after you update the graph, we can use this line to ensure the node that was clicked on rises to the top (over the links). Here's an example of that.
I have multiple group elements with text element inside them. When I'm zooming with the mouse wheel, then everything is fine, my text is still inside my paths (polygons).
But when I'm zooming in automatically, then my text doesn't relocate.
Here is my function with auto zoom, I'm trying to find a specific path by ID, fill it with yellow, center and zoom to it.
function findByID(ID) {
svgContainer.selectAll("path")
.data(feat.features)
.filter(function (d) {
if (d.properties.myID == ID) {
centered = centered !== d && d;
var paths = svgContainer.selectAll("path")
.classed("active", function (d) {
d === centered;
});
var t0 = projection.translate(),
s0 = projection.scale();
projection.fitSize([width, height], centered);
var interpolateTranslate = d3.interpolate(t0, projection.translate()),
interpolateScale = d3.interpolate(s0, projection.scale());
var interpolator = function (t) {
projection.scale(interpolateScale(t))
.translate(interpolateTranslate(t));
paths.attr("d", path);
};
d3.transition()
.duration(5000)
.tween("projection", function () {
return interpolator;
});
return true;
}
})
.attr("fill", "#e9f356");
}
Here is a screenshot where I used my mouse wheel:
And here is a screenshot after my auto zoom is done. My lines are fade away also, why is it so?
Edit: This is how I add my text:
svgContainer.selectAll(null)
.data(feat.features.filter(function (d) { return d.properties.myId > 0; }))
.enter()
.append("g").attr("id", "txt")
.attr("transform", function (a) {
var centro = path.centroid(a);
return "translate(" + centro[0] + "," + centro[1] + ")";
})
.append("text")
.attr("text-anchor", "middle")
.attr("font-size", function (d) {
var bb = path.bounds(d)
return ((bb[1][0] - bb[0][0]) / 10) + "px";
})
.text("A/10/10/3");
Ok, I did it but when I try to zoom out with the mouse wheel it zooms out completely instantly. How can I make it smooth?
function findByID(ID) {
svgContainer.selectAll("path")
.data(feat.features)
.filter(function (d) {
if (d.properties.myID == ID) {
var bounds = path.bounds(d),
dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = .9 / Math.max(dx / width, dy / height),
translate = [width / 2 - scale * x, height / 2 - scale * y];
d3.select("#mainGroup").transition()
.duration(5000)
.style("stroke-width", 1.5 / scale + "px")
.attr("transform", "translate(" + translate + ")scale(" + scale + ")");
return true;
}
})
.attr("fill", "#e9f356");
}
I make a drill down pie chart and it works well.
You can see it here.
But there is an issue:
1) click a node then it shows its children (level 1) or level 0 nodes.
2) Move mouse to another position and move back to the new node which contains its original position, the node disappears.
I think there is problem in this code (gradientPie.js)
var paths = gPie.selectAll("path").data(pieChart(currData), function(d) {return d.data.cat;});
var texts = gPie.selectAll("text").data(pieChart(currData), function(d) {return d.data.cat;});
var lines = gPie.selectAll("line").data(pieChart(currData), function(d) {return d.data.cat;});
var arcs = paths.enter().append("g").attr('class', 'slice');
arcs.append("path").attr("fill", function(d, i) { return "url(#gradient" + d.data.cat + ")"; })
.transition().duration(1000).attrTween("d", tweenIn).each("end", function(){
this._listenToEvents = true;
gradPie.transitioning = false;
})
.attr("id", function(d, i){return 'p' + i;})
.each(function(d) { this._current = d; });
arcs.append("text").attr("transform", function(d) {
var c = d3.svg.arc().outerRadius(radius * 1.4).innerRadius(radius).centroid(d);
return "translate(" + (0 + c[0]) + "," + (0 + c[1]) + ")";
})
.attr("dy", ".35em")
.attr("class", "text-main")
.style("text-anchor", "middle")
.style("fill", "#3f5763")
.style("font", "bold 14px Helvetica")
.text(function(d) {
$("#" + d.data.domID + " p").html(d.data.percent + "%");
return d.data.percent + "%";
});
arcs.append("line").attr("transform", function (d, i) {
var rAngle = ((d.startAngle + d.endAngle) / 2 - (Math.PI / 2)) * 180 / Math.PI;
return "rotate(" + rAngle + ")translate(" + radius * 1.1 + ")";
})
.attr("class", "line-ticks")
.attr('stroke-width', '1')
.attr("x2", -0.5 * radius)
.style("stroke", "#3f5763")
.style("fill", "none");
// Mouse interaction handling
paths.on("click", function(d, i){
if(this.childNodes[0]._listenToEvents && !gradPie.transitioning){
// Reset inmediatelly
d3.select(this).attr("transform", "translate(0,0)")
// Change level on click if no transition has started
paths.each(function(){
this.childNodes[0]._listenToEvents = false;
});
updateGraph(d.data.subfractions? d.data.cat : undefined);
}
})
.on("mouseover", function(d, i){
// Mouseover effect if no transition has started
if(this.childNodes[0]._listenToEvents && !gradPie.transitioning) {
// Calculate angle bisector
var ang = (d.endAngle + d.startAngle)/2;
// Transformate to SVG space
ang = (ang - (Math.PI / 2) ) * -1;
// Calculate a 10% radius displacement
var x = Math.cos(ang) * radius * 0.1;
var y = Math.sin(ang) * radius * -0.1;
d3.select(this).transition()
.duration(250).attr("transform", function() {
return "translate(" + x + ", " + y + ")";
})
}
})
.on("mouseout", function(d){
// Mouseout effect if no transition has started
if(this.childNodes[0]._listenToEvents && !gradPie.transitioning){
d3.select(this).transition()
.duration(150).attr("transform", function() {
return "translate(0,0)";
});
}
});
// Collapse sectors for the exit selection
paths.exit().transition()
.duration(1000)
.attrTween("d", tweenOut).remove();
texts.exit().transition()
.duration(100).remove();
lines.exit().transition()
.duration(100).remove();
Any help?
I am new to both d3 and web programming generally. I have put together a force layout graph based on https://gist.github.com/mbostock/1153292. The graph works fine in Safari, Chrome and Opera (I haven't checked IE yet).However when I try to use it in Firefox I get the error "Tick is not defined".I am using Firefox 12.
Any advice on this would be much appreciated
Thanks,
Claire
(The code is a js script file and is triggered on a mouse click, the force layout part is below.).
d3.csv("data/sharing.csv?r1", function(error, data) {
dataset = data
var nodes = {};
dataset.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name:link.source});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});
var w = 500;
var h = 600;
var force = d3.layout.force()
.nodes(d3.values(nodes))
.links(dataset)
.size([w-10,h-10])
.linkDistance(60)
.charge(-375)
.on("tick", tick)
.start();
//Draw svg canvas
var svg = d3.select("#svgContainer").append("svg").attr("id", "viz").attr("width", w).attr("height", h)
// Create arrowheads
svg.append("svg:defs").selectAll("marker")
.data(["end-arrow"])
.enter()
.append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.attr("fill", "black")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
//Add links between the nodes and draw arrowhead at end of it.
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter()
.append("svg:path")
.attr("stroke-width",2)
.attr("stroke", "black")
.attr("fill","none")
.attr("marker-end", "url(#end-arrow)");
//Draw circles for nodes
var circle = svg.append("svg:g").selectAll("circle")
.data(force.nodes())
.enter()
.append("svg:circle")
.attr("r", 6)
.attr("fill", "white")
.attr("stroke", "black")
.call(force.drag)
.on("mouseover", fade(.1))
.on("mouseout", fade(1))
//Label the nodes/circles
var text = svg.append("svg:g").selectAll("g")
.data(force.nodes())
.enter()
.append("svg:g")
text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.name; })
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});
circle.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
text.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
=============REPLY TO COMMENT == FULL SCRIPT INCLUDING CALL TO CSV===
//If sharing button is clicked, load sharing data
d3.select("#sharing").on("click", function() {
d3.csv("data/sharing.csv?r1", function(error, data) {
if (error)
{//If error is not null,(i.e : something goes wrong), log the error.
window.console.log(error);
}
else
{//If file loaded correctly, log the data to the console.
dataset = data
window.console.log(dataset)
color = getColor()
vizType = "force";
//Hide date fields/buttons as they are not applicable
d3.select("#instructions").classed("hidden", true);
d3.select("#instructions2").classed("hidden", false);
d3.select("#startLabel").classed("hidden", true);
d3.select("#startDate").classed("hidden", true);
d3.select("#endLabel").classed("hidden", true);
d3.select("#endDate").classed("hidden", true);
d3.select("#removeFilter").classed("hidden", true);
d3.select("#sharing").classed("hidden", true);
d3.select("#showData").classed("hidden", false);
d3.select("#showData").attr("value", "Back to Circles Vizualization");
d3.select("#tipsData").classed("hidden", true);
d3.select("#ncpData").classed("hidden", true);
d3.select("#tipsNCPData").classed("hidden", true);
d3.select("#tipsLabel").classed("hidden", true);
d3.select("#ncpLabel").classed("hidden", true);
d3.select("#tipsNCPLabel").classed("hidden", true);
//Clear the previous viz and data
d3.select("#viz").remove();
d3.select("#stageTable").remove();
d3.select("#userTable").remove();
//Gets a count of sender records/source and stage/type
var senderCount = getSortingCount(dataset,"Sender");
var stageCount = getSortingCount(dataset,"Stage");
//create tables summarising results
var summarySenderTable = tabulate(senderCount, ["Shared", "Sender"], vizType);
var summaryStageTable = tabulate(stageCount, ["Shared", "Stage"], vizType);
var nodes = {};
// For each datapoint, check if a node exists already, if not create a new one.
dataset.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] ={name: link.source});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});
//Set the width and height for the svg, that will display the viz
var w = 500;
var h = 600;
var force = d3.layout.force()
.nodes(d3.values(nodes))
.links(dataset)
.size([w-10,h-10])
.linkDistance(60)
.charge(-375)
.on("tick", tick)
.start();
//Draw svg
var svg = d3.select("#svgContainer").append("svg")
.attr("id","viz").attr("width",w).attr("height", h)
// Create arrowheads
svg.append("svg:defs").selectAll("marker")
.data(["end-arrow"])
.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.attr("fill", "black")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
//Add links between the nodes and draw arrowhead at end of it.
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter()
.append("svg:path")
.attr("stroke-width",2)
.attr("stroke", function(d){return color(d.ScreenName)})
.attr("fill","none")
.attr("marker-end", "url(#end-arrow)");
//Draw circles for nodes
var circle = svg.append("svg:g").selectAll("circle")
.data(force.nodes())
.enter()
.append("svg:circle")
.attr("r", 6)
.attr("fill", "white")
.attr("stroke", "black")
.call(force.drag)
.on("mouseover", fade(.1))
.on("mouseout", fade(1))
//Label nodes/circles
var text = svg.append("svg:g").selectAll("g")
.data(force.nodes())
.enter()
.append("svg:g")
text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.name; })
//Set radius for arrows and applies transform
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});
circle.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
text.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
//Allow for filter by row on stageTable
d3.select("#stage").select("#stageTable").selectAll("tr")
.on("click", function(d){
d3.select(this)
var rowText = this.childNodes[1].innerHTML
var svg = d3.select("#svgContainer").select("svg")
var path = svg.selectAll("path")
.style ("opacity", 1)
.transition()
.duration(250)
.style ("opacity", function(d){
if(d.ScreenName == rowText){
d3.selectAll("marker path").transition().style("stroke-opacity", 1);
return fade(1)
}
else{
d3.selectAll("marker path").transition().style("stroke-opacity", 0.1);
return 0.1
})
d3.select("#removeFilter").classed("hidden", false);
})
//Checks what links are connected to which(used for mouseover)
var linkedByIndex = {};
dataset.forEach(function(d) {linkedByIndex[d.source.index + "," + d.target.index] = 1;});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}
//Fades in/out circles and arrows on mouseover.
function fade(opacity) {
return function(d) {
circle.style("stroke-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
path.style("stroke-opacity", function(o) {
return o.source === d || o.target === d ? 1 : opacity;
});
};
}
}
})
})
Accessor for colour
function getColor(){
return color
}
Seeing the entire source code helped to clarify things. There is an if/else statement at the very top that checks for an error. The entire rest of the code is inside the else block. This is what's causing the problem.
Function declarations (such as tick() in your case) have browser-specific weird behaviour when defined inside conditional blocks. Here's a pretty good write-up that explains the differences between function declarations, function expressions and the ill-defined and inconsistently supported function statements (which is what you've inadvertently created with so much code living in an else block).
If you pull the code out of the else block, I think the behavior should be more predictable across browsers.
In general, it's not good programming practice to create enormous, long conditional blocks. Not only does it introduce the possibility of these types of errors but it can be very difficult to read and understand. Same thing goes for very deeply nested conditions.
Try to keep your conditions fairly tight so that the code living inside the conditional blocks corresponds directly to the meaning of the condition itself. You should be able to read the intention of condition and block contents out loud and they should make sense together. As much as possible, code that doesn't have to do with the condition should be at the top level of the function containing it. You can increase readability by factoring your code into meaningful functions and keeping conditions under control.
In your example above, you could do:
if (error) {
window.console.log(error);
}
else {
window.console.log(dataset);
}
dataset = data
color = getColor()
vizType = "force";
...
... rest of code
One final comment is that a tool like JSLint or JSHint to validate your code. It would point out problems like this automatically. It can be overly strict sometimes but its a good learning experience to at least understand what it's complaining about.
I am using a Partition tree as in this example to try and make a visualization for taxonomy trees. I tried to follow the code in the d3.js and the scripting in the html. It looks like the Layout and onclick event just increases the ’rect’ sizes and then clips it to fit in the same size SVG element. Would it be possible to use a polylinear scale on the x axis so I can keep each parent nodes on screen as I go deeper into the tree?
For example if the layout was 160px wide and four columns across each column is 40px wide. I’d like the tree to start with the first column 10px wide which makes the others fill up the 150px at 50px each. If the next column was clicked then the domain and range would change so that the 2 left columns would be 10px each and the others would be 70px etc.
I tried changing the range from ([0, 160]) to ([0, 10, 160]) and the domain to ([0, .25 ,1]). Is this the right approach? The positions changed but not the widths. I would probably want to change the range and domain depending on the depth.
Edit
Here is the code from the html script. I was thinking of changing the code below to something like
var parentcolumns = 30;
var numberleftcolumns = 0.25;
x = d3.scale.linear().domain([0, numberleftcolumns, 1]).range([0, parentcolumns, h]),
The numbers I used in the example were just to help discribe the problem. Here the width is 1120px.
<script type="text/javascript">
var w = 1120,
h = 600,
x = d3.scale.linear().range([0, w]),
y = d3.scale.linear().range([0, h]);
var vis = d3.select("#body").append("div")
.attr("class", "chart")
.style("width", w + "px")
.style("height", h + "px")
.append("svg:svg")
.attr("width", w)
.attr("height", h);
var partition = d3.layout.partition()
.value(function(d) { return d.size; });
d3.json("http://localhost:8080/flare.json", function(root) {
console.log("loadedJson:",root);
var g = vis.selectAll("g")
.data(partition.nodes(root))
.enter().append("svg:g")
.attr("transform", function(d) { return "translate(" + x(d.y) + "," + y(d.x) + ")"; })
.on("click", click);
var kx = w / root.dx,
ky = h / 1;
g.append("svg:rect")
.attr("width", root.dy * kx)
.attr("height", function(d) { return d.dx * ky; })
.attr("class", function(d) { return d.children ? "parent" : "child"; });
g.append("svg:text")
.attr("transform", transform)
.attr("dy", ".35em")
.style("opacity", function(d) { return d.dx * ky > 12 ? 1 : 0.15; })
.text(function(d) { return d.name; })
d3.select(window)
.on("click", function() { click(root); })
function click(d) {
if (!d.children) return;
kx = (d.y ? w - 40 : w) / (1 - d.y);
ky = h / d.dx;
x.domain([d.y, 1]).range([d.y ? 40 : 0, w]);
y.domain([d.x, d.x + d.dx]);
var t = g.transition()
.duration(d3.event.altKey ? 7500 : 750)
.attr("transform", function(d) { return "translate(" + x(d.y) + "," + y(d.x) + ")"; });
t.select("rect")
.attr("width", d.dy * kx)
.attr("height", function(d) { return d.dx * ky; });
t.select("text")
.attr("transform", transform)
.style("opacity", function(d) { return d.dx * ky > 12 ? 1 : 0; });
d3.event.stopPropagation();
}
function transform(d) {
return "translate(8," + d.dx * ky / 2 + ")";
}
});
</script>
I would have to rewrite the onclick function to deal with the domain and range changes and alter my parentcolumns each time.