{"spec_id":"titration-curve","library":"echarts","language":"javascript","code":"// anyplot.ai\n// titration-curve: Acid-Base Titration Curve\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 89/100 | Created: 2026-06-24\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Strong acid/strong base titration: 25 mL 0.1 M HCl + 0.1 M NaOH\nconst C      = 0.1;               // mol/L (both acid and base)\nconst V_ACID = 25.0;              // mL initial acid volume\nconst N_ACID = C * V_ACID / 1000; // 0.0025 mol HCl\n\n// Volumes: dense around the equivalence point at 25 mL for a smooth curve\nconst volumes = [];\nfor (let i = 0;   i <= 47;  i++) volumes.push(+(i * 0.5).toFixed(1));   // 0–23.5, step 0.5\nfor (let i = 236; i <= 264; i++) volumes.push(+(i / 10).toFixed(1));    // 23.6–26.4, step 0.1\nfor (let i = 53;  i <= 100; i++) volumes.push(+(i * 0.5).toFixed(1));   // 26.5–50.0, step 0.5\n\nfunction calcPH(v) {\n    const nBase  = C * v / 1000;\n    const totVol = (V_ACID + v) / 1000;\n    if (v < 24.999) return -Math.log10((N_ACID - nBase) / totVol);\n    if (v > 25.001) return 14 + Math.log10((nBase - N_ACID) / totVol);\n    return 7.0; // equivalence point: neutral pH for strong acid/strong base\n}\n\nconst pHArr         = volumes.map(calcPH);\nconst titrationData = volumes.map((v, i) => [v, +pHArr[i].toFixed(3)]);\n\n// Central-difference derivative dpH/dV — peaks sharply at the equivalence point\nconst derivData = [];\nfor (let i = 1; i < volumes.length - 1; i++) {\n    const dphdv = (pHArr[i + 1] - pHArr[i - 1]) / (volumes[i + 1] - volumes[i - 1]);\n    derivData.push([volumes[i], +dphdv.toFixed(3)]);\n}\n\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nchart.setOption({\n    animation: false,\n    color:           t.palette,\n    backgroundColor: \"transparent\",\n\n    title: {\n        text: \"titration-curve · javascript · echarts · anyplot.ai\",\n        left: \"center\",\n        top: 20,\n        textStyle: { color: t.ink, fontSize: 22, fontWeight: \"bold\" },\n    },\n\n    legend: {\n        data: [\"pH\", \"dpH/dV\"],\n        top: 62,\n        right: 120,\n        textStyle: { color: t.inkSoft, fontSize: 14 },\n        icon: \"line\",\n    },\n\n    grid: { left: 90, right: 115, top: 105, bottom: 90 },\n\n    xAxis: {\n        type: \"value\",\n        name: \"Volume of NaOH added (mL)\",\n        nameLocation: \"middle\",\n        nameGap: 50,\n        nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n        min: 0,\n        max: 50,\n        interval: 5,\n        axisLabel: { color: t.inkSoft, fontSize: 14 },\n        axisLine: { lineStyle: { color: t.inkSoft } },\n        axisTick: { show: false },\n        splitLine: { show: false },\n    },\n\n    yAxis: [\n        {\n            type: \"value\",\n            name: \"pH\",\n            nameLocation: \"middle\",\n            nameGap: 50,\n            nameTextStyle: { color: t.palette[0], fontSize: 14 },\n            min: 0,\n            max: 14,\n            interval: 2,\n            axisLabel: { color: t.inkSoft, fontSize: 14 },\n            axisLine: { show: true, lineStyle: { color: t.palette[0] } },\n            axisTick: { show: false },\n            splitLine: { lineStyle: { color: t.grid } },\n        },\n        {\n            type: \"value\",\n            name: \"dpH/dV\",\n            nameLocation: \"middle\",\n            nameGap: 60,\n            nameTextStyle: { color: t.palette[1], fontSize: 14 },\n            min: 0,\n            max: 40,\n            interval: 10,\n            axisLabel: { color: t.inkSoft, fontSize: 14 },\n            axisLine: { show: true, lineStyle: { color: t.palette[1] } },\n            axisTick: { show: false },\n            splitLine: { show: false },\n        },\n    ],\n\n    series: [\n        {\n            name: \"pH\",\n            type: \"line\",\n            yAxisIndex: 0,\n            data: titrationData,\n            showSymbol: false,\n            lineStyle: { color: t.palette[0], width: 3.5 },\n            itemStyle: { color: t.palette[0] },\n            markLine: {\n                silent: true,\n                symbol: [\"none\", \"none\"],\n                lineStyle: { type: \"dashed\", color: t.inkSoft, width: 1.5 },\n                label: {\n                    show: true,\n                    position: \"end\",\n                    formatter: \"EP: 25 mL, pH 7\",\n                    color: t.inkSoft,\n                    fontSize: 13,\n                },\n                data: [{ xAxis: 25 }],\n            },\n            markPoint: {\n                data: [{\n                    coord: [25, 7],\n                    symbol: \"circle\",\n                    symbolSize: 14,\n                    itemStyle: {\n                        color: t.palette[0],\n                        borderColor: t.pageBg,\n                        borderWidth: 2.5,\n                    },\n                }],\n                label: { show: false },\n            },\n        },\n        {\n            name: \"dpH/dV\",\n            type: \"line\",\n            yAxisIndex: 1,\n            data: derivData,\n            showSymbol: false,\n            lineStyle: { color: t.palette[1], width: 2.5, opacity: 0.85 },\n            itemStyle: { color: t.palette[1] },\n            areaStyle: { color: t.palette[1], opacity: 0.08 },\n        },\n    ],\n});\n"}