Related
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 which has following layers of data
world=>continents=>countries=>fuels
NOw I want to include names of elements only until countries and not names of fuels. With my code I can add names of all elements in the dropdown but not sure how to remove names of fuels from the dropdown.
Fiddle: http://jsfiddle.net/8wd2xt9n/14/
Full code:
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
console.log(d)
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) {
console.log(data)
click(data[0]);//call the click function
}
});
console.log(this.value + " :c " + dataObj["Iron and steel"] + " in " + (dataObj.parent && dataObj.parent.name));
});
};
d3.json("https://gist.githubusercontent.com/heenaI/cbbc5c5f49994f174376/raw/743b3964d1dcc0b005ec2b024414877a36b0bd33/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);
}
Code that creates dropdown
/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;
});
Data structure can be viewed here
As you are grabbing the values of the dropdown menu from the nodes of the partition, you have the depth of the nodes at hand when setting up the dropdown, thus you can filter:
var nodeArr = partition.nodes(root);
var options = dropDown.selectAll("option")
.data(nodeArr.filter(function(d){return d.depth < 3;}))
.enter()
.append("option");
I hope that helps!
(see fiddle)
I would just pre-process the data. In the original root structure you know the countries are 2 levels down so:
var countries = [];
root.children.forEach(function (c){
c.children.forEach(function (d){
countries.push(d.name.replace(/[_-]/g, " "));
});
});
And the dropdown becomes:
var options = dropDown.selectAll("option")
.data(countries)
.enter()
.append("option");
options.text(function (d) {
return d;
}).attr("value", function (d) {
return d;
});
Updated fiddle.
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 am have created chart using d3.js, when I zoom in or zoom out on web browser this charts do not re-size according to window.
Following is what I have done:
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style type="text/css">
svg {
font-family: "Helvetica Neue", Helvetica;
}
.line {
fill: none;
stroke: #000;
stroke-width: 2px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var m = [20, 20, 30, 20],
w = 960 - m[1] - m[3],
h = 500 - m[0] - m[2];
var x,
y,
duration = 1500,
delay = 500;
var color = d3.scale.category10();
var svg = d3.select("body").append("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
var stocks,
symbols;
// A line generator, for the dark stroke.
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
// A line generator, for the dark stroke.
var axis = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(h);
// A area generator, for the dark stroke.
var area = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y1(function(d) { return y(d.price); });
d3.csv("stocks.csv", function(data) {
var parse = d3.time.format("%b %Y").parse;
// Nest stock values by symbol.
symbols = d3.nest()
.key(function(d) { return d.symbol; })
.entries(stocks = data);
// Parse dates and numbers. We assume values are sorted by date.
// Also compute the maximum price per symbol, needed for the y-domain.
symbols.forEach(function(s) {
s.values.forEach(function(d) { d.date = parse(d.date); d.price = +d.price; });
s.maxPrice = d3.max(s.values, function(d) { return d.price; });
s.sumPrice = d3.sum(s.values, function(d) { return d.price; });
});
// Sort by maximum price, descending.
symbols.sort(function(a, b) { return b.maxPrice - a.maxPrice; });
var g = svg.selectAll("g")
.data(symbols)
.enter().append("g")
.attr("class", "symbol");
setTimeout(lines, duration);
});
function lines() {
x = d3.time.scale().range([0, w - 60]);
y = d3.scale.linear().range([h / 4 - 20, 0]);
// Compute the minimum and maximum date across symbols.
x.domain([
d3.min(symbols, function(d) { return d.values[0].date; }),
d3.max(symbols, function(d) { return d.values[d.values.length - 1].date; })
]);
var g = svg.selectAll(".symbol")
.attr("transform", function(d, i) { return "translate(0," + (i * h / 4 + 10) + ")"; });
g.each(function(d) {
var e = d3.select(this);
e.append("path")
.attr("class", "line");
e.append("circle")
.attr("r", 5)
.style("fill", function(d) { return color(d.key); })
.style("stroke", "#000")
.style("stroke-width", "2px");
e.append("text")
.attr("x", 12)
.attr("dy", ".31em")
.text(d.key);
});
function draw(k) {
g.each(function(d) {
var e = d3.select(this);
y.domain([0, d.maxPrice]);
e.select("path")
.attr("d", function(d) { return line(d.values.slice(0, k + 1)); });
e.selectAll("circle, text")
.data(function(d) { return [d.values[k], d.values[k]]; })
.attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.price) + ")"; });
});
}
var k = 1, n = symbols[0].values.length;
d3.timer(function() {
draw(k);
if ((k += 2) >= n - 1) {
draw(n - 1);
setTimeout(horizons, 500);
return true;
}
});
}
function horizons() {
svg.insert("defs", ".symbol")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", h / 4 - 20);
var color = d3.scale.ordinal()
.range(["#c6dbef", "#9ecae1", "#6baed6"]);
var g = svg.selectAll(".symbol")
.attr("clip-path", "url(#clip)");
area
.y0(h / 4 - 20);
g.select("circle").transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (-h / 4) + ")"; })
.remove();
g.select("text").transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (h / 4 - 20) + ")"; })
.attr("dy", "0em");
g.each(function(d) {
y.domain([0, d.maxPrice]);
d3.select(this).selectAll(".area")
.data(d3.range(3))
.enter().insert("path", ".line")
.attr("class", "area")
.attr("transform", function(d) { return "translate(0," + (d * (h / 4 - 20)) + ")"; })
.attr("d", area(d.values))
.style("fill", function(d, i) { return color(i); })
.style("fill-opacity", 1e-6);
y.domain([0, d.maxPrice / 3]);
d3.select(this).selectAll(".line").transition()
.duration(duration)
.attr("d", line(d.values))
.style("stroke-opacity", 1e-6);
d3.select(this).selectAll(".area").transition()
.duration(duration)
.style("fill-opacity", 1)
.attr("d", area(d.values))
.each("end", function() { d3.select(this).style("fill-opacity", null); });
});
setTimeout(areas, duration + delay);
}
function areas() {
var g = svg.selectAll(".symbol");
axis
.y(h / 4 - 21);
g.select(".line")
.attr("d", function(d) { return axis(d.values); });
g.each(function(d) {
y.domain([0, d.maxPrice]);
d3.select(this).select(".line").transition()
.duration(duration)
.style("stroke-opacity", 1)
.each("end", function() { d3.select(this).style("stroke-opacity", null); });
d3.select(this).selectAll(".area")
.filter(function(d, i) { return i; })
.transition()
.duration(duration)
.style("fill-opacity", 1e-6)
.attr("d", area(d.values))
.remove();
d3.select(this).selectAll(".area")
.filter(function(d, i) { return !i; })
.transition()
.duration(duration)
.style("fill", color(d.key))
.attr("d", area(d.values));
});
svg.select("defs").transition()
.duration(duration)
.remove();
g.transition()
.duration(duration)
.each("end", function() { d3.select(this).attr("clip-path", null); });
setTimeout(stackedArea, duration + delay);
}
function stackedArea() {
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse");
stack(symbols);
y
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
.range([h, 0]);
line
.y(function(d) { return y(d.price0); });
area
.y0(function(d) { return y(d.price0); })
.y1(function(d) { return y(d.price0 + d.price); });
var t = svg.selectAll(".symbol").transition()
.duration(duration)
.attr("transform", "translate(0,0)")
.each("end", function() { d3.select(this).attr("transform", null); });
t.select("path.area")
.attr("d", function(d) { return area(d.values); });
t.select("path.line")
.style("stroke-opacity", function(d, i) { return i < 3 ? 1e-6 : 1; })
.attr("d", function(d) { return line(d.values); });
t.select("text")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
setTimeout(streamgraph, duration + delay);
}
function streamgraph() {
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse")
.offset("wiggle");
stack(symbols);
line
.y(function(d) { return y(d.price0); });
var t = svg.selectAll(".symbol").transition()
.duration(duration);
t.select("path.area")
.attr("d", function(d) { return area(d.values); });
t.select("path.line")
.style("stroke-opacity", 1e-6)
.attr("d", function(d) { return line(d.values); });
t.select("text")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
setTimeout(overlappingArea, duration + delay);
}
function overlappingArea() {
var g = svg.selectAll(".symbol");
line
.y(function(d) { return y(d.price0 + d.price); });
g.select(".line")
.attr("d", function(d) { return line(d.values); });
y
.domain([0, d3.max(symbols.map(function(d) { return d.maxPrice; }))])
.range([h, 0]);
area
.y0(h)
.y1(function(d) { return y(d.price); });
line
.y(function(d) { return y(d.price); });
var t = g.transition()
.duration(duration);
t.select(".line")
.style("stroke-opacity", 1)
.attr("d", function(d) { return line(d.values); });
t.select(".area")
.style("fill-opacity", .5)
.attr("d", function(d) { return area(d.values); });
t.select("text")
.attr("dy", ".31em")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price) + ")"; });
svg.append("line")
.attr("class", "line")
.attr("x1", 0)
.attr("x2", w - 60)
.attr("y1", h)
.attr("y2", h)
.style("stroke-opacity", 1e-6)
.transition()
.duration(duration)
.style("stroke-opacity", 1);
setTimeout(groupedBar, duration + delay);
}
function groupedBar() {
x = d3.scale.ordinal()
.domain(symbols[0].values.map(function(d) { return d.date; }))
.rangeBands([0, w - 60], .1);
var x1 = d3.scale.ordinal()
.domain(symbols.map(function(d) { return d.key; }))
.rangeBands([0, x.rangeBand()]);
var g = svg.selectAll(".symbol");
var t = g.transition()
.duration(duration);
t.select(".line")
.style("stroke-opacity", 1e-6)
.remove();
t.select(".area")
.style("fill-opacity", 1e-6)
.remove();
g.each(function(p, j) {
d3.select(this).selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("x", function(d) { return x(d.date) + x1(p.key); })
.attr("y", function(d) { return y(d.price); })
.attr("width", x1.rangeBand())
.attr("height", function(d) { return h - y(d.price); })
.style("fill", color(p.key))
.style("fill-opacity", 1e-6)
.transition()
.duration(duration)
.style("fill-opacity", 1);
});
setTimeout(stackedBar, duration + delay);
}
function stackedBar() {
x.rangeRoundBands([0, w - 60], .1);
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse");
var g = svg.selectAll(".symbol");
stack(symbols);
y
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
.range([h, 0]);
var t = g.transition()
.duration(duration / 2);
t.select("text")
.delay(symbols[0].values.length * 10)
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
t.selectAll("rect")
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d.price0 + d.price); })
.attr("height", function(d) { return h - y(d.price); })
.each("end", function() {
d3.select(this)
.style("stroke", "#fff")
.style("stroke-opacity", 1e-6)
.transition()
.duration(duration / 2)
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.style("stroke-opacity", 1);
});
setTimeout(transposeBar, duration + symbols[0].values.length * 10 + delay);
}
function transposeBar() {
x
.domain(symbols.map(function(d) { return d.key; }))
.rangeRoundBands([0, w], .2);
y
.domain([0, d3.max(symbols.map(function(d) { return d3.sum(d.values.map(function(d) { return d.price; })); }))]);
var stack = d3.layout.stack()
.x(function(d, i) { return i; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; });
stack(d3.zip.apply(null, symbols.map(function(d) { return d.values; }))); // transpose!
var g = svg.selectAll(".symbol");
var t = g.transition()
.duration(duration / 2);
t.selectAll("rect")
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d.price0 + d.price) - 1; })
.attr("height", function(d) { return h - y(d.price) + 1; })
.attr("x", function(d) { return x(d.symbol); })
.attr("width", x.rangeBand())
.style("stroke-opacity", 1e-6);
t.select("text")
.attr("x", 0)
.attr("transform", function(d) { return "translate(" + (x(d.key) + x.rangeBand() / 2) + "," + h + ")"; })
.attr("dy", "1.31em")
.each("end", function() { d3.select(this).attr("x", null).attr("text-anchor", "middle"); });
svg.select("line").transition()
.duration(duration)
.attr("x2", w);
setTimeout(donut, duration / 2 + symbols[0].values.length * 10 + delay);
}
function donut() {
var g = svg.selectAll(".symbol");
g.selectAll("rect").remove();
var pie = d3.layout.pie()
.value(function(d) { return d.sumPrice; });
var arc = d3.svg.arc();
g.append("path")
.style("fill", function(d) { return color(d.key); })
.data(function() { return pie(symbols); })
.transition()
.duration(duration)
.tween("arc", arcTween);
g.select("text").transition()
.duration(duration)
.attr("dy", ".31em");
svg.select("line").transition()
.duration(duration)
.attr("y1", 2 * h)
.attr("y2", 2 * h)
.remove();
function arcTween(d) {
var path = d3.select(this),
text = d3.select(this.parentNode.appendChild(this.previousSibling)),
x0 = x(d.data.key),
y0 = h - y(d.data.sumPrice);
return function(t) {
var r = h / 2 / Math.min(1, t + 1e-3),
a = Math.cos(t * Math.PI / 2),
xx = (-r + (a) * (x0 + x.rangeBand()) + (1 - a) * (w + h) / 2),
yy = ((a) * h + (1 - a) * h / 2),
f = {
innerRadius: r - x.rangeBand() / (2 - a),
outerRadius: r,
startAngle: a * (Math.PI / 2 - y0 / r) + (1 - a) * d.startAngle,
endAngle: a * (Math.PI / 2) + (1 - a) * d.endAngle
};
path.attr("transform", "translate(" + xx + "," + yy + ")");
path.attr("d", arc(f));
text.attr("transform", "translate(" + arc.centroid(f) + ")translate(" + xx + "," + yy + ")rotate(" + ((f.startAngle + f.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
};
}
setTimeout(donutExplode, duration + delay);
}
function donutExplode() {
var r0a = h / 2 - x.rangeBand() / 2,
r1a = h / 2,
r0b = 2 * h - x.rangeBand() / 2,
r1b = 2 * h,
arc = d3.svg.arc();
svg.selectAll(".symbol path")
.each(transitionExplode);
function transitionExplode(d, i) {
d.innerRadius = r0a;
d.outerRadius = r1a;
d3.select(this).transition()
.duration(duration / 2)
.tween("arc", tweenArc({
innerRadius: r0b,
outerRadius: r1b
}));
}
function tweenArc(b) {
return function(a) {
var path = d3.select(this),
text = d3.select(this.nextSibling),
i = d3.interpolate(a, b);
for (var key in b) a[key] = b[key]; // update data
return function(t) {
var a = i(t);
path.attr("d", arc(a));
text.attr("transform", "translate(" + arc.centroid(a) + ")translate(" + w / 2 + "," + h / 2 +")rotate(" + ((a.startAngle + a.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
};
}
}
setTimeout(function() {
svg.selectAll("*").remove();
svg.selectAll("g").data(symbols).enter().append("g").attr("class", "symbol");
lines();
}, duration);
}
</script>
</body>
</html>
I am learning d3.js, so I don't know how to do it. Please help me.
Doing this ends up being a bit code heavy, but for my graphs I tend to have 3 different parts: setup, draw and redraw. In setup I set up all the SVG containers and bind the data. In draw, I do the initial data draw (this tends to have different animations, fade-ins, etc). Then I bind window.onresize to the redraw all of the SVG data based on window/container dimensions.
I can provide you with an example of my code if you would like.
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; });