{"spec_id":"funnel-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// funnel-basic: Basic Funnel Chart\n// Library: echarts 6.1.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) ---------------------------------------\nconst stages = [\"Applications\", \"Screened\", \"Interviewed\", \"Offer Extended\", \"Hired\"];\nconst counts = [2400, 1450, 620, 240, 150];\n\n// Imprint data colors are theme-invariant, so each segment's label needs a\n// fixed color chosen for that segment's own luminance rather than a\n// theme-linked token -- t.pageBg flips near-white/near-black with the theme\n// while the segment fill stays the same, producing dark-on-dark on the two\n// darkest hues (blue, matte red) once the theme flips.\nconst labelColors = [\"#1A1A17\", \"#1A1A17\", \"#FFFFFF\", \"#1A1A17\", \"#FFFFFF\"];\n\nconst funnelData = stages.map((stage, i) => ({\n  name: stage,\n  value: counts[i],\n  label: { color: labelColors[i] },\n}));\n\n// --- Init -------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option -----------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"funnel-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 30,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n  },\n  tooltip: {\n    show: true,\n    trigger: \"item\",\n    backgroundColor: t.elevatedBg,\n    borderColor: t.grid,\n    textStyle: { color: t.ink },\n    formatter: (params) =>\n      `${params.name}<br/>${params.value.toLocaleString()} (${Math.round((params.value / counts[0]) * 100)}% of ${stages[0]})`,\n  },\n  legend: {\n    show: false,\n  },\n  series: [\n    {\n      type: \"funnel\",\n      left: \"12%\",\n      right: \"12%\",\n      top: 110,\n      bottom: 60,\n      width: \"76%\",\n      min: 0,\n      max: counts[0],\n      minSize: \"10%\",\n      maxSize: \"100%\",\n      sort: \"descending\",\n      gap: 4,\n      label: {\n        show: true,\n        position: \"inside\",\n        formatter: (params) =>\n          `${params.name}\\n${params.value.toLocaleString()} (${Math.round((params.value / counts[0]) * 100)}%)`,\n        fontSize: 16,\n        fontWeight: 500,\n        lineHeight: 22,\n      },\n      labelLine: { show: false },\n      itemStyle: {\n        borderColor: t.pageBg,\n        borderWidth: 2,\n      },\n      emphasis: { disabled: true },\n      data: funnelData,\n    },\n  ],\n});\n"}