wootscootinboogie
wootscootinboogie

Reputation: 8705

D3.js adding/removing data pie chart slices

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

Answers (3)

Roland Heath
Roland Heath

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

Pavan Kumar Jorrigala
Pavan Kumar Jorrigala

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

SilentTremor
SilentTremor

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

Related Questions