gj/数学函数图像生成.html

558 lines
19 KiB
HTML
Raw Permalink Normal View History

2025-04-17 21:34:11 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>高级数学函数图像生成器</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mathjs@11.6.0/lib/browser/math.js"></script>
<style>
:root {
--primary-color: #4361ee;
--secondary-color: #3f37c9;
--accent-color: #4895ef;
--light-color: #f8f9fa;
--dark-color: #212529;
--success-color: #4cc9f0;
--warning-color: #f72585;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f5f7fa;
color: var(--dark-color);
line-height: 1.6;
padding: 20px;
min-width: 900px;
}
.container {
max-width: 1400px;
min-width: 900px;
margin: 0 auto;
padding: 30px;
background-color: white;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
}
header {
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
h1 {
color: var(--primary-color);
font-weight: 700;
margin-bottom: 10px;
font-size: 2.5rem;
}
.subtitle {
color: #6c757d;
font-size: 1.1rem;
margin-bottom: 15px;
}
.intro-box {
background-color: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
border-left: 4px solid var(--accent-color);
}
.intro-box h3 {
color: var(--primary-color);
margin-bottom: 10px;
}
.intro-box ul {
padding-left: 20px;
}
.intro-box li {
margin-bottom: 5px;
}
.app-container {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 30px;
}
.control-panel {
background-color: #f8f9fa;
padding: 25px;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
min-width: 350px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: var(--dark-color);
}
input, select {
width: 100%;
padding: 12px 15px;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 1rem;
transition: all 0.3s;
}
input:focus, select:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.2);
}
button {
background-color: var(--primary-color);
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
font-weight: 600;
transition: all 0.3s;
width: 100%;
margin-top: 10px;
}
button:hover {
background-color: var(--secondary-color);
transform: translateY(-2px);
}
.chart-container {
position: relative;
height: 500px;
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
padding: 15px;
min-width: 500px;
}
.examples-panel {
margin-top: 25px;
padding-top: 20px;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.examples-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
cursor: pointer;
}
.examples-header h3 {
color: var(--primary-color);
margin: 0;
}
.examples-content {
display: none;
padding: 10px;
background-color: white;
border-radius: 6px;
}
.examples-content.show {
display: block;
}
.example-list {
list-style: none;
}
.example-list li {
margin-bottom: 10px;
padding: 10px;
background-color: white;
border-radius: 6px;
border-left: 4px solid var(--accent-color);
cursor: pointer;
transition: all 0.2s;
}
.example-list li:hover {
background-color: #e9ecef;
transform: translateX(5px);
}
.error-message {
color: var(--warning-color);
margin-top: 10px;
font-size: 0.9rem;
display: none;
}
.footer {
text-align: center;
margin-top: 40px;
color: #6c757d;
font-size: 0.9rem;
}
.toggle-icon {
transition: transform 0.3s;
}
.toggle-icon.rotated {
transform: rotate(180deg);
}
.real-time-btn {
background-color: var(--accent-color);
}
.real-time-btn.active {
background-color: var(--success-color);
}
.button-group {
display: flex;
gap: 10px;
}
.button-group button {
margin-top: 0;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>数学函数图像生成器</h1>
<p class="subtitle">拥有基本运算,输入框不支持更高级参数填入</p>
</header>
<div class="intro-box">
<h3>使用说明</h3>
<p>手机请缩小屏幕,输入数学函数表达式,设置参数范围,即可生成精美的函数图像。</p>
<h3>支持的运算符和函数:</h3>
<ul>
<li>基本运算: +, -, *, /, ^ (幂)</li>
<li>三角函数: sin, cos, tan, asin, acos, atan</li>
<li>对数函数: log, log10, ln</li>
<li>其他函数: sqrt, abs, ceil, floor, round</li>
<li>常数: pi, e</li>
</ul>
<h3>注意事项:</h3>
<ul>
<li>使用 x 作为变量,区分大小写</li>
<li>不支持隐式乘法,必须使用 * 运算符</li>
<li>不支持分段函数和条件表达式</li>
<li>程序预留有示例方案</li>
<li>某些函数在特定区间可能无定义(如log(0))</li>
<li>复数结果将显示为NaN</li>
<li>无法生成创意图案,因为输入框限制,而且这个不是直角系</li>
<li>千万不要把所有数值输入过大和过小,否则会卡</li>
</ul>
</div>
<div class="app-container">
<div class="control-panel">
<div class="form-group">
<label for="function-input">函数表达式 (使用 x 作为变量)</label>
<input type="text" id="function-input" placeholder="例如: sin(x), x^2 + 2*x + 1" value="sin(x)">
</div>
<div class="form-group">
<label for="x-min">X 最小值</label>
<input type="number" id="x-min" value="-10" step="0.1">
</div>
<div class="form-group">
<label for="x-max">X 最大值</label>
<input type="number" id="x-max" value="10" step="0.1">
</div>
<div class="form-group">
<label for="step">步长 (精度)</label>
<input type="number" id="step" value="0.1" step="0.01" min="0.01">
</div>
<div class="form-group">
<label for="line-color">线条颜色</label>
<select id="line-color">
<option value="#4361ee">蓝色</option>
<option value="#f72585">粉色</option>
<option value="#4cc9f0">青色</option>
<option value="#7209b7">紫色</option>
<option value="#3a0ca3">深蓝</option>
</select>
</div>
<div class="button-group">
<button id="plot-button">绘制函数图像</button>
<button id="real-time-btn" class="real-time-btn">实时生成图像</button>
</div>
<div id="error-message" class="error-message"></div>
<div class="examples-panel">
<div class="examples-header" id="examples-toggle">
<h3>示例函数</h3>
<svg class="toggle-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</div>
<div class="examples-content" id="examples-content">
<ul class="example-list">
<li onclick="useExample('sin(x)')">正弦函数: sin(x)</li>
<li onclick="useExample('cos(x)')">余弦函数: cos(x)</li>
<li onclick="useExample('tan(x)')">正切函数: tan(x)</li>
<li onclick="useExample('x^2')">二次函数: x^2</li>
<li onclick="useExample('x^3 - 3*x')">三次函数: x^3 - 3*x</li>
<li onclick="useExample('sqrt(x)')">平方根函数: sqrt(x)</li>
<li onclick="useExample('log(x)')">自然对数: log(x)</li>
<li onclick="useExample('log10(x)')">常用对数: log10(x)</li>
<li onclick="useExample('exp(x)')">指数函数: exp(x)</li>
<li onclick="useExample('abs(x)')">绝对值函数: abs(x)</li>
<li onclick="useExample('sin(x)/x')">sinc函数: sin(x)/x</li>
<li onclick="useExample('1/x')">反比例函数: 1/x</li>
</ul>
</div>
</div>
</div>
<div class="chart-container">
<canvas id="function-chart"></canvas>
</div>
</div>
<div class="footer">
<p>© 2023 高级数学可视化工具 | 使用 Chart.js 和 Math.js 构建 | 支持缩放和平移功能</p>
</div>
</div>
<script>
// 初始化图表
const ctx = document.getElementById('function-chart').getContext('2d');
let chart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: '函数图像(支持横向触摸图像有信息跟踪)',
borderColor: '#4361ee',
borderWidth: 3,
pointRadius: 0,
fill: false,
tension: 0.1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
title: {
display: true,
text: 'X轴',
font: {
size: 14,
weight: 'bold'
}
},
grid: {
color: 'rgba(0, 0, 0, 0.05)'
}
},
y: {
title: {
display: true,
text: 'Y轴',
font: {
size: 14,
weight: 'bold'
}
},
grid: {
color: 'rgba(0, 0, 0, 0.05)'
}
}
},
plugins: {
legend: {
position: 'top',
labels: {
font: {
size: 14
}
}
},
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: function(context) {
return `f(${context.parsed.x.toFixed(2)}) = ${context.parsed.y.toFixed(4)}`;
}
}
},
zoom: {
zoom: {
wheel: {
enabled: true,
},
pinch: {
enabled: true
},
mode: 'xy',
},
pan: {
enabled: true,
mode: 'xy',
}
}
}
}
});
// 实时生成状态
let isRealTime = false;
let inputElements = [
document.getElementById('function-input'),
document.getElementById('x-min'),
document.getElementById('x-max'),
document.getElementById('step'),
document.getElementById('line-color')
];
// 防抖函数,避免频繁更新
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
// 绘制函数
function plotFunction() {
const funcInput = document.getElementById('function-input').value;
const xMin = parseFloat(document.getElementById('x-min').value);
const xMax = parseFloat(document.getElementById('x-max').value);
const step = parseFloat(document.getElementById('step').value);
const lineColor = document.getElementById('line-color').value;
const errorElement = document.getElementById('error-message');
errorElement.style.display = 'none';
try {
// 生成x值数组
const xValues = [];
for (let x = xMin; x <= xMax; x += step) {
xValues.push(x);
}
// 计算y值
const yValues = [];
const scope = {};
for (let i = 0; i < xValues.length; i++) {
scope.x = xValues[i];
try {
const y = math.evaluate(funcInput, scope);
yValues.push(y);
} catch (e) {
// 对于某些x值可能无法计算如log(0)
yValues.push(NaN);
}
}
// 更新图表
chart.data.labels = xValues;
chart.data.datasets[0].data = yValues.map((y, i) => ({x: xValues[i], y: y}));
chart.data.datasets[0].borderColor = lineColor;
chart.update();
} catch (error) {
errorElement.textContent = `错误: ${error.message}`;
errorElement.style.display = 'block';
}
}
// 使用示例函数
function useExample(func) {
document.getElementById('function-input').value = func;
if (isRealTime) {
plotFunction();
}
}
// 切换实时生成模式
function toggleRealTime() {
const realTimeBtn = document.getElementById('real-time-btn');
isRealTime = !isRealTime;
if (isRealTime) {
realTimeBtn.classList.add('active');
realTimeBtn.textContent = '实时生成中...';
// 立即绘制一次
plotFunction();
} else {
realTimeBtn.classList.remove('active');
realTimeBtn.textContent = '实时生成图像';
}
}
// 设置输入框监听
function setupInputListeners() {
const debouncedPlot = debounce(plotFunction, 500);
inputElements.forEach(element => {
element.addEventListener('input', () => {
if (isRealTime) {
debouncedPlot();
}
});
});
}
// 切换示例面板
document.getElementById('examples-toggle').addEventListener('click', function() {
const content = document.getElementById('examples-content');
const icon = this.querySelector('.toggle-icon');
content.classList.toggle('show');
icon.classList.toggle('rotated');
});
// 事件监听
document.getElementById('plot-button').addEventListener('click', plotFunction);
document.getElementById('real-time-btn').addEventListener('click', toggleRealTime);
// 设置输入监听
setupInputListeners();
// 初始绘制
plotFunction();
</script>
</body>
</html>