d3.js table
- load data from json
- render html table with selectable and sortable columns
license: mit |
{ | |
"rows": [ | |
{ | |
"alpha3": "BRN", | |
"name": "Brunei", | |
"alpha2": "BN", | |
"numeric": 99 | |
}, | |
{ | |
"alpha3": "KHM", | |
"name": "Cambodia", | |
"alpha2": "KH", | |
"numeric": 116 | |
}, | |
{ | |
"alpha3": "IDN", | |
"name": "Indonesia", | |
"alpha2": "ID", | |
"numeric": 360 | |
}, | |
{ | |
"alpha3": "LAO", | |
"name": "Laos", | |
"alpha2": "LA", | |
"numeric": 418 | |
}, | |
{ | |
"alpha3": "MYS", | |
"name": "Malaysia", | |
"alpha2": "MY", | |
"numeric": 458 | |
}, | |
{ | |
"alpha3": "MMR", | |
"name": "Myanmar", | |
"alpha2": "MM", | |
"numeric": 458 | |
}, | |
{ | |
"alpha3": "PHL", | |
"name": "Phillippines", | |
"alpha2": "PH", | |
"numeric": 608 | |
}, | |
{ | |
"alpha3": "SGP", | |
"name": "Singapore", | |
"alpha2": "SG", | |
"numeric": 702 | |
}, | |
{ | |
"alpha3": "THA", | |
"name": "Thailand", | |
"alpha2": "TH", | |
"numeric": 764 | |
}, | |
{ | |
"alpha3": "TIL", | |
"name": "Timor Leste", | |
"alpha2": "TL", | |
"numeric": 603 | |
}, | |
{ | |
"alpha3": "VNM", | |
"name": "Vietnam", | |
"alpha2": "VN", | |
"numeric": 704 | |
} | |
] | |
} |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<html> | |
<head> | |
<title>d3.js table</title> | |
<script type="text/javascript" src="//d3js.org/d3.v7.min.js"></script> | |
<style> | |
body { | |
font-family:sans-serif; | |
} | |
table { | |
margin:12px; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
d3.json('data.json') | |
.then((json)=>{ | |
console.log('json', json); | |
d3.select('body') | |
.selectAll('.root').data([json]) | |
.join('div').attr('class','root') | |
.call(sel=>{ | |
sel.selectAll('h1').data(d=>[d]) | |
.join('h1') | |
.html('select & sort columns') | |
sel.selectAll('form').data(d=>[d]) | |
.join('form') | |
.selectAll('.inputs').data(d=>Object.entries(d.rows[0]).map(d=>d[0])) | |
.join('div').attr('class','inputs') | |
.call(sel=>{ | |
sel.selectAll('input').data(d=>[d]) | |
.join('input') | |
.attr('type','checkbox') | |
.attr('checked', 'checked') | |
.on('input', function(e,d){ | |
d3.select('.root').call(renderTable); | |
}) | |
.html(d=>d) | |
sel.selectAll('span').data(d=>[d]) | |
.join('span') | |
.html(d=>d) | |
}); | |
sel.call(renderTable) | |
function renderTable(sel) { | |
sel.selectAll('table').data(d=>[d]) | |
.join('table') | |
.call(sel=>{ | |
sel.selectAll('thead').data(d=>[d]) | |
.join('thead') | |
.selectAll('tr').data(d=>[d]) | |
.join('tr') | |
.selectAll('th').data(d=>{ | |
return Object.entries(d.rows[0]) | |
.filter(d=>d3.selectAll('input:checked').data().includes(d[0])) | |
.map(d=>d[0]) | |
}) | |
.join('th') | |
.style('cursor','pointer') | |
.on('click', function(e,d){ | |
let sel = d3.select(this), | |
order_descending = !sel.classed('order_descending'); | |
sel.classed('order_descending', order_descending); | |
d3.select(this.closest('table')) | |
.select('tbody') | |
.selectAll('tr') | |
.sort((a,b)=>order_descending | |
? d3.descending(a[d],b[d]) | |
: d3.ascending(a[d],b[d]) | |
) | |
}) | |
.html(d=>d) | |
sel.selectAll('tbody').data(d=>[d]).join('tbody') | |
.selectAll('tr').data(d=>d.rows).join('tr') | |
.selectAll('td').data(d=>{ | |
return Object.entries(d) | |
.filter(d=>d3.selectAll('input:checked').data().includes(d[0])) | |
.map(d=>d[1]) | |
}).join('td') | |
.html(d=>d) | |
}); | |
} | |
}); | |
}); | |
</script> | |
</body> | |