{"spec_id":"chord-basic","library":"d3","language":"javascript","code":"// anyplot.ai\n// chord-basic: Basic Chord Diagram\n// Library: d3 7.9.0 | JavaScript 22.22.3\n// Quality: 92/100 | Created: 2026-06-17\n//# anyplot-orientation: square\n// anyplot.ai\n// chord-basic: Basic Chord Diagram\n// Library: d3 7.9.0 | JavaScript 22\n// Quality: pending | Created: 2026-06-17\n\nconst t = window.ANYPLOT_TOKENS;\nconst { width, height } = window.ANYPLOT_SIZE;\n\n// --- Data (in-memory, deterministic) ---------------------------------------\n// Weekly cross-team messages (thousands) between six departments. The matrix is\n// directional: matrix[i][j] = messages sent FROM department i TO department j.\nconst departments = [\n  \"Engineering\",\n  \"Product\",\n  \"Design\",\n  \"Sales\",\n  \"Marketing\",\n  \"Support\",\n];\n\nconst matrix = [\n  //  Eng  Prod Des  Sale Mkt  Supp\n  [0, 18, 9, 3, 2, 12], // Engineering →\n  [16, 0, 14, 7, 6, 8], // Product →\n  [8, 13, 0, 2, 9, 4], // Design →\n  [4, 8, 3, 0, 15, 11], // Sales →\n  [3, 7, 10, 14, 0, 5], // Marketing →\n  [11, 9, 5, 10, 4, 0], // Support →\n];\n\n// --- Geometry ---------------------------------------------------------------\nconst cx = width / 2;\nconst cy = height / 2 + 14; // nudge down to clear the title\nconst outerRadius = Math.min(width, height) * 0.5 - 165;\nconst innerRadius = outerRadius - 24;\n\n// --- Imprint categorical colour per department (first = brand green) --------\nconst color = d3\n  .scaleOrdinal()\n  .domain(d3.range(departments.length))\n  .range(t.palette);\n\n// --- Chord layout -----------------------------------------------------------\nconst chord = d3\n  .chord()\n  .padAngle(0.04)\n  .sortSubgroups(d3.descending)\n  .sortChords(d3.descending);\n\nconst chords = chord(matrix);\n\nconst arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);\nconst ribbon = d3.ribbon().radius(innerRadius - 1);\nconst fmt = d3.format(\",.0f\");\n\n// --- SVG mount --------------------------------------------------------------\nconst svg = d3\n  .select(\"#container\")\n  .append(\"svg\")\n  .attr(\"width\", width)\n  .attr(\"height\", height);\n\nconst g = svg.append(\"g\").attr(\"transform\", `translate(${cx},${cy})`);\n\n// --- Ribbons (flows), coloured by source department -------------------------\ng.append(\"g\")\n  .attr(\"fill-opacity\", 0.72)\n  .selectAll(\"path\")\n  .data(chords)\n  .join(\"path\")\n  .attr(\"d\", ribbon)\n  .attr(\"fill\", (d) => color(d.source.index))\n  .attr(\"stroke\", t.pageBg)\n  .attr(\"stroke-width\", 0.75)\n  .append(\"title\")\n  .text(\n    (d) =>\n      `${departments[d.source.index]} → ${departments[d.target.index]}: ${fmt(\n        d.source.value,\n      )}k\\n${departments[d.target.index]} → ${departments[d.source.index]}: ${fmt(\n        d.target.value,\n      )}k`,\n  );\n\n// --- Outer arcs (departments) ----------------------------------------------\nconst group = g\n  .append(\"g\")\n  .selectAll(\"g\")\n  .data(chords.groups)\n  .join(\"g\");\n\ngroup\n  .append(\"path\")\n  .attr(\"d\", arc)\n  .attr(\"fill\", (d) => color(d.index))\n  .attr(\"stroke\", t.pageBg)\n  .attr(\"stroke-width\", 1.5)\n  .append(\"title\")\n  .text(\n    (d) => `${departments[d.index]}: ${fmt(d.value)}k messages total`,\n  );\n\n// --- Department labels, rotated tangent to the arc --------------------------\ngroup\n  .append(\"text\")\n  .each((d) => {\n    d.angle = (d.startAngle + d.endAngle) / 2;\n  })\n  .attr(\"dy\", \"0.35em\")\n  .attr(\"transform\", (d) => {\n    const rot = (d.angle * 180) / Math.PI - 90;\n    const flip = d.angle > Math.PI ? \"rotate(180)\" : \"\";\n    return `rotate(${rot}) translate(${outerRadius + 16},0) ${flip}`;\n  })\n  .attr(\"text-anchor\", (d) => (d.angle > Math.PI ? \"end\" : \"start\"))\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"19px\")\n  .style(\"font-weight\", \"600\")\n  .text((d) => departments[d.index]);\n\n// --- Title ------------------------------------------------------------------\nsvg\n  .append(\"text\")\n  .attr(\"x\", width / 2)\n  .attr(\"y\", 52)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"30px\")\n  .style(\"font-weight\", \"600\")\n  .text(\"Inter-Team Messages · chord-basic · javascript · d3 · anyplot.ai\");\n\n// --- Subtitle ---------------------------------------------------------------\nsvg\n  .append(\"text\")\n  .attr(\"x\", width / 2)\n  .attr(\"y\", 88)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.inkSoft)\n  .style(\"font-size\", \"17px\")\n  .text(\"Weekly message volume between departments (thousands)\");\n"}