科学计算工具
<div class="cards-container" id="cards-container">
<!-- 卡片将通过JavaScript动态生成 -->
</div>
</div>
<!-- 模态框将通过JavaScript动态生成 -->
<div id="modals-container"></div>
<script>
// 公式配置数据
const formulasConfig = {
"kinetic-energy": {
title: "动能计算",
description: "计算物体的动能,基于质量和速度",
formula: "E_k = \\frac{1}{2}mv^2",
variables: [
{ name: "E_k", description: "动能 (J)", isResult: true },
{ name: "m", description: "质量 (kg)", className: "mass", placeholder: "输入质量" },
{ name: "v", description: "速度 (m/s)", className: "velocity", placeholder: "输入速度" }
],
calculation: function (row) {
const mass = parseFloat(row.querySelector('.mass').value) || 0;
const velocity = parseFloat(row.querySelector('.velocity').value) || 0;
return 0.5 * mass * Math.pow(velocity, 2);
}
},
"gravitational-force": {
title: "万有引力",
description: "计算两个物体之间的万有引力",
formula: "F = G\\frac{m_1m_2}{r^2}",
constants: [
{ name: "G", value: "6.674 \\times 10^{-11} N \\cdot m^2/kg^2", description: "万有引力常数" }
],
variables: [
{ name: "F", description: "引力 (N)", isResult: true },
{ name: "m_1", description: "质量1 (kg)", className: "mass1", placeholder: "输入质量1" },
{ name: "m_2", description: "质量2 (kg)", className: "mass2", placeholder: "输入质量2" },
{ name: "r", description: "距离 (m)", className: "distance", placeholder: "输入距离" }
],
calculation: function (row) {
const mass1 = parseFloat(row.querySelector('.mass1').value) || 0;
const mass2 = parseFloat(row.querySelector('.mass2').value) || 0;
const distance = parseFloat(row.querySelector('.distance').value) || 0;
const G = 6.67430e-11; // 万有引力常数
let force = 0;
if (distance !== 0) {
force = G * mass1 * mass2 / Math.pow(distance, 2);
}
return force;
},
formatResult: function (result) {
return result.toExponential(4);
}
},
"ohms-law": {
title: "欧姆定律",
description: "计算电压、电流或电阻",
formula: "V = IR",
variables: [
{ name: "V", description: "电压 (V)", className: "voltage", placeholder: "输入电压" },
{ name: "I", description: "电流 (A)", className: "current", placeholder: "输入电流" },
{ name: "R", description: "电阻 (Ω)", className: "resistance", placeholder: "输入电阻" }
],
calculation: function (row, changedField) {
const voltage = parseFloat(row.querySelector('.voltage').value);
const current = parseFloat(row.querySelector('.current').value);
const resistance = parseFloat(row.querySelector('.resistance').value);
let results = {};
// 根据已知的两个值计算第三个值
if (changedField === 'voltage') {
if (current !== 0 && !isNaN(current)) {
results.resistance = voltage / current;
}
if (resistance !== 0 && !isNaN(resistance)) {
results.current = voltage / resistance;
}
} else if (changedField === 'current') {
if (voltage !== 0 && !isNaN(voltage)) {
results.resistance = voltage / current;
}
if (resistance !== 0 && !isNaN(resistance)) {
results.voltage = current * resistance;
}
} else if (changedField === 'resistance') {
if (voltage !== 0 && !isNaN(voltage)) {
results.current = voltage / resistance;
}
if (current !== 0 && !isNaN(current)) {
results.voltage = current * resistance;
}
}
return results;
},
formatResult: function (result) {
return result.toFixed(4);
},
isInteractive: true
},
"pythagorean-theorem": {
title: "勾股定理",
description: "计算直角三角形的边长",
formula: "c = \\sqrt{a^2 + b^2}",
variables: [
{ name: "a", description: "直角边a", className: "side-a", placeholder: "输入边a" },
{ name: "b", description: "直角边b", className: "side-b", placeholder: "输入边b" },
{ name: "c", description: "斜边c", className: "side-c", placeholder: "输入边c" }
],
calculation: function (row, changedSide) {
const sideA = parseFloat(row.querySelector('.side-a').value);
const sideB = parseFloat(row.querySelector('.side-b').value);
const sideC = parseFloat(row.querySelector('.side-c').value);
let results = {};
// 根据已知的两个边计算第三个边
if (changedSide === 'a') {
if (!isNaN(sideB) && !isNaN(sideC)) {
results.a = Math.sqrt(Math.pow(sideC, 2) - Math.pow(sideB, 2));
} else if (!isNaN(sideA) && !isNaN(sideB)) {
results.c = Math.sqrt(Math.pow(sideA, 2) + Math.pow(sideB, 2));
} else if (!isNaN(sideA) && !isNaN(sideC)) {
results.b = Math.sqrt(Math.pow(sideC, 2) - Math.pow(sideA, 2));
}
} else if (changedSide === 'b') {
if (!isNaN(sideA) && !isNaN(sideC)) {
results.b = Math.sqrt(Math.pow(sideC, 2) - Math.pow(sideA, 2));
} else if (!isNaN(sideA) && !isNaN(sideB)) {
results.c = Math.sqrt(Math.pow(sideA, 2) + Math.pow(sideB, 2));
} else if (!isNaN(sideB) && !isNaN(sideC)) {
results.a = Math.sqrt(Math.pow(sideC, 2) - Math.pow(sideB, 2));
}
} else if (changedSide === 'c') {
if (!isNaN(sideA) && !isNaN(sideB)) {
results.c = Math.sqrt(Math.pow(sideA, 2) + Math.pow(sideB, 2));
} else if (!isNaN(sideA) && !isNaN(sideC)) {
results.b = Math.sqrt(Math.pow(sideC, 2) - Math.pow(sideA, 2));
} else if (!isNaN(sideB) && !isNaN(sideC)) {
results.a = Math.sqrt(Math.pow(sideC, 2) - Math.pow(sideB, 2));
}
}
return results;
},
formatResult: function (result) {
return result.toFixed(4);
},
isInteractive: true
},
"ratio-calculation": {
title: "扭度计算公式",
description: "计算扭度",
formula: "X = \\frac{2(AC-BD)}{(AC+BD)} \\times 100\\%",
variables: [
{ name: "X", description: "百分比比率 (%)", isResult: true },
{ name: "AC", description: "AC值", className: "ac-value", placeholder: "输入AC值" },
{ name: "BD", description: "BD值", className: "bd-value", placeholder: "输入BD值" }
],
calculation: function (row) {
const ac = parseFloat(row.querySelector('.ac-value').value) || 0;
const bd = parseFloat(row.querySelector('.bd-value').value) || 0;
let ratio = 0;
if ((ac + bd) !== 0) {
ratio = (2 * (ac - bd)) / (ac + bd) * 100;
}
return ratio;
},
formatResult: function (result) {
return result.toFixed(2) + "%";
}
}
};
// 初始化应用
document.addEventListener('DOMContentLoaded', function () {
// 生成卡片
const cardsContainer = document.getElementById('cards-container');
const modalsContainer = document.getElementById('modals-container');
for (const [id, config] of Object.entries(formulasConfig)) {
// 创建卡片
const card = document.createElement('div');
card.className = 'card';
card.setAttribute('onclick', `openModal('${id}-modal')`);
const title = document.createElement('h3');
title.textContent = config.title;
const description = document.createElement('p');
description.textContent = config.description;
card.appendChild(title);
card.appendChild(description);
cardsContainer.appendChild(card);
// 创建模态框
const modal = document.createElement('div');
modal.id = `${id}-modal`;
modal.className = 'modal';
const modalContent = document.createElement('div');
modalContent.className = 'modal-content';
// 模态框头部
const modalHeader = document.createElement('div');
modalHeader.className = 'modal-header';
const modalTitle = document.createElement('h2');
modalTitle.textContent = config.title;
const closeBtn = document.createElement('button');
closeBtn.className = 'close-btn';
closeBtn.innerHTML = '×';
closeBtn.setAttribute('onclick', `closeModal('${id}-modal')`);
modalHeader.appendChild(modalTitle);
modalHeader.appendChild(closeBtn);
// 模态框主体
const modalBody = document.createElement('div');
modalBody.className = 'modal-body';
// 公式容器
const formulaContainer = document.createElement('div');
formulaContainer.className = 'formula-container';
const formulaTitle = document.createElement('p');
formulaTitle.textContent = `${config.title}公式:`;
const formula = document.createElement('p');
formula.innerHTML = `\\[ ${config.formula} \\]`;
const variablesTitle = document.createElement('p');
variablesTitle.textContent = "其中:";
formulaContainer.appendChild(formulaTitle);
formulaContainer.appendChild(formula);
formulaContainer.appendChild(variablesTitle);
// 添加常量说明
if (config.constants) {
config.constants.forEach(constant => {
const constantP = document.createElement('p');
constantP.innerHTML = `\\( ${constant.name} \\) = ${constant.value} (${constant.description})`;
formulaContainer.appendChild(constantP);
});
}
// 添加变量说明
config.variables.forEach(variable => {
if (!variable.isResult) {
const variableP = document.createElement('p');
variableP.innerHTML = `\\( ${variable.name} \\) = ${variable.description}`;
formulaContainer.appendChild(variableP);
}
});
// 变量输入容器
const variablesContainer = document.createElement('div');
variablesContainer.className = 'variables-container';
const inputTitle = document.createElement('h3');
inputTitle.textContent = '输入数据';
variablesContainer.appendChild(inputTitle);
// 创建输入表格
const table = document.createElement('table');
table.className = 'input-table';
table.id = `${id}-table`;
const thead = document.createElement('thead');
const headerRow = document.createElement('tr');
// 添加表头
config.variables.forEach(variable => {
const th = document.createElement('th');
th.textContent = variable.description.split(')')[0] + ')';
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
const tbody = document.createElement('tbody');
// 添加输入行
const inputRow = document.createElement('tr');
config.variables.forEach(variable => {
const td = document.createElement('td');
if (variable.isResult) {
td.className = 'result-cell';
td.textContent = '0';
} else {
const input = document.createElement('input');
input.type = 'number';
input.className = variable.className;
input.placeholder = variable.placeholder;
if (config.isInteractive) {
// 交互式公式(如欧姆定律、勾股定理)
input.oninput = function () {
const changedField = variable.className.split('-')[config.id === 'pythagorean-theorem' ? 1 : 0];
const results = config.calculation(this.closest('tr'), changedField);
for (const [field, value] of Object.entries(results)) {
const inputField = this.closest('tr').querySelector(`.${config.id === 'pythagorean-theorem' ? 'side-' + field : field}`);
if (inputField && !inputField.isSameNode(this)) {
inputField.value = config.formatResult(value);
}
}
};
} else {
// 普通公式
input.oninput = function () {
const result = config.calculation(this.closest('tr'));
const resultCell = this.closest('tr').querySelector('.result-cell');
if (resultCell) {
resultCell.textContent = config.formatResult
? config.formatResult(result)
: result.toFixed(4);
}
};
}
td.appendChild(input);
}
inputRow.appendChild(td);
});
tbody.appendChild(inputRow);
table.appendChild(tbody);
variablesContainer.appendChild(table);
// 添加行按钮(非交互式公式才有)
if (!config.isInteractive) {
const addRowBtn = document.createElement('button');
addRowBtn.className = 'btn add-row-btn';
addRowBtn.textContent = '添加行';
addRowBtn.onclick = function () {
addRow(id, `${id}-table`, config);
};
variablesContainer.appendChild(addRowBtn);
} else {
// 添加提示文本
const hint = document.createElement('p');
hint.style.marginTop = '10px';
hint.style.color = '#666';
hint.style.fontSize = '14px';
hint.textContent = '提示: 输入任意两个值计算第三个值';
variablesContainer.appendChild(hint);
}
// 操作按钮
const actionButtons = document.createElement('div');
actionButtons.className = 'action-buttons';
const clearBtn = document.createElement('button');
clearBtn.className = 'btn';
clearBtn.textContent = '清空';
clearBtn.onclick = function () {
clearTable(`${id}-table`);
};
const closeModalBtn = document.createElement('button');
closeModalBtn.className = 'btn';
closeModalBtn.textContent = '关闭';
closeModalBtn.onclick = function () {
closeModal(`${id}-modal`);
};
actionButtons.appendChild(clearBtn);
actionButtons.appendChild(closeModalBtn);
variablesContainer.appendChild(actionButtons);
// 组装模态框
modalBody.appendChild(formulaContainer);
modalBody.appendChild(variablesContainer);
modalContent.appendChild(modalHeader);
modalContent.appendChild(modalBody);
modal.appendChild(modalContent);
modalsContainer.appendChild(modal);
}
// 重新渲染MathJax公式
if (MathJax.typeset) {
MathJax.typeset();
}
});
// 打开模态框
function openModal(modalId) {
document.getElementById(modalId).style.display = 'flex';
// 重新渲染MathJax公式,确保显示正确
if (MathJax.typeset) {
MathJax.typeset();
}
}
// 关闭模态框
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
// 添加行
function addRow(formulaId, tableId, config) {
const table = document.getElementById(tableId);
const tbody = table.querySelector('tbody');
const newRow = tbody.insertRow();
config.variables.forEach(variable => {
const td = document.createElement('td');
if (variable.isResult) {
td.className = 'result-cell';
td.textContent = '0';
} else {
const input = document.createElement('input');
input.type = 'number';
input.className = variable.className;
input.placeholder = variable.placeholder;
if (config.isInteractive) {
const changedField = variable.className.split('-')[formulaId === 'pythagorean-theorem' ? 1 : 0];
input.oninput = function () {
const results = config.calculation(this.closest('tr'), changedField);
for (const [field, value] of Object.entries(results)) {
const inputField = this.closest('tr').querySelector(`.${formulaId === 'pythagorean-theorem' ? 'side-' + field : field}`);
if (inputField && !inputField.isSameNode(this)) {
inputField.value = config.formatResult(value);
}
}
};
} else {
input.oninput = function () {
const result = config.calculation(this.closest('tr'));
const resultCell = this.closest('tr').querySelector('.result-cell');
if (resultCell) {
resultCell.textContent = config.formatResult
? config.formatResult(result)
: result.toFixed(4);
}
};
}
td.appendChild(input);
}
newRow.appendChild(td);
});
}
// 清空表格
function clearTable(tableId) {
const table = document.getElementById(tableId);
const tbody = table.querySelector('tbody');
// 保留第一行,清空其输入
const firstRow = tbody.rows[0];
for (let i = 0; i < firstRow.cells.length; i++) {
const input = firstRow.cells[i].querySelector('input');
if (input) {
input.value = '';
} else {
firstRow.cells[i].textContent = '0';
}
}
// 删除其他行
while (tbody.rows.length > 1) {
tbody.deleteRow(1);
}
}
</script>