2

I have 3 charts on the HTML page, I use class instead of id to avoid repeating code, I need help to change the data of one of them, I tried several ways but the issue still exists, This is the code

const charts = document.getElementsByClassName('doughnut-chart')
for (chart of charts) {
  const ctx = chart.getContext('2d');
  const config = {
    type: 'doughnut',
    data: {
      datasets: [{
        data: [50, 60, 20, 33],
        backgroundColor: ["#1CCFEC", "#A9EDF8", "#BDECDC", "#00D295"],
        label: 'Energy usage'
      }],
      labels: ["VISA", "AMEX", "MC", "DEBIT"]
    },
    options: {
      responsive: true,
      cutoutPercentage: 85,
      legend: {
        display: false
      },
      legendCallback: function (chart) {
        // Return the HTML string here.
        console.log(chart.data.datasets);
        const text = [];
        text.push(`<ul class="${chart.id}-legend flex-center-vh flex-space-evenly">`);
        for (let i = 0; i < chart.data.datasets[0].data.length; i++) {
          text.push(`<li class="flex-center-vh"><span class="item-bg" id="legend-${i}-item" style="background-color:${chart.data.datasets[0].backgroundColor[i]}">`);
          text.push(`</span>`);
          if (chart.data.labels[i]) {
            text.push(`<span class="legent-item text-gray fw600 fs10">${chart.data.labels[i]}</span>`);
          }
          text.push(`</li>`);
        }
        text.push(`</ul>`);
        return text.join("");
      },
    }
  };
    const legendContainer = document.querySelectorAll('.doughnut-legend')
  legendContainer.forEach(function (thisLegend) {
    thisLegend.innerHTML = window.chartInstance.generateLegend();
  })
  var chartInstance = new Chart(ctx, config);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.2/Chart.min.js"></script>
<div class="chart-container">
                <canvas id="chart1" class="doughnut-chart"></canvas>   
                <div class="doughnut-legend"></div>            
              </div>
              <div class="chart-container">
                <canvas id="chart2" class="doughnut-chart"></canvas>  
                <div class="doughnut-legend"></div>         
              </div>
              <div class="chart-container">
                <canvas id="chart3" class="doughnut-chart"></canvas>  
                <div class="doughnut-legend"></div>         
              </div>

3
  • Are you trying to change the data when first displaying them or after they are displayed? Commented Jan 11, 2022 at 11:39
  • 1
    If after, why aren't you storing the chart instance chartInstance = new Chart(ctx, config); in an array that exists outside of the loop? The chart instance is your reference to that individual chart. Commented Jan 11, 2022 at 11:40
  • @KScandrett when the first displaying Commented Jan 11, 2022 at 11:42

1 Answer 1

3

The window.chartInstance is not set and moreover, my understanding of the logic is to expect three different instances in order to call generateLegend() for each of them.

UPDATED to show how to change the data of one of the charts: Moved legendContainer outside of the charts loop ; Now using an array of chart instance as suggested by K Scandrett.

Here is a proposal (excerpt). Mind the instanciation of the charts inside the primary loop and the generation of the legends outside of the primary loop.

let allCharts = [];

const charts = document.getElementsByClassName("doughnut-chart");
for (chart of charts) {
  const ctx = chart.getContext("2d");
  const config = {
    // ...
  };

  var chartInstance = new Chart(ctx, config);
  allCharts.push(chartInstance);
}

let legendContainer = document.querySelectorAll(".doughnut-legend");
legendContainer.forEach(function (thisLegend, i) {
  thisLegend.innerHTML = allCharts[i].generateLegend();
});

// update data
const chartToModify = allCharts[1]
chartToModify.data.datasets[0].data.pop();
chartToModify.data.datasets[0].data.pop();
chartToModify.data.labels.pop();
chartToModify.data.labels.pop();
chartToModify.update();

// update legends
legendContainer = document.querySelectorAll(".doughnut-legend");
legendContainer.forEach(function (thisLegend, i) {
  thisLegend.innerHTML = allCharts[i].generateLegend();
});

Changing the data of one of the charts is documented at https://www.chartjs.org/docs/3.3.2/developers/updates.html. Mind the call to update().

Complete code here https://codepen.io/beezital/pen/yLzRqXz

Sign up to request clarification or add additional context in comments.

2 Comments

Can you please, change the data of one of them from 4 to 2?
@Kareem Sultan I have updated the code to show how to change the data of the second chart. This example is based on your code style and algorithm so to minimise the effort to understand the changes. I have not considered providing a well designed solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.