{"spec_id":"line-filled","library":"d3","language":"javascript","code":"// anyplot.ai\n// line-filled: Filled Line Plot\n// Library: d3 7.9.0 | JavaScript 22.23.2\n// Quality: 94/100 | Created: 2026-09-05\n\nconst t = window.ANYPLOT_TOKENS;\nconst { width, height } = window.ANYPLOT_SIZE;\nconst margin = { top: 110, right: 70, bottom: 90, left: 120 };\nconst iw = width - margin.left - margin.right;\nconst ih = height - margin.top - margin.bottom;\n\n// --- Data (in-memory, deterministic LCG) ------------------------------------\nfunction lcg(seed) {\n  let state = seed;\n  return () => {\n    state = (state * 1664525 + 1013904223) % 4294967296;\n    return state / 4294967296;\n  };\n}\nconst random = lcg(42);\n\nconst startDate = new Date(2026, 5, 1);\nconst dayCount = 60;\nconst dailyVisitors = [];\nfor (let i = 0; i < dayCount; i++) {\n  const trend = 820 + i * 7.5;\n  const weeklyCycle = 140 * Math.sin((i / 7) * 2 * Math.PI);\n  const noise = (random() - 0.5) * 160;\n  const date = new Date(startDate);\n  date.setDate(date.getDate() + i);\n  dailyVisitors.push({ date, visitors: Math.max(0, trend + weeklyCycle + noise) });\n}\n\n// --- Scales -------------------------------------------------------------------\nconst x = d3.scaleTime()\n  .domain(d3.extent(dailyVisitors, (d) => d.date))\n  .range([0, iw]);\nconst y = d3.scaleLinear()\n  .domain([0, d3.max(dailyVisitors, (d) => d.visitors) * 1.1])\n  .nice()\n  .range([ih, 0]);\n\n// --- SVG mount ----------------------------------------------------------------\nconst svg = d3.select(\"#container\").append(\"svg\").attr(\"width\", width).attr(\"height\", height);\nconst g = svg.append(\"g\").attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n// --- Gridlines (y-axis only, subtle) -------------------------------------------\nconst grid = g.append(\"g\").call(d3.axisLeft(y).tickSize(-iw).tickFormat(\"\"));\ngrid.selectAll(\"line\").attr(\"stroke\", t.grid);\ngrid.select(\".domain\").remove();\n\n// --- Area gradient (opaque near the line, fading to the baseline) --------------\nconst gradientId = \"line-filled-area-gradient\";\nconst gradient = svg.append(\"defs\")\n  .append(\"linearGradient\")\n  .attr(\"id\", gradientId)\n  .attr(\"gradientUnits\", \"userSpaceOnUse\")\n  .attr(\"x1\", 0).attr(\"y1\", 0)\n  .attr(\"x2\", 0).attr(\"y2\", ih);\ngradient.append(\"stop\").attr(\"offset\", \"0%\").attr(\"stop-color\", t.palette[0]).attr(\"stop-opacity\", 0.45);\ngradient.append(\"stop\").attr(\"offset\", \"100%\").attr(\"stop-color\", t.palette[0]).attr(\"stop-opacity\", 0.04);\n\n// --- Area + line ----------------------------------------------------------------\nconst area = d3.area()\n  .curve(d3.curveMonotoneX)\n  .x((d) => x(d.date))\n  .y0(ih)\n  .y1((d) => y(d.visitors));\nconst line = d3.line()\n  .curve(d3.curveMonotoneX)\n  .x((d) => x(d.date))\n  .y((d) => y(d.visitors));\n\ng.append(\"path\")\n  .datum(dailyVisitors)\n  .attr(\"d\", area)\n  .attr(\"fill\", `url(#${gradientId})`)\n  .attr(\"stroke\", \"none\");\n\ng.append(\"path\")\n  .datum(dailyVisitors)\n  .attr(\"d\", line)\n  .attr(\"fill\", \"none\")\n  .attr(\"stroke\", t.palette[0])\n  .attr(\"stroke-width\", 3.5);\n\n// --- End-point focal marker (emphasizes the overall upward trend) --------------\nconst last = dailyVisitors[dailyVisitors.length - 1];\nconst first = dailyVisitors[0];\nconst growthPct = Math.round(((last.visitors - first.visitors) / first.visitors) * 100);\ng.append(\"circle\")\n  .attr(\"cx\", x(last.date))\n  .attr(\"cy\", y(last.visitors))\n  .attr(\"r\", 6)\n  .attr(\"fill\", t.palette[0])\n  .attr(\"stroke\", t.pageBg)\n  .attr(\"stroke-width\", 2);\n\ng.append(\"text\")\n  .attr(\"x\", x(last.date))\n  .attr(\"y\", y(last.visitors) - 16)\n  .attr(\"text-anchor\", \"end\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"15px\")\n  .style(\"font-weight\", \"600\")\n  .text(`+${growthPct}% vs. day 1`);\n\n// --- Axes -----------------------------------------------------------------------\nconst xAxis = g.append(\"g\")\n  .attr(\"transform\", `translate(0,${ih})`)\n  .call(d3.axisBottom(x).ticks(d3.timeWeek.every(1)).tickFormat(d3.timeFormat(\"%b %d\")));\nconst yAxis = g.append(\"g\").call(d3.axisLeft(y).ticks(6));\nfor (const ax of [xAxis, yAxis]) {\n  ax.selectAll(\"text\").attr(\"fill\", t.inkSoft).style(\"font-size\", \"14px\");\n  ax.selectAll(\"line\").attr(\"stroke\", t.grid);\n  ax.select(\".domain\").attr(\"stroke\", t.inkSoft);\n}\nxAxis.selectAll(\"text\").attr(\"dy\", \"1.2em\");\n\n// --- Axis labels ------------------------------------------------------------------\ng.append(\"text\")\n  .attr(\"x\", iw / 2)\n  .attr(\"y\", ih + 70)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"16px\")\n  .text(\"Date\");\n\ng.append(\"text\")\n  .attr(\"transform\", \"rotate(-90)\")\n  .attr(\"x\", -ih / 2)\n  .attr(\"y\", -85)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"16px\")\n  .text(\"Daily Visitors (count)\");\n\n// --- Title ----------------------------------------------------------------------\nsvg.append(\"text\")\n  .attr(\"x\", width / 2)\n  .attr(\"y\", 56)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"22px\")\n  .style(\"font-weight\", \"600\")\n  .text(\"line-filled · javascript · d3 · anyplot.ai\");\n"}