1.2.1 三角不等式演示

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> &nbsp;&nbsp;&nbsp;
        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>
        &nbsp;&nbsp;&nbsp;&nbsp;当 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>
相关推荐
阿珊和她的猫2 小时前
TypeScript 中的 `extends` 条件类型:定义与应用
javascript·typescript·状态模式
众创岛2 小时前
iframe的属性获取
开发语言·javascript·ecmascript
小陈工2 小时前
Python Web开发入门(十一):RESTful API设计原则与最佳实践——让你的API既优雅又好用
开发语言·前端·人工智能·后端·python·安全·restful
星空2 小时前
前段--A_2--HTML属性标签
前端·html
a1117762 小时前
MapDesigner (html开源项目)六角格地图设计工具
开源·html
三万棵雪松2 小时前
【Linux 物联网网关主控系统-Web部分(一)】
linux·前端·嵌入式linux
摸鱼仙人~3 小时前
增量快照 vs 结构化共享:适用场景全解析
前端·vue.js
2301_771717213 小时前
Jackson的使用方法详解
java·服务器·前端
A923A3 小时前
【小兔鲜电商前台 | 项目笔记】第八天
前端·vue.js·笔记·项目·小兔鲜