Skip to content

Syncing chart data with table/grid

This tutorial will look at ways on how we can grab chart data and display it in an HTML table. We will then build on it to enhance for display in a Grid component. Finally, we’ll make chart data sync up with editable grid.

Since amCharts is not in the data grid business, we will be relying on 3rd parties for this specific functionality.

We will be looking at different libraries and solutions, just to give an idea on how it can be universally used.

Let’s use a common scenario char - an XYChart with date-based data and multi-series:

Open in CodePen

The first step in everything we will do in this tutorial is getting chart data into an HTML table.

One way would be to grab chart.data, iterate through it, and build HTML for it which we would then plop onto our document.

Doable, and quite easy, but we have a better solution: using built-in export API.

Among other things it supports exporting data as an HTML table markup, essentially doing all the job for us.

The export function that will give us that is called chart.exporting.getHTML().

This method returns a Promise, which means it’s asynchronous, requiring us to either use await or then() syntax:

chart.exporting.getHTML("html", {
addColumnNames: true
}, false).then(function(html) {
// html will contain fully formatted markup for data in a <table>
});

Now that we know how to grab chart’s data as a <table>, all we need to do is to plop it onto our document.

Let’s put our table into a separate <div> so that we can style and size it separately from the chart.

<div id="chartdiv"></div>
<div id="chartdata"></div>

Let’s also add very basic styling, to limit height of the resulting table.

#chartdata {
max-height: 400px;
overflow: auto;
}
#chartdata table {
width: 100%;
}

Now that we have our data container, let’s make the magic happen.

One thing before we start: when chart is created it hasn’t had a chance to parse it’s data yet.

Let’s use chart’s datavalidated event, to start our export instead.

This events kicks in whenever data is fully parsed and ready to be used.

An added bonus is that it will automatically update our table if/whenever chart’s data is updated, so it’s basically a healthy thing to do.

chart.events.on("datavalidated", function(ev) {
chart.exporting.getHTML("html", {
addColumnNames: true
}, false).then(function(html) {
let div = document.getElementById("chartdata");
div.innerHTML = html;
});
});

Let’s see how this works in real life:

Open in CodePen

Looks a bit dull, doesn’t it?

By default, <table> comes without any styling or even class names attached.

However, we can pass in class names to be attached to each of the elements of the table, via format options (second parameter to the getHTML() function):

Tag Option
<table> tableClass
<tr> rowClass
<th> and <td> cellClass

Let’s class-up our table for use with Bootstrap.

chart.events.on("datavalidated", function(ev) {
chart.exporting.getHTML("html", {
addColumnNames: true,
tableClass: "table table-striped table-hover table-sm"
}, false).then(function(html) {
let div = document.getElementById("chartdata");
div.innerHTML = html;
});
});

Let’s see how it looks like now:

Open in CodePen

Let’s keep on moving. Let’s turn our static table into a fully-featured grid.

As there are hundreds, or even thousands, of grid libraries out there, let’s explore ones that we like best.

DataTables is a free jQuery-based grid plugin. It can instantly turn a regular <table> element into a searchable, sortable table with paging and other neat features.

We don’t need to do much for it:

  1. Include jQuery, as well as CSS and JS for DataTables.
  2. Turn our plain table into a DataTable: $("#chartdata table").DataTable().
chart.events.on("datavalidated", function(ev) {
chart.exporting.getHTML("html", {
addColumnNames: true
}, false).then(function(html) {
let div = document.getElementById("chartdata");
div.innerHTML = html;
$("#chartdata table").DataTable();
});
});
Open in CodePen

DataGridXL is a no-nonsense light and super fast grid library, that does not require any additional dependencies, like jQuery.

It’s also allows editing any data displayed in it. We will explore this as well, to give it a two way communication between chart and grid.

Unlike DataTables we explored before, DataGridXL does not support turning a <table> into grid.

Instead it will accept data in a JavaScript array, which means we can skip the whole getHTML() step, and just dump chart’s data to the grid:

chart.events.on("datavalidated", function(ev) {
let grid = new DataGridXL("chartdata", {
data: chart.data
});
});

Live example:

Open in CodePen

DataGridXL allows editing value sin any cell.

Whenever it happens it triggers a cellvaluechange event.

At that point we could just use grid’s getData() method, then set chart’s data to it.

However, that would be very inneficient.

The parameter passed into handler function of cellvaluechange contains all the new values as well as identifiers of cells that were chainged.

Using those, we can modify items in chart’s data array individually, then call its invalidateRawData() method to take in just the changed values:

chart.events.on("datavalidated", function(ev) {
let grid = new DataGridXL("chartdata", {
data: chart.data
});
grid.events.on("cellvaluechange", function(ev) {
for(let r = 0; r < ev.rowIds.length; r++) {
var row = chart.data[ev.rowIds[r]];
for(let c = 0; c < ev.colIds.length; c++) {
var col = grid.getColFromStore(ev.colIds[c]).field;
row[col] = ev.changes[r][c];
}
}
chart.invalidateRawData();
});
});

Go ahead, try changing values in the grid:

Open in CodePen

Let’s add one final touch: a switch which would toggle data table on and off.

amCharts 4 has a perfect control for it: SwitchButton.

Let add one to our chart, as well as attach an event that would toggle data table:

// A button to toggle the data table
let button = chart.createChild(am4core.SwitchButton);
button.align = "right";
button.leftLabel.text = "Show data";
button.isActive = false;
// Set toggling of data table
button.events.on("toggled", function(ev) {
let div = document.getElementById("chartdata");
if (button.isActive) {
div.style.display = "block";
}
else {
div.style.display = "none";
}
});
Open in CodePen