(ctx, w, h)
| 17 | // parsed frame (history buffers, smoothing, etc.) before paint() runs. |
| 18 | |
| 19 | function paint(ctx, w, h) { |
| 20 | // Cream paper background + vignette. |
| 21 | ctx.fillStyle = theme.widget_base; |
| 22 | ctx.fillRect(0, 0, w, h); |
| 23 | |
| 24 | // Header strip. |
| 25 | ctx.fillStyle = theme.widget_text; |
| 26 | ctx.font = "bold 11px sans-serif"; |
| 27 | ctx.textAlign = "start"; |
| 28 | ctx.fillText((group.title || "PAINTER").toUpperCase(), 14, 18); |
| 29 | ctx.fillStyle = theme.placeholder_text; |
| 30 | ctx.font = "10px sans-serif"; |
| 31 | ctx.textAlign = "end"; |
| 32 | ctx.fillText("XY / Z", w - 14, 18); |
| 33 | ctx.fillStyle = theme.widget_border; |
| 34 | ctx.fillRect(14, 22, w - 28, 1); |
| 35 | |
| 36 | if (datasets.length < 2) { |
| 37 | ctx.fillStyle = theme.placeholder_text; |
| 38 | ctx.font = "12px sans-serif"; |
| 39 | ctx.textAlign = "center"; |
| 40 | ctx.fillText("Add at least 2 datasets (X, Y) to see the indicator.", |
| 41 | w / 2, h / 2); |
| 42 | return; |
| 43 | } |
| 44 | |
| 45 | const dsX = datasets[0]; |
| 46 | const dsY = datasets[1]; |
| 47 | const dsZ = datasets.length >= 3 ? datasets[2] : null; |
| 48 | |
| 49 | // Plot card with shadow + border. |
| 50 | const padL = 50; |
| 51 | const padR = 132; |
| 52 | const padT = 38; |
| 53 | const padB = 38; |
| 54 | const plotW = Math.max(1, w - padL - padR); |
| 55 | const plotH = Math.max(1, h - padT - padB); |
| 56 | const cx = padL + plotW * 0.5; |
| 57 | const cy = padT + plotH * 0.5; |
| 58 | |
| 59 | ctx.fillStyle = theme.widget_border; |
| 60 | ctx.fillRect(padL + 1, padT + 2, plotW, plotH); |
| 61 | ctx.fillStyle = theme.alternate_base; |
| 62 | ctx.fillRect(padL, padT, plotW, plotH); |
| 63 | ctx.strokeStyle = theme.widget_border; |
| 64 | ctx.lineWidth = 1; |
| 65 | ctx.strokeRect(padL + 0.5, padT + 0.5, plotW - 1, plotH - 1); |
| 66 | |
| 67 | // Cross-hair grid. |
| 68 | ctx.strokeStyle = theme.widget_border; |
| 69 | ctx.beginPath(); |
| 70 | ctx.moveTo(padL, cy); |
| 71 | ctx.lineTo(padL + plotW, cy); |
| 72 | ctx.moveTo(cx, padT); |
| 73 | ctx.lineTo(cx, padT + plotH); |
| 74 | ctx.stroke(); |
| 75 | |
| 76 | // Quarter divisions (subtle dotted feel via dashed slate ticks). |
nothing calls this directly
no test coverage detected