{"spec_id":"chord-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// chord-basic: Basic Chord Diagram\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 86/100 | Created: 2026-06-17\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Data — annual migration flows between continents (millions of people).\n// ECharts has no native chord type; a circular `graph` series is the idiomatic\n// equivalent — entities sit on a ring, arcs (chords) carry the flow magnitude.\nconst continents = [\n  \"Africa\",        // brand green — always first\n  \"Asia\",\n  \"Europe\",\n  \"N. America\",\n  \"S. America\",\n  \"Oceania\",\n];\n\n// Each entity gets a distinct Imprint color (canonical order 1→6).\nconst nodeColor = {\n  \"Africa\": t.palette[0],\n  \"Asia\": t.palette[1],\n  \"Europe\": t.palette[2],\n  \"N. America\": t.palette[3],\n  \"S. America\": t.palette[4],\n  \"Oceania\": t.palette[5],\n};\n\n// Directed flows (source → target, value in millions). Bidirectional pairs are\n// listed separately so both directions render as their own chord.\nconst flows = [\n  { source: \"Asia\", target: \"Europe\", value: 12 },\n  { source: \"Asia\", target: \"N. America\", value: 15 },\n  { source: \"Asia\", target: \"Oceania\", value: 4 },\n  { source: \"Africa\", target: \"Europe\", value: 9 },\n  { source: \"Africa\", target: \"Asia\", value: 5 },\n  { source: \"Africa\", target: \"N. America\", value: 3 },\n  { source: \"Africa\", target: \"Oceania\", value: 1 },\n  { source: \"Europe\", target: \"N. America\", value: 7 },\n  { source: \"Europe\", target: \"Asia\", value: 4 },\n  { source: \"Europe\", target: \"Oceania\", value: 2 },\n  { source: \"S. America\", target: \"N. America\", value: 8 },\n  { source: \"S. America\", target: \"Europe\", value: 5 },\n  { source: \"S. America\", target: \"Asia\", value: 1 },\n  { source: \"N. America\", target: \"Europe\", value: 3 },\n  { source: \"N. America\", target: \"Asia\", value: 2 },\n  { source: \"N. America\", target: \"S. America\", value: 2 },\n  { source: \"Oceania\", target: \"Europe\", value: 2 },\n  { source: \"Oceania\", target: \"Asia\", value: 3 },\n];\n\n// Node size encodes total throughput (in + out flow).\nconst throughput = Object.fromEntries(continents.map((c) => [c, 0]));\nfor (const f of flows) {\n  throughput[f.source] += f.value;\n  throughput[f.target] += f.value;\n}\nconst maxThroughput = Math.max(...Object.values(throughput));\nconst sizeFor = (c) => 34 + (throughput[c] / maxThroughput) * 44;\n\nconst nodes = continents.map((c) => ({\n  name: c,\n  symbolSize: sizeFor(c),\n  itemStyle: { color: nodeColor[c], borderColor: t.pageBg, borderWidth: 2 },\n}));\n\n// Chord width is proportional to flow magnitude; color follows the source node.\nconst links = flows.map((f) => ({\n  source: f.source,\n  target: f.target,\n  value: f.value,\n  lineStyle: {\n    // Minimum width + opacity floor keep low-volume flows (1–2M) legible.\n    width: 3 + f.value * 0.85,\n    curveness: 0.3,\n    color: nodeColor[f.source],\n    opacity: 0.65,\n  },\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: \"Migration Between Continents · chord-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 26,\n    textStyle: { color: t.ink, fontSize: 26, fontWeight: 500 },\n  },\n  tooltip: {\n    trigger: \"item\",\n    formatter: (p) =>\n      p.dataType === \"edge\"\n        ? `${p.data.source} → ${p.data.target}<br/>${p.data.value}M people`\n        : `${p.name}<br/>${throughput[p.name]}M total flow`,\n  },\n  series: [{\n    type: \"graph\",\n    layout: \"circular\",\n    circular: { rotateLabel: false },\n    data: nodes,\n    links: links,\n    roam: false,\n    // Reserve a title band at the top and shrink the ring slightly so the\n    // topmost node clears the title text (VQ-02 crowding fix).\n    top: \"12%\",\n    bottom: \"6%\",\n    center: [\"50%\", \"54%\"],\n    edgeSymbol: [\"none\", \"arrow\"],\n    edgeSymbolSize: 10,\n    label: {\n      show: true,\n      position: \"right\",\n      color: t.ink,\n      fontSize: 19,\n      fontWeight: 500,\n    },\n    lineStyle: { opacity: 0.65 },\n    emphasis: {\n      focus: \"adjacency\",\n      lineStyle: { opacity: 0.9 },\n      label: { fontSize: 21 },\n    },\n  }],\n});\n\nwindow.addEventListener(\"resize\", () => chart.resize());\nchart.on(\"finished\", () => { window.__anyplotReady = true; });\n"}