{"spec_id":"line-timeseries-rolling","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// line-timeseries-rolling: Time Series with Rolling Average Overlay\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 93/100 | Created: 2026-09-05\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic LCG) ------------------------------------\nconst WINDOW_DAYS = 7;\nconst NUM_DAYS = 120;\n\nlet seed = 42;\nfunction nextRandom() {\n  seed = (seed * 1664525 + 1013904223) % 4294967296;\n  return seed / 4294967296;\n}\n\nfunction hexToRgba(hex, alpha) {\n  const r = parseInt(hex.slice(1, 3), 16);\n  const g = parseInt(hex.slice(3, 5), 16);\n  const b = parseInt(hex.slice(5, 7), 16);\n  return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nconst startDate = new Date(Date.UTC(2026, 0, 1));\nconst labels = [];\nconst dailyActiveUsers = [];\n\nfor (let i = 0; i < NUM_DAYS; i++) {\n  const day = new Date(startDate);\n  day.setUTCDate(day.getUTCDate() + i);\n  labels.push(day.toISOString().slice(0, 10));\n\n  const trend = 4200 + i * 9.5;\n  const weekday = day.getUTCDay();\n  const weekendDip = weekday === 0 || weekday === 6 ? -420 : 0;\n  const noise = (nextRandom() - 0.5) * 520;\n  dailyActiveUsers.push(Math.round(trend + weekendDip + noise));\n}\n\nconst rollingAvg = dailyActiveUsers.map((_, i) => {\n  if (i < WINDOW_DAYS - 1) return null;\n  let sum = 0;\n  for (let j = i - WINDOW_DAYS + 1; j <= i; j++) sum += dailyActiveUsers[j];\n  return Math.round(sum / WINDOW_DAYS);\n});\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Chart -------------------------------------------------------------------\nnew Chart(canvas, {\n  type: \"line\",\n  data: {\n    labels,\n    datasets: [\n      {\n        label: \"Raw Data\",\n        data: dailyActiveUsers,\n        borderColor: hexToRgba(t.ink, 0.28),\n        backgroundColor: hexToRgba(t.ink, 0.28),\n        borderWidth: 1.5,\n        pointRadius: 0,\n        tension: 0,\n        spanGaps: false,\n      },\n      {\n        label: `Rolling Average (${WINDOW_DAYS}-day)`,\n        data: rollingAvg,\n        borderColor: t.palette[0],\n        borderWidth: 4,\n        pointRadius: rollingAvg.map((v, i) => (v !== null && i === rollingAvg.length - 1 ? 7 : 0)),\n        pointBackgroundColor: t.palette[0],\n        pointBorderColor: t.pageBg,\n        pointBorderWidth: 2,\n        tension: 0.25,\n        spanGaps: false,\n        fill: true,\n        backgroundColor: (context) => {\n          const { chartArea, ctx } = context.chart;\n          if (!chartArea) return hexToRgba(t.palette[0], 0.18);\n          const gradient = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom);\n          gradient.addColorStop(0, hexToRgba(t.palette[0], 0.32));\n          gradient.addColorStop(1, hexToRgba(t.palette[0], 0));\n          return gradient;\n        },\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: {\n      title: {\n        display: true,\n        text: \"line-timeseries-rolling · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 29, weight: \"600\" },\n        padding: { bottom: 24 },\n      },\n      legend: {\n        position: \"top\",\n        align: \"end\",\n        labels: {\n          color: t.ink,\n          font: { size: 16 },\n          usePointStyle: true,\n          pointStyle: \"circle\",\n          boxWidth: 10,\n          boxHeight: 10,\n          padding: 20,\n        },\n      },\n    },\n    scales: {\n      x: {\n        ticks: { color: t.inkSoft, font: { size: 14 }, maxTicksLimit: 10 },\n        grid: { color: t.grid },\n        title: { display: true, text: \"Date\", color: t.ink, font: { size: 16 } },\n      },\n      y: {\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { color: t.grid },\n        title: {\n          display: true,\n          text: \"Daily Active Users (count)\",\n          color: t.ink,\n          font: { size: 16 },\n        },\n      },\n    },\n  },\n});\n"}