Right, so I have this graph that works great. It has tooltips, labels, and a total value in the center:
However, when I hover over one of the arcs to activate the tooltips, the little dot that has the pointer coming out of it stays put, as seen here:
This is my mouse movement code
path.on('mouseenter', function(d){
d3.select(this)
.transition()
.duration(500)
.attr("d", arcOver);
});
path.on('mouseleave', function(d){
d3.select(this).transition()
.duration(500)
.attr("d", arc);
});
path.on('mouseover', function(d) {
var percent = Math.round(1000 * d.data.value / sum) / 10;
tooltip.style('opacity', 0);
tooltip.select('.label').html(d.data.label);
tooltip.select('.value').html(d3.format("$,.2f")(d.data.value));
tooltip.select('.percent').html(percent + '%');
tooltip.style('display', 'block');
tooltip.transition()
.duration(600)
.style("opacity",1);
});
path.on('mouseout', function() {
tooltip.transition()
.duration(600)
.style("opacity",0)
.style('pointer-events', 'none')
});
Here's the code that creates the labels:
svg.selectAll("text").data(pieData)
.enter()
.append("text")
.attr("class", "stickLabels")
.attr("text-anchor", "middle")
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cx = Math.cos(a) * (radius - 37.5);
return d.x = Math.cos(a) * (radius + 40);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 37.5);
return d.y = Math.sin(a) * (radius + 40);
})
.text(function(d) { return d3.format("s")(d.value); })
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width/2 - 2;
d.ox = d.x + bbox.width/2 + 2;
d.sy = d.oy = d.y + 5;
});
svg.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
svg.selectAll("path.pointer").data(pieData).enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.attr("d", function(d) {
if(d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
And here's a fiddle of the whole code: http://jsfiddle.net/18L6u5xf/
My question is this: How do I move the dot with the arc.
PS I know what I need to change it to, I just don't know how to do it with a mouseover. This is what it needs to end up being:
d.cx = Math.cos(a) * (radius - 17.5);
PPS It looks better with my styling than in the fiddle, just bear with me.
A slightly cleaner way of doing this is to wrap the arc, path and text in g and then just transition that on mouseenter and mouseout. This way you aren't repeating the same data binding and calculations 3 separate times:
// create a group
var gs = svg.selectAll('.slice')
.data(pieData)
.enter()
.append('g')
.attr('class', 'slice');
// add arcs to it
gs.append('path')
.attr('d', arc)
.attr('id', function(d){return d.data.id;})
.attr('class', 'arcPath')
.attr('fill', function(d, i) {
return color(d.data.label);
});
// add text to it
gs.append("text")
.attr("class", "stickLabels")
.attr("text-anchor", "middle")
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cx = Math.cos(a) * (radius - 37.5);
return d.x = Math.cos(a) * (radius + 40);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 37.5);
return d.y = Math.sin(a) * (radius + 40);
})
.text(function(d) { return d3.format("s")(d.value); })
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width/2 - 2;
d.ox = d.x + bbox.width/2 + 2;
d.sy = d.oy = d.y + 5;
});
// add connection paths
gs.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.attr("d", function(d) {
if(d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
// mouseenter of group
gs.on('mouseenter', function(d){
d3.select(this)
.transition()
.duration(500)
.attr("transform",function(d){
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
var x = Math.cos(a) * 20;
var y = Math.sin(a) * 20;
return 'translate(' + x + ',' + y + ')';
});
});
// on mouse leave
gs.on('mouseleave', function(d){
d3.select(this)
.transition()
.duration(500)
.attr("transform",function(d){
return 'translate(0,0)';
});
});
Example here.
Related
I was creating a radial tree and trying to download it to SVG but it has some issues
It downloads with those black thick strokes which are not displayed on the webpage.
Any idea where the black lines are coming from?
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + (width / 2 - 15) + ","
+ (height / 2 + 25) + ")");
var stratify = d3.stratify()
.parentId(function(d) {
console.log(d.id.substring(0, d.id.lastIndexOf(".")));
return d.id.substring(0, d.id.lastIndexOf(".")); });
var tree = d3.cluster()
tree.size([360, 360])
tree.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) /
a.depth; });
d3.csv("flare.csv", function(error, data) {
if (error) throw error;
var root = tree(stratify(data)
.sort(function(a, b) { return (a.height - b.height + 100) ||
a.id.localeCompare(b.id); }));
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + project(d.x, d.y)
+ "C" + project(d.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, d.parent.y);
});
link.attr('stroke', function(d) {
if (d.id.startsWith("Mother.Biological")){
return "#386eff";
}
if (d.id.startsWith("Mother.Env")){
return "#45cbf2";
}
else return '#70f2ad';
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--
internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + project(d.x,
d.y)
+ ")"; });
node.append("circle")
.attr("r", function(d) {
console.log(d.value);
if (d.id == "Mother") return 4.4;
else return 2.4;
} )
.style('fill', function(d) {
if (d.id.startsWith("Mother.Biological")){
return "#386eff";
}
if (d.id.startsWith("Mother.Env")){
return "#45cbf2";
}
if (d.id.startsWith("Mother.Biological")){
return "#386eff";
}
if (d.id.startsWith("Mother.Form")){
return '#70f2ad';
}
d.color = 'red';
return d.color});
node.append("text")
.attr("dy", ".31em")
.attr("x", function(d) { return d.x < 180 === !d.children ? 6 : -6; })
.style("text-anchor", function(d) { return d.x < 180 === !d.children ?
"start" : "end"; })
.attr("transform", function(d) { return "rotate(" + (d.x < 180 ? d.x - 90
: d.x + 90) + ")"; })
.text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });
});
function project(x, y) {
var angle = (x - 90) / 180 * Math.PI, radius = y;
return [radius * Math.cos(angle), radius * Math.sin(angle)];
}
d3.select("#download")
.on("mouseover", writeDownloadLink);
function writeDownloadLink(){
var html = d3.select("svg")
.attr("title", "svg_title")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
d3.select(this)
.attr("href-lang", "image/svg+xml")
.attr("href", "data:image/svg+xml;base64,\n" + btoa(html))
.on("mousedown", function(){
if(event.button != 2){
d3.select(this)
.attr("href", null)
.html("Use right click");
}
})
.on("mouseout", function(){
d3.select(this)
.html("Download");
});
};
It looks ok in any browser but when I download it and convert it to SVG or EFM it comes back with those lines.
Page that you provided contains style tag. I'm not sure how exactly do you export SVG, but some css rules seems to be lost along the way.
In similar case I managed to get current css properties and put them into style property:
d3.selectAll('...').each(function() {
var that = d3.select(this);
['stroke', 'stroke-width', 'opacity', 'fill', ...].forEach(function(property) {
that.style(property, that.style(property))
});
});
Hope this will help you.
I am trying to develop an application where users can click on the D3 pie chart and see information which relates to the selection. How can I rotate the arc's so that the clicked arc comes to the bottom (the centre of the arc clicked on should be at the bottom)? I have been playing around with rotating the pie by selecting the arc group but I would appreciate any idea on how to achieve this.
Here is some code I have so far.
var self = this;
var instanceId = Math.floor(Math.random() * 100000);
var margin = {
top: 5,
right: 15,
bottom: 50,
left: 20
};
self.width = this.htmlElement.parentElement.parentElement.offsetWidth - margin.right - margin.left;
self.height = window.innerHeight / 3 ;
self.curAngle = 0;
self.svgParent.html("<h4 style='color:green;'>Sponsors </h4><br>");
// Update data for the chart
self.updateChartData = function () {
if(!self.svg) {
this.svg = this.svgParent
.classed("svg-container", true)
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + this.width + " " + this.height)
.append("g")
.classed("svg-content-responsive", true);
//.attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")");
}
var svgg = this.svg
.append("g")
.classed("svg-content-responsive", true)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
self.svg.selectAll(".arctext").remove();
self.svg.selectAll(".pie-widget-total-label").remove();
var pie = d3.pie().sort(sort)(self.selectedData.map(function (d: any) {
return d.count;
}));
var path = d3.arc()
.outerRadius(radius)
.innerRadius(radius / 2);
var outsideLabel = d3.arc()
.outerRadius(radius * 0.9)
.innerRadius(radius * 0.9);
var middleLabel = d3.arc()
.outerRadius(radius * 0.75)
.innerRadius(radius * 0.75);
var insideLabel = d3.arc()
.outerRadius(radius * 0.6)
.innerRadius(radius * 0.6);
var g = self.svg
.attr("width", self.width + margin.left + margin.right)
.attr("height", self.height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");
var defs = g.append("defs");
var lightGradients = defs.selectAll(".arc")
.data(pie)
.enter()
.append("radialGradient")
.attr("id", function (d: any) {
return "lightGradient-" + instanceId + "-" + d.index;
})
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", "0")
.attr("cy", "0")
.attr("r", "120%");
var darkGradients = defs.selectAll(".arc")
.data(pie)
.enter()
.append("radialGradient")
.attr("id", function (d: any) {
return "darkGradient-" + instanceId + "-" + d.index;
})
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", "0")
.attr("cy", "0")
.attr("r", "120%");
lightGradients.append("stop")
.attr("offset", "0%")
.attr("style", function (d: any) {
return "stop-color: " + d3.color(color(d.index)) + ";";
});
lightGradients.append("stop")
.attr("offset", "100%")
.attr("style", function (d: any) {
return "stop-color: black;";
});
darkGradients.append("stop")
.attr("offset", "0%")
.attr("style", function (d: any) {
return "stop-color: " + d3.color(color(d.index)).darker(0.5) + ";";
});
darkGradients.append("stop")
.attr("offset", "100%")
.attr("style", function (d: any) {
return "stop-color: black;";
});
self.tooltip = d3.select("body")
.append("div")
.attr("class", "pie-widget-tooltip")
.style("opacity", 0);
self.arc = g.selectAll(".arc")
.data(pie)
.enter()
.append("g")
.attr("class", "arc");
var arcpath = self.arc.append("path")
.attr("id", function (d: any) {
return d.index;
})
.attr("d", path)
.attr("stroke", "white")
.attr("stroke-width", "2px")
.attr("fill", function (d: any) {
return "url(#lightGradient-" + instanceId + "-" + d.index + ")";
})
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
self.rotateChart();
})
.transition()
.duration(function(d:any, i:any) {
return i * 800;
})
.attrTween('d', function(d:any) {
var i = d3.interpolate(d.startAngle + 0.1, d.endAngle);
return function (t: any) {
d.endAngle = i(t);
return path(d);
}
});
function arcTween(a: any) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t: any) {
return path(i(t));
};
}
var gtext = self.svg
.append("g")
.attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ")");
var arctext = gtext.selectAll(".arctext")
.data(pie)
.enter()
.append("g")
.attr("class", "arctext");
var primaryLabelText = arctext.append("text")
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
})
.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + middleLabel.centroid(d) + ")";
})
.attr("dy", "-0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "15px")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getStudyLabel(d.index);
}
});
var secondaryLabelText = arctext.append("text")
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
})
.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + middleLabel.centroid(d) + ")";
})
.attr("dy", "0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getPatientsLabel(d.index);
}
});
var n = 0;
for (var i = 0; i < self.selectedData.length; i++) {
n = n + this.selectedData[i]["count"];
}
var total = self.svg
.append("g")
.attr("transform", "translate(" + (self.width / 2 - 20 ) + "," + self.height / 2 + ")")
total.append("text")
.attr("class", "pie-widget-total-label")
.text("Total\r\n" + n);
}.bind(self);
self.showDialog = function() {
this.router.navigateByUrl('/myRouteName');
}.bind(self);
self.rotateChart = function() {
self.arc.attr("transform", "rotate(-45)");
}.bind(self);
You could rotate the arcs by changing their start/end angles as appropriate, but this would be more complex than needed.
A simpler solution would be to just rotate a g that holds the entire pie chart, at the same time, rotate any labels the other way so they remain level.
I've just used the canonical pie chart from this block as an example:
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 2,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var data = [ {age:"<5", population: 2704659},{age:"5-13", population: 4499890},{age:"14-17", population: 2159981},{age:"18-24", population: 3853788},{age:"25-44", population: 14106543},{age:"45-64", population: 8819342},{age:"≥65", population: 612463} ]
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.population; });
var path = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var label = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var arc = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arc.append("path")
.attr("d", path)
.attr("fill", function(d) { return color(d.data.age); })
.on("click",function(d) {
// The amount we need to rotate:
var rotate = 180-(d.startAngle + d.endAngle)/2 / Math.PI * 180;
// Transition the pie chart
g.transition()
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + rotate + ")")
.duration(1000);
// Τransition the labels:
text.transition()
.attr("transform", function(dd) {
return "translate(" + label.centroid(dd) + ") rotate(" + (-rotate) + ")"; })
.duration(1000);
});
var text = arc.append("text")
.attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; })
.attr("dy", "0.35em")
.text(function(d) { return d.data.age; });
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
I am building a pie chart in d3. In this I have a very specific need to have labels extruding out with a horizontal line attached to the slice ticks.
Here is my code
svg.selectAll("g.arc")
.data(pie)
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d) {
var a = 180-(d.startAngle + (d.endAngle - d.startAngle)/2)-45 - Math.PI/2;
d.cx = Math.cos(a) * (radius - 75);
return d.x =(width/3)+ Math.cos(a) * (oldRadius - 20);
})
.attr("y", function(d) {
var a = 180-(d.startAngle + (d.endAngle - d.startAngle)/2)-45 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 75);
return d.y =(height/2)- Math.sin(a) * (oldRadius - 20);
})
.text(function(d) { return d.value; })
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width/2 - 2;
d.ox = d.x + bbox.width/2 + 2;
d.sy = d.oy = d.y + 5;
});
svg.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
svg.selectAll("g.arc")
.data(pie)
.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.attr("d", function(d,i) {
alert(d.cx);
if(d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
For this i need to use some values like cx,ox,sx from d variable.I am setting these values when i am building the chart in the first block of code.
The problem is when I am trying to retrieve these values when I am printing labels and ticks,i am getting 'undefined' values. Can anybody point out what i am doing wrong here,do i need to change something???
Thanks in advance
A fiddle would be helpful here...
I suspect that the issue is that you don't need the following two lines when appending the paths:
.data(pie)
.enter()
This is resetting the data. If you just select the arcs, svg.selectAll("g.arc"), the modified data should be available.
Here is a snippet where the values are not undefined (although using your math above, the lines are wonky).
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.arc path {
stroke: #fff;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var width = 200,
height = 200,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var data = [
{age: "<5", population: "2704659"},
{age: "5-13", population: "4499890"},
{age: "14-17", population: "2159981"},
{age: "18-24", population: "3853788"},
{age: "25-44", population: "14106543"},
{age: "45-64", population: "8819342"},
{age: "≥65", population: "612463"}];
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
var svg = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 600)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
data.forEach(function(d) {
d.population = +d.population;
});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.age); });
var oldRadius = radius / 2;
svg.selectAll("g.arc")
.append("text")
.attr("text-anchor", "middle")
.attr("x", function (d) {
var a = 180 - (d.startAngle + (d.endAngle - d.startAngle) / 2) - 45 - Math.PI / 2;
d.cx = Math.cos(a) * (radius - 75);
d.x = (width / 3) + Math.cos(a) * (oldRadius - 20);
return d.x;
})
.attr("y", function (d) {
var a = 180 - (d.startAngle + (d.endAngle - d.startAngle) / 2) - 45 - Math.PI / 2;
d.cy = Math.sin(a) * (radius - 75);
d.y = (height / 2) - Math.sin(a) * (oldRadius - 20);
return d.y;
})
.text(function (d) {
return d.data.population;
})
.each(function (d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width / 2 - 2;
d.ox = d.x + bbox.width / 2 + 2;
d.sy = d.oy = d.y + 5;
});
svg.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
svg.selectAll("g.arc")
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.attr("d", function (d, i) {
if (d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
</script>
</body>
</html>
I want to place rectangles inside partition layout with transform of arc position.
just like below image
JSfiddle
D3.js:
svg.selectAll("rect")
.data(node)
.enter()
.append("rect")
.attr("x", function (d) {return d.x;})
.attr("y", function (d) { return d.x + d.dx - 0.01 / (d.depth + 2.6); })
.attr("width", 20)
.attr("height", 100)
.attr("transform", function(d) { return "translate("+arc.centroid(d)+")rotate(" + ((2*Math.PI)+2.6*(d.x + d.dx))+ ")"});
In rect transform ,rotate need to rotate(" + ((d.x + (d.dx / 2)) - Math.PI ) / Math.PI * 180 + ")" instead of rotate(" + ((d.x + (d.dx / 2)) - Math.PI/2 ) / Math.PI * 180 + ")"
FIDDLE
svg.selectAll("rect")
.data(node)
.enter()
.append("rect")
.attr("x", function (d) {return d.x;})
.attr("y", function (d) { return d.x + d.dx - 0.01 / (d.depth + 2.6); })
.attr("width", 20)
.attr("height", 100)
.attr("transform", function(d) { return "translate("+arc.centroid(d)+")rotate(" + ((d.x + (d.dx / 2)) - Math.PI ) / Math.PI * 180 + ")"});
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; });