{"spec_id":"bar-horizontal","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// bar-horizontal: Horizontal Bar Chart\n// Library: chartjs 4.4.7 | JavaScript 22.23.1\n// Quality: 90/100 | Created: 2026-08-05\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Native speakers by language, descending so the largest bar sits on top.\nconst languages = [\n  \"Mandarin Chinese\",\n  \"Spanish\",\n  \"English\",\n  \"Hindi\",\n  \"Arabic\",\n  \"Bengali\",\n  \"Portuguese\",\n  \"Russian\",\n  \"Japanese\",\n  \"Vietnamese\",\n];\nconst speakersMillions = [941, 486, 380, 345, 274, 237, 232, 154, 123, 85];\n\n// Brand green at full strength for the top-ranked bar, muted for the rest —\n// a focal-point highlight layered on top of the sort order.\nfunction hexToRgba(hex, alpha) {\n  const r = parseInt(hex.slice(1, 3), 16);\n  const g = parseInt(hex.slice(3, 5), 16);\n  const b = parseInt(hex.slice(5, 7), 16);\n  return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\nconst barColors = speakersMillions.map((_, i) =>\n  i === 0 ? t.palette[0] : hexToRgba(t.palette[0], 0.55),\n);\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Chart -------------------------------------------------------------------\nconst title =\n  \"World's Most Spoken Languages · bar-horizontal · javascript · chartjs · anyplot.ai\";\n\n// Custom Chart.js plugin: draw the value at the end of each bar so exact\n// speaker counts are readable without a separate legend or tooltip.\n// Chart.js always paints via requestAnimationFrame (even with animation:\n// false), so `afterRender` also flips window.__anyplotReady — the harness's\n// signal that drawing (including this plugin's afterDatasetsDraw) is done,\n// instead of racing a generic fonts-ready/rAF heuristic against Chart's own\n// scheduled frame.\nconst valueLabelsPlugin = {\n  id: \"valueLabels\",\n  afterDatasetsDraw(chart) {\n    const { ctx } = chart;\n    const meta = chart.getDatasetMeta(0);\n    ctx.save();\n    ctx.font = `600 13px ${Chart.defaults.font.family}`;\n    ctx.fillStyle = t.ink;\n    ctx.textAlign = \"left\";\n    ctx.textBaseline = \"middle\";\n    meta.data.forEach((bar, i) => {\n      ctx.fillText(`${speakersMillions[i]}M`, bar.x + 8, bar.y);\n    });\n    ctx.restore();\n  },\n  afterRender() {\n    window.__anyplotReady = true;\n  },\n};\n\nnew Chart(canvas, {\n  type: \"bar\",\n  data: {\n    labels: languages,\n    datasets: [\n      {\n        label: \"Native Speakers (millions)\",\n        data: speakersMillions,\n        backgroundColor: barColors,\n        borderWidth: 0,\n        barPercentage: 0.7,\n        categoryPercentage: 0.8,\n      },\n    ],\n  },\n  plugins: [valueLabelsPlugin],\n  options: {\n    indexAxis: \"y\",\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    layout: { padding: { top: 8, right: 56, bottom: 8, left: 8 } },\n    plugins: {\n      title: {\n        display: true,\n        text: title,\n        color: t.ink,\n        font: { size: 18, weight: \"500\" },\n        padding: { bottom: 20 },\n      },\n      legend: { display: false },\n    },\n    scales: {\n      x: {\n        beginAtZero: true,\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { color: t.grid },\n        title: {\n          display: true,\n          text: \"Native Speakers (millions)\",\n          color: t.ink,\n          font: { size: 16 },\n        },\n        border: { color: t.inkSoft },\n      },\n      y: {\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { display: false },\n        border: { color: t.inkSoft },\n      },\n    },\n  },\n});\n"}