I am trying to display labels on my simple D3.js pie chart with the following code:
HTML:
<div id="chart"></div>
JS:
(function(d3) {
var last_login_today = <?php echo json_encode($last_login_today_count); ?>;
var last_login_before_today = <?php echo json_encode($did_not_login_today_count); ?>;
'use strict';
var dataset = [
{ label: 'Logged in Today', count: last_login_today },
{ label: 'Logged in Before Today', count: last_login_before_today }
];
var width = 360;
var height = 360;
var radius = Math.min(width, height) / 2;
var color = d3.scale.category20b();
var svg = d3.select('#chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var arc = d3.svg.arc()
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function(d) { return d.count; })
.sort(null);
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.label);
});
})(window.d3);
The chart itself is populating correctly but the labels "Logged in Today" and "Logged in Before Today" are not displaying.
I'll start with this, labels on pies are a pain when doing them dynamically due to unknown string lengths.
I use this to find the angle point, so I can put it left/right
function midAngle(d) {
return d.startAngle + ((d.endAngle - d.startAngle) / 2);
}
And you'll need this
var labels = svg.append("g")
.attr("class", "labels")
.selectAll("text")
.data(pie(dataset))
.enter()
.append("text")
.attr("transform", function (d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
var d2 = interpolate(0);
var pos = arc.centroid(d2);
pos[0] = radius * (midAngle(d2) < Math.PI ? 1.2 : -1.2));
return "translate(" + pos + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function (d) {
return d.data.Label;
});
Related
I am working on a d3 applicaton - with a pie chart -- I would like to get animation onload and on a call to action. Like when the chart becomes visible during a scroll.
Where the pie segments grow around the central pivot. So tween or snap to the other segment like a relay race
http://jsfiddle.net/pg886/192/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<div class="piechart" data-role="piechart" data-width=400 data-height=400 data-radius=30 data-innerradius=20
data-data=x>
</div>
<style>
.piechart{
/*border: 1px solid black;*/
/*text-align: center;
font-size: 12px;*/
}
</style>
<script>
$( document ).ready(function() {
console.log("test")
var $this = $('.piechart');
var data = [{
"label": "Apples",
"value": 100
},
{
"label": "Pears",
"value": 120
},
{
"label": "Bananas",
"value": 20
}];
var w = $this.data("width");
var h = $this.data("height");
var ir = $this.data("innerradius");
var r = $this.data("radius");
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
//var colores_g = ["#47abd5", "#005a70", "#f5a0a3", "#ff7276", "#a9a19c", "#d0743c", "#ff8c00"];
return colores_g[n % colores_g.length];
}
var radius = Math.min(w, h) / 4;
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var labelArc = d3.svg.arc()
.outerRadius(radius - r)
.innerRadius(radius - ir);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.value; });
var chart = d3.select('.piechart').append("svg")
.attr("class", "chart")
.attr("width", w)
.attr("height", h)
.attr("transform", "translate(0,0)");
var piechart = chart
.append("g")
.attr("class", "piechart")
.attr("width", (radius*2))
.attr("transform", "translate(0,"+h/4+")");
var path_group = piechart.append("g")
.attr("class", "path_group")
.attr("transform", "translate(90," + ((h / 4) - 20) + ")");
var padding = 45;
var legendPaddingTop = 30;
var legend = chart.append("g")
.attr("class", "legend")
.attr("width", w/2)
.attr("height", h)
.attr("transform", "translate(" + (w - 50) + "," + (h / 4) + ")");
var label_group = legend.append("svg:g")
.attr("class", "label_group")
.attr("transform", "translate(" + (-(w / 3) + 20) + "," + 0 + ")");
var legend_group = legend.append("svg:g")
.attr("class", "legend_group")
.attr("transform", "translate(" + (-(w / 3) - 100) + "," + 0 + ")");
var g = path_group.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d, i) {
return colores_google(i);
});
var legendHeight = legendPaddingTop;
var ySpace = 18;
//draw labels
var labels = label_group.selectAll("text.labels")
.data(data);
labels.enter().append("svg:text")
.attr("class", "labels")
.attr("dy", function(d, i) {
legendHeight+=ySpace;
return (ySpace * i) + 4;
})
.attr("text-anchor", function(d) {
return "start";
})
.text(function(d) {
return d.label;
});
labels.exit().remove();
//draw labels
//draw legend
var legend = legend_group.selectAll("circle").data(data);
legend.enter().append("svg:circle")
.attr("cx", 100)
.attr("cy", function(d, i) {
return ySpace * i;
})
.attr("r", 7)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {
return colores_google(i);
});
legend.exit().remove();
//draw legend
//reset legend height
//console.log("optimum height for legend", legendHeight);
$this.find('.legend').attr("height", legendHeight);
function type(d) {
d.value = +d.value;
return d;
}
});
</script>
So you can achieve this pretty easily, and there are a couple of blocks that will help you.
Arc Tween Firstly this block gives you an example of how to tween an arc. Basically you can't get that automatically so you have to write your own attrTween function. Fortunately this is pretty simple and Mike Bostock gives a really good example in there.
Here's a code sample - but the link gives a really good verbose description of what's going on.
.attrTween("d", function(d) {
var interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
d.endAngle = interpolate(t);
return arc(d);
};
}
Next you want something like this Donut with transitions. This is actually the end-result for where you're trying to get to. This effect is really easy to achieve, all you need to do is set your angles correctly and the timings.
Angles: So here you want both the endAngle and the startAngle to be the same at the start (which should be the endAngle value of the previous segment or 0 for the first segment).
Timing: You want to allow 1 animation to complete before you start the next, simply by delaying them. You can see how that's done with this snippet:
.transition()
.delay(function(d,i) { return i * 500; })
.duration(500)
.attrTween(...)
const dataset = [
{ 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 },
];
const TIME = 2000 / dataset.length;
const color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
const pie = d3.pie()
.sort(null)
.value(function(d) { return d.population; });
const path = d3.arc()
.innerRadius(0)
.outerRadius(350);
d3.select("#container")
.selectAll(".arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.append("path")
.attr("fill", function(d) { return color(d.data.age); })
.transition()
.duration(TIME)
.ease(d3.easeLinear)
.delay(function(d, i) { return i * TIME; })
.attrTween("d", function(d) {
// Note the 0.1 to prevent errors generating the path
const angleInterpolation = d3.interpolate(d.startAngle + 0.1, d.endAngle);
return function(t) {
d.endAngle = angleInterpolation(t);
return path(d);
}
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="800" height="800">
<g id="container" transform="translate(400, 400)"></g>
</svg>
I have js code that plots a simple polar chart in the HTML page. I am trying to have it update the data on the plot every 1 second.
I was able to update the data and plot the new points, however, there are two things I have not figured out yet.
Right now every second I am cleaning the plot area and plotting everything new, instead I would like to update the data by creating a smooth sliding transition from the previous position to the new one.
The second issue is that the labeling of the points is not being deleted with the old point position, which creates multiple labeling on top of each other.
What should I add in order to create this smooth transition for the plotted points and their labels?
Here is my code snippet:
<html>
<head>
<meta charset='ISO-8859-1'>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body style='background-color:lightgray'>
<div id="chart" style='width: 400px; height: 400px; padding-left: 5px; padding-bottom: 5px;'></div>
<script>
var color = d3.scale.category20();
var deg2rad = Math.PI / 180;
var width = 400,
height = 350,
radius = Math.min(width, height) / 2 - 30;
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var r = d3.scale.linear()
.domain([90, 0])
.range([0, radius]);
var line = d3.svg.line.radial()
.radius(function(d) {
return r(d[1]);
})
.angle(function(d) {
return -d[0] + Math.PI / 2;
});
var gr = null;
createSkyplot();
updateSkyPlot();
function createSkyplot() {
//////////////////////
gr = svg.append("g")
.attr("class", "r axis")
.selectAll("g")
.data(r.ticks(5))
.enter().append("g");
gr.append("circle").attr("r", r).style('fill', 'white');
gr.append("text")
.attr("y", function(d) {
return -r(d) - 4;
})
.attr("transform", "rotate(20)")
.style("text-anchor", "middle")
.style('fill', 'blue')
.text(function(d) {
return d;
});
/////////////////////
/////////////////////
var ga = svg.append("g")
.attr("class", "a axis")
.selectAll("g")
.data(d3.range(0, 360, 45))
.enter().append("g")
.attr("transform", function(d) {
return "rotate(" + (d - 90) + ")";
});
ga.append("line").attr("x2", radius).style('stroke', 'black').style('stroke-dasharray', '1,8');
ga.append("text")
.attr("x", radius + 6)
.attr("dy", ".35em")
.style("text-anchor", function(d) {
return d < 360 && d > 90 ? "end" : null;
})
.attr("transform", function(d) {
return d < 360 && d > 90 ? "rotate(180 " + (radius + 3) + ",0)" : null;
})
.text(function(d) {
return d + "°";
});
/////////////////////
}
function updateSkyPlot() {
var pos = [{
"position": [1, Math.random() * 20, Math.random() * 20],
"label": 1
}, {
"position": [3, Math.random() * 20, Math.random() * 20],
"label": 5
}];
var r = d3.scale.linear()
.domain([90, 0])
.range([0, radius]);
var line = d3.svg.line.radial()
.radius(function(d) {
return r(d[1]);
})
.angle(function(d) {
return -d[0] + Math.PI / 2;
});
svg.selectAll('circle').remove();
gr.append("circle").attr("r", r).style('fill', 'white');
var points = svg.selectAll("point")
.data(pos)
.enter()
.append("a") // The container
.attr("transform", function(d) {
var coors = line([d.position]).slice(1).slice(0, -1);
return "translate(" + coors + ")"
});
points.append("circle")
.attr("class", "point")
.attr("r", 10)
.attr("fill", function(d, i) {
return color(i);
});
points.append("text")
.attr("class", "label")
.text(function(d) {
return d.label
})
.style("font-size", "10")
.attr("transform", "translate(-4,5)");
setTimeout(updateSkyPlot, 1000);
}
</script>
</body>
</html>
Code can also be seen here.
I have tried adding
svg.selectAll("label").remove(); or svg.selectAll('point.label').remove();
but it does not work and when i add svg.selectAll("text").remove(); it removes all the text in the plot which is obviously something i don't want.
Any help on fixing those issues would be appreciated. Thank you.
I'm trying to make a pie chart that is updated when I press the button "2016" but instead of updating I create a new pie chart, how can I change the values of my pie chart? Thanks in advance. I tried to search a question but all of them are so specific.
var dataset = [{
key: "Alumnos",
value: 15
}, {
key: "AlumnosFCT",
value: 12
}];
var w = 300;
var h = 300;
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var color = d3.scale.ordinal()
.domain([15, 12])
.range(["#FF4081", "#3F51B5"]);
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
});
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + ", " + outerRadius + ")");
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.text(function(d) {
return d.value;
});
d3.selectAll("button").on("click", function() {
var paragraphID = d3.select(this).attr("id");
if (paragraphID == "2016") {
dataset.push({
key: "Alumnos",
value: 20
}, {
key: "AlumnosFCT",
value: 18
});
dataset.shift();
dataset.shift();
}
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var color = d3.scale.ordinal()
.domain([15, 12])
.range(["#FF4081", "#3F51B5"]);
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
});
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + ", " + outerRadius + ")");
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.text(function(d) {
return d.value;
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<button id="2016">2016</button>
In general, d3 is pretty good about managing DOM elements as long as you work within their API. In that way you can write a function that can create new elements for new data, or update existing elements with new data pertaining to those elements.
See the following updated version of your code snippet, specifically pulling out the data dependent DOM manipulations into a function called update:
/***
* Original Code
***/
var dataset = [{
key: "Alumnos",
value: 15
}, {
key: "AlumnosFCT",
value: 12
}];
var w = 300;
var h = 300;
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var color = d3.scale.ordinal()
.domain([15, 12])
.range(["#FF4081", "#3F51B5"]);
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
});
/***
* update function for data dependent manipulations
***/
function update(data) {
var arcs = svg.selectAll("g.arc").data(pie(data));
arcs.exit().remove();
arcs.enter().append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + ", " + outerRadius + ")");
var paths = arcs.selectAll('path').data(function (d, i) {
d.idx = i;
return [d];
})
paths.enter().append('path');
paths
.attr("fill", function(d) {
return color(d.idx);
})
.attr("d", arc);
var texts = arcs.selectAll('text').data(function (d) {
return [d];
})
texts.enter().append('text');
texts.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.text(function(d) {
return d.value;
});
}
update(dataset);
/***
* Handler to set new data based on button clicked
***/
d3.select('button').on('click', function() {
var newData;
if (this.id === '2016') {
newData = [{
key: "Alumnos",
value: 20
}, {
key: "AlumnosFCT",
value: 18
}];
update(newData);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<button id="2016">2016</button>
(depending on your browser, you might need to scroll the view to see the "2016" button)
Note the following advantages:
only elements whose data need to change are updated when update is called.
if you add a new data point when updating, a new element will be added without touching elements that should remain unchanged (via enter)
if you remove a data point when updating, that element will be removed (via exit)
d3 version: 3.4.11
Hi there I currently have a template helper that returns me an array with various values used to generate different rows in a table in my HTML.
<template name="stop">
{{#each thumb}}
<tr>
<td>
<h2> Do you like this product? </h2>
<h2>{{text}}</h2>
<svg id="donutChart"> </svg>
</td>
</tr>
{{/each}}
</template>
It also contains a svg tag which I also want to generate a graph for each element generated as a table row and this is what the template helper looks like.
Template.stop.helpers({
'thumb': function(data) {
var result = tweetImages.findOne();
var newResult = [];
for (var i = 0; i < result.data.length; i++) {
newResult[i] = {
data: result.data[i],
text: result.text[i]
};
}
console.log(newResult)
return newResult;
}
I'm trying to create a pie reactive pie chart for each element in the table however I don't seem to be able to access the svg in the stop template.
The d3 code works fine outside that table but cant seem to be generated for each element of the table because it can't access the svg element.
Template.donutChart.rendered = function() {
//my d3 code is here
//Width and height
var w = 300;
var h = 300;
var center = w / 2;
var outerRadius = w / 2;
var innerRadius = 0;
var radius = 150;
var arc = d3.svg.arc()
.innerRadius(40)
.outerRadius(radius + 10 - 25);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.data;
});
//Create SVG element
var svg = d3.select("#donutChart")
.attr("width", w)
.attr("height", h)
.attr("transform", "translate(" + 200 + "," + 100 + ")");
// GROUP FOR CENTER TEXT
var center_group = svg.append("svg:g")
.attr("class", "ctrGroup")
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
// CENTER LABEL
var pieLabel = center_group.append("svg:text")
.attr("dy", ".35em").attr("class", "chartLabel")
.attr("text-anchor", "middle")
.text("Clothes")
.attr("fill", "white");
Deps.autorun(function() {
var modifier = {
fields: {
value: 1
}
};
Deps.autorun(function() {
var arcs = svg.selectAll("g.arc")
.data(pie(players))
var arcOutter = d3.svg.arc()
.innerRadius(outerRadius - 10)
.outerRadius(outerRadius);
var arcPhantom = d3.svg.arc()
.innerRadius(-180)
.outerRadius(outerRadius + 180);
var newGroups =
arcs
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + 150 + "," + 150 + ")")
//Set up outter arc groups
var outterArcs = svg.selectAll("g.outter-arc")
.data(pie(players))
.enter()
.append("g")
.attr("class", "outter-arc")
.attr("transform", "translate(" + 150 + ", " + 150 + ")");
//Set up phantom arc groups
var phantomArcs = svg.selectAll("g.phantom-arc")
.data(pie(players))
.enter()
.append("g")
.attr("class", "phantom-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
outterArcs.append("path")
.attr("fill", function(d, i) {
return slickColor[i];
})
.attr("fill-opacity", 0.85)
.attr("d", arcOutter).style('stroke', '#0ca7d2')
.style('stroke-width', 2)
//Draw phantom arc paths
phantomArcs.append("path")
.attr("fill", 'white')
.attr("fill-opacity", 0.1)
.attr("d", arcPhantom).style('stroke', '#0ca7d2')
.style('stroke-width', 5);
//Draw arc paths
newGroups
.append("path")
.attr("fill", function(d, i) {
return slickColor[i];
})
.attr("d", arc);
//Labels
newGroups
.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
})
.style("font-size", function(d) {
return 24;
})
svg.selectAll("g.phantom-arc")
.transition()
.select('path')
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
arcs
.transition()
.select('path')
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
arcs
.transition()
.select('text')
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.text(function(d) {
return d.value;
})
.attr("fill", function(d, i) {
return textColor[i];
})
arcs
.exit()
.remove();
});
});
}
}
I can't seem to find much information on using d3.js or SVG's within a templates #each wrapper. Any help would be truly appreciated.
I would suggest wrapping your d3 code in a Deps.autorun() function as what's most likely happening is your data isn't available yet when your pie is bound to the data function and thus doesn't render anything.
Template.donutChart.rendered = function() {
Tracker.autorun(function () {
//all d3 code
});
}
You look like you're using autoruns further down but not for the bit that gets your data.
I have a problem. Look at the picture below.
The data for my pie is:
var data = [{statusid:"Paid", price:10},
{statusid:"Not accepted", price:20},
{statusid:"Canceled", price:20},
{statusid:"Waiting", price:1},
{statusid:"Refunded", price:1},
{statusid:"Pending", price:1}];
Is it possible to solve this problem by sorting input data? How?
Thanks!
P.S: D3.js code below:
var data = [{statusid:"Paid", price:10}, {statusid:"Not accepted", price:20}, {statusid:"Canceled", price:20}, {statusid:"Waiting", price:1}, {statusid:"Refunded", price:1}, {statusid:"Pending", price:1}];
var sumprice = 0;
for (var i in data) {
sumprice += data[i].price;
}
/* ==============================================================
Setting up the chart
============================================================== */
var width = 600,
height = 500,
radius = Math.min(width, height) / 4;
var color = d3.scale.ordinal()
.range(["#227fbc", "#64a620", "#7b6888", "#a15c57", "#961819", "#d8d13a", "#d3723b"]);
var arc = d3.svg.arc()
.outerRadius(radius * 0.8)
.innerRadius(radius * 0.4);
var outerArc = d3.svg.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.price; });
/* ==============================================================
Creating the svg element
============================================================== */
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.append("g")
.attr("class", "lines");
svg.append("g")
.attr("class", "labels");
/* ==============================================================
Drawning the pizza
============================================================== */
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.statusid);
});
/* ==============================================================
Drawning the labels
============================================================== */
var key = function(d){ return d.data.statusid; };
var text = svg.select(".labels").selectAll("text")
.data(pie(data), key);
text.enter()
.append("text")
.attr("dy", ".35em")
.text(function(d) {
return d.data.statusid;
});
function midAngle(d){
return d.startAngle + (d.endAngle - d.startAngle)/2;
}
text.transition().duration(1000)
.attrTween("transform", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
var pos = outerArc.centroid(d2);
pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
return "translate("+ pos +")";
};
})
.styleTween("text-anchor", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
return midAngle(d2) < Math.PI ? "start":"end";
};
});
text.exit()
.remove();
/* ==============================================================
Drawning the inside-labels
============================================================== */
var arcs = svg.selectAll(".arc");
// Add a magnitude value to the larger arcs, translated to the arc centroid and rotated.
arcs.filter(function(d) { return d.endAngle - d.startAngle > .2; }).append("svg:text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
//.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; })
.attr("transform", function(d) { //set the label's origin to the center of the arc
//we have to make sure to set these before calling arc.centroid
d.outerRadius = arc.outerRadius; // Set Outer Coordinate
d.innerRadius = arc.outerRadius/2; // Set Inner Coordinate
console.log('omg');
return "translate(" + arc.centroid(d) + ")";
})
.style("fill", "White")
.style("font", "bold 12px Arial")
.text(function(d) { return (d.data.price*100/sumprice).toFixed(1)+'%'; });
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
/* ==============================================================
Drawning the label-lines
============================================================== */
var polyline = svg.select(".lines").selectAll("polyline")
.data(pie(data), key);
polyline.enter()
.append("polyline");
polyline.transition()
.attrTween("points", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
var pos = outerArc.centroid(d2);
pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
return [arc.centroid(d2), outerArc.centroid(d2), pos];
};
});
polyline.exit()
.remove();