Published
Edited
Oct 26, 2020
Importers
Insert cell
md`# Table Utils`
Insert cell
d3 = require('d3@5')
Insert cell
import { formatNumber, toTitleCase } from '@nuuuwan/string-utils'
Insert cell
import { addDefaults } from '@nuuuwan/option-utils'
Insert cell
DEFAULT_OPTIONS = Object({
fontFamily: 'Futura',
tableBorderColor: '#eee',
tableHeaderBackgroundColor: '#ddd',
lastRowTotalBackgroundColor: '#eee'
})
Insert cell
function drawTable(dataList, options) {
options = addDefaults(options, DEFAULT_OPTIONS);
options = addDefaults(options, {
caption: 'No Label',
classTable: '',
fieldToClass: {},
isLastRowTotal: false
});
options = addDefaults(options, {
fGetClass: function(iRow, fieldName, datum) {
let className = options.fieldToClass[fieldName];
if (options.isLastRowTotal && iRow === dataList.length - 1) {
className += ' total';
}
return className;
}
});
options = addDefaults(options, {
fGetCellValue: function(iRow, fieldName, datum) {
let className = options.fGetClass(iRow, fieldName, datum);

const v = datum[fieldName];
if (v === undefined) {
return '';
}
switch (className) {
case 'number':
return formatNumber(v);
default:
return v.toLocaleString();
}
}
});
const fieldNameList = Object.keys(dataList[0]);

const table = document.createElement('table');

const trHeader = document.createElement('tr');
fieldNameList.map(function(fieldName) {
const th = document.createElement('th');
th.appendChild(
document.createTextNode(toTitleCase(fieldName.replace(/_/g, ' ')))
);
trHeader.appendChild(th);
});
table.appendChild(trHeader);

dataList.map(function(datum, i) {
const tr = document.createElement('tr');
fieldNameList.map(function(fieldName) {
const td = document.createElement('td');
const className = options.fGetClass(i, fieldName, datum);
if (className) {
td.setAttribute('class', className);
}
td.appendChild(
document.createTextNode(options.fGetCellValue(i, fieldName, datum))
);
tr.appendChild(td);
});

table.appendChild(tr);
});

table.appendChild(
document
.createElement('caption')
.appendChild(document.createTextNode('Table: ' + options.caption))
);

return html`
<style>
table {
font-family: ${options.fontFamily};
}

th, td {
border-bottom: 1px solid ${options.tableBorderColor};
padding: 12px;
text-align: left;
}

th {
text-align: center;
}

caption {
font-family: ${options.fontFamily};
font-weight: bold;
text-align: center;
font-size: small;
}

.number, .year {
text-align: right;
color: brown;
font-family: monospace;
}

.total {
font-weight: bold;
}

</style>
${table}
`;
}
Insert cell
drawTable(
[
Object({ name: 'Tom', age: 10, points: 1234 }),
Object({ name: 'Dick', age: 12, points: 853234 }),
Object({ name: 'Harry', age: 14, points: 955 }),
Object({ name: 'Total', age: 123, points: 3333 })
],
{
fieldToClass: { age: 'number', points: 'number' },
isLastRowTotal: true
}
)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more