{"spec_id":"gantt-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// gantt-basic: Basic Gantt Chart\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-05\n\n//# anyplot-orientation: landscape\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ---------------------------------------\nconst tasks = [\n  { name: \"Requirements Gathering\", category: \"Design\", start: \"2026-08-03\", end: \"2026-08-11\" },\n  { name: \"UX Wireframes\", category: \"Design\", start: \"2026-08-10\", end: \"2026-08-21\" },\n  { name: \"Visual Design\", category: \"Design\", start: \"2026-08-17\", end: \"2026-08-28\" },\n  { name: \"Backend API\", category: \"Development\", start: \"2026-08-24\", end: \"2026-09-25\" },\n  { name: \"Database Migration\", category: \"Development\", start: \"2026-08-31\", end: \"2026-09-11\" },\n  { name: \"Frontend Build\", category: \"Development\", start: \"2026-09-07\", end: \"2026-10-02\" },\n  { name: \"Third-Party Integration\", category: \"Development\", start: \"2026-09-14\", end: \"2026-09-30\" },\n  { name: \"Unit Testing\", category: \"Testing\", start: \"2026-09-21\", end: \"2026-10-09\" },\n  { name: \"QA Regression\", category: \"Testing\", start: \"2026-10-05\", end: \"2026-10-21\" },\n  { name: \"User Acceptance Testing\", category: \"Testing\", start: \"2026-10-19\", end: \"2026-10-30\" },\n  { name: \"Staging Deployment\", category: \"Deployment\", start: \"2026-10-26\", end: \"2026-11-02\" },\n  { name: \"Production Launch\", category: \"Deployment\", start: \"2026-11-02\", end: \"2026-11-06\" },\n];\n\nconst categories = [\"Design\", \"Development\", \"Testing\", \"Deployment\"];\nconst categoryColor = {\n  Design: t.palette[0],\n  Development: t.palette[1],\n  Testing: t.palette[2],\n  Deployment: t.palette[3],\n};\nconst taskNames = tasks.map((task) => task.name);\nconst today = new Date(\"2026-09-05\").getTime();\n\n// --- Render item: one rectangle per task, spanning [start, end] on the time axis\nfunction renderTaskBar(params, api) {\n  const categoryIndex = api.value(0);\n  const start = api.coord([api.value(1), categoryIndex]);\n  const end = api.coord([api.value(2), categoryIndex]);\n  const barHeight = api.size([0, 1])[1] * 0.6;\n  const rectShape = echarts.graphic.clipRectByRect(\n    { x: start[0], y: start[1] - barHeight / 2, width: end[0] - start[0], height: barHeight },\n    { x: params.coordSys.x, y: params.coordSys.y, width: params.coordSys.width, height: params.coordSys.height }\n  );\n  return rectShape && { type: \"rect\", shape: rectShape, style: api.style() };\n}\n\n// One series per category — gives the legend a color-coded swatch per group\nconst series = categories.map((category, categoryPos) => ({\n  name: category,\n  type: \"custom\",\n  renderItem: renderTaskBar,\n  itemStyle: { color: categoryColor[category] },\n  encode: { x: [1, 2], y: 0 },\n  data: tasks\n    .map((task, taskIndex) => ({ task, taskIndex }))\n    .filter(({ task }) => task.category === category)\n    .map(({ task, taskIndex }) => [taskIndex, task.start, task.end, task.name]),\n  markLine:\n    categoryPos === categories.length - 1\n      ? {\n          silent: true,\n          symbol: \"none\",\n          lineStyle: { color: t.amber, type: \"dashed\", width: 2 },\n          label: { formatter: \"Today\", color: t.inkSoft, fontSize: 13, position: \"insideEndTop\" },\n          data: [{ xAxis: today }],\n        }\n      : undefined,\n}));\n\n// --- Init -------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option -----------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"gantt-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n  },\n  legend: {\n    data: categories,\n    top: 56,\n    textStyle: { color: t.inkSoft, fontSize: 14 },\n    itemWidth: 16,\n    itemHeight: 10,\n  },\n  grid: { left: 260, right: 70, top: 130, bottom: 70 },\n  xAxis: {\n    type: \"time\",\n    axisLabel: { color: t.inkSoft, fontSize: 13 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    splitLine: { show: true, lineStyle: { color: t.grid } },\n  },\n  yAxis: {\n    type: \"category\",\n    data: taskNames,\n    inverse: true,\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    splitLine: { show: false },\n  },\n  series,\n});\n"}