求助:如何实现JavaScript基础补水计算器的函数图表展示?
解决补水计算器图表无法正常展示的问题
问题诊断
当前代码存在以下核心问题导致图表无法正常渲染:
- 未实现
calcularFuncion函数:代码中调用了该函数但未定义,导致图表无数据来源 - 图表数据维度不匹配:仅使用固定的4个x轴标签,无法完整展示分段函数的趋势(尤其是30kg以上趋近333.33cc/hr的部分)
- 重复创建Chart实例:每次点击按钮都会生成新的Chart实例,导致画布冲突
- 按钮无操作文本:HTML按钮缺少显示文本,影响用户操作体验
修正后的完整代码
HTML部分
<!DOCTYPE html> <html lang="en"> <head> <title>Calculadora de hidratación</title> <link rel="stylesheet" href="./style.css" /> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <!-- 引入注释插件支持渐近线标注 --> <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@2.2.0/dist/chartjs-plugin-annotation.min.js"></script> </head> <body> <div> <div id="calculadora"> <h2>Hidratación Basal</h2> <input type="number" id="peso" placeholder="Indicar peso en kilogramos" /> <button onclick="handleSubmit()">Calcular y Mostrar Gráfica</button> </div> <div> <p> <output id="Resultado"></output> </p> </div> <div id="descripcion"> <h3>¿Cómo se calcula?</h3> <ul> <li>De 0kg a 10kg, se calcula 100cc por cada kilo.</li> <li>Se suman 50cc por cada kilo de peso por arriba de 10kg, hasta 20kg</li> <li>De 20kg y hasta 30kg, se suman 20cc por cada kilo adicional</li> <li>De 30kg para arriba, se determina mediante la superficie corporal del paciente </li> </ul> </div> </div> <div> <canvas id="grafica" width="400" height="200"></canvas> </div> <script src="./index-calculadoralucas.js"></script> </body> </html>
JavaScript部分
// 全局存储Chart实例,用于销毁旧实例避免冲突 let myChart = null; // 核心计算函数,提取为独立方法复用 function calcularPeso(peso) { if (isNaN(peso) || peso < 0) { return "Ingrese un número válido"; } let ccPorHora; if (peso <= 10) { ccPorHora = (peso * 100) / 16; } else if (peso <= 20) { ccPorHora = (((peso - 10) * 50) + 1500) / 16; } else if (peso <= 30) { ccPorHora = (((peso - 20) * 20) + 1500) / 16; } else { ccPorHora = ((((peso * 4 + 7) / (peso + 90)) * 2000) / 24).toFixed(2); } return `La cantidad necesaria es: ${ccPorHora}cc/hr`; } // 实现缺失的calcularFuncion,生成连续数据点 function calcularFuncion(maxPeso) { const data = []; const step = 1; // 步长设为1保证曲线平滑 // 生成0到输入体重的连续数据 for (let x = 0; x <= maxPeso; x += step) { let y; if (x <= 10) { y = (x * 100) / 16; } else if (x <= 20) { y = (((x - 10) * 50) + 1500) / 16; } else if (x <= 30) { y = (((x - 20) * 20) + 1500) / 16; } else { y = ((((x * 4 + 7) / (x + 90)) * 2000) / 24); } data.push(y); } // 体重超过30kg时,额外添加更远的点展示渐近趋势 if (maxPeso > 30) { const x = maxPeso + 50; const y = ((((x * 4 + 7) / (x + 90)) * 2000) / 24); data.push(y); } return data; } // 图表渲染函数 function mostrarGrafica(peso) { const ctx = document.getElementById('grafica').getContext('2d'); // 销毁旧实例避免画布冲突 if (myChart) { myChart.destroy(); } // 生成对应x轴标签数组 const labels = []; const step = 1; for (let x = 0; x <= peso; x += step) { labels.push(x); } if (peso > 30) { labels.push(peso + 50); } myChart = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: 'Función de cálculo de hidratación', data: calcularFuncion(peso), borderColor: '#e50914', borderWidth: 2, fill: false, tension: 0.1 // 让折线更平滑 }] }, options: { scales: { x: { title: { display: true, text: 'Peso (kg)' } }, y: { min: 0, title: { display: true, text: 'CC/Hora' } } }, plugins: { annotation: { annotations: { asymptoticLine: { type: 'line', yMin: 333.33, yMax: 333.33, borderColor: 'rgba(0,0,0,0.3)', borderWidth: 2, borderDash: [5,5], label: { content: 'Límite asintótico (333.33cc/hr)', enabled: true, position: 'end' } } } } } } }); } // 统一处理提交事件 function handleSubmit() { const peso = parseInt(document.getElementById("peso").value); const resultado = document.getElementById("Resultado"); resultado.innerHTML = calcularPeso(peso); // 仅当输入有效时渲染图表 if (!isNaN(peso) && peso >= 0) { mostrarGrafica(peso); } }
关键优化说明
- 实现
calcularFuncion函数:生成从0到输入体重的连续数据点,30kg以上额外添加更远的点,直观展示趋近333.33cc/hr的渐近趋势 - 管理Chart实例:全局存储实例对象,每次渲染前销毁旧实例,避免画布冲突
- 统一事件处理:将计算和渲染逻辑合并到
handleSubmit,增加输入合法性校验 - 增强图表可读性:添加坐标轴标题、333.33cc/hr的虚线参考线及标注,清晰展示函数趋势
- 修复UI细节:给按钮添加明确操作文本,提升用户体验
内容的提问来源于stack exchange,提问作者Lucas Sitzmann
相关产品推荐
相关产品推荐

