{"spec_id":"donut-basic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// donut-basic: Basic Donut Chart\n// Library: chartjs 4.4.7 | JavaScript 22.23.0\n// Quality: 93/100 | Created: 2026-06-25\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data -------------------------------------------------------------------\nconst departments = ['Engineering', 'Marketing', 'Operations', 'Sales', 'Research'];\nconst budgets = [900000, 480000, 420000, 360000, 240000]; // total: 2,400,000\nconst total = budgets.reduce((a, b) => a + b, 0);\n\n// --- Center label plugin ----------------------------------------------------\nconst centerPlugin = {\n  id: 'centerLabel',\n  afterDraw(chart) {\n    const { ctx, chartArea } = chart;\n    const cx = chartArea.left + chartArea.width / 2;\n    const cy = chartArea.top + chartArea.height / 2;\n    ctx.save();\n    ctx.textAlign = 'center';\n    ctx.textBaseline = 'middle';\n    ctx.font = 'bold 38px sans-serif';\n    ctx.fillStyle = t.ink;\n    ctx.fillText('$2.4M', cx, cy - 24);\n    ctx.font = '20px sans-serif';\n    ctx.fillStyle = t.inkSoft;\n    ctx.fillText('Total Budget', cx, cy + 24);\n    ctx.restore();\n  },\n};\n\n// --- Segment percentage label plugin ----------------------------------------\nconst segmentLabelsPlugin = {\n  id: 'segmentLabels',\n  afterDraw(chart) {\n    const { ctx } = chart;\n    const meta = chart.getDatasetMeta(0);\n    meta.data.forEach((arc, i) => {\n      const pct = ((budgets[i] / total) * 100).toFixed(1) + '%';\n      const midAngle = (arc.startAngle + arc.endAngle) / 2;\n      const r = (arc.innerRadius + arc.outerRadius) / 2;\n      const x = arc.x + Math.cos(midAngle) * r;\n      const y = arc.y + Math.sin(midAngle) * r;\n      ctx.save();\n      ctx.textAlign = 'center';\n      ctx.textBaseline = 'middle';\n      ctx.font = 'bold 16px sans-serif';\n      ctx.strokeStyle = 'rgba(0,0,0,0.3)';\n      ctx.lineWidth = 4;\n      ctx.lineJoin = 'round';\n      ctx.strokeText(pct, x, y);\n      ctx.fillStyle = '#FFFFFF';\n      ctx.fillText(pct, x, y);\n      ctx.restore();\n    });\n  },\n};\n\n// --- Mount ------------------------------------------------------------------\nconst canvas = document.createElement('canvas');\ndocument.getElementById('container').appendChild(canvas);\n\n// --- Chart ------------------------------------------------------------------\nnew Chart(canvas, {\n  type: 'doughnut',\n  plugins: [centerPlugin, segmentLabelsPlugin],\n  data: {\n    labels: departments,\n    datasets: [{\n      data: budgets,\n      backgroundColor: departments.map((_, i) => t.palette[i]),\n      borderWidth: 3,\n      borderColor: t.pageBg,\n      hoverOffset: 0,\n    }],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    cutout: '65%',\n    layout: { padding: { top: 10, bottom: 10, left: 20, right: 20 } },\n    plugins: {\n      title: {\n        display: true,\n        text: 'donut-basic · javascript · chartjs · anyplot.ai',\n        color: t.ink,\n        font: { size: 22, weight: 'bold' },\n        padding: { top: 16, bottom: 24 },\n      },\n      legend: {\n        position: 'bottom',\n        labels: {\n          color: t.ink,\n          font: { size: 16 },\n          padding: 24,\n          usePointStyle: true,\n          generateLabels(chart) {\n            return chart.data.labels.map((label, i) => ({\n              text: `${label}  (${((budgets[i] / total) * 100).toFixed(1)}%)`,\n              fillStyle: t.palette[i],\n              strokeStyle: t.palette[i],\n              hidden: false,\n              index: i,\n              datasetIndex: 0,\n            }));\n          },\n        },\n      },\n    },\n  },\n});\n"}