Related
I want to create zoomable circle-pack graph with edges between most internal children,I used this code for base,
and my code is :
var year=[]
var edges
var svg
function main_graph(){
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);
svg.append("svg:defs")
.append("svg:marker")
.attr("id", "arrow")
.attr("viewBox", "0 0 10 10")
.attr("refX", 10)
.attr("refY", 5)
.attr("markerUnits", "strokeWidth")
.attr("markerWidth", 6)
.attr("markerHeight", 3)
.attr("orient", "auto")
.append("svg:path")
.style("stroke","none")
.attr("d", "M 0 0 L 10 5 L 0 10 z");
var pack = d3.pack()
.size([diameter/20, diameter/20])
.padding(20)
d3.json("flare.json", function(error, root) {
edges=root.links
var leyer1=root.children
var leyer1_len=leyer1.length
console.log(leyer1_len)
for(i=0;i<leyer1_len;i++){
var leyer2_len=(leyer1[i]).children.length
var leyer2=(leyer1[i]).children
for(j=0;j<leyer2_len;j++){
var from_year=leyer2[j].from
var to_year=leyer2[j].to
var id_auther=leyer2[j].id
year.push({from:from_year,to:to_year,id:id_auther})
}
}
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"; })
.attr("id",function(d){return d.data.id})
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.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");
const arrow = svg.selectAll('path.arrow').data(edges);
arrow.enter()
.append("path")
.attr("class","arrow")
.attr("x1", function(d){
debugger
let translate = getTranslate(d.source);
console.log(translate[0])
return translate[0]
})
.attr("x2", function(d){
let translate = getTranslate(d.target);
console.log(translate[0])
return translate[0]
})
.attr("y1", function(d){
let translate = getTranslate(d.source);
console.log(translate[1])
return translate[1]
})
.attr("y2", function(d){
let translate = getTranslate(d.target);
console.log(translate[1])
return translate[1]
})
.attr("d", function(d) {
let source = getTranslate(d.source),
target = getTranslate(d.target),
x1= source[0],
x2= target[0],
y1= source[1],
y2= target[1];
diffX = x2 - x1;
diffY = y2 - y1;
// 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 * 10) / pathLength;
offsetY = (diffY * 10) / pathLength;
return "M" + x1 + "," + y1 + "L" + (x2 - offsetX) + "," + (y2 - offsetY);
})
.style("stroke", "black")
.style("fill", "none")
.style("stroke-width", 0.5)
.attr("marker-end", "url(#arrow)");
function getTranslate(datum) {
debugger
var myselect=d3.select('#'+datum)
const string = myselect.attr("transform");
const translate = string.substring(string.indexOf("(")+1, string.indexOf(")")).split(",");
return translate;
}
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; });
}
});
}
I append path to graph but I don't get result.
my json format also is here
{"name":"variants","links":[{"source":"i0","target":"i2"},
{"source":"i12","target":"i13"}],"id":14,"children":[{"name":"19","id":15,"children":
[{"name":"aaaacxi7gjuvmascvqjaabaadm","size":25,"from":1930,"to":2006,"id":'i15'},
{"name":"undefined","size":25,"from":1910,"to":2008,"id":"i1"},
{"name":"aaaacxi7gjuvmascvqjaabaadi","size":25,"from":1955,"to":1965,"id":"i14"},
{"name":"aaaacxi7gjuvmascvqjaabaade","size":25,"from":1980,"to":2015,"id":"i0"},
{"name":"aaaacxi7gjuvmascvqjaabaac4","size":25,"from":1950,"to":2070,"id":"i2"},
{"name":"aaaacxi7gjuvmascvqjaabaada","size":25,"from":1900,"to":2020,"id":"i3"},
{"name":"aaaacxi7gjuvmascvqjaabaadu","size":25,"from":1980,"to":2008,"id":"i4"},
{"name":"aaaacxi7gjuvmascvqjaabaadq","size":25,"from":1990,"to":2000,"id":"i5"}]}
,{"name":"22","id":"i16","children":[{"name":"neda","size":25,"from":2000,"to":2020,"id":"i8"},
{"name":"aaaacxi7gka5qascvqjaabaaai","size":25,"from":1940,"to":2000,"id":"i9"},
{"name":"aaaacxi7gka5oascvqjaabaacq","size":55,"from":1960,"to":2010,"id":"i10"},
{"name":"aaaacxi7gka5qascvqjaabaaay","size":55,"from":1940,"to":2000,"id":"i11"},
{"name":"aaaacxi7gj4eqascvqjaabaab4","size":55,"from":1980,"to":2020,"id":"i12"},
{"name":"aaaacxi7gka5oascvqjaabaacm","size":55,"from":1940,"to":2000,"id":"i13"}]}
]}
my code add path in svg element but I think they are not in correct position,
and also this post is nearly to my purpose
Thank you very much for helping me.
I am making a Sunburst chart and am almost complete, but I want the text to flip half-way around the circle to make it easier to read. Using help from another question here on stackoverflow I have been able to get the text to flip, but it drops down a level. I have tried modifying the computeTextRotation function to account for this, but to no prevail. I am curious if anyone is able to help me solve this problem.
Here is a picture of the chart:
Here is the computeTextRotation functions code:
function computeTextRotation(d) {
var rotation = (d.x + d.dx / 2) * 180 / Math.PI - 90;
return {
global: rotation,
correction: rotation > 90 ? 180 : 0
};
}
...
.attr("transform", function(d)
{
var r = computeTextRotation(d);
return "rotate(" + r.global + ")"
+ "translate(" + radius / 3. * d.depth + ")"
+ "rotate(" + -r.correction + ")";
}
)
Here is the entire JavaScript code:
var margin = {top: 500, right: 500, bottom: 500, left: 500},
radius = Math.min(margin.top, margin.right, margin.bottom, margin.left) - 150;
function filter_min_arc_size_text(d, i) {return (d.dx*d.depth*radius/1)>14};
var hue = d3.scale.category10();
var luminance = d3.scale.sqrt()
.domain([0, 1e6])
.clamp(true)
.range([90, 20]);
var svg = d3.select("body").append("svg")
.attr("width", margin.left + margin.right)
.attr("height", margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var partition = d3.layout.partition()
.sort(function(a, b) { return d3.ascending(a.name, b.name); })
.size([2 * Math.PI, radius]);
var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx - .01 / (d.depth + .5); })
.innerRadius(function(d) { return radius / 3 * d.depth; })
.outerRadius(function(d) { return radius / 3 * (d.depth + 1) - 1; });
//Tooltip description
var tooltip = d3.select("body")
.append("div")
.attr("id", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("opacity", 0);
function format_number(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function format_description(d) {
var description = d.description;
return '<b>' + d.name + '</b></br>'+ d.description + '<br> (' + format_number(d.value) + ')';
}
function computeTextRotation(d) {
var angle=(d.x +d.dx/2)*180/Math.PI - 90
return angle;
}
function mouseOverArc(d) {
d3.select(this).attr("stroke","black")
tooltip.html(format_description(d));
return tooltip.transition()
.duration(50)
.style("opacity", 0.9);
}
function mouseOutArc(){
d3.select(this).attr("stroke","")
return tooltip.style("opacity", 0);
}
function mouseMoveArc (d) {
return tooltip
.style("top", (d3.event.pageY-10)+"px")
.style("left", (d3.event.pageX+10)+"px");
}
var root_ = null;
d3.json("data/davis-aroma-wheel.json", function(error, root) {
if (error) return console.warn(error);
// Compute the initial layout on the entire tree to sum sizes.
// Also compute the full name and fill color for each node,
// and stash the children so they can be restored as we descend.
partition
.value(function(d) { return d.size; })
.nodes(root)
.forEach(function(d) {
d._children = d.children;
d.sum = d.value;
d.key = key(d);
d.fill = fill(d);
});
// Now redefine the value function to use the previously-computed sum.
partition
.children(function(d, depth) { return depth < 3 ? d._children : null; })
.value(function(d) { return d.sum; });
var center = svg.append("circle")
.attr("r", radius / 3)
.on("click", zoomOut);
center.append("title")
.text("zoom out");
var partitioned_data = partition.nodes(root).slice(1)
var path = svg.selectAll("path")
.data(partitioned_data)
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return d.fill; })
.each(function(d) { this._current = updateArc(d); })
.on("click", zoomIn)
.on("mouseover", mouseOverArc)
.on("mousemove", mouseMoveArc)
.on("mouseout", mouseOutArc);
var texts = svg.selectAll("text")
.data(partitioned_data)
.enter().append("text")
.filter(filter_min_arc_size_text)
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) { return radius / 3 * d.depth; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.text(function(d,i) {return d.name})
function zoomIn(p) {
if (p.depth > 1) p = p.parent;
if (!p.children) return;
zoom(p, p);
}
function zoomOut(p) {
if (!p.parent) return;
zoom(p.parent, p);
}
// Zoom to the specified new root.
function zoom(root, p) {
if (document.documentElement.__transition__) return;
// Rescale outside angles to match the new layout.
var enterArc,
exitArc,
outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]);
function insideArc(d) {
return p.key > d.key
? {depth: d.depth - 1, x: 0, dx: 0} : p.key < d.key
? {depth: d.depth - 1, x: 2 * Math.PI, dx: 0}
: {depth: 0, x: 0, dx: 2 * Math.PI};
}
function outsideArc(d) {
return {depth: d.depth + 1, x: outsideAngle(d.x), dx: outsideAngle(d.x + d.dx) - outsideAngle(d.x)};
}
center.datum(root);
// When zooming in, arcs enter from the outside and exit to the inside.
// Entering outside arcs start from the old layout.
if (root === p) enterArc = outsideArc, exitArc = insideArc, outsideAngle.range([p.x, p.x + p.dx]);
var new_data=partition.nodes(root).slice(1)
path = path.data(new_data, function(d) { return d.key; });
// When zooming out, arcs enter from the inside and exit to the outside.
// Exiting outside arcs transition to the new layout.
if (root !== p) enterArc = insideArc, exitArc = outsideArc, outsideAngle.range([p.x, p.x + p.dx]);
d3.transition().duration(d3.event.altKey ? 7500 : 750).each(function() {
path.exit().transition()
.style("fill-opacity", function(d) { return d.depth === 1 + (root === p) ? 1 : 0; })
.attrTween("d", function(d) { return arcTween.call(this, exitArc(d)); })
.remove();
path.enter().append("path")
.style("fill-opacity", function(d) { return d.depth === 2 - (root === p) ? 1 : 0; })
.style("fill", function(d) { return d.fill; })
.on("click", zoomIn)
.on("mouseover", mouseOverArc)
.on("mousemove", mouseMoveArc)
.on("mouseout", mouseOutArc)
.each(function(d) { this._current = enterArc(d); });
path.transition()
.style("fill-opacity", 1)
.attrTween("d", function(d) { return arcTween.call(this, updateArc(d)); });
});
texts = texts.data(new_data, function(d) { return d.key; })
texts.exit()
.remove()
texts.enter()
.append("text")
texts.style("opacity", 0)
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) { return radius / 3 * d.depth; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.filter(filter_min_arc_size_text)
.text(function(d,i) {return d.name})
.transition().delay(750).style("opacity", 1)
}
});
function key(d) {
var k = [], p = d;
while (p.depth) k.push(p.name), p = p.parent;
return k.reverse().join(".");
}
function fill(d) {
var p = d;
while (p.depth > 1) p = p.parent;
var c = d3.lab(hue(p.name));
c.l = luminance(d.sum);
return c;
}
function arcTween(b) {
var i = d3.interpolate(this._current, b);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
function updateArc(d) {
return {depth: d.depth, x: d.x, dx: d.dx};
}
d3.select(self.frameElement).style("height", margin.top + margin.bottom + "px");
Your corrective factor rotates the text 180 degrees, this is only half of what you need:
By rotating 180 degrees, you get text that is right way up, but now that moves in the opposite direction because the direction of the text is also rotated.
For the second half of the circle, you need to specify a text-anchor of "end" so that the text is anchored where it should be. Currently it is anchored where it starts, which is fine for the first half of the circle.
When styling the text you'll need to perform a check to see if the text anchor needs to be set to "end" as opposed to "start":
text.style("text-anchor",function(d) { return isRotated(d) ? "end" : "start" })
With the check looking something like:
function isRotated(d) {
var rotation = (d.x + d.dx / 2) * 180 / Math.PI - 90;
return rotation > 90 ? true : false
}
The margins also need to be adjusted:
.attr("dx", function(d) {return isRotated(d) ? "-6" : "6"}) //margin
I'm using D3 and javascript to create a BiLevel Partition following this example. The labels in the left side of the diagram are upside down, and I was trying to rotate them, but I've not been successful yet.
I found numerous cases of people with the same problem, but using Sunburst. Also tried to implement those solutions, but I'm still unable to solve this problem.
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
/*var margin = {top: 350, right: 480, bottom: 350, left: 480},
radius = Math.min(margin.top, margin.right, margin.bottom, margin.left) - 10;*/
var width = 1200,
height = 1200,
radius = Math.min(width, height) / 2;
function filter_min_arc_size_text(d, i) {return (d.dx*d.depth*radius/3)>14};
var hue = d3.scale.category10();
var luminance = d3.scale.sqrt()
.domain([0, 1e6])
.clamp(true)
.range([90, 20]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var partition = d3.layout.partition()
.sort(function(a, b) { return d3.ascending(a.name, b.name); })
.size([2 * Math.PI, radius]);
var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx - .01 / (d.depth + .5); })
.innerRadius(function(d) { return radius / 3 * d.depth; })
.outerRadius(function(d) { return radius / 3 * (d.depth + 1) - 1; });
//Tooltip description
var tooltip = d3.select("body")
.append("div")
.attr("id", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("opacity", 0);
function format_number(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function format_description(d) {
var description = d.description;
return /* '<b>' + d.name + '</b></br>'+*/ d.description + '<br> (' + format_number(d.value) + ')';
}
function computeTextRotation(d) {
var ang = ((d.x + d.dx / 2) - Math.PI / 2) / Math.PI * 180;
return (ang > 90) ? 180 + ang : ang;
}
function mouseOverArc(d) {
d3.select(this).attr("stroke","black")
tooltip.html(format_description(d));
return tooltip.transition()
.duration(50)
.style("opacity", 0.9);
}
function mouseOutArc(){
d3.select(this).attr("stroke","")
return tooltip.style("opacity", 0);
}
function mouseMoveArc (d) {
return tooltip
.style("top", (d3.event.pageY-10)+"px")
.style("left", (d3.event.pageX+10)+"px");
}
var root_ = null;
d3.json("flare.json", function(error, root) {
if (error) return console.warn(error);
// Compute the initial layout on the entire tree to sum sizes.
// Also compute the full name and fill color for each node,
// and stash the children so they can be restored as we descend.
partition
.value(function(d) { return d.size; })
.nodes(root)
.forEach(function(d) {
d._children = d.children;
d.sum = d.value;
d.key = key(d);
d.fill = fill(d);
});
// Now redefine the value function to use the previously-computed sum.
partition
.children(function(d, depth) { return depth < 2 ? d._children : null; })
.value(function(d) { return d.sum; });
var center = svg.append("circle")
.attr("r", radius / 3)
.on("click", zoomOut);
center.append("title")
.text("zoom out");
var partitioned_data=partition.nodes(root).slice(1)
var path = svg.selectAll("path")
.data(partitioned_data)
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return d.fill; })
.each(function(d) { this._current = updateArc(d); })
.on("click", zoomIn)
.on("mouseover", mouseOverArc)
.on("mousemove", mouseMoveArc)
.on("mouseout", mouseOutArc);
var texts = svg.selectAll("text")
.data(partitioned_data)
.enter().append("text")
.filter(filter_min_arc_size_text)
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) { return radius / 3 * d.depth; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.text(function(d,i) {return d.name})
function zoomIn(p) {
if (p.depth > 1) p = p.parent;
if (!p.children) return;
zoom(p, p);
}
function zoomOut(p) {
if (!p.parent) return;
zoom(p.parent, p);
}
// Zoom to the specified new root.
function zoom(root, p) {
if (document.documentElement.__transition__) return;
// Rescale outside angles to match the new layout.
var enterArc,
exitArc,
outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]);
function insideArc(d) {
return p.key > d.key
? {depth: d.depth - 1, x: 0, dx: 0} : p.key < d.key
? {depth: d.depth - 1, x: 2 * Math.PI, dx: 0}
: {depth: 0, x: 0, dx: 2 * Math.PI};
}
function outsideArc(d) {
return {depth: d.depth + 1, x: outsideAngle(d.x), dx: outsideAngle(d.x + d.dx) - outsideAngle(d.x)};
}
center.datum(root);
// When zooming in, arcs enter from the outside and exit to the inside.
// Entering outside arcs start from the old layout.
if (root === p) enterArc = outsideArc, exitArc = insideArc, outsideAngle.range([p.x, p.x + p.dx]);
var new_data=partition.nodes(root).slice(1)
path = path.data(new_data, function(d) { return d.key; });
// When zooming out, arcs enter from the inside and exit to the outside.
// Exiting outside arcs transition to the new layout.
if (root !== p) enterArc = insideArc, exitArc = outsideArc, outsideAngle.range([p.x, p.x + p.dx]);
d3.transition().duration(d3.event.altKey ? 7500 : 750).each(function() {
path.exit().transition()
.style("fill-opacity", function(d) { return d.depth === 1 + (root === p) ? 1 : 0; })
.attrTween("d", function(d) { return arcTween.call(this, exitArc(d)); })
.remove();
path.enter().append("path")
.style("fill-opacity", function(d) { return d.depth === 2 - (root === p) ? 1 : 0; })
.style("fill", function(d) { return d.fill; })
.on("click", zoomIn)
.on("mouseover", mouseOverArc)
.on("mousemove", mouseMoveArc)
.on("mouseout", mouseOutArc)
.each(function(d) { this._current = enterArc(d); });
path.transition()
.style("fill-opacity", 1)
.attrTween("d", function(d) { return arcTween.call(this, updateArc(d)); });
});
texts = texts.data(new_data, function(d) { return d.key; })
texts.exit()
.remove()
texts.enter()
.append("text")
texts.style("opacity", 0)
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) { return radius / 3 * d.depth; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.filter(filter_min_arc_size_text)
.text(function(d,i) {return d.name})
.transition().delay(750).style("opacity", 1)
}
});
function key(d) {
var k = [], p = d;
while (p.depth) k.push(p.name), p = p.parent;
return k.reverse().join(".");
}
function fill(d) {
var p = d;
while (p.depth > 1) p = p.parent;
var c = d3.lab(hue(p.name));
c.l = luminance(d.sum);
return c;
}
function arcTween(b) {
var i = d3.interpolate(this._current, b);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
function updateArc(d) {
return {depth: d.depth, x: d.x, dx: d.dx};
}
d3.select(self.frameElement).style("height", margin.top + margin.bottom + "px");
</script>
The problem I have is that it is only showing the right half of the Partition.
I have a sunburst for which I would like to initiate zoom ability via dropdown. That is when a country name is selected from the drop down menu its part in the sunburst zooms exactly like when its clicked.
js fiddle: http://jsfiddle.net/8wd2xt9n/7/
var width = 960,
height = 700,
radius = Math.min(width, height) / 2;
var b = {
w: 130, h: 30, s: 3, t: 10
};
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var changeArray = [100,80,60,0, -60, -80, -100];
var colorArray = ["#67000d", "#b73e43", "#d5464a", "#f26256", "#fb876e", "#fca78e", "#fcbba1", "#fee0d2", "#fff5f0"];
var svg = d3.select("#diagram").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var partition = d3.layout.partition()
.value(function(d) { return d.Total; });
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)); });
console.log(arc)
function checkIt(error, root){
initializeBreadcrumbTrail();
//intilaize dropdown
if (error) throw error;
var g = svg.selectAll("g")
.data(partition.nodes(root))
.enter().append("g");
var path = g.append("path")
.attr("d", arc)
.style("fill", function(d) { var color;
if(d.Total_Change > 100)
{color = colorArray[0]
}
else if(d.Total_Change > 0 && d.Total_Change < 100)
{color = colorArray[1]
}
else
{
color = colorArray[2]
}
d.color = color;
return color})
.on("click", click)
.on("mouseover", mouseover);
var tooltip = d3.select("body")
.append("div")
.attr("id", "tooltips")
.style("position", "absolute")
.style("background-color", "#fff")
.style("z-index", "10")
.style("visibility", "hidden");
g.on("mouseover", function(d){return tooltip.style("visibility", "visible")
.html("<div class=" + "tooltip_container>"+"<h4 class=" + "tooltip_heading>" +d.name.replace(/[_-]/g, " ") +"</h4>" +"<br>" + "<p> Emissions 2013:" + " " + "<br>" + d.Total + " " +"<span>in Million Tons</span></p>"+ "<br>"+ "<p> Change in Emissions: <span>" + (d.Total_Change/d.Total*100).toPrecision(3) + "%" + "</span></p>"+"</div>" );})
.on("mousemove", function(){return tooltip.style("top",(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});
//creating a dropdown
var dropDown = d3.select("#dropdown_container")
.append("select")
.attr("class", "selection")
.attr("name", "country-list");
var nodeArr = partition.nodes(root);
var options = dropDown.selectAll("option")
.data(nodeArr)
.enter()
.append("option");
options.text(function (d) {
var prefix = new Array(d.depth + 1);
var dropdownValues = d.name.replace(/[_-]/g, " ");
return dropdownValues;
}).attr("value", function (d) {
var dropdownValues = d.name;
return dropdownValues;
});
// transition on click
function click(d) {
// fade out all text elements
path.transition()
.duration(750)
.attrTween("d", arcTween(d))
.each("end", function(e, i) {
// check if the animated element's data e lies within the visible angle span given in d
if (e.x >= d.x && e.x < (d.x + d.dx)) {
// get a selection of the associated text element
var arcText = d3.select(this.parentNode).select("text");
// fade in the text element and recalculate positions
arcText.transition().duration(750)
.attr("opacity", 1)
.attr("transform", function() { return "rotate(" + computeTextRotation(e) + ")" })
.attr("x", function(d) { return y(d.y); });
}
});
};
d3.select(".selection").on("change", function changePie() {
var value = this.value;
var index = this.selectedIndex;
var dataObj = nodeArr[index];
path[0].forEach(function(p){
var data = d3.select(p).data();//get the data from the path
if (data[0].name === value){
path.transition()
.duration(750)
.attrTween("d", arcTween(d))
.each("end", function(e, i) {
// check if the animated element's data e lies within the visible angle span given in d
if (e.x >= d.x && e.x < (d.x + d.dx)) {
// get a selection of the associated text element
var arcText = d3.select(this.parentNode).select("text");
// fade in the text element and recalculate positions
arcText.transition().duration(750)
.attr("opacity", 1)
.attr("transform", function() { return "rotate(" + computeTextRotation(e) + ")" })
.attr("x", function(d) { return y(d.y); });
}
});
}
});
console.log(this.value + " :c " + dataObj["Iron and steel"] + " in " + (dataObj.parent && dataObj.parent.name));
});
};
d3.json("https://gist.githubusercontent.com/heenaI/cbbc5c5f49994f174376/raw/55c672bbca7991442f1209cfbbb6ded45d5e8c8e/data.json", checkIt);
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(d) {
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(d, i) {
return i
? function(t) { return arc(d); }
: function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
};
}
function initializeBreadcrumbTrail() {
// Add the svg area.
var trail = d3.select("#sequence").append("svg:svg")
.attr("width", width)
.attr("height", 50)
.attr("id", "trail");
// Add the label at the end, for the percentage.
trail.append("svg:text")
.attr("id", "endlabel")
.style("fill", "#000");
}
function breadcrumbPoints(d, i) {
var points = [];
points.push("0,0");
points.push(b.w + ",0");
points.push(b.w + b.t + "," + (b.h / 2));
points.push(b.w + "," + b.h);
points.push("0," + b.h);
if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
points.push(b.t + "," + (b.h / 2));
}
return points.join(" ");
}
// Update the breadcrumb trail to show the current sequence and percentage.
function updateBreadcrumbs(nodeArray) {
// Data join; key function combines name and depth (= position in sequence).
var g = d3.select("#trail")
.selectAll("g")
.data(nodeArray, function(d) { return d.name.replace(/[_-]/g, " ") + d.Total; });
// Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g");
entering.append("svg:polygon")
.attr("points", breadcrumbPoints)
.style("fill", "#d3d3d3");
entering.append("svg:text")
.attr("x", (b.w + b.t) / 2)
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.name.replace(/[_-]/g, " "); });
// Set position for entering and updating nodes.
g.attr("transform", function(d, i) {
return "translate(" + i * (b.w + b.s) + ", 0)";
});
// Remove exiting nodes.
g.exit().remove();
// Now move and update the percentage at the end.
d3.select("#trail").select("#endlabel")
.attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle");
// Make the breadcrumb trail visible, if it's hidden.
d3.select("#trail")
.style("visibility", "");
}
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
function mouseover(d) {
var sequenceArray = getAncestors(d);
updateBreadcrumbs(sequenceArray);}
Add this one line and it will work :)
Inside your selection change add this var d = data[0]; as shown below:
d3.select(".selection").on("change", function changePie() {
var value = this.value;
var index = this.selectedIndex;
var dataObj = nodeArr[index];
path[0].forEach(function(p){
var data = d3.select(p).data();//get the data from the path
if (data[0].name === value){
var d = data[0];//this line is missing
path.transition()
Working code here
Other option is to call the click function on selection change like below
d3.select(".selection").on("change", function changePie() {
var value = this.value;
var index = this.selectedIndex;
var dataObj = nodeArr[index];
path[0].forEach(function (p) {
var data = d3.select(p).data(); //get the data from the path
if (data[0].name === value) {
console.log(data)
click(data[0]);//call the click function
}
Working code here
Hope this helps!
I'm trying to add text to the partition-sunburst example. I have followed a hint given on Google Group and I was able to add the text. Now I want to rotate it. The new angles seem to be correct, but all the text get gathered in one point.
This is the piece of code where I add and rotate the text:
var text = vis.data([json]).selectAll("text")
.data(partition.nodes)
.enter().append("svg:text")
.attr("x", function(d) { return radius * Math.cos(d.x + d.dx/2); } )
.attr("y", function(d) { return radius * Math.sin(d.x + d.dx/2); } )
.attr("dy", ".31em")
.style("font-size", "5px")
.attr("transform", function(d) {
var angle = (2 * Math.PI - d.x) * (180/Math.PI);
var rotation = "rotate(" + angle + ")";
console.log(rotation);
console.log("d.x=" + d.x + ", d.y=" + d.y);
return rotation;
})
.text(function(d) { return d.name; });
This is an image of what I get:
and this is the full script:
var width = 1000,
height = 1000,
radius = 350,
x = d3.scale.linear().range([0, 2 * Math.PI]),
y = d3.scale.pow().exponent(1.3).domain([0, 1]).range([0, radius]),
padding = 5,
color = d3.scale.category20c();
var vis = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var partition = d3.layout.partition()
.sort(null)
.size([2 * Math.PI, radius * radius])
.value(function(d) { return 1; });
var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx; })
.innerRadius(function(d) { return Math.sqrt(d.y); })
.outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });
d3.json("fracking.json", function(json) {
var path = vis.data([json]).selectAll("path")
.data(partition.nodes)
.enter().append("svg:path")
.attr("display", function(d) { return d.depth ? null : "none"; })
// hide inner ring
.attr("d", arc)
.attr("fill-rule", "evenodd")
.style("stroke", "#fff")
.style("fill", function(d) { return color((d.children ? d : d.parent).name); })
.each(stash);
var text = vis.data([json]).selectAll("text")
.data(partition.nodes)
.enter().append("svg:text")
.attr("x", function(d) { return radius * Math.cos(d.x + d.dx/2); } )
.attr("y", function(d) { return radius * Math.sin(d.x + d.dx/2); } )
.attr("dy", ".31em")
.style("font-size", "5px")
.attr("transform", function(d) {
var angle = (2 * Math.PI - d.x) * (180/Math.PI);
var rotation = "rotate(" + angle + ")";
console.log(rotation);
console.log("d.x=" + d.x + ", d.y=" + d.y);
return rotation;
})
.text(function(d) { return d.name; });
d3.select("#size").on("click", function() {
path
.data(partition.value(function(d) { return d.size; }))
.transition()
.duration(1500)
.attrTween("d", arcTween);
d3.select("#size").classed("active", true);
d3.select("#count").classed("active", false);
});
d3.select("#count").on("click", function() {
path
.data(partition.value(function(d) { return 1; }))
.transition()
.duration(1500)
.attrTween("d", arcTween);
d3.select("#size").classed("active", false);
d3.select("#count").classed("active", true);
});
});
// Stash the old values for transition.
function stash(d) {
d.x0 = d.x;
d.dx0 = d.dx;
}
// Interpolate the arcs in data space.
function arcTween(a) {
var i = d3.interpolate({x: a.x0, dx: a.dx0}, a);
return function(t) {
var b = i(t);
a.x0 = b.x;
a.dx0 = b.dx;
return arc(b);
};
}
I think you need to specify the center of rotation. Try this:
var text = vis.data([json]).selectAll("text")
.data(partition.nodes)
.enter().append("svg:text")
.attr("x", function(d) { return radius * Math.cos(d.x + d.dx/2); } )
.attr("y", function(d) { return radius * Math.sin(d.x + d.dx/2); } )
.attr("dy", ".31em")
.style("font-size", "5px")
.attr("transform", function(d) {
var angle = (2 * Math.PI - d.x) * (180/Math.PI);
var rotation = "rotate(" + angle + "," + d3.select(this).attr("x") + "," d3.select(this).attr("y") +")";
console.log(rotation);
console.log("d.x=" + d.x + ", d.y=" + d.y);
return rotation;
})
.text(function(d) { return d.name; });