function clickableTable(
rows,
cols,
values,
w = width,
h = 300,
scaleColor = (d) => "white",
drawText = "auto"
) {
let selectedCell = { row: -1, col: -1 };
const W = w - 2;
const H = h - 2;
const cellHeight = H / (rows.length + 1);
const cellWidth = W / (cols.length + 1);
if (drawText === "auto") {
drawText = Math.min(cellWidth, cellHeight) > 25;
}
const context = DOM.context2d(w, h);
const canvas = context.canvas;
canvas.value = selectedCell;
canvas.dispatchEvent(new CustomEvent("input"));
function drawTable() {
context.fillStyle = "white";
context.fillRect(0, 0, w, h);
context.fillStyle = "black";
context.strokeStyle = "black";
context.textAlign = "center";
context.textBaseline = "middle";
if (drawText === true) {
for (const [r, row] of rows.entries()) {
const x = 0;
const y = (r + 1) * cellHeight;
context.fillText(row, x + cellWidth / 2, y + cellHeight / 2);
}
for (const [c, col] of cols.entries()) {
const x = (c + 1) * cellWidth;
const y = 0;
context.fillText(col, x + cellWidth / 2, y + cellHeight / 2);
}
}
for (const [r, row] of rows.entries()) {
for (const [c, col] of cols.entries()) {
const x = (c + 1) * cellWidth;
const y = (r + 1) * cellHeight;
const fillColor = scaleColor(values[r][c], r, c);
context.fillStyle = fillColor;
context.fillRect(x, y, cellWidth, cellHeight);
if (drawText === true) {
if (getColorLightness(fillColor) < 50) {
context.fillStyle = "white";
} else {
context.fillStyle = "black";
}
context.fillText(values[r][c], x + cellWidth / 2, y + cellHeight / 2);
}
}
}
}
drawTable();
canvas.onmouseup = (event) => {
event.preventDefault();
const row = Math.floor(event.offsetY / cellHeight) - 1;
const col = Math.floor(event.offsetX / cellWidth) - 1;
selectedCell = { row, col };
drawTable();
const x = (col + 1) * cellWidth;
const y = (row + 1) * cellHeight;
context.strokeRect(x, y, cellWidth, cellHeight);
canvas.value = selectedCell;
canvas.dispatchEvent(new CustomEvent("input"));
};
return canvas;
}