Chartjs-Creating multiple charts based on dictionary length

0👍

When looking at your data I think that you could start by improving the structure of your data. The reason for this is that the data is the only thing that is different with each chart. So tuning the data to the need of the chart is a great way to make it easier for the frontend to create your charts.

The values and name_param lists are both separate, but they are both linked by their indexes. This could be improved by makes name_param / value groups in a new dictionary. And naming the properties to mirror the settings of the Chart instance will even better, like label and data.

Try to modify your list to the following structure.

{
  labels: [], // Labels remains unchanged.
  datasets: [ // New array with objects.
    {
      label: '', // previously known as name_param
      data: '' // previously known as value
    },
    {
      label: '',
      data: ''
    },
    // ... etc.
  ]
}

This enables you to easily loop over each group in the dataset property and create a new chart for each set. But first you’ll need some helper functions that create the <div>, <canvas> and Chart instances.

First the <div> and <canvas>. The function below creates both the bootstrap column and the canvas element which will be placed inside the DOM.

function createCanvasAndColumn() {
  const column = document.createElement('div');
  div.classList.add('col-sm-4');

  const canvas = document.createElement('canvas');
  canvas.width = 400;
  canvas.height = 400;

  column.append(canvas);
 
  /** 
   * Return both the canvas and the column.
   * The column is needed to append to the row.
   * The canvas is needed to create a chart with.
   */
  return { canvas, column };
}

We don’t need an id attribute as we have a reference to the element already in the canvas constant. The canvas will be appended to the <div>. It then returns an object with a reference to the column (which we need to add to the document) and a reference to the canvas (which we need for the Chart instance).

Now for creating the charts. I’ve kept the changed data structure suggested at the beginning of the answer in mind as how the data should appear in your application, so the following function uses that structure.

const chartsRow = document.getElementById('charts-row');

function createCharts({ labels, datasets }) {
  /**
   * Loop over each item in datasets and create a
   * new chart for each item. Each chart is then returned
   * resulting in an array of Chart instances.
   */
  const charts = datasets.map((dataset) => {
    const { canvas, column } = createCanvasAndColumn();

    const chart = new Chart(canvas, {
      type: 'line',
      data: {
        labels: labels,
        datasets: [{
          ...dataset,
          fill: false
        }]
      }
    });

    // Add column (and canvas) to the row.
    chartsRow.append(column);
    return chart;
  });

  /**
   * Return the charts array. This is not mandatory,
   * but it might come in handy if you'd need to access
   * the Chart instances at some point.
   */
  return charts;
}

This createCharts function expects an object with a labels and dataset key. It loops over the datasets array to create a canvas element per set. That canvas element will then be used to create a new Chart instance. The name and value of each dataset will be used to set the data of that Chart instance.

You may have noticed that the loop is done with map. This will loop over each item in the array and expects a return statement for each item. This will result in a new array being created based on the returned values inside the loop. The charts constant will actually be an array of Chart instances.

Now with these functions in place all you’d have to do is pass the data you’ve received from your Django application into the createCharts function to build the charts.

Make your row easy to select by adding an id attribute. This attribute should have a unique value. In the createCharts snippet above the element is being selected from the document to append the charts with.

<div class='row' id="charts-row">
  <div class='col-sm-12' url-endpoint='{% url "api-data" %}'>
    <h1>Hello World</h1>
  </div>
</div>

From here you call your request and pass the data to your createCharts function, which then loops over the data and creates a chart for each item.

const endpoint = '/api/chart/data/';

$.ajax({
  method: "GET",
  url: endpoint,
  success: function(data) {
    createCharts(data);
  },
  error: function(jqXHR, textStatus, errorThrown) {
    console.log("error");
    console.log(textStatus);
  }
})

Leave a comment