html
复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>三角不等式动态演示:||x|-|a|| ≤ |x-a|</title>
<style>
canvas { background: #f8f9fa; border: 1px solid #ccc; display: block; margin: 20px auto; }
.controls { text-align: center; font-family: Arial, sans-serif; }
input { width: 300px; cursor: pointer; }
p { font-size: 18px; }
.note { color: #555; font-size: 14px; }
</style>
</head>
<body>
<div class="controls">
<h3>📐 三角不等式:||x| - |a|| ≤ |x - a|</h3>
<p>
a = <span id="a_val">0</span>
x = <span id="x_val">0</span>
</p>
<p>
<span style="color:red;">红色长度 = ||x| - |a|| = <span id="d1">0</span></span><br>
<span style="color:blue;">蓝色长度 = |x - a| = <span id="d2">0</span></span><br>
<strong>✅ 红色 ≤ 蓝色 永远成立</strong>
</p>
<p>
<label>拖动 a 的值:</label>
<input type="range" id="a_slider" min="-5" max="5" step="0.1" value="2">
</p>
<p>
<label>拖动 x 的值:</label>
<input type="range" id="x_slider" min="-5" max="5" step="0.1" value="-2">
</p>
<p class="note">
💡 观察:当 a 和 x 在原点同侧时,红蓝长度相等;<br>
当 a 和 x 在原点异侧时,红色长度小于蓝色长度。
</p>
</div>
<canvas id="canvas" width="800" height="300"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const width = 800, height = 300;
canvas.width = width; canvas.height = height;
// 坐标映射:数轴范围 -6 到 6,画布 x 范围 100 到 700
function toX(value) {
return 100 + (value + 6) / 12 * 600;
}
// 获取 DOM 元素
const aSlider = document.getElementById('a_slider');
const xSlider = document.getElementById('x_slider');
const aValSpan = document.getElementById('a_val');
const xValSpan = document.getElementById('x_val');
const d1Span = document.getElementById('d1');
const d2Span = document.getElementById('d2');
function draw() {
let a = parseFloat(aSlider.value);
let x = parseFloat(xSlider.value);
// 更新数值显示
aValSpan.innerText = a.toFixed(2);
xValSpan.innerText = x.toFixed(2);
let absA = Math.abs(a);
let absX = Math.abs(x);
let d1 = Math.abs(absX - absA);
let d2 = Math.abs(x - a);
d1Span.innerText = d1.toFixed(3);
d2Span.innerText = d2.toFixed(3);
// 清空画布
ctx.clearRect(0, 0, width, height);
// 绘制数轴
ctx.beginPath();
ctx.moveTo(50, height/2);
ctx.lineTo(width-50, height/2);
ctx.strokeStyle = '#aaa';
ctx.stroke();
// 绘制刻度
for (let val = -6; val <= 6; val += 1) {
let xc = toX(val);
ctx.beginPath();
ctx.moveTo(xc, height/2 - 5);
ctx.lineTo(xc, height/2 + 5);
ctx.stroke();
ctx.fillStyle = '#333';
ctx.fillText(val, xc-5, height/2 - 10);
}
// 原点标注
ctx.fillStyle = 'black';
ctx.fillText("0", toX(0)-5, height/2 - 10);
// 画 a 点(蓝色)
let ax = toX(a);
ctx.beginPath();
ctx.arc(ax, height/2, 8, 0, 2*Math.PI);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.fillStyle = 'white';
ctx.font = 'bold 14px Arial';
ctx.fillText("a", ax-4, height/2+4);
// 画 x 点(红色)
let xx = toX(x);
ctx.beginPath();
ctx.arc(xx, height/2, 8, 0, 2*Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
ctx.fillStyle = 'white';
ctx.fillText("x", xx-4, height/2+4);
// 画 |a| 点(浅蓝色,位于正半轴)
let absAx = toX(absA);
ctx.beginPath();
ctx.arc(absAx, height/2 - 40, 6, 0, 2*Math.PI);
ctx.fillStyle = '#66c2ff';
ctx.fill();
ctx.fillStyle = 'black';
ctx.fillText("|a|", absAx-8, height/2 - 45);
// 画 |x| 点(浅红色,位于正半轴)
let absXx = toX(absX);
ctx.beginPath();
ctx.arc(absXx, height/2 - 40, 6, 0, 2*Math.PI);
ctx.fillStyle = '#ff9999';
ctx.fill();
ctx.fillStyle = 'black';
ctx.fillText("|x|", absXx-8, height/2 - 45);
// 绘制蓝色线段:a 到 x(实际距离)
ctx.beginPath();
ctx.moveTo(ax, height/2);
ctx.lineTo(xx, height/2);
ctx.strokeStyle = 'blue';
ctx.lineWidth = 3;
ctx.stroke();
// 绘制红色线段:|a| 到 |x|(绝对值距离)
ctx.beginPath();
ctx.moveTo(absAx, height/2 - 40);
ctx.lineTo(absXx, height/2 - 40);
ctx.strokeStyle = 'red';
ctx.lineWidth = 3;
ctx.stroke();
// 可选:从 a 和 x 到它们绝对值点的虚线(展示翻折效果)
ctx.beginPath();
ctx.moveTo(ax, height/2);
ctx.lineTo(absAx, height/2 - 40);
ctx.strokeStyle = 'gray';
ctx.lineWidth = 1;
ctx.setLineDash([5, 5]);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(xx, height/2);
ctx.lineTo(absXx, height/2 - 40);
ctx.stroke();
ctx.setLineDash([]); // 恢复实线
// 标注长度
ctx.font = '14px Arial';
ctx.fillStyle = 'blue';
let midX = (ax + xx)/2;
ctx.fillText("|x-a|", midX, height/2 - 15);
ctx.fillStyle = 'red';
let midAbsX = (absAx + absXx)/2;
ctx.fillText("||x|-|a||", midAbsX, height/2 - 55);
// 额外文字提示比较
if (d1 <= d2) {
ctx.fillStyle = 'green';
ctx.font = 'bold 16px Arial';
ctx.fillText("✓ 不等式成立", width-150, 50);
}
}
aSlider.addEventListener('input', draw);
xSlider.addEventListener('input', draw);
draw();
</script>
</body>
</html>