{"spec_id":"line-reaction-coordinate","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// line-reaction-coordinate: Reaction Coordinate Energy Diagram\n// Library: chartjs 4.4.7 | JavaScript 22.22.3\n// Quality: 89/100 | Created: 2026-06-24\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data -------------------------------------------------------------------\n// Single-step exothermic reaction: reactants=50 kJ/mol, TS=120 kJ/mol, products=20 kJ/mol\nconst POINTS = 200;\nconst curveData = [];\nfor (let i = 0; i <= POINTS; i++) {\n  const x = i / POINTS;\n  const base = 50 - 30 * x;\n  const barrier = 85 * Math.exp(-0.5 * Math.pow((x - 0.5) / 0.15, 2));\n  curveData.push({ x, y: parseFloat((base + barrier).toFixed(3)) });\n}\n\n// Dashed horizontal reference lines at reactant and product energy levels\nconst reactantRef = [{ x: 0, y: 50 }, { x: 0.28, y: 50 }];\nconst productRef  = [{ x: 0.72, y: 20 }, { x: 1.0, y: 20 }];\n\n// --- Mount ------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Background plugin ------------------------------------------------------\nconst bgPlugin = {\n  id: \"bg\",\n  beforeDraw(chart) {\n    const { ctx, width, height } = chart;\n    ctx.save();\n    ctx.fillStyle = t.pageBg;\n    ctx.fillRect(0, 0, width, height);\n    ctx.restore();\n  },\n};\n\n// --- Arrow helper -----------------------------------------------------------\nfunction arrowHead(ctx, fromX, fromY, toX, toY, size) {\n  const angle = Math.atan2(toY - fromY, toX - fromX);\n  ctx.beginPath();\n  ctx.moveTo(toX, toY);\n  ctx.lineTo(\n    toX - size * Math.cos(angle - Math.PI / 6),\n    toY - size * Math.sin(angle - Math.PI / 6)\n  );\n  ctx.lineTo(\n    toX - size * Math.cos(angle + Math.PI / 6),\n    toY - size * Math.sin(angle + Math.PI / 6)\n  );\n  ctx.closePath();\n  ctx.fill();\n}\n\n// --- Annotation plugin: state labels + Ea and ΔH double-headed arrows ------\nconst annotPlugin = {\n  id: \"annot\",\n  afterDraw(chart) {\n    const ctx = chart.ctx;\n    const xS  = chart.scales.x;\n    const yS  = chart.scales.y;\n    const px  = (xv, yv) => ({ x: xS.getPixelForValue(xv), y: yS.getPixelForValue(yv) });\n\n    ctx.save();\n    ctx.fillStyle   = t.ink;\n    ctx.strokeStyle = t.ink;\n\n    // State labels\n    ctx.font         = \"bold 16px sans-serif\";\n    ctx.textAlign    = \"center\";\n    ctx.textBaseline = \"bottom\";\n\n    const rPos = px(0.06, 50);\n    ctx.fillText(\"Reactants\", rPos.x, rPos.y - 14);\n\n    const tsPos = px(0.5, 120);\n    ctx.fillText(\"Transition State ‡\", tsPos.x, tsPos.y - 14);\n\n    const pPos = px(0.94, 20);\n    ctx.fillText(\"Products\", pPos.x, pPos.y - 14);\n\n    // Ea double-headed arrow (reactant energy level → transition state peak)\n    const EA_X  = 0.34;\n    const eaBot = px(EA_X, 50);\n    const eaTop = px(EA_X, 120);\n\n    ctx.lineWidth = 1.5;\n    ctx.beginPath();\n    ctx.moveTo(eaBot.x, eaBot.y);\n    ctx.lineTo(eaTop.x, eaTop.y);\n    ctx.stroke();\n    arrowHead(ctx, eaBot.x, eaBot.y, eaTop.x, eaTop.y, 9);\n    arrowHead(ctx, eaTop.x, eaTop.y, eaBot.x, eaBot.y, 9);\n\n    const eaMid = px(EA_X, 85);\n    ctx.font         = \"italic 16px sans-serif\";\n    ctx.textAlign    = \"right\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillText(\"Ea = 70 kJ/mol\", eaMid.x - 10, eaMid.y);\n\n    // ΔH double-headed arrow (reactant energy level → product energy level)\n    const DH_X  = 0.91;\n    const dhTop = px(DH_X, 50);\n    const dhBot = px(DH_X, 20);\n\n    ctx.lineWidth = 1.5;\n    ctx.beginPath();\n    ctx.moveTo(dhTop.x, dhTop.y);\n    ctx.lineTo(dhBot.x, dhBot.y);\n    ctx.stroke();\n    arrowHead(ctx, dhBot.x, dhBot.y, dhTop.x, dhTop.y, 9);\n    arrowHead(ctx, dhTop.x, dhTop.y, dhBot.x, dhBot.y, 9);\n\n    const dhMid = px(DH_X, 35);\n    ctx.font         = \"italic 16px sans-serif\";\n    ctx.textAlign    = \"left\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillText(\"ΔH = −30 kJ/mol\", dhMid.x + 10, dhMid.y);\n\n    ctx.restore();\n  },\n};\n\n// --- Chart ------------------------------------------------------------------\nnew Chart(canvas, {\n  type: \"line\",\n  plugins: [bgPlugin, annotPlugin],\n  data: {\n    datasets: [\n      {\n        label: \"Potential Energy\",\n        data: curveData,\n        borderColor: t.palette[0],\n        backgroundColor: \"transparent\",\n        borderWidth: 3,\n        tension: 0.3,\n        pointRadius: 0,\n        pointHoverRadius: 0,\n        fill: false,\n      },\n      {\n        label: \"Reactant level\",\n        data: reactantRef,\n        borderColor: t.inkSoft,\n        backgroundColor: \"transparent\",\n        borderWidth: 1.5,\n        borderDash: [10, 6],\n        tension: 0,\n        pointRadius: 0,\n        pointHoverRadius: 0,\n        fill: false,\n      },\n      {\n        label: \"Product level\",\n        data: productRef,\n        borderColor: t.inkSoft,\n        backgroundColor: \"transparent\",\n        borderWidth: 1.5,\n        borderDash: [10, 6],\n        tension: 0,\n        pointRadius: 0,\n        pointHoverRadius: 0,\n        fill: false,\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    layout: {\n      padding: { top: 20, right: 140, bottom: 10, left: 10 },\n    },\n    plugins: {\n      title: {\n        display: true,\n        text: \"line-reaction-coordinate · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 22 },\n        padding: { bottom: 20 },\n      },\n      legend: { display: false },\n      tooltip: { enabled: false },\n    },\n    scales: {\n      x: {\n        type: \"linear\",\n        min: 0,\n        max: 1,\n        title: {\n          display: true,\n          text: \"Reaction Coordinate\",\n          color: t.ink,\n          font: { size: 16 },\n          padding: { top: 8 },\n        },\n        ticks: {\n          color: t.inkSoft,\n          font: { size: 13 },\n          maxTicksLimit: 6,\n        },\n        grid: { color: t.grid },\n        border: { display: false },\n      },\n      y: {\n        min: 0,\n        max: 145,\n        title: {\n          display: true,\n          text: \"Potential Energy (kJ/mol)\",\n          color: t.ink,\n          font: { size: 16 },\n          padding: { bottom: 8 },\n        },\n        ticks: {\n          color: t.inkSoft,\n          font: { size: 13 },\n        },\n        grid: { color: t.grid },\n        border: { display: false },\n      },\n    },\n  },\n});\n"}