JSFiddle - React, Tailwind, and code Playground
by neonDog
HTML
<div class="test">
</div>
SCSS
body, html { padding:0; margin: 0; background: #222; }
.neon-heatmap {
--color-dark-blue: #1E2537;
--color-light-gray: #ECECEC;
--color-light-green: rgb(225,229,162);
--color-dark-green: rgb(57,132,162);
//font-family: -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
font-size: 11px;
&__row {
display: flex;
flex-wrap: wrap;
height: 50px;
}
&__cell {
display: flex;
justify-content: center;
width: 100%;
flex: 1;
justify-items: center;
align-items: center;
color: rgba(255,255,255,0.8);
font-weight: 900;
//background: red;
overflow: hidden;
white-space: nowrap;
border:1px #44444444 solid;
&:hover {
opacity: 0.8;
cursor: pointer;
}
}
&__header {
.neon-heatmap__cell {
color: rgb(153,153,153);
background: var(--color-light-gray);
font-weight: 500;
border-color: transparent;
}
}
&__left-header {
display: flex;
width: 100px;
align-items: center;
justify-content: center;
background: var(--color-dark-blue);
color: white;
font-weight: 600;
&:hover {
opacity: 0.6;
cursor: pointer;
}
}
}
JavaScript
const heatMapColorforValue = function(value, hue=0, invert=false) {
//Invert?
let l = invert ? 100 - value : value;
return `hsl(${hue}, 100%, ${l}%)`;
}
const normalizeArray = function(min, max) {
const delta = max - min;
return function (val) {
return (val - min) / delta;
};
}
//console.log([0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 25].map(normalizeArray(0, 25)));
const normalize = function(val, max, min) { return (val - min) / (max - min); }
class NeonHeatmap {
constructor(container, settings={}) {
const defaults = {
x: 24,
y: ['S','M','T','W','T','F','S'],
render: {
y: (value) => value,
x: (value) => value + ':00',
cell: (value) => value
//columnRender:(value) => value
},
invert: false,
hue:-90,
scaleOffset: 50
};
this.options = Object.assign({}, defaults, settings);
this.container = container;
this.cells = []; //Flat
this.cellsMulti = []; //Multidimensional
this.generate();
}
outputFlat(data, max=255, min=0) {
const renderFn = this.options.render.cell;
const hue = this.options.hue;
const invert = this.options.invert;
const scaleOffset = this.options.scaleOffset;
for (let i=0, l=data.length; i < l; i++) {
const d = data[i];
const cell = this.cells[i];
const isValue = typeof d === 'number';
//Todo: normalize the data
const n = normalize(isValue ? d : d.value, max, min);
cell.style.background = heatMapColorforValue(n * 255 * scaleOffset, hue, invert);
cell.innerHTML = renderFn(d, cell);
}
}
generate() {
const table = document.createElement('div');
table.className = 'neon-heatmap';
table.append(this.generateRows());
this.container.appendChild(table);
}
generateRows() {
const axis = this.options.y;
const isArray = Array.isArray(axis);
const render = this.options.render.y;
const axis2...