Published
Edited
Apr 22, 2021
Insert cell
Insert cell
t4 = generateTable();
Insert cell
function generateTable() {
const rows = 5;
const cols = 2;
const table = document.createElement('table');
const random = (n) => {
return Math.floor(Math.random() * n) + 1;
}
for(let i=0; i<rows; ++i) {
const row = document.createElement('tr');
const alpha = String.fromCharCode(97 + i).toUpperCase();
for(let x=1; x<=cols; ++x) {
const cell = document.createElement('td');
cell.innerHTML = alpha+x;
const r1 = random(2);
const r2 = random(2);
r1 > 1 && cell.setAttribute('colspan', r1);
r2 > 1 && cell.setAttribute('rowspan', r2);
row.append(cell);
}
table.append(row);
}
return table;
}
Insert cell
t3 = html`
<table>
<tr>
<td rowspan=3>A</td>
<td colspan=2>B</td>
<td rowspan=3>C</td>
</tr>
<tr>
<td colspan=2>where</td>
</tr>
</table>
`
Insert cell
t2 = html`
<table>
<tr>
<td rowspan=3>A</td>
<td colspan=2>B</td>
<td rowspan=3>C</td>
</tr>
<tr><td colspan=2>where</td></tr>
</table>
`
Insert cell
t1 = html`<table>
<tr>
<td>A1</td>
<td rowspan=4 colspan=3>B2:B4</td>
</tr>
<tr>
<td>A2</td>
</tr>
</table>`
Insert cell
t5 = html`<table><tr><td rowspan="2">A1</td><td colspan="2">A2</td></tr><tr><td colspan="2" rowspan="2">B1</td><td colspan="2">B2</td></tr><tr><td>C1</td><td colspan="2">C2</td></tr><tr><td rowspan="2">D1</td><td colspan="2">D2</td></tr><tr><td colspan="2" rowspan="2">E1</td><td colspan="2" rowspan="2">E2</td></tr></table>`
Insert cell
parseTable(t5);
Insert cell
function parseTable(t) {
const total_rows = t.rows.length;
const rows = t.rows;
/*
* rocc = rows occupied
* keep track of rowspans
* index is colspan
* value is number of rows occupied by previous merged cell
*/
const rocc = [];
const find_index = (n, start) => {
/*
* find consecutive 0s by looping through and decrementing total occurences
* from last stored index -> total colspans
* nonzero = reset to n, zero = decrement
* expand the bound check to solve edge case ex: [3,0,0]
*/
for (let i=start,occur=n; i <= rocc.length + n; ++i) {
if (occur === 0) return i-n;
if (rocc[i]) occur = n;
else occur--;
}
}
// main loop for rows
for (let i=0; i<total_rows; ++i) {
const row = rows[i];
const cells = row.cells;
const total_cells = row.cells.length;
let idx = 0 /* cache last stored index in rocc */;

// loop each cell in a row
for (let c=0; c<total_cells; ++c) {
const cell = cells[c];
const cspan = cell.hasAttribute('colspan') ? parseInt(cell.getAttribute('colspan')) : 1;
const rspan = cell.hasAttribute('rowspan') ? parseInt(cell.getAttribute('rowspan')) : 1;

// find available col space
idx = find_index(cspan, idx);
// fill the space
for (let i=idx; i<idx+cspan; ++i) rocc[i] = rspan;
// console.log({ rowIndex: i, colIndex: c, rspan, cspan, contents: cell.innerHTML});
}
// decrement after each row to restart the counts
for (let i=0; i<rocc.length; ++i) if (rocc[i]) --rocc[i];
}

return rocc;
}
Insert cell
Insert cell
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