renderHeatmapChart function
Renders a heatmap chart onto screen within area.
Implementation
void renderHeatmapChart(
Screen screen,
Rectangle area,
HeatmapChartProps props,
) {
final width = area.width;
final height = area.height;
if (width <= 0 || height <= 0 || props.data.isEmpty) return;
final bg = fg(props.backgroundColor ?? '#1A1A2E');
final margins = resolveMargins(props.margins);
fillRect(screen, area, 0, 0, width, height, bg);
var titleOffset = 0;
if (props.title != null) {
putText(
screen,
area,
margins.left,
0,
props.title!,
mergeStyle(fg(props.titleColor ?? '#FFFFFF'), bg),
);
titleOffset = 1;
}
final plotX = margins.left;
final plotY = margins.top + titleOffset;
final plotW = width - margins.left - margins.right;
final plotH = height - margins.top - margins.bottom - titleOffset;
final rows = props.data.length;
final cols = props.data[0].length;
var minV = double.infinity;
var maxV = double.negativeInfinity;
for (final row in props.data) {
for (final v in row) {
if (v < minV) minV = v;
if (v > maxV) maxV = v;
}
}
if (minV == maxV) maxV = minV + 1;
final cellW = math.max(1, plotW ~/ cols);
final cellH = math.max(1, plotH ~/ rows);
final colorScale = props.colorScale ?? defaultColors;
for (var r = 0; r < rows; r++) {
for (var c = 0; c < cols; c++) {
final v = props.data[r][c];
final t = (v - minV) / (maxV - minV);
final idx = (t * (colorScale.length - 1)).round().clamp(
0,
colorScale.length - 1,
);
final cellColor = fg(colorScale[idx]);
final x = plotX + c * cellW;
final y = plotY + r * cellH;
for (var rr = 0; rr < cellH; rr++) {
for (var cc = 0; cc < cellW; cc++) {
final px = x + cc;
final py = y + rr;
if (px >= plotX &&
px < plotX + plotW &&
py >= plotY &&
py < plotY + plotH) {
putSolidChartCell(screen, px, py, cellColor, Block.full);
}
}
}
if (props.showValues ?? false) {
final valStr = formatNumber(v);
if (valStr.length <= cellW) {
putText(
screen,
area,
x + (cellW - valStr.length) ~/ 2,
y + (cellH - 1) ~/ 2,
valStr,
mergeStyle(fg('#000000'), bg),
);
}
}
}
}
if (props.xLabels != null) {
for (var c = 0; c < math.min(props.xLabels!.length, cols); c++) {
final x = plotX + c * cellW + cellW ~/ 2;
final label = props.xLabels![c];
putText(
screen,
area,
x - label.length ~/ 2,
plotY + rows * cellH,
label,
mergeStyle(fg('#888888'), bg),
);
}
}
if (props.yLabels != null) {
for (var r = 0; r < math.min(props.yLabels!.length, rows); r++) {
final y = plotY + r * cellH + cellH ~/ 2;
putText(
screen,
area,
math.max(0, plotX - props.yLabels![r].length - 1),
y,
props.yLabels![r],
mergeStyle(fg('#888888'), bg),
);
}
}
}