{"spec_id":"bar-stacked-percent","library":"echarts","language":"javascript","code":"// anyplot.ai\n// bar-stacked-percent: 100% Stacked Bar Chart\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 90/100 | Created: 2026-08-18\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Urban commute mode share, thousands of commuters per year. Yearly totals\n// drift (500 -> 512), which is exactly why a 100% stacked view is useful here:\n// it isolates the share shift from the underlying volume growth.\nconst years = [\"2019\", \"2020\", \"2021\", \"2022\", \"2023\", \"2024\"];\nconst components = [\"Car\", \"Public Transit\", \"Bicycle\", \"Walking\"];\nconst rawByComponent = [\n  [310, 305, 288, 275, 260, 245], // Car\n  [120, 110, 95, 115, 130, 150], // Public Transit\n  [40, 55, 62, 70, 78, 85], // Bicycle\n  [30, 45, 40, 38, 35, 32], // Walking\n];\n\nconst totalsByYear = years.map((_, yearIdx) =>\n  rawByComponent.reduce((sum, series) => sum + series[yearIdx], 0)\n);\nconst percentByComponent = rawByComponent.map((series) =>\n  series.map((value, yearIdx) => (value / totalsByYear[yearIdx]) * 100)\n);\n\n// --- Init --------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option --------------------------------------------------------------------\nconst title = \"Urban Commute Mode Share · bar-stacked-percent · javascript · echarts · anyplot.ai\";\n\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  title: {\n    text: title,\n    left: \"center\",\n    top: 24,\n    textStyle: { color: t.ink, fontSize: 18, fontWeight: 500 },\n  },\n  tooltip: {\n    trigger: \"axis\",\n    axisPointer: { type: \"shadow\" },\n    valueFormatter: (value) => `${value.toFixed(1)}%`,\n  },\n  legend: {\n    data: components,\n    top: 76,\n    textStyle: { color: t.ink, fontSize: 16 },\n  },\n  grid: { left: 90, right: 60, top: 140, bottom: 70, containLabel: true },\n  xAxis: {\n    type: \"category\",\n    data: years,\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  yAxis: {\n    type: \"value\",\n    min: 0,\n    max: 100,\n    interval: 20,\n    axisLabel: { color: t.inkSoft, fontSize: 14, formatter: \"{value}%\" },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  series: components.map((name, i) => ({\n    name,\n    type: \"bar\",\n    stack: \"total\",\n    barWidth: \"55%\",\n    data: percentByComponent[i],\n    itemStyle: { color: t.palette[i] },\n    label: {\n      show: true,\n      position: \"inside\",\n      formatter: (params) => (params.value >= 6 ? `${Math.round(params.value)}%` : \"\"),\n      color: t.ink,\n      textBorderColor: t.pageBg,\n      textBorderWidth: 3,\n      fontSize: 13,\n    },\n  })),\n});\n"}