0

So I've been experimenting with Chart.js lately and I'm working on a project where I need to loop three Charts dynamically and I need each of them to have their own Custom Legend generated by the generateLegend() function. The problem is that the functionality of the legends isn't correct. Clicking any of the legends seems to affect only the last iteration of the Chart, which means that the last Chart gets affected only no matter which Chart's legend I click. Here's the code:

jQuery(document).ready(function($) {

            if ($(".stats-content__chart__embed").length) {

                var chartCount = $(".stats-content__chart__embed").length;
                var chartCounter = 1;

                window.toggleVisibility = function(element) {
                    $(element).toggleClass("striken");
                }

                while (chartCounter <= chartCount) {

                    var statsChartOptions = {
                        responsive: true,
                        maintainAspectRatio: false,
                        scales: {
                            yAxes: [{
                                ticks: {
                                    stepSize: 1000
                                }
                            }]
                        },
                        legendCallback: function(chart) {
                            var legendHtml = [];
                            for (var i = 0; i < chart.data.datasets.length; i++) {                  
                                if (chart.data.datasets[i].label) {
                                    legendHtml.push('<li class="stats-content__chart__legend__item" onclick="toggleVisibility(this); updateDataset(event, ' + '\'' + chart.legend.legendItems[i].datasetIndex + '\'' + ')"><span>' + chart.data.datasets[i].label + '</span></li>');
                                }                                                                              
                            }                                                                                                                                        
                            return legendHtml.join("");                                                        
                        },                                                                                     
                        legend: {                                                                              
                            display: false                                                                     
                        }                                                                                 
                    };    

                    // You can ignore this
                    if ($(".stats-content").eq(chartCounter - 1).find(".stats-content__chart__datasets").length) {

                        var chartDatasets = $(".stats-content").eq(chartCounter - 1).find(".stats-content__chart__datasets");
                        var datasetsCount = chartDatasets.length;
                        var datasetsArray = [];
                        var datasetsLineColors = ["rgb(0,42,72)", "rgb(0,174,239)"];

                        for (var i = 0; i < datasetsCount; i++) {

                            var dataEntry = chartDatasets.eq(i).find("span").length;
                            var datasetLineColor;
                            var dataArrayString = [];

                            for (var x = 0; x < dataEntry; x++) {
                                var dataValue = chartDatasets.eq(i).find("span").eq(x).text();
                                dataArrayString.push(dataValue);
                                var dataArrayNumbers = dataArrayString.map(Number);
                            }

                            if ($(this).find("h6").length) {
                                var datasetLabel = chartDatasets.eq(i).find("h6").text();
                            }

                            if (i % 2 == 0) {
                                datasetLineColor = datasetsLineColors[0];
                            } else {
                                datasetLineColor = datasetsLineColors[1];
                            }

                            datasetsArray.push({
                                label: datasetLabel,
                                backgroundColor: "transparent",
                                lineTension: 0,
                                pointBackgroundColor: "transparent",
                                pointBorderColor: "transparent",
                                borderColor: datasetLineColor,
                                data: dataArrayNumbers,
                                borderWidth: 2
                            });

                        }

                    } 

                    if ($(".stats-content").eq(chartCounter - 1).find(".stats-content__chart__labels > span").length) {

                        var chartDatasetLabels = $(".stats-content").eq(chartCounter - 1).find(".stats-content__chart__labels > span");
                        var labelCount = chartDatasetLabels.length;
                        var labelsArray = [];

                        for (var i = 0; i < labelCount; i++) {
                            var labelText = chartDatasetLabels.eq(i).text();
                            labelsArray.push(labelText);
                        }

                    }
                    // Ignore all the way to here

                    var ctx = document.getElementById("stats-content__chart__embed-" + chartCounter).getContext("2d");
                    window.statsChart = new Chart(ctx, {
                        type: 'line',
                        data: {
                            labels: labelsArray,
                            datasets: datasetsArray
                        },
                        options: statsChartOptions
                    });

                    updateDataset = function(e, datasetIndex) {
                        var index = datasetIndex;
                        var ci = e.view.statsChart;
                        var meta = ci.getDatasetMeta(index);
                        meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
                        ci.update();
                    };

                    document.getElementById("stats-content__chart__legend-" + chartCounter).innerHTML = window.statsChart.generateLegend();

                    chartCounter++;

                }
            }

        });

You can ignore the code that I've put inside comments since that's not relevant to the issue (I've gotten comments that it's too big of a chunk of code so I try to lessen the strain on you guys haha). Please, offer me any type of help. I really need it. Here's also the HTML for it, in case it helps in any way (the actual content is generated dynamically through Wordpress' Advanced Custom Fields plugin).

<?php if ( have_rows( 'stats_tabs' ) ) : ?>

                <div id="statsTabContent" class="tab-content stats-holder">

                    <?php while ( have_rows( 'stats_tabs' ) ) : the_row();

                        $index = get_row_index(); ?>

                        <div class="tab-pane fade <?php echo ( $index == 1 ) ? 'in active' : '' ?> stats-content" id="tab-<?php echo $index; ?>">

                            <ul id="stats-content__chart__legend-<?php echo $index; ?>" class="stats-content__chart__legend"></ul>

                            <div class="stats-content__description">
                                <?php the_sub_field( 'tab_description' ); ?>
                            </div>

                            <div class="stats-content__chart__holder">

                                <?php if ( have_rows( 'tab_dataset' ) ) :

                                    while ( have_rows( 'tab_dataset' ) ) : the_row(); ?>

                                        <div class="stats-content__chart__datasets">

                                            <h6><?php the_sub_field( 'dataset_label' ); ?></h6>

                                            <?php if ( have_rows( 'dataset_data' ) ) :

                                                while ( have_rows( 'dataset_data' ) ) : the_row(); ?>

                                                    <span><?php the_sub_field( 'dataset_value' ); ?></span>

                                                <?php endwhile;

                                            endif; ?>

                                        </div>

                                    <?php endwhile;

                                endif; ?>

                                <div class="stats-content__chart__labels">

                                    <?php if ( have_rows( 'tab_labels' ) ) :

                                        while ( have_rows( 'tab_labels' ) ) : the_row(); ?>

                                            <span><?php the_sub_field( 'tab_label' ); ?></span>

                                        <?php endwhile;

                                    endif; ?>

                                </div>

                            </div>

                            <div class="stats-content__chart">

                                <canvas id="stats-content__chart__embed-<?php echo $index; ?>"  class="stats-content__chart__embed"></canvas>

                            </div>

                        </div>

                    <?php endwhile; ?>

                </div>

            <?php endif; ?>

1 Answers1

0

You are replacing your variable on each iteration, so naturally the variable refers to the last thing assigned (i.e. the last chart created):

while (chartCounter <= chartCount) {
  ...
  window.statsChart = new Chart(ctx, {...});
  ...
}

Clicking a legend item calls updateDataset wherein you reference back to window.statsChart via the line:

var ci = e.view.statsChart;

Since statsChart is assigned to the last chart iterated your code affects only that chart.

Either make statsChart an array and pass the relevant index via onclick or simply pass the chart object itself to updateDataset (although that won't work via the inline onclick; you'd need to bind to the element).

timclutton
  • 12,682
  • 3
  • 33
  • 43
  • So your suggestion is pretty good, but unfortunately that didn't fix the problem. I've created a Codepen repository where you can check live the issue. Maybe even have some input in case you're interested and manage to fix it? - https://codepen.io/MiroMargineanu/pen/BvLoNv (I already am eternally grateful for your input already. I've asked on many Slacks, StackOverflow, even the GitHub for Chart.js and no one showed any interest to help me, and this is the last touch I need to do for my project and it's been holding me back for a week already). – Miro Mărgineanu Dec 17 '18 at 21:32