{"spec_id":"bar-diverging","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// bar-diverging: Diverging Bar Chart\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 95/100 | Created: 2026-08-18\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Employee engagement survey: net agreement score (% agree − % disagree) per\n// topic, sorted descending so the pattern (strong positives to strong\n// negatives) reads at a glance.\nconst topics = [\n  \"Career Growth\",\n  \"Work-Life Balance\",\n  \"Team Collaboration\",\n  \"Remote Flexibility\",\n  \"Job Security\",\n  \"Training & Development\",\n  \"Management Support\",\n  \"Compensation\",\n];\nconst netScores = [62, 48, 31, 14, -8, -19, -33, -45];\n\nconst positiveColor = t.palette[0]; // #009E73 brand green — sentiment: agree\nconst negativeColor = t.palette[4]; // #AE3030 matte red — sentiment: disagree\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Title (fontsize scaled against this spec's own mandated-title length) --\n// Only shrink once the descriptive prefix pushes the full title past 1.8x the\n// bare mandated suffix (\"bar-diverging · javascript · chartjs · anyplot.ai\");\n// short spec-ids like this one keep the full base size instead of being\n// over-shrunk against a generic fixed-length reference.\nconst mandatedTitle = \"bar-diverging · javascript · chartjs · anyplot.ai\";\nconst title = `Employee Engagement Survey · ${mandatedTitle}`;\nconst titleFontSize = Math.round(26 * Math.min(1, (mandatedTitle.length * 1.8) / title.length));\n\n// --- End-of-bar value labels (custom Chart.js plugin, canvas-drawn) ---------\n// Gives every bar an explicit numeric focal point (e.g. Career Growth +62,\n// Compensation -45) instead of relying on axis reading alone.\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 sans-serif\";\n    ctx.textBaseline = \"middle\";\n    meta.data.forEach((bar, i) => {\n      const value = netScores[i];\n      ctx.fillStyle = value >= 0 ? positiveColor : negativeColor;\n      ctx.textAlign = value >= 0 ? \"left\" : \"right\";\n      ctx.fillText(`${value > 0 ? \"+\" : \"\"}${value}`, bar.x + (value >= 0 ? 8 : -8), bar.y);\n    });\n    ctx.restore();\n  },\n};\n\n// --- Chart ---------------------------------------------------------------\nnew Chart(canvas, {\n  type: \"bar\",\n  data: {\n    labels: topics,\n    datasets: [\n      {\n        label: \"Net agreement\",\n        data: netScores,\n        backgroundColor: netScores.map((v) => (v >= 0 ? positiveColor : negativeColor)),\n        borderWidth: 0,\n        borderRadius: 3,\n      },\n    ],\n  },\n  plugins: [valueLabelsPlugin],\n  options: {\n    indexAxis: \"y\",\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    layout: { padding: { top: 20, right: 36, bottom: 16, left: 12 } },\n    plugins: {\n      title: { display: true, text: title, color: t.ink, font: { size: titleFontSize, weight: \"500\" } },\n      legend: { display: false },\n    },\n    scales: {\n      x: {\n        min: -70,\n        max: 70,\n        title: { display: true, text: \"Net Agreement Score (%)\", color: t.ink, font: { size: 15 } },\n        ticks: { color: t.inkSoft, font: { size: 13 } },\n        grid: {\n          color: (ctx) => (ctx.tick.value === 0 ? t.ink : t.grid),\n          lineWidth: (ctx) => (ctx.tick.value === 0 ? 2 : 1),\n        },\n        border: { display: false },\n      },\n      y: {\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { display: false },\n        border: { display: false },\n      },\n    },\n  },\n});\n"}