Search code examples
vue.jsd3.jspaginationlegendpie-chart

D3 pie chart legends with horizontal pagination


I have a requirement where i need to show pagination for legends if the number of legends is more than two. I am using d3 pie chart. Any help would be appreciated. I have found out something similar but unable to implement using d3 version 5.


Solution

  • I have modified the code you gave in this bl.ocks link.

    Here is a link of the codepen I created link.

    The pagination implemented here could be directly used with d3 v5. The problem was coming up with the chart.

    var legendCount = dataSet.series.length;
    
    var legendWidth = 10;
    var legendSpacing = 6;
    
    var netLegendHeight = (legendWidth + legendSpacing) * legendCount;
    var legendPerPage, totalPages, pageNo;
    
    // if (netLegendHeight / height > 1) {
    
    legendPerPage = 2;
    totalPages = Math.ceil(legendCount / legendPerPage);
    
    pageNo = 1;
    
    var startIndex = (pageNo - 1) * legendPerPage;
    var endIndex = startIndex + legendPerPage;
    var seriesSubset = [],
        colorSubset = [];
    
    for (var i = 0; i < dataSet.series.length; i++) {
        if (i >= startIndex && i < endIndex) {
            seriesSubset.push(dataSet.series[i]);
            colorSubset.push(colors[i]);
        }
    }
    
    DrawLegendSubset(seriesSubset, colorSubset, legendPerPage, pageNo, totalPages);
    // }
    
    function DrawLegendSubset(seriesSubset, colorSubset, legendPerPage, pageNo, totalPages) {
    
        var legend = svg.selectAll("g.legendg")
            .data(seriesSubset)
            .enter().append("g")
            .attr('class', 'legendg')
            .attr("transform", function(d, i) {
                return "translate(" + (width - 40) + "," + i * (legendWidth + legendSpacing) + ")";
            });
    
        legend.append("rect")
            .attr("x", 45)
            .attr("width", legendWidth)
            .attr("height", legendWidth)
            .attr("class", "legend")
            .style('fill', function(d, i) {
                return colorSubset[i];
            });
    
    
        legend.append("text")
            .attr("x", 60)
            .attr("y", 6)
            .attr("dy", ".35em")
            .style("text-anchor", "start")
            .text(function(d) {
                return d;
            });
    
    
        var pageText = svg.append("g")
            .attr('class', 'pageNo')
            .attr("transform", "translate(" + (width + 7.5) + "," + (legendPerPage + 1) * (legendWidth + legendSpacing) + ")");
    
        pageText.append('text').text(pageNo + '/' + totalPages)
            .attr('dx', '.25em');
    
        var prevtriangle = svg.append("g")
            .attr('class', 'prev')
            .attr("transform", "translate(" + (width + 5) + "," + (legendPerPage + 1.5) * (legendWidth + legendSpacing) + ")")
            .on('click', prevLegend)
            .style('cursor', 'pointer');
    
        var nexttriangle = svg.append("g")
            .attr('class', 'next')
            .attr("transform", "translate(" + (width + 20) + "," + (legendPerPage + 1.5) * (legendWidth + legendSpacing) + ")")
            .on('click', nextLegend)
            .style('cursor', 'pointer');
    
        nexttriangle.append('polygon')
            .style('stroke', '#000')
            .style('fill', '#000')
            .attr('points', '0,0, 10,0, 5,5');
    
        prevtriangle.append('polygon')
            .style('stroke', '#000')
            .style('fill', '#000')
            .attr('points', '0,5, 10,5, 5,0');
    
        if (pageNo == totalPages) {
            nexttriangle.style('opacity', '0.5')
            nexttriangle.on('click', '')
                .style('cursor', '');
        } else if (pageNo == 1) {
            prevtriangle.style('opacity', '0.5')
            prevtriangle.on('click', '')
                .style('cursor', '');
        }
    
    }
    
    function prevLegend() {
        pageNo--;
    
        svg.selectAll("g.legendg").remove();
        svg.select('.pageNo').remove();
        svg.select('.prev').remove();
        svg.select('.next').remove();
    
        var startIndex = (pageNo - 1) * legendPerPage;
        var endIndex = startIndex + legendPerPage;
    
        var seriesSubset = [],
            colorSubset = [];
    
        for (var i = 0; i < dataSet.series.length; i++) {
            if (i >= startIndex && i < endIndex) {
                seriesSubset.push(dataSet.series[i]);
                colorSubset.push(colors[i]);
            }
        }
    
        DrawLegendSubset(seriesSubset, colorSubset, legendPerPage, pageNo, totalPages);
    }
    
    function nextLegend() {
        pageNo++;
    
        svg.selectAll("g.legendg").remove();
        svg.select('.pageNo').remove();
        svg.select('.prev').remove();
        svg.select('.next').remove();
    
        var startIndex = (pageNo - 1) * legendPerPage;
        var endIndex = startIndex + legendPerPage;
    
        var seriesSubset = [],
            colorSubset = [];
    
        for (var i = 0; i < dataSet.series.length; i++) {
            if (i >= startIndex && i < endIndex) {
                seriesSubset.push(dataSet.series[i]);
                colorSubset.push(colors[i]);
            }
        }
    
        DrawLegendSubset(seriesSubset, colorSubset, legendPerPage, pageNo, totalPages);
    }
    

    Here is an image of the final pie chart with pagination:

    enter image description here