{"spec_id":"line-annotated-events","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// line-annotated-events: Annotated Line Plot with Event Markers\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 88/100 | Created: 2026-09-05\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Tiny fixed-seed LCG — the browser has no seeded RNG.\nlet lcgState = 42;\nfunction lcgRandom() {\n  lcgState = (lcgState * 1103515245 + 12345) & 0x7fffffff;\n  return lcgState / 0x7fffffff;\n}\n\nconst dayMs = 24 * 60 * 60 * 1000;\nconst startDate = Date.UTC(2024, 0, 1);\nconst numDays = 180;\n\n// Milestones that shift the daily-active-users trajectory.\nconst events = [\n  { day: 18, label: \"v2.0 Launch\", stepGain: 55 },\n  { day: 52, label: \"Referral Program\", stepGain: 35 },\n  { day: 88, label: \"Server Outage\", stepGain: -70 },\n  { day: 124, label: \"Marketing Campaign\", stepGain: 60 },\n  { day: 158, label: \"Holiday Surge\", stepGain: 40 },\n];\n\nconst dailyActiveUsers = [];\nlet growthRate = 20;\nlet level = 9800;\nfor (let day = 0; day < numDays; day++) {\n  const milestone = events.find((e) => e.day === day);\n  if (milestone) growthRate += milestone.stepGain > 0 ? 6 : -4;\n\n  const weeklySeasonality = Math.sin((day / 7) * 2 * Math.PI) * 220;\n  const noise = (lcgRandom() - 0.5) * 260;\n  level += growthRate + (lcgRandom() - 0.5) * 8;\n  if (milestone) level += milestone.stepGain;\n\n  const value = Math.round(level + weeklySeasonality + noise);\n  dailyActiveUsers.push([startDate + day * dayMs, value]);\n}\n\n// Positive milestones stay brand-lavender; the one negative event (the outage)\n// gets the Imprint semantic-red anchor so color reinforces the up/down story.\nconst eventColor = (e) => (e.stepGain < 0 ? t.palette[4] : t.palette[1]);\n\nconst eventPoints = events.map((e) => ({\n  x: startDate + e.day * dayMs,\n  y: dailyActiveUsers[e.day][1],\n  color: eventColor(e),\n}));\n\n// --- Chart -------------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"spline\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    spacingTop: 4,\n    style: { fontFamily: \"inherit\" },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"line-annotated-events · javascript · highcharts · anyplot.ai\",\n    margin: 10,\n    style: { color: t.ink, fontSize: \"27px\", fontWeight: \"600\" },\n  },\n  xAxis: {\n    type: \"datetime\",\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineColor: t.grid,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    title: { text: \"Date\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    plotLines: events.map((e, i) => ({\n      value: startDate + e.day * dayMs,\n      color: eventColor(e),\n      dashStyle: \"Dash\",\n      width: 1.5,\n      zIndex: 1,\n      label: {\n        text: e.label,\n        rotation: 0,\n        align: \"left\",\n        x: 6,\n        y: i % 2 === 0 ? 22 : 42,\n        style: { color: t.inkSoft, fontSize: \"12px\" },\n      },\n    })),\n  },\n  yAxis: {\n    title: {\n      text: \"Daily Active Users\",\n      style: { color: t.inkSoft, fontSize: \"16px\" },\n    },\n    gridLineColor: t.grid,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    maxPadding: 0.04,\n    endOnTick: false,\n  },\n  legend: {\n    enabled: true,\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  plotOptions: {\n    series: { animation: false },\n    spline: { lineWidth: 3, marker: { enabled: false } },\n  },\n  series: [\n    {\n      name: \"Daily Active Users\",\n      data: dailyActiveUsers,\n      color: t.palette[0],\n      zIndex: 1,\n    },\n    {\n      type: \"scatter\",\n      name: \"Milestones\",\n      data: eventPoints,\n      color: t.palette[1],\n      marker: { radius: 7, symbol: \"circle\", lineWidth: 1.5, lineColor: t.pageBg },\n      zIndex: 10,\n      // legend swatch stays lavender for the series as a whole; the one\n      // negative event (Server Outage) overrides its own marker color above.\n    },\n  ],\n});\n"}