Home > database >  How do I create a highchart from datatables?
How do I create a highchart from datatables?

Time:12-08

I have the following datatable using highcharts. I searched the datatables blog (enter image description here

$(document).ready(function() {

  var tableData = [];
  var tableCategories = [];

  var table = $("#example1").DataTable({
    initComplete: function(settings, json) {
      let api = new $.fn.dataTable.Api(settings);

      // get the seris data as an array of numbers from the table row data:
      api.rows().data().toArray()[0].forEach(function(element, index) {
        if (index > 0) {
          tableData.push(parseFloat(element.replace(/,/g, '')));
        }
      });

      // get the x-axis caregories from the table headings:
      api.columns().header().toArray().forEach(function(element, index) {
        if (index > 0) {
          tableCategories.push($(element).html());
        }
      });

        
    }
  });

  var myChart = Highcharts.chart("container", {
    chart: {
      type: "column"
    },
    title: {
      text: "Test Data"
    },
    xAxis: {
      categories: tableCategories
    },
    series: [{
      data: tableData
    }]
  });

});
<!DOCTYPE html>
<html>
  <head>
    <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>

    <link href="https://nightly.datatables.net/css/jquery.dataTables.css" rel="stylesheet" type="text/css" />
    <script src="https://nightly.datatables.net/js/jquery.dataTables.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
    <meta charset=utf-8 />
    <title>DataTables - JS Bin</title>
  </head>
  <body>
    <div id="container" style="width:100%; height:400px;"></div>
    <div >
      <table id="example1"  width="100%">
        <thead>
          <tr>
             <th>Year</th>
            <th>Data1</th>
            <th>Data2</th>
            <th>Data3</th>
            <th>Total</th>
            
          </tr>
        </thead>

        <tfoot>
          <tr>
            <th>Year</th>
            <th>Data1</th>
            <th>Data2</th>
            <th>Data3</th>
            <th>Total</th>
           
          </tr>
        </tfoot>

        <tbody>
          <tr>
<td scope="row" style=" text-align: center;">2015</td>
<td style=" text-align: center;">10,000</td>
<td style=" text-align: center;">19,000</td>
<td style=" text-align: center;">5000</td>
<td style=" text-align: center;">5000</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2016</td>
<td style=" text-align: center;">22,142</td>
<td style=" text-align: center;">18,481</td>
<td style=" text-align: center;">877</td>
<td style=" text-align: center;">41,500</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2017</td>
<td style=" text-align: center;">20,038</td>
<td style=" text-align: center;">16,700</td>
<td style=" text-align: center;">658</td>
<td style=" text-align: center;">37,396</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2018</td>
<td style=" text-align: center;">22,195</td>
<td style=" text-align: center;">16,489</td>
<td style=" text-align: center;">796</td>
<td style=" text-align: center;">39,480</td>
</tr>

<tr>
<td scope="row" style=" text-align: center;">2019</td>
<td style=" text-align: center;">21,836</td>
<td style=" text-align: center;">13,958</td>
<td style=" text-align: center;">1,239</td>
<td style=" text-align: center;">37,033</td>
</tr>
</table>

CodePudding user response:

You can model your chart on the Highcharts basic column demo - and you can see the source code for that demo here.

That demo shows you the structure of the data which Highcharts needs, to draw the graph you want.

In your case, that structure means you need the following HighChart series, using the data in your HTML table

series: [{
    name: "2015",
    data: [10000, 19000, 5000]
}, {
    name: "2016",
    data: [22142, 18481, 877]
}, {
    name: "2017",
    data: [20038, 16700, 658]
}, {
    name: "2018",
    data: [22195, 16489, 796]
}, {
    name: "2019",
    data: [21836, 13958, 1239]
}]

You can try this for yourself by using the above hard-coded data in your HighChart - ignoring the DataTable.


Now, the task is to extract and transform your DataTable data into the above structure, so it can be used by the chart.

Your current code only reads the first row of data - see that [0]:

api.rows().data().toArray()[0].forEach( ... )

So, you need to remove that [0].

Then you can create the transformation logic.

In the below example, there are 2 loops - the outer loop processes each row, and the inner loop processes each cell in the current row (ignoring the final cell, which contains totals):

let rows = api.rows().data().toArray();
rows.forEach(function (row) {
  group = { name: '', data: [] };
  row.forEach(function (cell, idx) {
    if (idx == 0) { // the first cell in each row is the year
      group.name = cell;
    } else if (idx < row.length -1) { // ignore the last cell in each row
      group.data.push( parseFloat(cell.replace(/,/g, '')) );
    }
  });
  allSeriesData.push( group );
})

This creates an object { name: '', data: [] } for each row - and then collects all those objects into the series data.

The final code:

$(document).ready(function() {

  var allSeriesData = [];
  var categories = [];

  var table = $("#example1").DataTable({
    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);
      });  
    }
  });

  var myChart = Highcharts.chart("container", {
    chart: {
      type: "column"
    },
    title: {
      text: "Test Data"
    },
    xAxis: {
      categories: categories
    },
    series: allSeriesData
  });

});
<!DOCTYPE html>
<html>

<head>
  <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>

  <link href="https://nightly.datatables.net/css/jquery.dataTables.css" rel="stylesheet" type="text/css" />
  <script src="https://nightly.datatables.net/js/jquery.dataTables.js"></script>
  <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>

  <link href="https://nightly.datatables.net/css/jquery.dataTables.css" rel="stylesheet" type="text/css" />
  <script src="https://nightly.datatables.net/js/jquery.dataTables.js"></script>
  <script src="https://code.highcharts.com/highcharts.js"></script>
  <meta charset=utf-8 />

</head>

<body>

  <div id="container" style=" width: 100%; height: 400px;"></div>

  <div >

    <table id="example1"  width="100%">
      <thead>
        <tr>
          <th>Year</th>
          <th>Data1</th>
          <th>Data2</th>
          <th>Data3</th>
          <th>Total</th>

        </tr>
      </thead>

      <tfoot>
        <tr>
          <th>Year</th>
          <th>Data1</th>
          <th>Data2</th>
          <th>Data3</th>
          <th>Total</th>

        </tr>
      </tfoot>

      <tbody>
        <tr>
          <td scope="row" style=" text-align: center;">2015</td>
          <td style=" text-align: center;">10,000</td>
          <td style=" text-align: center;">19,000</td>
          <td style=" text-align: center;">5000</td>
          <td style=" text-align: center;">5000</td>
        </tr>

        <tr>
          <td scope="row" style=" text-align: center;">2016</td>
          <td style=" text-align: center;">22,142</td>
          <td style=" text-align: center;">18,481</td>
          <td style=" text-align: center;">877</td>
          <td style=" text-align: center;">41,500</td>
        </tr>

        <tr>
          <td scope="row" style=" text-align: center;">2017</td>
          <td style=" text-align: center;">20,038</td>
          <td style=" text-align: center;">16,700</td>
          <td style=" text-align: center;">658</td>
          <td style=" text-align: center;">37,396</td>
        </tr>

        <tr>
          <td scope="row" style=" text-align: center;">2018</td>
          <td style=" text-align: center;">22,195</td>
          <td style=" text-align: center;">16,489</td>
          <td style=" text-align: center;">796</td>
          <td style=" text-align: center;">39,480</td>
        </tr>

        <tr>
          <td scope="row" style=" text-align: center;">2019</td>
          <td style=" text-align: center;">21,836</td>
          <td style=" text-align: center;">13,958</td>
          <td style=" text-align: center;">1,239</td>
          <td style=" text-align: center;">37,033</td>
        </tr>
    </table>



    </tbody>

    </table>


I recommend you take the above code and use console.log( ... ) statements to help with any lines which may be unclear.

You are already using api.rows().data().toArray() in your question to access the table's data - most of the remaining logic is JavaScript to re-arrange that data into the structure needed by HighCharts.

  • Related