{"spec_id":"area-cumulative-flow","library":"echarts","language":"javascript","code":"// anyplot.ai\n// area-cumulative-flow: Cumulative Flow Diagram for Workflow Analytics\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 94/100 | Created: 2026-08-18\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Simple LCG so the sample data is reproducible without Math.random().\nlet seed = 42;\nfunction rand() {\n  seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n  return seed / 0x7fffffff;\n}\n\nconst DAYS = 90;\nconst MONTHS = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\nconst stageNames = [\"Backlog\", \"Analysis\", \"Development\", \"Testing\", \"Done\"];\n// Daily throughput capacity limiting how many items can advance into each\n// stage (Backlog has no upstream cap — it only receives new intake). Testing\n// is deliberately the tightest gate, so a Development-stage queue builds up\n// in front of it — the classic CFD bottleneck signature — while the other\n// stages keep pace with their own upstream and stay comparatively narrow.\nconst capacity = [null, 7, 7, 4, 4];\n\nconst dates = [];\nconst cumulative = stageNames.map(() => []);\nconst startDate = new Date(Date.UTC(2026, 0, 5));\n\nfor (let d = 0; d < DAYS; d++) {\n  const dt = new Date(startDate.getTime() + d * 86400000);\n  dates.push(`${MONTHS[dt.getUTCMonth()]} ${String(dt.getUTCDate()).padStart(2, \"0\")}`);\n\n  const intake = 5 + Math.floor(rand() * 5); // 5-9 new items entering Backlog\n  cumulative[0].push(d === 0 ? intake : cumulative[0][d - 1] + intake);\n\n  for (let s = 1; s < stageNames.length; s++) {\n    const prevCount = d === 0 ? 0 : cumulative[s][d - 1];\n    const advance = Math.max(capacity[s] + Math.floor(rand() * 3) - 1, 0);\n    cumulative[s].push(Math.min(prevCount + advance, cumulative[s - 1][d]));\n  }\n}\n\n// Band width (work-in-progress) per stage = its cumulative count minus the\n// next stage's cumulative count — the quantity a CFD band actually encodes.\nconst wip = stageNames.map((name, i) =>\n  cumulative[i].map((v, d) => v - (i + 1 < stageNames.length ? cumulative[i + 1][d] : 0))\n);\n\nconst stageColor = {\n  Backlog: t.palette[0],\n  Analysis: t.palette[1],\n  Development: t.palette[2],\n  Testing: t.palette[3],\n  Done: t.palette[4],\n};\n\n// Give each band a little depth: a vertical gradient fill (richer near the\n// band's own boundary, softer toward the stack) instead of a flat opacity.\nfunction hexToRgba(hex, alpha) {\n  const n = parseInt(hex.slice(1), 16);\n  return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${alpha})`;\n}\nfunction bandGradient(hex) {\n  return new echarts.graphic.LinearGradient(0, 0, 0, 1, [\n    { offset: 0, color: hexToRgba(hex, 0.92) },\n    { offset: 1, color: hexToRgba(hex, 0.55) },\n  ]);\n}\n\n// Development is the bottleneck stage: Testing's capacity is the tightest\n// gate, so the Development band widens steadily as the run progresses.\n// Highlight the back half of the run where that widening is unmistakable.\nconst bottleneckStartDay = Math.floor(DAYS * 0.45);\n\n// --- Init --------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option --------------------------------------------------------------------\n// Stack bottom-to-top in series order: Done at the bottom (closest to the\n// axis), Backlog on top — matching the spec's required stacking direction.\nconst stackOrder = [\"Done\", \"Testing\", \"Development\", \"Analysis\", \"Backlog\"];\n\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"area-cumulative-flow · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 20,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n  },\n  tooltip: {\n    trigger: \"axis\",\n    axisPointer: { type: \"cross\" },\n    valueFormatter: (value) => `${value} items`,\n  },\n  legend: {\n    data: stageNames,\n    top: 66,\n    left: \"center\",\n    textStyle: { color: t.ink, fontSize: 16 },\n    itemWidth: 18,\n    itemHeight: 12,\n  },\n  grid: {\n    left: 90,\n    right: 60,\n    top: 130,\n    bottom: 70,\n    containLabel: true,\n  },\n  xAxis: {\n    type: \"category\",\n    data: dates,\n    boundaryGap: false,\n    name: \"Date\",\n    nameLocation: \"middle\",\n    nameGap: 40,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    axisLabel: { color: t.inkSoft, fontSize: 13 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  yAxis: {\n    type: \"value\",\n    name: \"Cumulative Items\",\n    nameLocation: \"middle\",\n    nameGap: 60,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    axisLabel: { color: t.inkSoft, fontSize: 13 },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  series: stackOrder.map((name) => ({\n    name,\n    type: \"line\",\n    stack: \"flow\",\n    data: wip[stageNames.indexOf(name)],\n    symbol: \"none\",\n    lineStyle: { width: 1.5, color: stageColor[name] },\n    areaStyle: { color: bandGradient(stageColor[name]) },\n    itemStyle: { color: stageColor[name] },\n    emphasis: { focus: \"series\" },\n    // Call out the widening Development band — the CFD's bottleneck signature\n    // — with a labeled shaded window instead of leaving it only implicit in\n    // the data.\n    ...(name === \"Development\"\n      ? {\n          markArea: {\n            silent: true,\n            itemStyle: { color: t.ink, opacity: 0.05 },\n            label: {\n              show: true,\n              position: \"insideTop\",\n              color: t.inkSoft,\n              fontSize: 13,\n              formatter: \"Bottleneck: Development WIP widens as Testing throughput caps it\",\n            },\n            data: [[{ xAxis: dates[bottleneckStartDay] }, { xAxis: dates[dates.length - 1] }]],\n          },\n        }\n      : {}),\n  })),\n});\n"}