Search code examples
javascripthighcharts

How do I reload/animate highcharts everytime I click on a button?


I am using highcharts. Everything seems to work fine. I am trying to enhance the loading process. By default when the page loads, chart shows data for "ZX". When I click on "XZ", or "X" button, the chart doesn't animate. It displays instantly. Is there a way I can animate the chart everytime user clicks on any of the buttons? Here is link to my code -

https://live.datatables.net/nikusucu/5/edit

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

    // Create chart
    const chart = Highcharts.chart(chartId, {
        chart: {
            type: 'pie',
            styledMode: false
          
        },
        title: {
            text: chartTitle
        },
       colors: ['#003489', '#ED7D31', '#A5A5A5', '#FFC000', '#5B9BD5', '#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572', '#FF9655', '#FFF263', '#6AF9C4'],
        tooltip: {
            pointFormat: '</b> {point.y:.1f}%'
        },
        series: [
            {
                data: chartData(table)
            }
             
        ],
        credits: {
            enabled: false
        },
        plotOptions: {
            pie: {
                allowPointSelect: true,
                cursor: 'pointer',
                series: {
            animation: {
                duration: 2000
            }
        },
                dataLabels: {
                    enabled: true,
                    format: '{point.y:.1f}%'
                },
                showInLegend: true  // Show legends
            }
        }
    });

    // On each draw, update the data in the chart
    table.on('draw', function () {
        chart.series[0].setData(chartData(table));
    });

    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;
    }
}

document.addEventListener('DOMContentLoaded', function () {
    // Check if Highcharts is defined before calling the function
    if (typeof Highcharts !== 'undefined') {
        initializeChart('demo-output', '#example', 'test1');
        initializeChart('demo-output2', '#example1', 'test 2');

        var allSeriesData = [];
        var categories = [];
        $('#example2').data('scrollX-custom', true);

        var table = $("#example2").DataTable({
            searching: false,
            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 - 1) {
                        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 - 1) {
                            group.data.push(parseFloat(cell.replace(/,/g, '')));
                        }
                    });
                    allSeriesData.push(group);
                });
            }
        });

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

        var myChart = Highcharts.chart("chart-A", {
            chart: {
                type: "column",
                borderColor: 'black',
                borderWidth: 1,
                marginTop: 50
            },
            legend: {
                symbolRadius: 0,
                itemStyle: {
                    color: '#000000',
                    fontSize: '16px'
                }
            },
            
            credits: {
                enabled: false
            },
         
            title: {
                text: "Test3"
            },
            xAxis: {
                categories: categories,
                labels: {
                    style: {
                        fontWeight: '600',
                        fontSize: '16px',
                        color: '#000000'
                    }
                }
            },
            yAxis: {
                title: false,
                tickInterval: 10,
                max: 70,
                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 === 'button-2') {
        $('#chart1').hide();
        $('#chart2').show();
        $('#chart3').hide();
    } else if (buttonId === 'button-3') {
        $('#chart1').hide();
        $('#chart2').hide();
        $('#chart3').show();
    } else {
        // Default case, show chart1
        $('#chart1').show();
        $('#chart2').hide();
        $('#chart3').hide();
    }

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

// Set default highlight on button-2023
$('#button-1').addClass('active');
    }
});
<!DOCTYPE html>
<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="button-1" class="usa-button usa-button--outline">zx</button>
<button id="button-2" class="usa-button usa-button--outline">xz</button>
<button id="button-3" class="usa-button usa-button--outline">x</button>
  </div>
<div id="chart1">
<div id="demo-output" class="chart-display" style=" margin-bottom: 2em; height: 650px; border: solid 1px lightgray;"></div>

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

</thead>
<tr>
<td scope="row">1</td>
<td>3.2%</td>
</tr>

<tr>
<td scope="row">2</td>
<td>1.1%</td>
</tr>

<tr>
<td scope="row">3</td>
<td>1.6%</td>
</tr>

<tr>
<td scope="row">4</td>
<td>1.9%</td>
</tr>

<tr>
<td scope="row">5</td>
<td>2.5%</td>
</tr>

<tr>
<td scope="row">6</td>
<td>4.4%</td>
</tr>

<tr>
<td scope="row">7</td>
<td>18.6%</td>
</tr>

<tr>
<td scope="row">8</td>
<td>1.1%</td>
</tr>

<tr>
<td scope="row">9</td>
<td>1.4%</td>
</tr>

<tr>
<td scope="row">10</td>
<td>1.9%</td>
</tr>

<tr>
<td scope="row">11</td>
<td>2.2%</td>
</tr>

<tr>
<td scope="row">12</td>
<td>3.4%</td>
</tr>

<tr>
<td scope="row">13</td>
<td>5.0%</td>
</tr>

<tr>
<td scope="row">14</td>
<td>51.9%</td>
</tr>
</table>
</div>

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

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

</thead>
<tr>
<td scope="row">2</td>
<td>18.6</td>
</tr>

<tr>
<td scope="row">3</td>
<td>0</td>
</tr>

<tr>
<td scope="row">4</td>
<td>0</td>
</tr>

<tr>
<td scope="row">5</td>
<td>5.0</td>
</tr>

<tr>
<td scope="row">6</td>
<td>2.2</td>
</tr>

<tr>
<td scope="row">7</td>
<td>0</td>
</tr>

<tr>
<td scope="row">8</td>
<td>2.5</td>
</tr>

<tr>
<td scope="row">9</td>
<td>3.4</td>
</tr>

<tr>
<td scope="row">10</td>
<td>4.4</td>
</tr>

<tr>
<td scope="row">11</td>
<td>0</td>
</tr>

<tr>
<td scope="row">12</td>
<td>0</td>
</tr>

<tr>
<td scope="row">13</td>
<td>12.2</td>
</tr>
</table>
</div>

<div id="chart3" style=" display: none;"><!--<div style=" text-align: center;"><img src="/images/complaint-data-chart-1.svg" alt="Cases Received From Consumers" title="Cases Received From Consumers" style=" width: 700px;" /></div> -->
<div id="chart-A" style=" width: 100%; height: 400px;"></div>

<table class="row-border stripe dt-right dataTable no-footer dtr-inline" id="example2" style=" width: 100%;"><thead>
<tr>
<th scope="col" style=" text-align: center; width: 12%;">Year</th>
<th scope="col" style=" text-align: center; width: 22%;">1</th>
<th scope="col" style=" text-align: center; width: 22%;">2</th>
<th scope="col" style=" text-align: center; width: 22%;">3</th>
<th scope="col" style=" text-align: center; width: 22%;">4</th>
<th scope="col" style=" text-align: center; width: 22%;">5</th>
<th scope="col" style=" text-align: center; width: 22%;">6</th>
</tr>

</thead>
<tr>
<td scope="row" style=" text-align: center;">2019</td>
<td style=" text-align: center;">42.5%</td>
<td style=" text-align: center;">30.1%</td>
<td style=" text-align: center;">12.5%</td>
<td style=" text-align: center;">6%</td>
<td style=" text-align: center;">11.3%</td>
<td style=" text-align: center;">10%</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2020</td>
<td style=" text-align: center;">50.01%</td>
<td style=" text-align: center;">26.5%</td>
<td style=" text-align: center;">15%</td>
<td style=" text-align: center;">12%</td>
<td style=" text-align: center;">11%</td>
<td style=" text-align: center;">10%</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2021</td>
<td style=" text-align: center;">29.5%</td>
<td style=" text-align: center;">35%</td>
<td style=" text-align: center;">66%</td>
<td style=" text-align: center;">7%</td>
<td style=" text-align: center;">6%</td>
<td style=" text-align: center;">56%</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2022</td>
<td style=" text-align: center;">40.1%</td>
<td style=" text-align: center;">76%</td>
<td style=" text-align: center;">7%</td>
<td style=" text-align: center;">8%</td>
<td style=" text-align: center;">86%</td>
<td style=" text-align: center;">54%</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2023</td>
<td style=" text-align: center;">38.9%</td>
<td style=" text-align: center;">55%</td>
<td style=" text-align: center;">5%</td>
<td style=" text-align: center;">45%</td>
<td style=" text-align: center;">55%</td>
<td style=" text-align: center;">55%</td>
</tr>
</table>
</div>


Solution

  • Your question has already been answered on the highcharts forum

    Q: Animation on show/hide of a chart

    A: The simplest way is to render the chart again on click: https://codepen.io/anon/pen/pMzLNj?editors=0010

    Solution

    var chart = Highcharts.chart('container', chartOptions)
    let hidden = false
    
    function showHide(){
       if (!hidden) {
         chart.destroy()
       } else {
         chart = Highcharts.chart('container', chartOptions)
       }
      hidden = !hidden;
    }
    

    To apply this solution to your code you need to save the Chart in a variable when you initialize it. For example you could return it within your initializeChart function. Then call .destroy on the reference and set a new one on the variable. There are multiple ways of implementing this solution. Your approach wasn't clean and easy for me to read. I recommend sticking to what the linked solution does:

    • separate function for the chartOptions
    • using only one container for your chart

    Documentation for Highchart.Chart#destroy

    For the sake of already diving to deep into this and to avoid further discussion - this code should work within your local environment. Please keep in mind that online live editors might not work as explained in this forum post.

    function initializeChart(chartId, table, chartTitle) {
        function chartData(table) {
            var data = [];
            table.rows().every(function() {
                var row = this.data();
                data.push({
                    name: row[0],
                    y: parseFloat(row[1])
                });
            });
    
            return data;
        }
    
        return Highcharts.chart(chartId, {
            chart: {
                type: 'pie',
                styledMode: false
            },
            title: {
                text: chartTitle
            },
            colors: ['#003489', '#ED7D31', '#A5A5A5', '#FFC000', '#5B9BD5', '#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572', '#FF9655', '#FFF263', '#6AF9C4'],
            tooltip: {
                pointFormat: '</b> {point.y:.1f}%'
            },
            series: [{
                data: chartData(table)
            }],
            credits: {
                enabled: false
            },
            plotOptions: {
                pie: {
                    allowPointSelect: true,
                    cursor: 'pointer',
                    dataLabels: {
                        enabled: true,
                        format: '{point.y:.1f}%'
                    },
                    showInLegend: true
                }
            },
            accessibility: {
              enabled: false
            }
        });
    }
    
    const createDataTable = (id) => new DataTable(id, {
        searching: false,
        info: false,
        paging: false,
        sort: false
    });
    const table1 = createDataTable('#example')
    const table2 = createDataTable('#example1')
    const table3 = createDataTable('#example2')
    
    document.addEventListener('DOMContentLoaded', function() {
        let currentChart
        if (typeof Highcharts !== 'undefined') {
            currentChart = initializeChart('demo-output', table1, 'test1');
    
    
            $('.usa-button').on('click', function() {
                var buttonId = $(this).attr('id');
    
                if (currentChart) {
                    currentChart.destroy();
                }
    
                if (buttonId === 'button-2') {
                    currentChart = initializeChart('demo-output', table2, 'test 2');
                } else if (buttonId === 'button-3') {
                    currentChart = initializeChart('demo-output', table3, 'test 3');
                } else {
                    currentChart = initializeChart('demo-output', table1, 'test 1');
                }
    
                $('.usa-button').removeClass('active');
                $(this).addClass('active');
            });
    
            $('#button-1').addClass('active');
        }
    });
    #container {
        min-width: 300px;
        max-width: 600px;
        margin: 0 auto;
    }
    <!DOCTYPE html>
    <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="button-1" class="usa-button usa-button--outline">zx</button>
    <button id="button-2" class="usa-button usa-button--outline">xz</button>
    <button id="button-3" class="usa-button usa-button--outline">x</button>
      </div>
    <div id="chart1">
    <div id="demo-output" class="chart-display" style=" margin-bottom: 2em; height: 650px; border: solid 1px lightgray;"></div>
    
    <table id="example" class="display" style=" width: 100%;"><thead>
    <tr>
    <th scope="col">test 1</th>
    <th scope="col">Percent</th>
    </tr>
    
    </thead>
    <tr>
    <td scope="row">1</td>
    <td>3.2%</td>
    </tr>
    
    <tr>
    <td scope="row">2</td>
    <td>1.1%</td>
    </tr>
    
    <tr>
    <td scope="row">3</td>
    <td>1.6%</td>
    </tr>
    
    <tr>
    <td scope="row">4</td>
    <td>1.9%</td>
    </tr>
    
    <tr>
    <td scope="row">5</td>
    <td>2.5%</td>
    </tr>
    
    <tr>
    <td scope="row">6</td>
    <td>4.4%</td>
    </tr>
    
    <tr>
    <td scope="row">7</td>
    <td>18.6%</td>
    </tr>
    
    <tr>
    <td scope="row">8</td>
    <td>1.1%</td>
    </tr>
    
    <tr>
    <td scope="row">9</td>
    <td>1.4%</td>
    </tr>
    
    <tr>
    <td scope="row">10</td>
    <td>1.9%</td>
    </tr>
    
    <tr>
    <td scope="row">11</td>
    <td>2.2%</td>
    </tr>
    
    <tr>
    <td scope="row">12</td>
    <td>3.4%</td>
    </tr>
    
    <tr>
    <td scope="row">13</td>
    <td>5.0%</td>
    </tr>
    
    <tr>
    <td scope="row">14</td>
    <td>51.9%</td>
    </tr>
    </table>
    </div>
    
    <div id="chart2" style=" display: none;">
    <div id="demo-output2" class="chart-display2" style=" margin-bottom: 2em; height: 600px; border: solid 1px lightgray;"></div>
    
    <table id="example1" class="display" style=" width: 100%;"><thead>
    <tr>
    <th scope="col">1</th>
    <th scope="col">Percent</th>
    </tr>
    
    </thead>
    <tr>
    <td scope="row">2</td>
    <td>18.6</td>
    </tr>
    
    <tr>
    <td scope="row">3</td>
    <td>0</td>
    </tr>
    
    <tr>
    <td scope="row">4</td>
    <td>0</td>
    </tr>
    
    <tr>
    <td scope="row">5</td>
    <td>5.0</td>
    </tr>
    
    <tr>
    <td scope="row">6</td>
    <td>2.2</td>
    </tr>
    
    <tr>
    <td scope="row">7</td>
    <td>0</td>
    </tr>
    
    <tr>
    <td scope="row">8</td>
    <td>2.5</td>
    </tr>
    
    <tr>
    <td scope="row">9</td>
    <td>3.4</td>
    </tr>
    
    <tr>
    <td scope="row">10</td>
    <td>4.4</td>
    </tr>
    
    <tr>
    <td scope="row">11</td>
    <td>0</td>
    </tr>
    
    <tr>
    <td scope="row">12</td>
    <td>0</td>
    </tr>
    
    <tr>
    <td scope="row">13</td>
    <td>12.2</td>
    </tr>
    </table>
    </div>
    
    <div id="chart3" style=" display: none;"><!--<div style=" text-align: center;"><img src="/images/complaint-data-chart-1.svg" alt="Cases Received From Consumers" title="Cases Received From Consumers" style=" width: 700px;" /></div> -->
    <div id="chart-A" style=" width: 100%; height: 400px;"></div>
    
    <table class="row-border stripe dt-right dataTable no-footer dtr-inline" id="example2" style=" width: 100%;"><thead>
    <tr>
    <th scope="col" style=" text-align: center; width: 12%;">Year</th>
    <th scope="col" style=" text-align: center; width: 22%;">1</th>
    <th scope="col" style=" text-align: center; width: 22%;">2</th>
    <th scope="col" style=" text-align: center; width: 22%;">3</th>
    <th scope="col" style=" text-align: center; width: 22%;">4</th>
    <th scope="col" style=" text-align: center; width: 22%;">5</th>
    <th scope="col" style=" text-align: center; width: 22%;">6</th>
    </tr>
    
    </thead>
    <tr>
    <td scope="row" style=" text-align: center;">2019</td>
    <td style=" text-align: center;">42.5%</td>
    <td style=" text-align: center;">30.1%</td>
    <td style=" text-align: center;">12.5%</td>
    <td style=" text-align: center;">6%</td>
    <td style=" text-align: center;">11.3%</td>
    <td style=" text-align: center;">10%</td>
    </tr>
    
    <tr>
    <td scope="row" style=" text-align: center;">2020</td>
    <td style=" text-align: center;">50.01%</td>
    <td style=" text-align: center;">26.5%</td>
    <td style=" text-align: center;">15%</td>
    <td style=" text-align: center;">12%</td>
    <td style=" text-align: center;">11%</td>
    <td style=" text-align: center;">10%</td>
    </tr>
    
    <tr>
    <td scope="row" style=" text-align: center;">2021</td>
    <td style=" text-align: center;">29.5%</td>
    <td style=" text-align: center;">35%</td>
    <td style=" text-align: center;">66%</td>
    <td style=" text-align: center;">7%</td>
    <td style=" text-align: center;">6%</td>
    <td style=" text-align: center;">56%</td>
    </tr>
    
    <tr>
    <td scope="row" style=" text-align: center;">2022</td>
    <td style=" text-align: center;">40.1%</td>
    <td style=" text-align: center;">76%</td>
    <td style=" text-align: center;">7%</td>
    <td style=" text-align: center;">8%</td>
    <td style=" text-align: center;">86%</td>
    <td style=" text-align: center;">54%</td>
    </tr>
    
    <tr>
    <td scope="row" style=" text-align: center;">2023</td>
    <td style=" text-align: center;">38.9%</td>
    <td style=" text-align: center;">55%</td>
    <td style=" text-align: center;">5%</td>
    <td style=" text-align: center;">45%</td>
    <td style=" text-align: center;">55%</td>
    <td style=" text-align: center;">55%</td>
    </tr>
    </table>
    </div>