{"spec_id":"step-basic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// step-basic: Basic Step Plot\n// Library: chartjs 4.4.7 | JavaScript 22.23.1\n// Quality: 90/100 | Created: 2026-07-25\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Auto-scaling group size for a web service over a 24h day. Each point marks\n// a scaling event; the instance count holds constant until the next event.\nconst scalingEvents = [\n  { hour: 0, instances: 4 },\n  { hour: 2.5, instances: 8 },\n  { hour: 5, instances: 14 },\n  { hour: 7, instances: 22 },\n  { hour: 9.5, instances: 30 },\n  { hour: 12, instances: 26 },\n  { hour: 14.5, instances: 20 },\n  { hour: 17, instances: 24 },\n  { hour: 19, instances: 16 },\n  { hour: 21.5, instances: 10 },\n  { hour: 24, instances: 4 },\n];\nconst points = scalingEvents.map((e) => ({ x: e.hour, y: e.instances }));\nconst peakIndex = points.reduce((best, p, i, arr) => (p.y > arr[best].y ? i : best), 0);\n\nconst formatHour = (hour) => {\n  const h = Math.floor(hour) % 24;\n  const m = Math.round((hour - Math.floor(hour)) * 60);\n  return `${String(h).padStart(2, \"0\")}:${String(m).padStart(2, \"0\")}`;\n};\n\nconst hexToRgba = (hex, alpha) => {\n  const int = parseInt(hex.slice(1), 16);\n  const r = (int >> 16) & 255;\n  const g = (int >> 8) & 255;\n  const b = int & 255;\n  return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Peak callout plugin (labels the daily peak as a storytelling focal point) --\nconst peakCalloutPlugin = {\n  id: \"peakCallout\",\n  afterDatasetsDraw(chart) {\n    const point = chart.getDatasetMeta(0).data[peakIndex];\n    if (!point) return;\n    const { ctx } = chart;\n    ctx.save();\n    ctx.fillStyle = t.ink;\n    ctx.font = \"600 14px sans-serif\";\n    ctx.textAlign = \"left\";\n    ctx.fillText(\"Daily peak\", point.x + 12, point.y - 12);\n    ctx.restore();\n  },\n};\n\n// --- Chart ---------------------------------------------------------------\nnew Chart(canvas, {\n  type: \"line\",\n  data: {\n    datasets: [\n      {\n        label: \"Active instances\",\n        data: points,\n        stepped: \"after\",\n        borderColor: t.palette[0],\n        backgroundColor: hexToRgba(t.palette[0], 0.14),\n        fill: \"origin\",\n        borderWidth: 3.5,\n        // Scriptable point styling: the daily-peak marker reads larger than the\n        // rest, giving the viewer a focal point without introducing a new color.\n        pointRadius: (ctx) => (ctx.dataIndex === peakIndex ? 8 : 5),\n        pointHoverRadius: (ctx) => (ctx.dataIndex === peakIndex ? 9 : 6),\n        pointBackgroundColor: t.palette[0],\n        pointBorderColor: t.pageBg,\n        pointBorderWidth: (ctx) => (ctx.dataIndex === peakIndex ? 2.5 : 1.5),\n        tension: 0,\n      },\n    ],\n  },\n  plugins: [peakCalloutPlugin],\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    layout: { padding: { top: 8, right: 40, bottom: 4, left: 4 } },\n    plugins: {\n      title: {\n        display: true,\n        text: \"step-basic · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 22, weight: \"500\" },\n        padding: { bottom: 20 },\n      },\n      legend: { display: false },\n    },\n    scales: {\n      x: {\n        type: \"linear\",\n        min: 0,\n        max: 24,\n        ticks: {\n          color: t.inkSoft,\n          font: { size: 14 },\n          stepSize: 3,\n          callback: (value) => formatHour(value),\n        },\n        grid: { display: false },\n        title: { display: true, text: \"Time of Day\", color: t.ink, font: { size: 16 } },\n      },\n      y: {\n        beginAtZero: true,\n        grace: \"10%\",\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { color: t.grid },\n        title: { display: true, text: \"Active Instances\", color: t.ink, font: { size: 16 } },\n      },\n    },\n  },\n});\n"}