( canvas, updateHistory, drawHistory, historyIndex, peakEl, )
| 41 | * @param {HTMLElement} peakEl - element to display peak value |
| 42 | */ |
| 43 | export function drawFrameGraph( |
| 44 | canvas, |
| 45 | updateHistory, |
| 46 | drawHistory, |
| 47 | historyIndex, |
| 48 | peakEl, |
| 49 | ) { |
| 50 | const g = prepareGraph(canvas); |
| 51 | if (g === null) { |
| 52 | return; |
| 53 | } |
| 54 | const { ctx, w, h, barW } = g; |
| 55 | |
| 56 | let peak = 1; |
| 57 | for (let i = 0; i < GRAPH_SAMPLES; i++) { |
| 58 | const total = updateHistory[i] + drawHistory[i]; |
| 59 | if (total > peak) { |
| 60 | peak = total; |
| 61 | } |
| 62 | } |
| 63 | peak = roundPeak(peak); |
| 64 | peakEl.textContent = `peak ${peak}ms`; |
| 65 | |
| 66 | // target frame time line (e.g. 16.67ms for 60fps) |
| 67 | const targetMs = 1000 / timer.maxfps; |
| 68 | const targetY = h - (targetMs / peak) * h; |
| 69 | if (targetY > 0 && targetY < h) { |
| 70 | ctx.strokeStyle = "rgba(40,80,140,0.5)"; |
| 71 | ctx.setLineDash([2, 2]); |
| 72 | ctx.beginPath(); |
| 73 | ctx.moveTo(0, targetY); |
| 74 | ctx.lineTo(w, targetY); |
| 75 | ctx.stroke(); |
| 76 | ctx.setLineDash([]); |
| 77 | } |
| 78 | |
| 79 | // stacked bars: draw (amber) on bottom, update (cyan) on top |
| 80 | for (let i = 0; i < GRAPH_SAMPLES; i++) { |
| 81 | const idx = (historyIndex + i) % GRAPH_SAMPLES; |
| 82 | const updateH = (updateHistory[idx] / peak) * h; |
| 83 | const drawH = (drawHistory[idx] / peak) * h; |
| 84 | const x = Math.round(i * barW); |
| 85 | const bw = Math.max(1, Math.round((i + 1) * barW) - x); |
| 86 | |
| 87 | if (drawH > 0) { |
| 88 | ctx.fillStyle = "#ffb800"; |
| 89 | ctx.fillRect(x, h - drawH - updateH, bw, drawH); |
| 90 | } |
| 91 | if (updateH > 0) { |
| 92 | ctx.fillStyle = "#00e0ff"; |
| 93 | ctx.fillRect(x, h - updateH, bw, updateH); |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Draw the memory heap area graph. |
no test coverage detected