(ctx, w, h)
| 33 | } |
| 34 | |
| 35 | function paint(ctx, w, h) { |
| 36 | // Cream paper background. |
| 37 | ctx.fillStyle = theme.widget_base; |
| 38 | ctx.fillRect(0, 0, w, h); |
| 39 | |
| 40 | if (datasets.length === 0) return; |
| 41 | |
| 42 | const cols = Math.max(1, Math.ceil(Math.sqrt(datasets.length * w / h))); |
| 43 | const rows = Math.ceil(datasets.length / cols); |
| 44 | const padX = 12; |
| 45 | const padY = 12; |
| 46 | const gap = 8; |
| 47 | const cw = (w - padX * 2 - gap * (cols - 1)) / cols; |
| 48 | const ch = (h - padY * 2 - gap * (rows - 1)) / rows; |
| 49 | |
| 50 | for (let i = 0; i < datasets.length; ++i) { |
| 51 | const r = Math.floor(i / cols); |
| 52 | const c = i % cols; |
| 53 | const x = padX + c * (cw + gap); |
| 54 | const y = padY + r * (ch + gap); |
| 55 | const ds = datasets[i]; |
| 56 | const traceColor = theme.widget_colors[i % theme.widget_colors.length]; |
| 57 | |
| 58 | // Card with shadow. |
| 59 | ctx.fillStyle = theme.widget_border; |
| 60 | ctx.fillRect(x + 1, y + 2, cw, ch); |
| 61 | ctx.fillStyle = theme.alternate_base; |
| 62 | ctx.fillRect(x, y, cw, ch); |
| 63 | ctx.strokeStyle = theme.widget_border; |
| 64 | ctx.lineWidth = 1; |
| 65 | ctx.strokeRect(x + 0.5, y + 0.5, cw - 1, ch - 1); |
| 66 | |
| 67 | // Title. |
| 68 | ctx.fillStyle = theme.placeholder_text; |
| 69 | ctx.font = "bold 10px sans-serif"; |
| 70 | ctx.textAlign = "start"; |
| 71 | ctx.textBaseline = "alphabetic"; |
| 72 | ctx.fillText((ds.title || "").substring(0, 22), x + 10, y + 16); |
| 73 | |
| 74 | // Trend arrow on the right. |
| 75 | const dir = trend_dir(traces[i]); |
| 76 | if (dir !== 0) { |
| 77 | const ax = x + cw - 14; |
| 78 | const ay = y + 14; |
| 79 | ctx.fillStyle = dir > 0 ? theme.widget_highlight : theme.alarm; |
| 80 | ctx.beginPath(); |
| 81 | if (dir > 0) { |
| 82 | ctx.moveTo(ax, ay - 4); |
| 83 | ctx.lineTo(ax + 5, ay + 3); |
| 84 | ctx.lineTo(ax - 5, ay + 3); |
| 85 | } else { |
| 86 | ctx.moveTo(ax, ay + 4); |
| 87 | ctx.lineTo(ax + 5, ay - 3); |
| 88 | ctx.lineTo(ax - 5, ay - 3); |
| 89 | } |
| 90 | ctx.closePath(); |
| 91 | ctx.fill(); |
| 92 | } |
nothing calls this directly
no test coverage detected