You can use D3 for pivoting. It has a .nest() function lets you group data elements by the specified key.
HTML
<div>
<table id="myTable"></table>
</div>
JS
var dataArray = [];
dataArray.push({
"STATE": "FL",
"YEAR": 2018,
"MONTH": 1,
"SALES": 100
});
dataArray.push({
"STATE": "FL",
"YEAR": 2018,
"MONTH": 2,
"SALES": 200
});
dataArray.push({
"STATE": "FL",
"YEAR": 2018,
"MONTH": 3,
"SALES": 250
});
dataArray.push({
"STATE": "FL",
"YEAR": 2019,
"MONTH": 1,
"SALES": 200
});
dataArray.push({
"STATE": "FL",
"YEAR": 2019,
"MONTH": 2,
"SALES": 225
});
dataArray.push({
"STATE": "FL",
"YEAR": 2019,
"MONTH": 3,
"SALES": 175
});
dataArray.push({
"STATE": "TX",
"YEAR": 2018,
"MONTH": 1,
"SALES": 300
});
dataArray.push({
"STATE": "TX",
"YEAR": 2018,
"MONTH": 2,
"SALES": 350
});
dataArray.push({
"STATE": "TX",
"YEAR": 2018,
"MONTH": 3,
"SALES": 280
});
dataArray.push({
"STATE": "LA",
"YEAR": 2017,
"MONTH": 2,
"SALES": 100
});
dataArray.push({
"STATE": "LA",
"YEAR": 2017,
"MONTH": 3,
"SALES": 150
});
dataArray.push({
"STATE": "NM",
"YEAR": 2016,
"MONTH": 2,
"SALES": 300
})
//Sort the data array
dataArray = dataArray.sort(function(a, b) {
return (a['YEAR'] == b['YEAR'] ? ((a['MONTH'] == b['MONTH']) ? ((a['STATE'] > b['STATE']) ? 1 : -1) : (a['MONTH'] - b['MONTH'])) : (a['YEAR'] - b['YEAR']))
});
//Nesting for the Years and Months headers i.e. group by Year and then Month
var nestedArrayForHeaders = d3.nest()
.key(d => d['YEAR'])
.key(d => d['MONTH'])
.entries(dataArray);
//Nesting for the data i.e. group by STATE
var nestedArrayForData = d3.nest()
.key(d => d['STATE'])
.entries(dataArray);
var yearsRow = $('<tr></tr>');
var monthsRow = $('<tr></tr>');
$(yearsRow).append($('<td></td>').addClass('rowHeader').text('Year'));
$(monthsRow).append($('<td></td>').addClass('rowHeader').text('Month'));
/*START: Rendering the Years and Months rows*/
nestedArrayForHeaders.forEach(function(yearObj) {
yearObj['values'].forEach(function(monthObj) {
$(yearsRow).append($('<td></td>').addClass('columnHeader').text(yearObj['key']));
$(monthsRow).append($('<td></td>').addClass('columnHeader').text(monthObj['key']));
});
$('#myTable').append(yearsRow);
$('#myTable').append(monthsRow);
});
/*END: Rendering the Years and Months rows*/
/*START: Rendering the State rows*/
nestedArrayForData.forEach(function(stateObj){
var stateRow = $('<tr></tr>');
$(stateRow).append($('<td></td>').addClass('rowHeader').text(stateObj['key']));
nestedArrayForHeaders.forEach(function(yearObj) {
yearObj['values'].forEach(function(monthObj) {
var currDataObj = stateObj['values'].find(d=>{return d['YEAR']==yearObj['key'] && d['MONTH']==monthObj['key']});
if(currDataObj){
$(stateRow).append($('<td></td>').text(currDataObj['SALES']));
}
else{
$(stateRow).append($('<td></td>').text('-'));
}
});
});
$('#myTable').append(stateRow);
});
/*END: Rendering the State rows*/
CSS:
body {
padding: 20px;
}
#myTable{
border-collapse: collapse;
}
#myTable td{
border: 1px solid black;
border-collapse: collapse;
color: black;
padding:4px;
text-align: center;
}
#myTable td.rowHeader{
color: red;
}
#myTable td.columnHeader{
color: blue;
}
You can play around with it [here][1].
[1]: http://jsfiddle.net/bn4qvkd9/74/