{"spec_id":"venn-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// venn-basic: Venn Diagram\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 92/100 | Created: 2026-09-09\n//# anyplot-orientation: square\n// anyplot.ai\n// venn-basic: Venn Diagram\n// Library: MUI X Charts | React | Node 22\n// License: @mui/x-charts — MIT (community). Pro/Premium are out of scope.\n// Quality: pending | Created: 2026-09-09\nimport * as React from \"react\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { ChartContainer } from \"@mui/x-charts/ChartContainer\";\nimport { useDrawingArea } from \"@mui/x-charts/hooks\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Skill overlap across a 200-person data team.\nconst setLabels = [\"Python\", \"SQL\", \"Statistics\"];\nconst setSizes = [120, 95, 80];\nconst pairAB = 45; // Python & SQL\nconst pairAC = 38; // Python & Statistics\nconst pairBC = 30; // SQL & Statistics\nconst tripleABC = 18; // all three\n\nconst onlyA = setSizes[0] - pairAB - pairAC + tripleABC;\nconst onlyB = setSizes[1] - pairAB - pairBC + tripleABC;\nconst onlyC = setSizes[2] - pairAC - pairBC + tripleABC;\nconst onlyAB = pairAB - tripleABC;\nconst onlyAC = pairAC - tripleABC;\nconst onlyBC = pairBC - tripleABC;\n\nconst seriesColors = [t.palette[0], t.palette[1], t.palette[2]];\n\n// --- Custom SVG marks, placed via ChartContainer's drawing area -------------\n// MUI X community has no native Venn primitive, so this follows MUI X's\n// documented composition pattern (ChartContainer + useDrawingArea) to\n// hand-place plain SVG circles/text inside the theme-aware ChartsSurface.\nfunction VennMarks() {\n  const area = useDrawingArea();\n  const cx = area.left + area.width / 2;\n  const cy = area.top + area.height / 2;\n\n  const maxRadius = Math.min(area.width, area.height) * 0.32;\n  const scale = maxRadius / Math.sqrt(Math.max(...setSizes));\n  const radii = setSizes.map((size) => Math.sqrt(size) * scale);\n  const avgRadius = (radii[0] + radii[1] + radii[2]) / 3;\n  const offset = avgRadius * 0.55;\n\n  const centers = [\n    { x: cx, y: cy - offset },\n    { x: cx - offset * 0.87, y: cy + offset * 0.5 },\n    { x: cx + offset * 0.87, y: cy + offset * 0.5 },\n  ];\n\n  const textProps = {\n    textAnchor: \"middle\" as const,\n    dominantBaseline: \"middle\" as const,\n    fill: t.ink,\n    paintOrder: \"stroke\" as const,\n    stroke: t.pageBg,\n    strokeWidth: 5,\n    strokeLinejoin: \"round\" as const,\n  };\n\n  const onlyRegions = [\n    { name: setLabels[0], count: onlyA, x: centers[0].x, y: centers[0].y - radii[0] * 0.45 },\n    { name: setLabels[1], count: onlyB, x: centers[1].x - radii[1] * 0.32, y: centers[1].y + radii[1] * 0.4 },\n    { name: setLabels[2], count: onlyC, x: centers[2].x + radii[2] * 0.32, y: centers[2].y + radii[2] * 0.4 },\n  ];\n\n  const pairOverlapRegions = [\n    { count: onlyAB, x: (centers[0].x + centers[1].x) / 2 - offset * 0.08, y: (centers[0].y + centers[1].y) / 2 },\n    { count: onlyAC, x: (centers[0].x + centers[2].x) / 2 + offset * 0.08, y: (centers[0].y + centers[2].y) / 2 },\n    { count: onlyBC, x: cx, y: centers[1].y + radii[1] * 0.62 },\n  ];\n\n  const tripleX = cx;\n  const tripleY = cy + offset * 0.05;\n  const calloutRadius = avgRadius * 0.24;\n  const circleStrokeWidths = [3, 2.25, 1.5];\n\n  return (\n    <>\n      {centers.map((c, i) => (\n        <circle\n          key={setLabels[i]}\n          cx={c.x}\n          cy={c.y}\n          r={radii[i]}\n          fill={seriesColors[i]}\n          fillOpacity={0.55}\n          stroke={seriesColors[i]}\n          strokeWidth={circleStrokeWidths[i]}\n        />\n      ))}\n      {onlyRegions.map((r) => (\n        <React.Fragment key={r.name}>\n          <text {...textProps} x={r.x} y={r.y - 20} fontSize={20} fontWeight={600}>\n            {r.name}\n          </text>\n          <text {...textProps} x={r.x} y={r.y + 14} fontSize={30} fontWeight={700}>\n            {r.count}\n          </text>\n        </React.Fragment>\n      ))}\n      {pairOverlapRegions.map((r, i) => (\n        <text key={i} {...textProps} x={r.x} y={r.y} fontSize={22} fontWeight={600}>\n          {r.count}\n        </text>\n      ))}\n      {/* Callout badge on the triple overlap — the diagram's focal point. */}\n      <circle\n        cx={tripleX}\n        cy={tripleY}\n        r={calloutRadius}\n        fill={t.pageBg}\n        fillOpacity={0.85}\n        stroke={t.ink}\n        strokeWidth={1.5}\n      />\n      <text {...textProps} x={tripleX} y={tripleY} fontSize={28} fontWeight={800} strokeWidth={4}>\n        {tripleABC}\n      </text>\n    </>\n  );\n}\n\n// --- Chart (default-exported component — the harness mounts it) -------------\nexport default function Chart() {\n  const width = window.ANYPLOT_SIZE.width;\n  const height = window.ANYPLOT_SIZE.height;\n  const titleHeight = 76;\n\n  return (\n    <Box sx={{ width, height, display: \"flex\", flexDirection: \"column\" }}>\n      <Typography\n        sx={{\n          height: titleHeight,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          fontSize: 26,\n          fontWeight: 500,\n          color: t.ink,\n        }}\n      >\n        venn-basic · javascript · muix · anyplot.ai\n      </Typography>\n      <ChartContainer\n        width={width}\n        height={height - titleHeight}\n        margin={{ top: 20, bottom: 20, left: 20, right: 20 }}\n        series={[]}\n        skipAnimation\n      >\n        <VennMarks />\n      </ChartContainer>\n    </Box>\n  );\n}\n"}