Reputation: 8705
I have an input control that should on the key up event on the control either add or subtract a slice from a pie chart depending on if you hit the left or right arrow keys. It doesn't really work as expected because it seems that the new pie slice is sometimes being taken out of existing pie slices and the entire chart is not being recalculated. I'm not sure if I'm messing up the enter
or the exit
selection. Help is appreciated, TIA.
fiddle http://jsfiddle.net/jaqj3usb/
pertinent code
function removeSlices(n){
var i = -1;
while(++i < n){
data.pop();
}
paths.data(pie(data)).exit().remove();
paths.data(pie(data)).attr('d',arc).attr('transform','translate(100,200)')
}
function changeSlices(){
console.log('woot');
var shouldAddSlice = d3.event.target.valueAsNumber > data.length,
numDifference = Math.abs(data.length - d3.event.target.valueAsNumber);
if(shouldAddSlice){
addSlices(numDifference);
}
else{
removeSlices(numDifference);
}
}
sliceSlider.on('keyup',changeSlices);
Upvotes: 0
Views: 1692
Reputation: 334
In the same way that you use this code:
svg.selectAll('path').append('g')
.data(pie(data))
.enter()
.append('path')
You can use:
svg.selectAll('path').append('g')
.data(pie(data))
.exit()
.remove()
This should remove pie graph elements which no longer have data associated with them.
Upvotes: 0
Reputation: 3085
I am also new to D3js, trying to learn. I used jQuery for handling keyup events. I did some changes, so left arrow adds and right arrow subtracts slices.
passed jquery as in argument to self executing function
(function(d3, $) {
})(window.d3, $);
In addSlices() changed
paths
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i]
});
to
paths.data(pie([])).exit().remove();
paths = svg.selectAll('path').append('g')
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i];
});
above code deletes and redraws the pie.
full code:
(function(d3,$){
var svg = d3.select('body').append('svg').attr({
height: 500,
width: 500,
id: 'mySvg'
});
var data = [10,20,30];
var sliceSlider = d3.select('body').append('input').attr({
type: 'range',
max: 10,
min: 1,
value : data.length
});
var colors=['orange','blue','steelblue','green','red','yellow','purple','pink','indigo'];
var pie = d3.layout.pie();
pie.value(function(d){ return d});
var arc = d3.svg.arc().innerRadius(10).outerRadius(100);
var paths = svg.selectAll('path').append('g')
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i]
});
function addSlices(n){
var i = -1;
function randomBetween(min,max){
return Math.floor(Math.random()*(max-min+1)+min);
}
while(++i <n){
data.push(randomBetween(10,50));
}
paths.data(pie([])).exit().remove();
paths = svg.selectAll('path').append('g')
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i];
});
}
function removeSlices(n){
var i = -1;
while(++i < n){
data.pop();
}
paths.data(pie(data)).exit().remove();
paths.data(pie(data)).attr('d',arc).attr('transform','translate(100,200)');
}
function changeSlices(){
console.log('woot');
var max=$("input[type='range']").attr("max")-data.length;
var shouldAddSlice = max > data.length;
if(shouldAddSlice){
addSlices(1);
}
}
$(document).keyup(function(e) {
switch(e.which) {
case 37: // left
changeSlices();
break;
case 39: // right
removeSlices(1);
break;
default: return; // exit this handler for other keys
}
e.preventDefault(); // prevent the default action (scroll / move caret)
});
})(window.d3,$);
example : http://jsfiddle.net/jaqj3usb/2/
Upvotes: 1
Reputation: 4922
Here is first variant (I think this is correct), base on this please add comments because you are not computing correctly from the start svg's added to the page.
You can remove individual pie slice like this but this will is not update correct your plate:
svg.selectAll('path')[0][pos].remove();
where pos 0 < data.length (in your original code not correct)
Adding in this way you are overlapping unmoved slices:
paths
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i]
});
Anyhow:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Eat my pie</title>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>
<script type='text/javascript'>
window.onload=function(){
/**
* Created by cecild on 5/21/2015.
* Updated by SilentTremor 5/25/2015.
*/
(function(d3){
svg = d3.select('body').append('svg').attr({
height: 800,
width: 900,
id: 'mySvg'
});
var data = [10];
var sliceSlider = d3.select('body').append('input').attr({
type: 'range',
max: 10,
min: 1,
value : data.length
});
var colors=['orange','blue','steelblue','green','red','yellow','purple','pink','indigo'];
var pie = d3.layout.pie();
pie.value(function(d){ return d});
var arc = d3.svg.arc().innerRadius(10).outerRadius(100);
var paths = svg.selectAll('path').append('g')
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i]
});
function addSlices(n){
var i = -1;
function randomBetween(min,max){
return Math.floor(Math.random()*(max-min+1)+min);
}
while(++i <n){
data.push(randomBetween(10,50));
}
svg.selectAll("path").remove();
paths = svg.selectAll('path').append('g')
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i]
});
}
function removeSlices(n){
var i = -1;
while(++i < n){
data.pop();
}
svg.selectAll("path").remove()
paths = svg.selectAll('path').append('g')
.data(pie(data))
.enter()
.append('path')
.attr('d',arc)
.attr('transform','translate(100,200)')
.attr('fill',function(d,i){
return colors[i]
});
}
function changeSlices(){
var shouldAddSlice = d3.event.target.valueAsNumber > data.length,
numDifference = Math.abs(data.length - d3.event.target.valueAsNumber);
if(shouldAddSlice){
addSlices(numDifference);
}
else{
removeSlices(numDifference);
}
}
sliceSlider.on('keyup',changeSlices);
})(window.d3);
}
</script>
</head>
<body>
</body>
</html>
Upvotes: 1