I am trying to make a zoomable circle packing chart. I'd like each child circle to contain a smaller chart which would always have the same structure (i.e. 4 columns, only the heights of the bars would change).
I have tried adding a simple rect to my chart so far but the rects are not added in the circle and are statics:
JS:
var margin = 20,
diameter = 400;
var color = d3.scale.linear()
.domain([-1, 5])
.range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
.interpolate(d3.interpolateHcl);
var pack = d3.layout.pack()
.padding(2)
.size([diameter - margin, diameter - margin])
.value(function(d) { return d.size; })
var svg = d3.select(".container").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
d3.json("flare.json", function(error, root) {
if (error) return console.error(error);
var focus = root,
nodes = pack.nodes(root),
view;
var 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(); });
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.parent === root ? null : "none"; })
.text(function(d) { return d.name; });
// Adding Rect to each child circle
var bar = svg.selectAll(".bar")
.data(nodes)
.enter().append("rect")
.attr("class", "bar")
.style("fill", function(d) { return d.children ? color(d.depth) : null; })
.style("fill-opacity", function(d) { return d.parent === root ? 1 : 0; })
.style("display", function(d) { return d.parent === root ? null : "none"; })
.attr("width", 20)
.attr("x", 100)
.attr("height", function(d) { return 40; });
var node = svg.selectAll("circle,text");
d3.select(".container")
.style("background", color(-1))
.on("click", function() { zoom(root); });
zoomTo([root.x, root.y, root.r * 2 + margin]);
function zoom(d) {
var focus0 = focus; focus = d;
var transition = d3.transition()
.duration(d3.event.altKey ? 7500 : 750)
.tween("zoom", function(d) {
var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
return function(t) { zoomTo(i(t)); };
});
transition.selectAll("text")
.filter(function(d) { return d.parent === focus || this.style.display === "inline"; })
.style("fill-opacity", function(d) { return d.parent === focus ? 1 : 0; })
.each("start", function(d) { if (d.parent === focus) this.style.display = "inline"; })
.each("end", function(d) { if (d.parent !== focus) this.style.display = "none"; });
}
function zoomTo(v) {
var k = diameter / v[2]; view = v;
node.attr("transform", function(d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; });
circle.attr("r", function(d) { return d.r * k; });
}
});
d3.select(self.frameElement).style("height", diameter + "px");
I have also added a plunkr: http://plnkr.co/edit/CfJqUQMISDzed2F71JpT?p=preview
How can I add this rect inside the child circles only?
Many thanks
Yes, zooming feature adds some difficulty.
Here is a little bit dirty example of how this can be achieved: plunkr
The key code is:
// Adding Rects to each child circle
var bar1 = svg.selectAll(".bar1")
.data(nodes)
.enter().append("rect")
.attr("class", "bar1")
.style("fill", "red")
.style("display", function(d) { return (d.depth == 4) ? null : "none"; });
var bar2 = svg.selectAll(".bar2")
.data(nodes)
.enter().append("rect")
.attr("class", "bar2")
.style("fill", "green")
.style("display", function(d) { return (d.depth == 4) ? null : "none"; });
var bar3 = svg.selectAll(".bar3")
.data(nodes)
.enter().append("rect")
.attr("class", "bar3")
.style("fill", "blue")
.style("display", function(d) { return (d.depth == 4) ? null : "none"; });
and
var node = svg.selectAll("circle,text,rect");
and
bar1.attr("y", function(d) { return -d.r/2 * k - d.r/4; })
bar1.attr("x", function(d) { return -d.r/20 * k; })
bar1.attr("width", function(d) { return d.r/10 * k -1; });
bar1.attr("height", function(d) { return d.r/2 * k; });
bar2.attr("y", function(d) { return -d.r/2 * k - d.r/4; })
bar2.attr("x", function(d) { return -d.r/20 * k + d.r/10 * k; })
bar2.attr("width", function(d) { return d.r/10 * k-1; });
bar2.attr("height", function(d) { return d.r/2 * k; });
bar3.attr("y", function(d) { return -d.r/2 * k - d.r/4; })
bar3.attr("x", function(d) { return -d.r/20 * k - d.r/10 * k; })
bar3.attr("width", function(d) { return d.r/10 * k-1; });
bar3.attr("height", function(d) { return d.r/2 * k; });
Related
i am working in d3 ,rotating cluster layout ..i want to resize the cluster layout based on number of child nodes..
based on my code ,when i open the parent with minimum child ,there is no problem
when i open a parent that contains more child,there is some overlapping ,so want to reduce the cluster size further,when there is more number of child in the parent...how can i do this??
my entire code is
myJSON= http://pastebin.com/vZ32jGQc
treeData = myJSON;
var selectedNode = null;
var draggingNode = null;
var panSpeed = 200;
var panBoundary = 0;
var i = 0;
var duration = 750;
var root;
var width = 5000;
var height = 5000;
var diameter = 750;
var tree = d3.layout.tree().size([360, diameter / 2 - 120])
.separation(function (a, b) {
return (a.parent == b.parent ? 1 : 5) / a.depth;
});
var diagonal = d3.svg.diagonal.radial()
.projection(function (d) {
return [d.y, d.x / 180 * Math.PI];
});
root = treeData;
root.x0 = height / 2;
root.y0 = 0;
function sortTree() {
tree.sort(function (a, b) {
return b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1;
});
}
sortTree();
var baseSvg = d3.select("#tree-container").append("svg")
.attr("width", 1200)
.attr("height",1200)
.attr("class", "overlay")
.attr("transform", "translate(" + 1000 + "," + 1000 + ")");
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
update(d);
}
function expand(d) {
if (d._children) {
d.children = d._children;
d.children.forEach(expand);
d._children = null;
}
}
function toggleChildren(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else if (d._children) {
d.children = d._children;
d._children = null;
}
return d;
}
function click(d) {
if(!d.parent){
return;
}
if (!d.children)
myJSON.children.forEach(collapse);
if (d3.event.defaultPrevented) return;
d = toggleChildren(d);
update(d);
}
function update(source) {
var levelWidth = [1];
var childCount = function (level, n) {
if (n.children && n.children.length > 0) {
if (levelWidth.length <= level + 1) levelWidth.push(0);
levelWidth[level + 1] += n.children.length;
n.children.forEach(function (d) {
childCount(level + 1, d);
});
}
};
childCount(0, root);
var nodes = tree.nodes(root);
links = tree.links(nodes);
node = svgGroup.selectAll("g.node")
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.on('click', click)
nodeEnter.append("circle")
.attr("class", "smallcircle")
.style("stroke", function(d) {
return d.color;
})
nodeEnter.append("text")
.text(function (d) {
return d.name;
})
// .style("font", "12px serif")
.style("opacity", 1)
.style("fill-opacity", 0)
.on("mouseover", function (d) {
var r = d3.select(this).node().getBoundingClientRect();
d3.select("div#tooltip")
.style("display", "inline")
.style("top", (r.top-25) + "px")
.style("top", 10 + "px")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 40) + "px")
.style("left", r.left + 40+"px")
.style("left", + "px")
.style("position", "absolute")
.text(d.t);
})
.on("mouseout", function(){
d3.select("div#tooltip").style("display", "none")
})
node.select("circle.nodeCircle")
.attr("r", 4.5)
.style("fill", function (d) {
return d._children ? "red" : "#fff";
});
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "rotate(" + (d.x - 90) + ")
translate(" + d.y + ")rotate(" + (-d.x + 90) + ")";
});
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeUpdate.select("text")
.style("fill-opacity", 9)
.attr("fill",function(d){return (d.children?"red":"black");})
.attr("font-size",function(d)
{return (d.children?"20px":"12px");})
.attr("dy", ".35em")
.attr("text-anchor", function (d) {
return d.x < 180 ? "start" : "end";
})
.attr("transform", function (d) {
return d.x < 180 ? "translate(8)"
: "rotate(360)translate(-8)";
});
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + source.x + "," + source.y + ")";
})
.remove();
nodeExit.select("circle")
.attr("r", 0);
nodeExit.select("text")
.style("fill-opacity", 0);
var link = svgGroup.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
})
link.style("stroke", function(d) {
return d.color;
})
link.enter().insert("path", "g")
.attr("class", "link")
link.style("stroke", function(d) {
return d.target.color;
})
.attr("d", function (d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
});
link.transition()
.duration(duration)
.attr("d", diagonal);
link.exit().transition()
.duration(duration)
.attr("d", function (d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
nodes.forEach(function (d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
var svgGroup = baseSvg.append("g")
.attr("transform", "translate(" + 550 + "," + 300 + ")")
d3.selectAll("text").style("fill", function (d)
{ return d3.select(this).classed(d.cond, true); })
root.children.forEach(function (child) {
collapse(child);
});
update(root);
d3.select(self.frameElement).style("height", width);
I would like to set individual colors of children circles in a packed circle chart in D3. I would also like text of the size to appear under the name text. How do I achieve this? I've added color codes to the json, example below. Link to JSfiddle is https://jsfiddle.net/smitty1788/9fw51gL1/1/
{
"name": "Maryland",
"children": [{
"name": "Montgomery",
"children": [{
"name": "French",
"size": 600,
"fill":"#105908"
}, {
"name": "Italian",
"size": 700,
"fill":"#59084e"
}, {
"name": "Laotian",
"size": 800,
"fill":"#f45333"
}, {
"name": "African Languages",
"size": 900,
"fill":"#fFF000"
}]
}
This is the d3 script
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = 20,
diameter = +svg.attr("width"),
g = svg.append("g").attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
var color = d3.scaleLinear()
.domain([-1, 5])
.range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
.interpolate(d3.interpolateHcl);
var pack = d3.pack()
.size([diameter - margin, diameter - margin])
.padding(2);
d3.json("/flare.json", function(error, root) {
if (error) throw error;
root = d3.hierarchy(root)
.sum(function(d) { return d.size; })
.sort(function(a, b) { return b.value - a.value; });
var focus = root,
nodes = pack(root).descendants(),
view;
var circle = g.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(); });
var text = g.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) { return d.data.name; });
var node = g.selectAll("circle,text");
svg
.style("background", color(-1))
.on("click", function() { zoom(root); });
zoomTo([root.x, root.y, root.r * 2 + margin]);
function zoom(d) {
var focus0 = focus; focus = d;
var transition = d3.transition()
.duration(d3.event.altKey ? 7500 : 750)
.tween("zoom", function(d) {
var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
return function(t) { zoomTo(i(t)); };
});
transition.selectAll("text")
.filter(function(d) { return d.parent === focus || this.style.display === "inline"; })
.style("fill-opacity", function(d) { return d.parent === focus ? 1 : 0; })
.on("start", function(d) { if (d.parent === focus) this.style.display = "inline"; })
.on("end", function(d) { if (d.parent !== focus) this.style.display = "none"; });
}
function zoomTo(v) {
var k = diameter / v[2]; view = v;
node.attr("transform", function(d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; });
circle.attr("r", function(d) { return d.r * k; });
}
});
</script>
Thanks for the help!
Instead of null, return d.data.fill for the circles without children:
.style("fill", function(d) { return d.children ? color(d.depth) : d.data.fill; })
Here is your updated fiddle (your colored circles are in the far right side): https://jsfiddle.net/jv4ku850/
I am trying to add panning only (don't want zoom for now), to my D3 force-directed graph visualization. No matter what I try, I keep getting an error - "Cannot read property 'translate' of null". I feel as though I am setting things up like in all the examples I find, but something isn't quite right.
Here's my latest attempt. As far as I know, the relevant code should be at the top where I define svg, but I included the rest in case something is affecting it of which I'm not aware.
var isiOS = false;
var agent = navigator.userAgent.toLowerCase();
if(agent.indexOf('iphone') >= 0 || agent.indexOf('ipad') >= 0){
isiOS = true;
};
var h = 1000;
var w = 1000;
var width = 1500,
var height = 1500;
var default_node_color = '#FF9900';
var shining_node_color = '#fc5f05';
var text_color = 'white';
var link_color = '#666699';
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().on("zoom", function() {
svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}))
.append('g');
var g = svg.append('g');
var force = d3.layout.force()
.gravity(0.05)
.distance(100)
.charge(-100)
.size([w, h]);
d3.xhr("{{ url_for('visualization_data', interactions_filter = interactions_filter)}}")
.header("Content-Type", "application/json")
.post(
JSON.stringify({
"fileindicator": "{{fileindicator}}"
}), function(error, rawData) {
if (error) throw error;
var json = JSON.parse(rawData.response);
force
.nodes(json.nodes)
.links(json.links)
.start();
var link_scale = d3.scale.linear()
.domain([0, d3.max(json.links, function(d) {
return (d.value);
})])
.range([1, 13]);
var link = g.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) {
return link_scale(d.value);
})
.style('stroke', link_color)
.attr("fill-opacity", .75);
var node = g.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag)
.style("fill", default_node_color);
var radius_scale = d3.scale.sqrt()
.domain([0, d3.max(json.nodes, function(d) {
return (d.n_interactions);
})])
.range([2, 17]);
if (isiOS) {
// single click centers node
var centerEvent = "click";
} else {
// double click centers node
var centerEvent = "dblclick";
}
var all_links = d3.selectAll('.link');
var all_nodes = d3.selectAll('.node');
//populate select box
var select_box = $('.chzn-select');
select_box.empty();
select_box.trigger('chosen:updated');
var character_to_node_id = []
for (var i = 0; i < all_nodes[0].length; i++) {
var option = '<option value="' + all_nodes[0][i].__data__.index + '">' + all_nodes[0][i].__data__.name + '</option>';
character_to_node_id.push(option);
select_box.append("<option value='' selected='selected'></option>");
select_box.append(character_to_node_id);
var onClick = window.onClick = function(d, i) {
// console.log(this)
// console.log('d, i, this:', d, i, this);
var index_of_clicked_node = d.index;
// Moves clicked node to center
var dcx = (w / 2 - d.x * zoom.scale());
var dcy = (h / 2 - d.y * zoom.scale());
zoom.translate([dcx, dcy]);
g.transition()
.duration(2000)
.attr("transform", "translate(" + dcx + "," + dcy + ")scale(" + zoom.scale() + ")");
//select all links NOT related to the clicked node and fade
var fade_links = d3.selectAll('.link').filter(function(d) {
return index_of_clicked_node !== d.source.index && index_of_clicked_node !== d.target.index;
});
// console.log(fade_links);
fade_links.style('opacity', .2);
var active_links = d3.selectAll('.link').filter(function(d) {
return index_of_clicked_node === d.source.index || index_of_clicked_node === d.target.index;
});
// active_links.style('stroke', 'red')
active_links.style('opacity', .85);
var active_link_id_list = [];
active_links[0].forEach(function(link) {
active_link_id_list.push(link.__data__.target.index)
active_link_id_list.push(link.__data__.source.index)
});
console.log('number of active links: ', active_link_id_list.length);
//select all nodes not connected to the clicked node and fade
var fade_nodes = d3.selectAll('.node').filter(function(d) {
return !active_link_id_list.includes(d.index);
});
fade_nodes.style('opacity', .2);
var active_nodes = d3.selectAll('.node').filter(function(d) {
return active_link_id_list.includes(d.index);
});
console.log('number of active nodes: ', active_nodes);
d3.selectAll('circle').filter(function(d, i) {
if (d.name === name) {
// call click event on the circle
window.onClick(d, i);
}
});
active_nodes.style('opacity', .85)
.transition()
.duration(1000)
.style('fill', shining_node_color)
.transition()
.duration(1000)
.style('fill', default_node_color);
};
node.append('circle')
.attr("class", "circle")
.attr("r", function(d, i) {
return radius_scale(d.n_interactions);
})
.style('opacity', .85)
.style('stroke', 'black')
.style('stroke-width', 10)
.style('stroke-opacity', 0.0)
.call(force.drag)
.on(centerEvent, onClick);
var text_scale = d3.scale.linear()
.domain([0, d3.max(json.nodes, function(d) {
return (d.n_interactions);
})])
.range([6, 16]);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.attr('fill', 'black')
.text(function(d) {
return d.name
})
.style("font-size", function(d) {
return text_scale(d.n_interactions) + "px";
})
.style('font-family', "futura-pt")
.style('fill', text_color);
force.on("tick", function() {
link.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
node.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
$('#loading-text').hide();
I have a D3 partition which shows all the levels for the entire partition.
I would like to only show the first level when the chart loads and then show subsequent levels on click.
For example in this Tree the next level is shown on click of a node: D3Tree
Here is the code for my partition: Plunker link
$(document).ready(function(){
var width = 600,
height = 400,
radius = (Math.min(width, height) / 2) - 10;
var formatNumber = d3.format(",d");
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var color = d3.scale.category20c();
var partition = d3.layout.partition()
.value(function(d) {
if(d.depth == 2)
console.log(d.depth, d);
return 1; // d.size;
});
var arc = d3.svg.arc()
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
.innerRadius(function(d) { return Math.max(0, y(d.y)); })
.outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")");
d3.json("flare.json", function(error, root) {
if (error) throw error;
svg.selectAll("path")
.data(partition.nodes(root))
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return color((d.children ? d : d.parent).name); })
.on("click", click)
.append("title")
.text(function(d) { return d.name + "\n" + formatNumber(d.value); });
});
function click(d) {
svg.transition()
.duration(750)
.tween("scale", function() {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); };
})
.selectAll("path")
.attrTween("d", function(d) { return function() { return arc(d); }; });
}
d3.select(self.frameElement).style("height", height + "px");
});
I would like to do something like toggle on click:
// Toggle children.
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
Where the children get set and unset, then redrawn
To do something like the tree layout would be a little tough doing it with the help of display is a a cake walk.
When the path are drawn for the first time make all the nodes whose depth > 1 disappear using display:none:
svg.selectAll("path")
.data(partition.nodes(root))
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) {
return color((d.children ? d : d.parent).name);
})
.style("display", function(d) {
if (d.depth > 1) {
return "none";//nodes whose depth is more than 1 make its vanish
} else {
return "";
}
})
Now on node click make all nodes reappear except when root node is clicked.
.style("display", function(d1) {
if (d.depth == 0 && d1.depth > 1) {
return "none"//root node clicked so show only 2 depths.
} else {
return "";
}
})
Working code here
I am refactoring the d3.layout.pack graph example here into a reusable module. However, the root node is no longer in the center - I couldn't find the culprit.
Here is a jsfiddle demo of the app:
d3.visio.clustering = function module(){
var width = 700,//default width
height= 500;//default height
var svg;
//takes a DOM container or an array of DOM containers
function exports(_selection){
console.log(_selection);
_selection.each(function(_data){
var r = Math.min(width, height) - 10;
var x = d3.scale.linear().range([0, r]),
y = d3.scale.linear().range([0, r]),
node,
root;
var pack = d3.layout.pack()
.size([r, r])
.value(function(d) { return d.size; });
//if the svg element is already defined, don't define it again
if(!svg){
svg = d3.select(this).append("svg:svg");
}
svg.attr("width", width)
.attr("height", height)
.append("svg:g")
.attr("transform", "translate(" + (width - r) / 2 + "," + (height - r) / 2 + ")");
node = root = _data;
var nodes = pack.nodes(root);
svg.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) { return zoom(node == d ? root : d); });
svg.selectAll("text")
.data(nodes)
.enter().append("svg:text")
.attr("class", function(d) { return d.children ? "parent" : "child"; })
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("opacity", function(d) { return d.r > 20 ? 1 : 0; })
.text(function(d) { return d.name; });
d3.select(window).on("click", function() { zoom(root); });
function zoom(d, i) {
var k = r / d.r / 2;
x.domain([d.x - d.r, d.x + d.r]);
y.domain([d.y - d.r, d.y + d.r]);
var t = svg.transition()
.duration(d3.event.altKey ? 7500 : 750);
t.selectAll("circle")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.attr("r", function(d) { return k * d.r; });
t.selectAll("text")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.style("opacity", function(d) { return k * d.r > 20 ? 1 : 0; });
node = d;
d3.event.stopPropagation();
}
});
}
//getter and setter for property width
exports.width = function(_x){
if(!arguments.length) return width;
width = parseInt(_x);
return this;//allow method chaining
}
//getter and setter for property height
exports.height = function(_x){
if(!arguments.length) return height;
height = parseInt(_x);
return this;//allow method chaining
}
//getter and setter for property radius = r
exports.radius = function(_x){
if(!arguments.length) return r;
r = parseInt(_x);
return this//allow method chaining
}
return exports;
};
var cluster = d3.visio.clustering()
.width(document.getElementById("vis").offsetWidth)
.height(document.getElementById("vis").offsetHeight);
d3.select('#vis')
.datum(data)
.call(cluster);
Could you please check what's wrong?
The problem in your code is that you're appending a g element that is correctly translated, but you're appending everything else to the top level svg, which is not translated. To make it work, you can simply reassign svg with the top level g, i.e.
svg = svg.append("g").attr("transform", "translate(" + ... + ")");
Complete jsfiddle here.