The following is the pie chart I'm working on:
http://bl.ocks.org/lydiawawa/9fb92d9982f0b41b63be142ce279acf5/52e3b54ea61fc55071992d15993a5fbe21174729
It should be a very simple code to learn from, but after I updated the code to D3 v4, when I switch from Apple to Orange then Apple, there is a missing data and is causing a gap on the apple pie graph.
Something could be wrong with this part of the code, and I don't know how this only worked in D3 v3 but not in V4:
// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
// Interpolate exiting arcs start and end angles to Math.PI * 2
// so that they 'exit' at the end of the data
function arcTweenOut(a) {
var i = d3.interpolate(this._current, {startAngle: Math.PI * 2, endAngle: Math.PI * 2, value: 0});
this._current = i(0);
return function (t) {
return arc(i(t));
};
}
In D3 v4/5 the enter selection doesn't modify the update selection anymore. You have to change the update selection accordingly or merge the selections.
I re-wrote your selections in a purposefully verbose way, naming all the selections, so you can see what's happening:
var paths = svg.selectAll("path").data(pie(dataset[this.value]));
var pathsExit = paths.exit()
.transition()
.duration(750)
.attrTween('d', arcTweenOut)
.remove();
var pathsEnter = paths.enter().append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc(enterAntiClockwise))
.each(function(d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterAntiClockwise.startAngle,
endAngle: enterAntiClockwise.endAngle
};
});
paths = pathsEnter.merge(paths);
paths.transition().duration(750).attrTween("d", arcTween);
I also created a 5th colour, which is necessary (unless you want repetition).
Here is your updated code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
text {
font: 10px sans-serif;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
</style>
<form>
<label><input type="radio" name="dataset" value="apples" checked> Apples</label>
<label><input type="radio" name="dataset" value="oranges"> Oranges</label>
</form>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var dataset = {
apples: [53245, 28479, 19697, 24037, 40245],
oranges: [200, 200, 200, 200] // previously 5 values, now only 4
};
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var enterAntiClockwise = {
startAngle: Math.PI * 2,
endAngle: Math.PI * 2
};
var color = d3.scaleOrdinal()
.domain(d3.range(0, length))
.range(["#9E519F", "#ADBCCC", "#0079BB", "#6d7fcc", "teal"])
var pie = d3.pie()
.sort(null);
var arc = d3.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 20);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(dataset.apples))
.enter().append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc)
.each(function(d) {
this._current = d;
}); // store the initial values
d3.selectAll("input").on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"oranges\"]").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(timeout);
var paths = svg.selectAll("path").data(pie(dataset[this.value])); // update the data
// set the start and end angles to Math.PI * 2 so we can transition
var pathsExit = paths.exit()
.transition()
.duration(750)
.attrTween('d', arcTweenOut)
.remove() // now remove the exiting arcs
// anticlockwise to the actual values later
var pathsEnter = paths.enter().append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc(enterAntiClockwise))
.each(function(d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterAntiClockwise.startAngle,
endAngle: enterAntiClockwise.endAngle
};
});
paths = pathsEnter.merge(paths);
paths.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
// Interpolate exiting arcs start and end angles to Math.PI * 2
// so that they 'exit' at the end of the data
function arcTweenOut(a) {
var i = d3.interpolate(this._current, {
startAngle: Math.PI * 2,
endAngle: Math.PI * 2,
value: 0
});
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
</script>
Related
I have created a donut chart and I am trying to make it responsive. I want the height to have a maximum value. If the window size changes, the donut changes attributes (width and height). Now, I want to set a maximum height value and off course I need the ratio to remain the same. Note that I want the donut chart to be horizontally aligned (same margin from the right and left of the screen).
I have tried changing the values in the width by using the window.innerWidth and innerHeight with no success. I have also tried adding a max attribute for the height in the D3 part of my code.
var dataset = {
numbers: [3200, 5400, 8600]
};
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var enterClockwise = {
startAngle: 0,
endAngle: 0
};
var enterAntiClockwise = {
startAngle: Math.PI * 2,
endAngle: Math.PI * 2
};
//var color = d3.scale.category20();
var color = d3.scale.ordinal().range([d3.rgb("#c7003b"), d3.rgb('#000'), d3.rgb('#ccc'),d3.rgb('transparent')])
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 80)
.outerRadius(radius - 40);
var arcThin = d3.svg.arc()
.innerRadius(radius - 65)
.outerRadius(radius - 55);
var svg = d3.select('#Donut-chart').append('svg')
.attr('id', 'Donut-chart-render')
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox', (-width / 2) + ' ' + (-height / 2) + ' ' + width + ' ' + height)
.attr('preserveAspectRatio', 'xMinYMin').append("g").attr("class", "parent");
var angleData = pie(dataset.numbers);
angleData[1].startAngle = 0;
angleData[1].endAngle = -angleData[1].endAngle + angleData[0].endAngle;
angleData[2].startAngle = angleData[0].endAngle;
angleData[2].endAngle = (2*Math.PI) + angleData[1].endAngle;
var path = svg.selectAll("path")
.data(angleData)
.enter().append("path")
.attr("fill", function (d, i) { return color(i); })
.attr("d", function(d){
return arc(enterClockwise);
})
.each(function (d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterClockwise.startAngle,
endAngle: enterClockwise.endAngle
}
});
path.transition()
.duration(750)
.attrTween("d", arcTween);
function createChart() {
path = path.data(pie(dataset[this.value]));
path.enter().append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc(enterAntiClockwise))
.each(function (d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterAntiClockwise.startAngle,
endAngle: enterAntiClockwise.endAngle
};
});
}
function arcTween(a, j) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function (t) {
return (j === (dataset.numbers.length - 1)) ? arcThin(i(t)) : arc(i(t));
};
}
function type(d) {
d.value = +d.value;
return d;
}
#import url(https://fonts.googleapis.com/css?family=Karla);body{font-family:Karla,sans-serif;margin:auto;position:relative}.text{text-anchor:middle;color:#000;font-size:1.7em;font-weight:700;text-transform:uppercase}#legend{align-items:center;border-radius:5px;display:flex;height:0%;justify-content:space-around;width:95%;font-size:25px}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.min.js"></script>
<div id="Donut-chart"></div>
Remove width, height and preserveAspectRatio attributes from SVG element and set max-height on it via CSS. Like so:
var dataset = {
numbers: [3200, 5400, 8600]
};
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var enterClockwise = {
startAngle: 0,
endAngle: 0
};
var enterAntiClockwise = {
startAngle: Math.PI * 2,
endAngle: Math.PI * 2
};
//var color = d3.scale.category20();
var color = d3.scale.ordinal().range([d3.rgb("#c7003b"), d3.rgb('#000'), d3.rgb('#ccc'),d3.rgb('transparent')])
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 80)
.outerRadius(radius - 40);
var arcThin = d3.svg.arc()
.innerRadius(radius - 65)
.outerRadius(radius - 55);
var svg = d3.select('#Donut-chart').append('svg')
.attr('id', 'Donut-chart-render')
// .attr("width", '100%')
// .attr("height", '100%')
.attr('viewBox', (-width / 2) + ' ' + (-height / 2) + ' ' + width + ' ' + height)
//.attr('preserveAspectRatio', 'xMinYMin')
.append("g").attr("class", "parent");
var angleData = pie(dataset.numbers);
angleData[1].startAngle = 0;
angleData[1].endAngle = -angleData[1].endAngle + angleData[0].endAngle;
angleData[2].startAngle = angleData[0].endAngle;
angleData[2].endAngle = (2*Math.PI) + angleData[1].endAngle;
var path = svg.selectAll("path")
.data(angleData)
.enter().append("path")
.attr("fill", function (d, i) { return color(i); })
.attr("d", function(d){
return arc(enterClockwise);
})
.each(function (d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterClockwise.startAngle,
endAngle: enterClockwise.endAngle
}
});
path.transition()
.duration(750)
.attrTween("d", arcTween);
function createChart() {
path = path.data(pie(dataset[this.value]));
path.enter().append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc(enterAntiClockwise))
.each(function (d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterAntiClockwise.startAngle,
endAngle: enterAntiClockwise.endAngle
};
});
}
function arcTween(a, j) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function (t) {
return (j === (dataset.numbers.length - 1)) ? arcThin(i(t)) : arc(i(t));
};
}
function type(d) {
d.value = +d.value;
return d;
}
#Donut-chart svg {
max-height: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.min.js"></script>
<div id="Donut-chart"></div>
I trying to mimic an example from Mike Bostock Extending Arcs. My code is very similar to Mike's, but mines doesn't work like his.
Here below is the JavaScript code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example</title>
<script src="static/d3.min.js"></script>
</head>
<body>
<script>
var Width = 500, Height = 400, innerRadius = 45, outerRadius = 100;
var colors = d3.scale.category10();
var svg = d3.select('body')
.append('svg')
.attr({ width: Width, height: Height });
var data = [40, 32, 35, 64, 83],
pieData = d3.layout.pie()(data)
var ArcGen = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.padAngle(0.02)
.startAngle(function(d){
return d.startAngle;
})
.endAngle(function(d){
return d.endAngle;
});
var group = svg.append('g')
.attr('transform', 'translate(' + [Width / 2.0, Height / 2.0] + ')');
var segment = group.selectAll('g')
.data(pieData)
.enter()
.append('g');
segment
.append('path')
.attr('d', ArcGen)
.attr('fill', function(d,i){ return colors(i); })
.on('mouseover', arcTween(outerRadius * 1.2, 0))
.on('mouseout', arcTween(outerRadius, 150));
function arcTween(oRadius, delay){
// closure function
return function(){
d3.select(this)
.transition()
.delay(delay)
.attrTween('d', function(d){
var i = d3.interpolate(d.outerRadius, oRadius);
return function(t){
d.outerRadius = i(t);
return ArcGen(d);
}
})
};
};
</script>
</body>
</html>
This routine is simple, no error no action either.
I have two questions:
If it's necessary to chain startAngle and endAngle attributes at every arc generator? I read some pros' code, such as Mike Bostock's, don't add this two attributes at the initial stage and their codes work fine when constructing path elements.
Where am I wrong? is anybody can give me more attrTween examples.
Thanks, everyone!
Your code has 2 problems, that you can easily find comparing it with Bostock's code.
First, this line:
var i = d3.interpolate(d.outerRadius, oRadius);
Uses the property outerRadius in the element's datum. But it has none. You can fix this with:
.each(function(d) { d.outerRadius = outerRadius; })
Second, your arc generator is setting the outer radius:
var ArcGen = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.padAngle(0.02)
.startAngle(function(d) {
return d.startAngle;
})
.endAngle(function(d) {
return d.endAngle;
});
Remove it:
var ArcGen = d3.svg.arc()
.innerRadius(innerRadius)
.padAngle(0.02)
.startAngle(function(d) {
return d.startAngle;
})
.endAngle(function(d) {
return d.endAngle;
});
Here is your working code with the 2 changes:
var Width = 500,
Height = 400,
innerRadius = 45,
outerRadius = 100;
var colors = d3.scale.category10();
var svg = d3.select('body')
.append('svg')
.attr({
width: Width,
height: Height
});
var data = [40, 32, 35, 64, 83],
pieData = d3.layout.pie()(data)
var ArcGen = d3.svg.arc()
.padAngle(0.02)
.innerRadius(innerRadius)
.startAngle(function(d) {
return d.startAngle;
})
.endAngle(function(d) {
return d.endAngle;
});
var group = svg.append('g')
.attr('transform', 'translate(' + [Width / 2.0, Height / 2.0] + ')');
var segment = group.selectAll('g')
.data(pieData)
.enter()
.append('g');
segment
.append('path')
.each(function(d) {
d.outerRadius = outerRadius;
})
.attr('d', ArcGen)
.attr('fill', function(d, i) {
return colors(i);
})
.on('mouseover', arcTween(outerRadius * 1.2, 0))
.on('mouseout', arcTween(outerRadius, 150));
function arcTween(oRadius, delay) {
// closure function
return function() {
d3.select(this)
.transition()
.delay(delay)
.attrTween('d', function(d) {
var i = d3.interpolate(d.outerRadius, oRadius);
return function(t) {
d.outerRadius = i(t);
return ArcGen(d);
}
})
};
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
I am quitte a newbie to D3.js and for a project i need to make a donutchart with data that changes every 2 seconds. But every time I try to change the data i get an error:
Uncaught TypeError: path.data is not a function
I used this code as an example for the change function
Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3 donuttest</title>
<script src="//d3js.org/d3.v3.min.jss"></script>
<style>
body {
font: 10px sans-serif;
}
</style>
</head>
<body>
</body>
<div id="chartwrapper">
</div>
</body>
<script>
var wrapper="#chartwrapper";
var dummydata=70;
var data=[dummydata,100-dummydata];
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select(wrapper).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(data))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.transition()
.ease("bounce")
.duration(1000)
.attrTween("d", initTween);
var label=svg.append("g")
.attr("class", "display")
.attr("transform", "translate(-30,10)");
var labeltext=label.append("text")
.attr("font-size","2rem")
.text(dummydata + "%");
function change(data){
labeltext.text(data[0] + "%");
path.data(pie(data));
path.transition().duration(750).attrTween("d",arcTween);
};
//animation tween for when graph is drawn
function initTween(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
//animation for when data is changed
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
};
//simulating data changes
setInterval(function() {
dummydata = parseInt(Math.random() * 100);
data=[dummydata,100-dummydata];
console.log(data)
change(data);
},2000);
</script>
Here's a slight modification of your code that might help you. I used this answer as a guide.
The modifications include:
only store the result of append() in the path variable;
when first drawing the chart, store the initial angles in _current instead of using the initTween function.
var wrapper = "#chartwrapper";
var dummydata = 70;
var data = [dummydata, 100 - dummydata];
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var arc = d3.svg.arc()
.outerRadius(radius - 100)
.innerRadius(radius - 50);
var pie = d3.layout.pie()
.sort(null);
var svg = d3.select(wrapper).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(data))
.enter()
.append("path");
path.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc)
.transition()
.ease("bounce")
.duration(1000)
.each(function(d) {
this._current = d;
}); // store the initial angles
var label = svg.append("g")
.attr("class", "display")
.attr("transform", "translate(-30,10)");
var labeltext = label.append("text")
.attr("font-size", "2rem")
.text(dummydata + "%");
function change(data) {
labeltext.text(data[0] + "%");
path.data(pie(data));
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
setInterval(function() {
dummydata = parseInt(Math.random() * 100);
data = [dummydata, 100 - dummydata];
console.log(data)
change(data);
}, 2000);
body {
font: 10px sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chartwrapper"></div>
How would I apply an animated transition when sorting a pie chart? I don't mean updating values, I mean sorting each arc of the pie to move into place the way bars do here.
There are plenty of transition examples for updating using new values of an existing data set (or switching data sets). I can't find anything on how to re-sort (using the same values, same data set).
I'm using this for now which simply redraws the arc by applying the same tween used when initializing the rendering, but it starts each arc from zero.
.attr('d', arc)
.transition()
.duration(1000)
.attrTween("d", tweenPie);
function tweenPie(b) {
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
};
Would I need to store the existing start and end angles somehow and run the tween from those?
I see something kind of like that here, though this example is updating values, not sorting.
Thanks.
Building on the Bostock example here.
setInterval(change, 2000);
var sort = false;
function change() {
sort = !sort;
if (sort){
pie = d3.layout.pie() //<-- pie with default sort
.value(function(d) {
return d.value;
});
} else {
pie = d3.layout.pie() //<-- pie with no sort
.value(function(d) {
return d.value;
})
.sort(null);
}
path = path.data(pie); // compute the new angles
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
Full code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 400px;
}
text {
font: 10px sans-serif;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<body>
<script>
var width = 400,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.value(function(d) {
return d.value;
})
.sort(null);
var defaultSort = pie.sort;
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 20);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var data = [{
value: 1
}, {
value: 5
}, {
value: 2
}, {
value: 6
}
];
var path = svg.datum(data).selectAll("path")
.data(pie)
.enter().append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc)
.each(function(d) {
this._current = d;
}); // store the initial angles
setInterval(change, 2000);
var sort = false;
function change() {
sort = !sort;
if (sort){
pie = d3.layout.pie()
.value(function(d) {
return d.value;
});
} else {
pie = d3.layout.pie()
.value(function(d) {
return d.value;
})
.sort(null);
}
path = path.data(pie); // compute the new angles
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
</script>
</body>
I work for the first time with the D3 library and basically also with javascript and i rly need some help.
I want to create this beautiful pie chart in a while loop when the mysql-query is true. It works. It makes three pie charts and the associated forms with the radio inputs. But after that, only the last pie chart works when I want to switch the radio buttons value. The other two pie charts dont switch their value when I activate the unselected radio button.
What should i do?
<?php
$gem_stud_data = $db->prepare("SELECT * FROM ergebnisse WHERE studiengang_1 <> 0 AND studiengang_2 <> 0 AND semester_id=1");
$gem_stud_data->execute();
if($_GET["id"] == 1){
while($gem_stud_datas = $gem_stud_data->fetch()){
$stud1_data = $db->prepare("SELECT * FROM studiengaenge WHERE id=:eins");
$stud1_data->bindParam(":eins", $gem_stud_datas["studiengang_1"]);
$stud1_data->execute();
$stud1_datas = $stud1_data->fetch();
$stud2_data = $db->prepare("SELECT * FROM studiengaenge WHERE id=:eins");
$stud2_data->bindParam(":eins", $gem_stud_datas["studiengang_2"]);
$stud2_data->execute();
$stud2_datas = $stud2_data->fetch();
?>
<form>
<label><input type="radio" name="dataset" value="stud_1" checked> <?php echo $stud1_datas["kuerzel"]; ?></label>
<label><input type="radio" name="dataset" value="stud_2"> <?php echo $stud2_datas["kuerzel"]; ?></label>
</form>
<script>
var dataset = {
stud_1: [53245, 28479, 19697, 24037, 40245],
stud_2: [200, 200, 200, 200]
};
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var enterClockwise = {
startAngle: 0,
endAngle: 0
};
var enterAntiClockwise = {
startAngle: Math.PI * 2,
endAngle: Math.PI * 2
};
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 20);
var svg = d3.select("main").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// set the start and end angles to 0 so we can transition
// clockwise to the actual values later
var path = svg.selectAll("path")
.data(pie(dataset.stud_1))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc(enterClockwise))
.each(function(d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterClockwise.startAngle,
endAngle: enterClockwise.endAngle
}
}); // store the initial values
path.transition() // update
.duration(750)
.attrTween("d", arcTween);
d3.selectAll("input").on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"stud_2\"]").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(timeout);
path = path.data(pie(dataset[this.value])); // update the data
// set the start and end angles to Math.PI * 2 so we can transition
// anticlockwise to the actual values later
path.enter().append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc(enterAntiClockwise))
.each(function (d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterAntiClockwise.startAngle,
endAngle: enterAntiClockwise.endAngle
};
}); // store the initial values
path.exit()
.transition()
.duration(750)
.attrTween('d', arcTweenOut)
.remove() // now remove the exiting arcs
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
function arcTweenOut(a) {
var i = d3.interpolate(this._current, {startAngle: Math.PI * 2, endAngle: Math.PI * 2, value: 0});
this._current = i(0);
return function (t) {
return arc(i(t));
};
}
</script>
<?php
}
} ?>
I really hope you can help me! I am very frustrated :(
I thank you in advance!
Please see below, this works for me and changes the data on the timeout you created.
<form>
<label><input type="radio" name="dataset" value="stud_1" checked> Option 1 </label>
<label><input type="radio" name="dataset" value="stud_2"> Option 2 </label>
</form>
<script>
var dataset = {
stud_1: [53245, 28479, 19697, 24037, 40245],
stud_2: [200, 200, 200, 200]
};
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var enterClockwise = {
startAngle: 0,
endAngle: 0
};
var enterAntiClockwise = {
startAngle: Math.PI * 2,
endAngle: Math.PI * 2
};
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 20);
var svg = d3.select("#main").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// set the start and end angles to 0 so we can transition
// clockwise to the actual values later
var path = svg.selectAll("path")
.data(pie(dataset.stud_1))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc(enterClockwise))
.each(function(d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterClockwise.startAngle,
endAngle: enterClockwise.endAngle
}
}); // store the initial values
path.transition() // update
.duration(750)
.attrTween("d", arcTween);
d3.selectAll("input").on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"stud_2\"]").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(timeout);
path = path.data(pie(dataset[this.value])); // update the data
// set the start and end angles to Math.PI * 2 so we can transition
// anticlockwise to the actual values later
path.enter().append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc(enterAntiClockwise))
.each(function (d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterAntiClockwise.startAngle,
endAngle: enterAntiClockwise.endAngle
};
}); // store the initial values
path.exit()
.transition()
.duration(750)
.attrTween('d', arcTweenOut)
.remove() // now remove the exiting arcs
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
function arcTweenOut(a) {
var i = d3.interpolate(this._current, {startAngle: Math.PI * 2, endAngle: Math.PI * 2, value: 0});
this._current = i(0);
return function (t) {
return arc(i(t));
};
}
</script>
See revised solution ... there you must grab all svgs and then select the paths and then append data ... see change in the change function.
<form>
<label><input type="radio" name="dataset" value="stud_1" checked> Option 1 </label>
<label><input type="radio" name="dataset" value="stud_2"> Option 2 </label>
</form>
<script>
var dataset = {
stud_1: [53245, 28479, 19697, 24037, 40245],
stud_2: [200, 200, 200, 200]
};
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var enterClockwise = {
startAngle: 0,
endAngle: 0
};
var enterAntiClockwise = {
startAngle: Math.PI * 2,
endAngle: Math.PI * 2
};
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 20);
var svg = d3.select("#main").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 3 + "," + height / 3 + ")");
var svg2 = d3.select("#main2").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + (width / 3 * 2) + "," + (height / 3 * 2) + ")");
var svg3 = d3.select("#main3").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + (width / 3 * 2) + "," + (height / 3 * 2)+ ")");
// set the start and end angles to 0 so we can transition
// clockwise to the actual values later
var path = d3.selectAll('svg').selectAll("path")
.data(pie(dataset.stud_1))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc(enterClockwise))
.each(function(d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterClockwise.startAngle,
endAngle: enterClockwise.endAngle
}
}); // store the initial values
path.transition() // update
.duration(750)
.attrTween("d", arcTween);
d3.selectAll("input").on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"stud_2\"]").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(timeout);
path = d3.selectAll('svg').selectAll('path').data(pie(dataset[this.value])); // update the data
// set the start and end angles to Math.PI * 2 so we can transition
// anticlockwise to the actual values later
path.enter().append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", arc(enterAntiClockwise))
.each(function (d) {
this._current = {
data: d.data,
value: d.value,
startAngle: enterAntiClockwise.startAngle,
endAngle: enterAntiClockwise.endAngle
};
}); // store the initial values
path.exit()
.transition()
.duration(750)
.attrTween('d', arcTweenOut)
.remove() // now remove the exiting arcs
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
function arcTweenOut(a) {
var i = d3.interpolate(this._current, {startAngle: Math.PI * 2, endAngle: Math.PI * 2, value: 0});
this._current = i(0);
return function (t) {
return arc(i(t));
};
}
</script>