Search code examples
javascripthighcharts

Highcharts and piechart filter


I have a webpage featuring pie charts and a bar chart. While the rest of the functionality works as expected, I'm encountering issues with the filtering mechanism. Specifically, when I filter out a segment from a pie chart, it's being visually represented as if the remaining segments fill up the entire pie.

For instance, let's consider Chart A with three segments: 50%, 25%, and 25%. When I click on the legend to filter out the segment representing 50%, instead of greying out this segment and displaying the remaining segments (25%, 25%) as they are, the chart appears as if the remaining segments now occupy the entire pie.

I'd like the filtered-out segment to be visually differentiated, perhaps by graying it out, while still showing the remaining segments (25%, 25%) as they are.

Here is my code -

document.addEventListener('DOMContentLoaded', function () {
    // Check if Highcharts is defined before calling the function
    if (typeof Highcharts !== 'undefined') {
        var example1Table;
        var exampleTable;
        
        // Initialize DataTable for #example1
        initializeChart('demo-output', '#example1', 'test 2023');
        // Initialize DataTable for #example
        initializeChart('demo-output2', '#example', 'test 2022');

       var allSeriesData = [];
        var categories = [];

        var table = $("#example2").DataTable({
            searching: false,
            responsive: true,
            lengthChange: false,
            ordering: false,
            info: false,
           paging: false,
            initComplete: function (settings, json) {
                let api = new $.fn.dataTable.Api(settings);

                // get the x-axis caregories from the table headings:
                var headers = api.columns().header().toArray();
                headers.forEach(function (heading, index) {
                    if (index > 0 && index < headers.length) {
                        categories.push($(heading).html());
                    }
                });

                // get the seris data as an array of numbers from the table row data:
                let rows = api.rows().data().toArray();
                rows.forEach(function (row) {
                    group = {
                        name: '',
                        data: []
                    };
                    row.forEach(function (cell, idx) {
                        if (idx == 0) {
                            group.name = cell;
                        } else if (idx < row.length) {
                            group.data.push(parseFloat(cell.replace(/,/g, '')));
                        }
                    });
                    allSeriesData.push(group);
                });
            }
        });

        Highcharts.setOptions({
            lang: {
                thousandsSep: ','
            }
        });

        // Function to initialize chart
        function initializeChart(chartId, tableId, chartTitle) {
            // Destroy existing DataTable instance
            if ($.fn.DataTable.isDataTable(tableId)) {
                $(tableId).DataTable().destroy();
            }

            // Create DataTable
            const table = new DataTable(tableId, {
                searching: false,
                info: true,
                paging: false,
                sort: false
            });

            // Create chart
            const chart = Highcharts.chart(chartId, {
                chart: {
                    type: 'pie',
                    styledMode: false
                },
                title: {
                    text: chartTitle
                },
                colors: ['#1a4480', '#e52207', '#e66f0e', '#ffbe2e', '#fee685', '#538200', '#04c585', '#97d4ea', '#009ec1', '#0076d6', '#adadad', '#8168b3', '#d72d79', '#f2938c' ],
                tooltip: {
                    pointFormat: '</b> {point.y:.1f}%'
                },
                series: [
                    {
                        data: chartData(table)
                    }
                ],
                credits: {
                    enabled: false
                },
                plotOptions: {
                    pie: {
                        size: 270,
                        innerSize:70,
                        allowPointSelect: true,
                        cursor: 'pointer',
                        dataLabels: {
                            enabled: true,
                            distance: 30,
                            padding: 1,
                            style: {
                                fontSize: "12px"
                            },
                            format: '{point.y:.1f}%'
                        },
                        showInLegend: true  // Show legends
                    }
                }
            });

           // On each draw, update the data in the chart
    table.on('draw', function () {
        if (chart && chart.series && chart.series.length > 0) {
            // Update the chart data only if series is initialized
            chart.series[0].setData(chartData(table));
        } else {
            // If chart or chart series is not properly initialized, log an error
           
        }
    });

    // Function to get chart data from DataTable
    function chartData(table) {
        var data = [];
        table.rows().every(function () {
            var row = this.data();
            data.push({
                name: row[0],  // Assuming the first column is the name
                y: parseFloat(row[1])  // Assuming the second column is the numeric value
            });
        });

        return data;
    }
}
        // Function to initialize trend chart
        function initializeTrendChart() {
            // Your trend chart initialization code here
            // Example:
            var trendChart = Highcharts.chart("chart-A", {
                chart: {
                    type: "column",
                    borderColor: 'lightgray',
                    borderWidth: 1,
                    marginTop: 50
                },
                tooltip: {
                    headerFormat: '{point.key}<br/>',
                    pointFormat: '{series.name}: <b>{point.y:.1f}%</b>'
                },
                legend: {
                    symbolRadius: 0,
                    itemStyle: {
                        color: '#000000',
                        fontSize: '16px'
                    }
                },
                colors: ['#003489', '#ED7D31', '#A5A5A5', '#FFC000', '#5B9BD5'],
                credits: {
                    enabled: false
                },
                title: {
                    text: "test3"
                },
                xAxis: {
                    categories: categories,
                    labels: {
                        style: {
                            fontWeight: '600',
                            fontSize: '16px',
                            color: '#000000'
                        }
                    }
                },
                yAxis: {
                    title: false,
                    tickInterval: 10,
                   max: 60,
                    labels: {
                        formatter: function () {
                            return Highcharts.numberFormat(this.value, 0);
                        },
                        style: {
                            fontWeight: '600',
                            fontSize: '16px',
                            color: '#000000'
                        }
                    }
                },
                series: allSeriesData
            });
        }

        // Button click event listeners
        $('.usa-button').on('click', function () {
            var buttonId = $(this).attr('id');

            // Toggle chart visibility based on button click
            if (buttonId === 'previous') {
                $('#chart2').show();
                $('#chart1').hide();
                $('#chart3').hide();
                initializeChart('demo-output2', '#example', 'test 2022');
            } else if (buttonId === 'trend') {
                $('#chart2').hide();
                $('#chart1').hide();
                $('#chart3').show();
                initializeTrendChart(); // Reinitialize trend chart
            } else {
                // Default case, show chart1
                $('#chart2').hide();
                $('#chart1').show();
                $('#chart3').hide();
                initializeChart('demo-output', '#example1', 'test 2023');
            }

            // Highlight the active button
            $('.usa-button').removeClass('active');
            $(this).addClass('active');
        });

        // Set default highlight on 2023 button
        $('#current').addClass('active');
    }
});
<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

    <link href="https://nightly.datatables.net/css/dataTables.dataTables.css" rel="stylesheet" type="text/css" />
    <script src="https://nightly.datatables.net/js/dataTables.js"></script>

 <script src="https://code.highcharts.com/highcharts.js"></script>

  </head>
  <body>




<div class="ar-controls grid-row tablet:flex-justify-start">
<div class="tablet:grid-col-auto margin-bottom-205"><button id="current" class="usa-button usa-button--outline" title="Select to see related information below">one</button> <button id="previous" class="usa-button usa-button--outline" title="Select to see related information below">two</button> <button id="trend" class="usa-button usa-button--outline" title="Select to see related information below">three</button></div>
</div>

<div id="chart1">
<div id="demo-output" class="chart-display" style=" margin-bottom: 2em; height: 500px; border: solid 1px lightgray;"></div>

<table id="example1" class="display" style=" width: 100%;"><thead>
<tr>
<th scope="col">2023</th>
<th scope="col">Percent</th>
</tr>

</thead>
<tr>
<td scope="row">ABC</td>
<td>45.9%</td>
</tr>

<tr>
<td scope="row">DEF</td>
<td>22.0%</td>
</tr>

<tr>
<td scope="row">GHI</td>
<td>13.6%</td>
</tr>

</table>
</div>

<div id="chart2" style=" display: none;">
<div id="demo-output2" class="chart-display2" style=" margin-bottom: 2em; height: 680px; border: solid 1px lightgray;"></div>

<table id="example" class="display" style=" width: 100%;"><thead>
<tr>
<th scope="col">2022</th>
<th scope="col">Percent</th>
</tr>

</thead>
<tr>
<td>AAA</td>
<td>51.90%</td>
</tr>

<tr>
<td>BBB</td>
<td>18.60%</td>
</tr>

</table>
</div>

<div id="chart3" style=" display: none;">
<div id="chart-A" style=" width: 100%; height: 500px;"></div>

<table class="row-border stripe no-footer cell-border padding-top-5" id="example2" style=" width: 100%;"><thead>
<tr>
<th>Year</th>
<th>column1</th>
<th>column2</th>
<th>column3</th>

</tr>

</thead>
<tr>
<td scope="row" style=" text-align: left; white-space: nowrap;">FY19</td>
<td style=" text-align: left;">42.7%</td>
<td style=" text-align: left;">17.3%</td>
<td style=" text-align: left;">9.5%</td>

</tr>

<tr>
<td scope="row" style=" text-align: left;">FY20</td>
<td style=" text-align: left;">49.5%</td>
<td style=" text-align: left;">16.3%</td>
<td style=" text-align: left;">3.4%</td>

</tr>


</table>
</div>
</div>


Solution

  • To disabling hiding slices on pie chart you need to use series.point.events.legendItemClick function. Over there you can also update the point's color.

       legendItemClick: function() {
          this.update({
            color: 'gray'
          })
          return false;
        }
    

    API references: https://api.highcharts.com/class-reference/Highcharts.Point#update

    Demo: https://jsfiddle.net/BlackLabel/w7r2dkzo/