{"spec_id":"gantt-basic","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// gantt-basic: Basic Gantt Chart\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-05\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ---------------------------------------\n// Software launch project timeline, ordered by start date. Only the core\n// Highcharts bundle is loaded (no highcharts-gantt / xrange module), so the\n// timeline is built from a stacked horizontal bar chart: an invisible\n// \"offset\" series pushes each bar's start to the right date, and one visible\n// series per category supplies the duration segment on top of it.\nconst categories = [\"Planning\", \"Design\", \"Development\", \"Testing\", \"Launch\"];\nconst categoryColors = {\n  Planning: t.palette[0],\n  Design: t.palette[1],\n  Development: t.palette[2],\n  Testing: t.palette[3],\n  Launch: t.palette[4],\n};\n\nconst tasks = [\n  { task: \"Market Research\", start: Date.UTC(2026, 0, 5), end: Date.UTC(2026, 0, 12), category: \"Planning\" },\n  { task: \"Requirements Gathering\", start: Date.UTC(2026, 0, 10), end: Date.UTC(2026, 0, 19), category: \"Planning\" },\n  { task: \"Wireframing\", start: Date.UTC(2026, 0, 19), end: Date.UTC(2026, 0, 28), category: \"Design\" },\n  { task: \"UI Design\", start: Date.UTC(2026, 0, 26), end: Date.UTC(2026, 1, 6), category: \"Design\" },\n  { task: \"Database Setup\", start: Date.UTC(2026, 1, 2), end: Date.UTC(2026, 1, 13), category: \"Development\" },\n  { task: \"Backend API\", start: Date.UTC(2026, 1, 2), end: Date.UTC(2026, 1, 27), category: \"Development\" },\n  { task: \"Frontend Build\", start: Date.UTC(2026, 1, 9), end: Date.UTC(2026, 2, 6), category: \"Development\" },\n  { task: \"Integration Testing\", start: Date.UTC(2026, 2, 2), end: Date.UTC(2026, 2, 13), category: \"Testing\" },\n  { task: \"Marketing Prep\", start: Date.UTC(2026, 2, 6), end: Date.UTC(2026, 2, 18), category: \"Launch\" },\n  { task: \"User Acceptance Testing\", start: Date.UTC(2026, 2, 9), end: Date.UTC(2026, 2, 18), category: \"Testing\" },\n  { task: \"Product Launch\", start: Date.UTC(2026, 2, 18), end: Date.UTC(2026, 2, 20), category: \"Launch\" },\n];\n\nconst taskNames = tasks.map((d) => d.task);\nconst offsets = tasks.map((d) => d.start);\n\nconst dayMs = 24 * 3600 * 1000;\nconst projectStart = Math.min(...tasks.map((d) => d.start));\nconst projectEnd = Math.max(...tasks.map((d) => d.end));\nconst statusCheck = Date.UTC(2026, 1, 15); // mid-project progress check\n\n// One series per category (sparse, null elsewhere) so the legend doubles as\n// the category key while still sharing a single stack with the offset series.\n// Tasks fully finished before the status check render at reduced opacity, a\n// lightweight \"done vs. upcoming\" hierarchy relative to the reference line.\nconst categorySeries = categories.map((cat) => ({\n  name: cat,\n  color: categoryColors[cat],\n  stack: \"gantt\",\n  data: tasks.map((d) =>\n    d.category === cat ? { y: d.end - d.start, opacity: d.end <= statusCheck ? 0.55 : 1 } : null\n  ),\n}));\n\n// --- Chart -------------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"bar\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"gantt-basic · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  xAxis: {\n    categories: taskNames,\n    reversed: true,\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  yAxis: {\n    type: \"datetime\",\n    min: projectStart - 3 * dayMs,\n    max: projectEnd + 3 * dayMs,\n    startOnTick: false,\n    endOnTick: false,\n    // Highcharts stacks series bottom-to-top in *reverse* array order by\n    // default (reversedStacks: true) — that would put the invisible \"offset\"\n    // series on top and the visible duration segment at the zero baseline\n    // (off-screen). Keep array order so offset stacks first, at the bottom.\n    reversedStacks: false,\n    title: { text: \"Project Timeline (2026)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    gridLineColor: t.grid,\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    labels: {\n      style: { color: t.inkSoft, fontSize: \"14px\" },\n      format: \"{value:%b %e}\",\n    },\n    plotLines: [\n      {\n        value: statusCheck,\n        color: t.ink,\n        width: 2,\n        dashStyle: \"ShortDash\",\n        zIndex: 5,\n        label: {\n          text: \"Status check\",\n          rotation: 0,\n          align: \"center\",\n          verticalAlign: \"top\",\n          style: { color: t.ink, fontSize: \"12px\", fontWeight: \"600\" },\n          y: -6,\n        },\n      },\n    ],\n  },\n  legend: {\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  tooltip: {\n    backgroundColor: t.elevatedBg,\n    borderColor: t.inkSoft,\n    style: { color: t.ink, fontSize: \"13px\" },\n    formatter: function () {\n      const d = tasks[this.point.index];\n      const fmt = \"%b %e, %Y\";\n      return (\n        \"<b>\" + d.task + \"</b><br/>\" +\n        d.category + \"<br/>\" +\n        Highcharts.dateFormat(fmt, d.start) + \" – \" + Highcharts.dateFormat(fmt, d.end)\n      );\n    },\n  },\n  plotOptions: {\n    series: { animation: false, stacking: \"normal\" },\n    bar: { groupPadding: 0.1, pointPadding: 0.02, borderWidth: 0, pointWidth: 24 },\n  },\n  series: [\n    {\n      name: \"offset\",\n      data: offsets,\n      stack: \"gantt\",\n      color: \"transparent\",\n      enableMouseTracking: false,\n      showInLegend: false,\n    },\n    ...categorySeries,\n  ],\n});\n"}