pivot table gird with sticky head label
by Maxim_Wolf
HTML
<div class='container'>
<div class="column-headers">
headers
</div>
<div class="row-labels">
labels
</div>
<div class="data">
data
</div>
<div class="blank">
</div>
</div>
CSS
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
}
.table__row {
transition: background-color 0.3s ease;
}
.table__row:hover{
background-color:rgba(111, 138, 231, 0.5);
}
.container {
display: grid;
grid-template-columns: 10em 1fr;
grid-template-rows: 2em 1fr;
gap: 0.1em 0.1em;
grid-auto-flow: row;
justify-content: start;
align-content: start;
justify-items: start;
align-items: start;
grid-template-areas:
"b h"
"l d";
}
.container {
background: linear-gradient(45deg, rgba(255, 255, 0, 1) 0%, rgba(255, 255, 255, 0.5) 100%);
margin: 0.2em;
width:min-content;
}
.blank {
display: inline-block;
width: 10em;
height: 2em;
background: magenta;
position: sticky;
left: 0;
top: 0;
/*z-index: 1;*/
}
.column-headers {
display: inline-block;
grid-area: h;
height: 2em;
position: sticky;
top: 0;
background: linear-gradient(90deg, rgba(0, 255, 255, 1) 0%, rgba(255, 255, 255, 0.5) 100%);
}
.row-labels {
grid-area: l;
position: sticky;
background: rgb(127, 208, 255);
background: linear-gradient(180deg, rgba(127, 208, 255, 1) 0%, rgba(255, 255, 255, 0.5) 100%);
left: 0;
width: 10em;
}
.data {
grid-area: d;
background: rgb(255, 127, 147);
background: linear-gradient(45deg, rgba(255, 127, 147, 1) 0%, rgba(255, 255, 255, 0.5) 100%);
}
JavaScript
const COLUMN_COUNT = 20;
const ROW_COUNT = 37;
const MIN_WIDTH = 2.5;
const MAX_WIDTH = 20;
const columns = Array.from({
length: COLUMN_COUNT
}).map((_, ix) => {
const columnName = `Column ${ix}`;
return {
label: columnName,
format: (r) => r[columnName],
width: MIN_WIDTH + Math.floor(Math.random() * (MAX_WIDTH - MIN_WIDTH)),
}
});
const data = Array.from({
length: ROW_COUNT
}).map((_, r) => {
return columns.reduce((a, b) => ({
...a,
[b.label]: `Row: ${r}, ${b.label}`
}), {});
})
const createElement = (tag, props = {}, children = []) => {
const rv =
Object.keys(props).filter((key) => key !== 'style').reduce((a, b) => {
a[b] = props[b]
return a;
}, document.createElement(tag));
const style = props.style;
if (typeof style === 'object' && style !== null) {
Object.keys(style).forEach((s) => rv.style[s] = style[s]);
}
return children.reduce((a, c) => {
a.append(c);
return a;
}, rv)
}
const render = (container, content) => {
container.innerHTML = '';
container.append(content)
}
const cellContent = (r, column) => {
return createElement('div', {
style: {
'width': `${column.width}em`,
overflowX: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
},
},
[column.format(r)],
)
}
const cell = (r, column) => {
return createElement('td', {
'style': {},
title: column.format(r),
},
[cellContent(r, column)],
);
}
const row = (r, columns) => {
return createElement('tr', {className:'table__row'}, columns.map((column) => cell(r, column)));
}
const tbody = (data, columns) => {
return createElement('tbody', {}, data.map((r) => row(r, columns)));
}
const table = (children) => {
return createElement('table', {
style: {
width: '100%'
}
}, children)
}
const df = document.createDocumentFragment();
const headRow = (columns) => {
return createElement('tr', {}, columns.map((column) => cell({}, {
...