Update data of chartjs chart

First of all, I would like to say that I’m a student learning programming for … Read more Update data of chartjs chart

First of all, I would like to say that I’m a student learning programming for around a month, so expect to see many mistakes.

I’m working on a website where I use a chart from the ChartJs library. The data used for this chart is taken through requests to a server. I am working on making requests to the server every X number of seconds, so the data displayed on the chart gets updated automatically without having to refresh or do anything.

I would say I have most of it done, but I have a problem with ChartJs. I have the chart together with the request to server, all in one function which I then call on windows.onload. I have used setInterval to call this function every 5 seconds, and in practice this works, but I get this error :

Uncaught Error: Canvas is already in use. Chart with ID ‘0’ must be
destroyed before the canvas can be reused.

So I understand what is happening, I am trying to create the chart over and over again on the same canvas element, and that of course doesn’t work. I have seen about the destroy() method and update() method, but I haven’t been able to find a solution for my specific case. If anyone could tell me any ideas on how to do this in this case, I would really appreciate it. Here is the code:

let serverData;
let stundenGesamt;
let date;
const url = 'https://urlsample.de/'; // Hidden the actual URL as it is the actual server from my company
const chart = document.getElementById("multie-pie-chart");

// Function that calculates the workdays passed up until today
const workdaysCount = () => 
[...new Array(new Date().getDate())]
.reduce((acc, _, monthDay) => {
  const date = new Date()
  ![0, 6].includes(date.getDay()) && acc++
  return acc      
  }, 0)

window.onload = function() {
  chartRender(); // Calling the function that renders the chart
  setInterval(chartRender, 5000); // Rendering the chart every 5 seconds


let chartRender = () => {


  let http = new XMLHttpRequest();
  http.open("GET", url);
  http.setRequestHeader('key', 'key-sample'); // Hidden the actual key as it is from the actual server from my company

  http.onload = () => {

    // Parsing the JSON file and storing it into a variable (Console.Log() to make sure it works)
    serverData = JSON.parse(http.responseText);

    stundenGesamt = serverData.abzurechnen.gesamt; // Storing the value of total hours from the database in a variable
    // Basic UI of the pie chart
    const data = {
      labels: ['Summe', 'Noch um Ziel zu erreichen', 'Arbeitstage', 'Verbleibende Tage im Monat'],
      datasets: [
          backgroundColor: ['#5ce1e6', '#2acaea'],
          data: [stundenGesamt, (800 - stundenGesamt)]
          backgroundColor: ['#cd1076', '#8b0a50'],
          data: [workdaysCount(), (22 - workdaysCount())] 

    // Configuration of the pie chart
    let outterChart = new Chart(chart, {
      type: 'pie',
      data: data,
      options: {
      responsive: true,
      plugins: {
        datalabels: {
          font: {
            weight: 'bold',
            size: 20
          color: 'white',
          formatter: (val, chart) => {
            const totalDatasetSum = chart.chart.data.datasets[chart.datasetIndex].data.reduce((a, b) => (a + b), 0);
            const percentage = val * 100 / totalDatasetSum;
            const roundedPercentage = Math.round(percentage * 100) / 100
            return `${roundedPercentage}%`
        legend: {
          labels: {
            color: 'white',
              font: {
                size: 14,
                family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
                weight: 'bold'
              generateLabels: function(chart) {
              // Get the default label list
              const original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
              const labelsOriginal = original.call(this, chart);

              // Build an array of colors used in the datasets of the chart
              var datasetColors = chart.data.datasets.map(function(e) {
              return e.backgroundColor;
              datasetColors = datasetColors.flat();

              // Modify the color and hide state of each label
              labelsOriginal.forEach(label => {

              // Change the color to match the dataset
              label.fillStyle = datasetColors[label.index];

            return labelsOriginal;
        onClick: function(mouseEvent, legendItem, legend) {
          // toggle the visibility of the dataset from what it currently is
          ).hidden = legend.chart.isDatasetVisible(legendItem.datasetIndex);
      tooltip: {
        callbacks: {
          label: function(context) {
            const labelIndex = (context.datasetIndex * 2) + context.dataIndex;
            return context.chart.data.labels[labelIndex] + ': ' + context.formattedValue;


<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="style.css">
    <title>Redmine Monitor</title>
    <div class="container">
        <canvas id="multie-pie-chart" height="200" width="200"></canvas>
            <div class="titles">
                <h3>Ziel: 800 Stunden</h3>
                <h3>Monat: September</h3>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<script src="script.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>


Source: JavaSript – Stack Overflow

Categories: NewsTags: , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *