(host)
| 1267 | ]; |
| 1268 | |
| 1269 | function initRolling(host) { |
| 1270 | if (!host) return; |
| 1271 | host.innerHTML = ""; |
| 1272 | host.classList.add("lc-rolling"); |
| 1273 | |
| 1274 | // Header with live indicator |
| 1275 | const head = htmlEl("div", { class: "lc-rolling__head" }); |
| 1276 | head.appendChild(htmlEl("span", { class: "lc-mono lc-muted" }, "ROLLING EVAL SCORE · last 10 days · production")); |
| 1277 | const live = htmlEl("span", { class: "lc-rolling__live" }); |
| 1278 | live.appendChild(htmlEl("span", { class: "lc-rolling__livepulse" })); |
| 1279 | live.appendChild(htmlEl("span", { class: "lc-mono", style: "color: #34a853;" }, "LIVE")); |
| 1280 | head.appendChild(live); |
| 1281 | host.appendChild(head); |
| 1282 | |
| 1283 | // SVG chart |
| 1284 | const W = 560, H = 170; |
| 1285 | const PAD_L = 18, PAD_R = 18, PAD_T = 24, PAD_B = 26; |
| 1286 | const dx = (W - PAD_L - PAD_R) / (ROLLING_DATA.length - 1); |
| 1287 | const yScale = (s) => PAD_T + (1 - s) * (H - PAD_T - PAD_B); |
| 1288 | |
| 1289 | const pts = ROLLING_DATA.map((p, i) => Object.assign({}, p, { cx: PAD_L + i * dx, cy: yScale(p.score) })); |
| 1290 | const linePath = pts.map((p, i) => (i === 0 ? "M " : "L ") + p.cx + " " + p.cy).join(" "); |
| 1291 | const areaPath = "M " + pts[0].cx + " " + (H - PAD_B) + " " + |
| 1292 | pts.map((p) => "L " + p.cx + " " + p.cy).join(" ") + |
| 1293 | " L " + pts[pts.length - 1].cx + " " + (H - PAD_B) + " Z"; |
| 1294 | const yT = yScale(0.8); |
| 1295 | |
| 1296 | const svg = svgEl("svg", { viewBox: "0 0 " + W + " " + H, width: "100%", role: "img", "aria-label": "Rolling production eval score, last 10 days" }); |
| 1297 | host.appendChild(svg); |
| 1298 | |
| 1299 | // Threshold band |
| 1300 | svg.appendChild(svgEl("rect", { x: PAD_L, y: yT, width: W - PAD_L - PAD_R, height: H - PAD_B - yT, fill: "color-mix(in srgb, #ea4335 10%, transparent)" })); |
| 1301 | svg.appendChild(svgEl("line", { x1: PAD_L, x2: W - PAD_R, y1: yT, y2: yT, stroke: "var(--md-default-fg-color--light)", "stroke-dasharray": "3 4", "stroke-width": 1 })); |
| 1302 | const thLabel = svgEl("text", { x: W - PAD_R - 2, y: yT - 4, "text-anchor": "end", "font-family": "var(--md-code-font-family)", "font-size": "9", fill: "var(--md-default-fg-color--light)" }); |
| 1303 | thLabel.textContent = "threshold 0.80"; |
| 1304 | svg.appendChild(thLabel); |
| 1305 | |
| 1306 | // Faint area beneath the line |
| 1307 | const area = svgEl("path", { d: areaPath, fill: "color-mix(in srgb, #34a853 14%, transparent)", opacity: "0" }); |
| 1308 | area.style.transition = "opacity 600ms ease"; |
| 1309 | svg.appendChild(area); |
| 1310 | |
| 1311 | // The line — stroke-dashoffset reveal |
| 1312 | const line = svgEl("path", { |
| 1313 | d: linePath, fill: "none", stroke: "#34a853", "stroke-width": "2", "stroke-linecap": "round", |
| 1314 | pathLength: "1", "stroke-dasharray": "1", "stroke-dashoffset": "1", |
| 1315 | }); |
| 1316 | line.style.transition = "stroke-dashoffset 1100ms ease-out"; |
| 1317 | svg.appendChild(line); |
| 1318 | |
| 1319 | // Dots + annotations |
| 1320 | pts.forEach((p, i) => { |
| 1321 | const isLast = i === pts.length - 1; |
| 1322 | const annotated = !!p.ann; |
| 1323 | const annColor = annotated && p.ann.kind === "regression" ? "#ea4335" : "var(--md-primary-fg-color)"; |
| 1324 | |
| 1325 | // Live pulse halo on last point |
| 1326 | if (isLast) { |
no test coverage detected