Skip to content

Instantly share code, notes, and snippets.

@davebarnwell
Last active October 24, 2022 14:35
Show Gist options
  • Save davebarnwell/cb786db3593f49a443df42ecef51759c to your computer and use it in GitHub Desktop.
Save davebarnwell/cb786db3593f49a443df42ecef51759c to your computer and use it in GitHub Desktop.
add bar graph as background to html table column
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML table with bar graph background in one or more columns</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="grid">
<!-- ROW -->
<div>
<h1>Default style &amp;<br>value in td is float or int</h1>
<!-- data-barcol attribute specifies column with numbers in TBODY -->
<table data-barcol="2">
<thead>
<tr>
<th class="text-start">Fruit</th>
<th class="text-end">Qty</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td class="text-end">83</td>
</tr>
<tr>
<td>Pear</td>
<td class="text-end">151</td>
</tr>
<tr>
<td>Strawberry</td>
<td class="text-end">15</td>
</tr>
<tr>
<td>Melon</td>
<td class="text-end">17</td>
</tr>
<tr>
<td>Grape</td>
<td class="text-end">30</td>
</tr>
<tr>
<td>Orange</td>
<td class="text-end">90</td>
</tr>
<tr>
<td>Bannana</td>
<td class="text-end">115</td>
</tr>
<tr>
<td>Kiwi</td>
<td class="text-end">135</td>
</tr>
<tr>
<td>Star</td>
<td class="text-end">2</td>
</tr>
<tr>
<td>Mango</td>
<td class="text-end">50</td>
</tr>
</tbody>
</table>
</div>
<!-- ROW -->
<div>
<h1>Override color &amp;<br>value in td data attribute</h1>
<table data-barcol="2">
<thead>
<tr>
<th class="text-start">Fruit</th>
<th class="text-end">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td class="text-end" data-value="83">$83.00</td>
</tr>
<tr>
<td>Pear</td>
<!-- value in data-value="" -->
<td class="text-end" data-value="151.8">$151.80</td>
</tr>
<tr>
<td>Strawberry</td>
<td class="text-end" data-value="15.2">$15.20</td>
</tr>
<tr>
<td>Melon</td>
<td class="text-end" data-value="17.2">$17.20</td>
</tr>
<tr>
<td>Grape</td>
<td class="text-end" data-value="30">$30.00</td>
</tr>
<tr>
<td>Orange</td>
<td class="text-end" data-value="90">$90.00</td>
</tr>
<tr>
<td>Bannana</td>
<td class="text-end" data-value="115">$115.00</td>
</tr>
<tr>
<td>Kiwi</td>
<td class="text-end" data-value="135">$135.00</td>
</tr>
<tr>
<td>Star</td>
<td class="text-end" data-value="2">$2.00</td>
</tr>
<tr>
<td>Mango</td>
<td class="text-end" data-value="50">$50.00</td>
</tr>
</tbody>
</table>
</div>
<!-- ROW -->
<div>
<h1>Color via heatmap function &amp;<br> specify multiple columns</h1>
<!-- data-barcol attribute is CSV for cols to add bar background to -->
<table data-barcol="2,3">
<thead>
<tr>
<th class="text-start">Fruit</th>
<th class="text-end">Qty</th>
<th class="text-end">% Extinction</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td class="text-end">83</td>
<td class="text-end">20</td>
</tr>
<tr>
<td>Pear</td>
<td class="text-end">151.8</td>
<td class="text-end">10</td>
</tr>
<tr>
<td>Strawberry</td>
<td class="text-end">15.2</td>
<td class="text-end">10</td>
</tr>
<tr>
<td>Melon</td>
<td class="text-end">17.2</td>
<td class="text-end">20</td>
</tr>
<tr>
<td>Grape</td>
<td class="text-end">30</td>
<td class="text-end">10</td>
</tr>
<tr>
<td>Orange</td>
<td class="text-end">90</td>
<td class="text-end">10</td>
</tr>
<tr>
<td>Bannana</td>
<td class="text-end">115</td>
<td class="text-end">80</td>
</tr>
<tr>
<td>Kiwi</td>
<td class="text-end">135</td>
<td class="text-end">20</td>
</tr>
<tr>
<td>Star</td>
<td class="text-end">2</td>
<td class="text-end">0</td>
</tr>
<tr>
<td>Mango</td>
<td class="text-end">50</td>
<td class="text-end">0</td>
</tr>
</tbody>
</table>
</div>
</div>
<p class="text-center">bar length is percentage the current value is of max value in the column</p>
<script defer src="main.js"></script>
</body>
</html>
/* NO CSS required to use this, purely for styling of this example */
:root {
--bg-row-color: #dedede;
}
body {
font-family: sans-serif;
background-color: #f0f0f0;
}
.text-center {
text-align: center;
}
.grid {
display: grid;
column-gap: 1rem;
grid-template-columns: 1fr 1fr 1fr;
justify-items: center;
}
h1 {
font-size: 1.5rem;
}
table {
border-spacing: 0.25rem;
border: solid 1px var(--bg-row-color);
}
thead th {
min-width: 100px;
}
th,
td {
padding: 0.25rem;
}
tr:nth-child(even) {
/* Works with striped tables */
background-color: var(--bg-row-color);
}
.text-start {
text-align: start;
}
.text-end {
text-align: end;
}
/**
The function to call that adds the bars
*/
// TODO option for bars to grow from right, currently always the left of td
// TODO handle nagtive numbers e.g. min -10 to max 10, bar is percent of 20
// TODO postive and negative numbers create bars in opposite directions from a common offset origin
function addTableDataBar(tableElm, opts = {}) {
const options = {
color: "rgba(179, 255, 201,1)" /* CSS color */,
dataAttr: null /* look for data-{attribute} for value on table cell */,
...opts
};
let cols = tableElm.dataset.barcol.split(",");
cols = cols.map((v) => parseInt(v, 10));
cols.forEach((col) => {
// get elms
const dataElms = tableElm.querySelectorAll(`tbody tr td:nth-child(${col})`);
// get values
const values = [];
let max = 0;
dataElms.forEach(function (elm, i) {
const row = {
elm: elm,
value: parseFloat(
options.dataAttr != null
? elm.dataset[options.dataAttr]
: elm.innerHTML
),
percent: null
};
max = Math.max(max, row.value);
values.push(row);
});
// Calc percent
values.forEach(function (row) {
row.percent = (row.value / max) * 100;
});
// add background bar
values.forEach(function (row) {
// set background bar
const color =
typeof options.color === "function"
? options.color(row.percent / 100)
: options.color;
if (row.percent !== 0) {
row.elm.style.background = `linear-gradient(90deg, ${color} 0%, ${color} ${row.percent}%, rgba(0,0,0,0) ${row.percent}%)`;
}
});
});
}
/**
* Call function on table
*/
// Get the tables value of data-graphcol attribute specifies column to style
const tables = document.querySelectorAll("[data-barcol]");
// 1st table use default options
addTableDataBar(tables[0]);
// 2nd table use custom color and use value from data-value="" attribute on td rather than td content
addTableDataBar(tables[1], {
color: "rgba(237,151,187,1)",
dataAttr: "value"
});
// 3rd table use heatmap colors by passing a function, and specify more than one column via data-graphcol="" on table
const heatMapColorforValue = (value) => {
/** 0=blue, 0.25=cyan, 0.5=green, 0.75=yellow, 1=red */
const h = (1.0 - (value < 1 ? value : 1)) * 240;
return `hsl(${h}, 100%, 75%)`;
};
addTableDataBar(tables[2], {
color: heatMapColorforValue
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment