SOURCE

console 命令行工具 X clear

                    
>
console
<!DOCTYPE html>
<html>

<head>
    <title>有限差分离散化演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        #canvas {
            border: 1px solid #999;
            margin: 20px;
            position: relative;
        }

        .controls {
            margin: 20px 0;
        }

        .formula {
            background-color: #f5f5f5;
            padding: 15px;
            margin: 10px 0;
            font-family: monospace;
            width: 800px;
            text-align: center;
        }

        .legend {
            position: absolute;
            top: 20px;
            left: 20px;
            background-color: rgba(255, 255, 255, 0.8);
            padding: 10px;
            border: 1px solid #ccc;
        }

        .legend-item {
            display: flex;
            align-items: center;
            margin-bottom: 5px;
        }

        .legend-color {
            width: 20px;
            height: 20px;
            margin-right: 10px;
        }
    </style>
</head>

<body>
    <div class="controls">
        <label>步长 h:
            <input type="range" id="hSlider" min="0.1" max="2" step="0.1" value="1">
            <span id="hValue">1.0</span>
        </label>
    </div>
    <div class="formula">
        前向差分: f'(x) ≈ (f(x + h) - f(x)) / h<br>
        中心差分: f'(x) ≈ (f(x + h) - f(x - h)) / (2h)<br>
        后向差分: f'(x) ≈ (f(x) - f(x - h)) / h
    </div>
    <div style="position: relative;">
        <canvas id="canvas" width="800" height="400"></canvas>
        <div class="legend">
            <div class="legend-item">
                <div class="legend-color" style="background-color: #e44;"></div>
                <span>前向差分</span>
            </div>
            <div class="legend-item">
                <div class="legend-color" style="background-color: #2a2;"></div>
                <span>中心差分</span>
            </div>
            <div class="legend-item">
                <div class="legend-color" style="background-color: #00f;"></div>
                <span>后向差分</span>
            </div>
        </div>
    </div>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const hSlider = document.getElementById('hSlider');
        const hValue = document.getElementById('hValue');

        // 坐标变换参数
        const scale = 40;
        const offsetX = 100;
        const offsetY = 200;

        function drawGrid() {
            ctx.strokeStyle = '#ddd';
            ctx.beginPath();
            // 绘制网格线
            for (let x = 0; x <= canvas.width; x += scale) {
                ctx.moveTo(x, 0);
                ctx.lineTo(x, canvas.height);
            }
            for (let y = 0; y <= canvas.height; y += scale) {
                ctx.moveTo(0, y);
                ctx.lineTo(canvas.width, y);
            }
            ctx.stroke();
        }

        function func(x) {
            return Math.sin(x); // 示例函数
        }

        function animate() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            drawGrid();

            const h = parseFloat(hSlider.value);
            hValue.textContent = h.toFixed(1);

            const x0 = 4; // 关注点x坐标
            const x = x0 * scale + offsetX;
            const y = offsetY - func(x0) * scale;

            // 绘制函数曲线
            ctx.beginPath();
            ctx.strokeStyle = '#333';
            ctx.lineWidth = 2;
            for (let i = 0; i < canvas.width; i++) {
                const xx = (i - offsetX) / scale;
                const yy = offsetY - func(xx) * scale;
                if (i === 0) ctx.moveTo(i, yy);
                else ctx.lineTo(i, yy);
            }
            ctx.stroke();

            // 绘制离散点
            ctx.fillStyle = '#e44';
            [x0 - h, x0, x0 + h].forEach(xx => {
                const px = xx * scale + offsetX;
                const py = offsetY - func(xx) * scale;
                ctx.beginPath();
                ctx.arc(px, py, 5, 0, Math.PI * 2);
                ctx.fill();
            });

            // 绘制前向差分线段
            ctx.strokeStyle = '#e44';
            ctx.setLineDash([5, 5]);
            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo((x0 + h) * scale + offsetX, offsetY - func(x0 + h) * scale);
            ctx.stroke();

            // 绘制中心差分线段
            ctx.strokeStyle = '#2a2';
            ctx.beginPath();
            ctx.moveTo((x0 - h) * scale + offsetX, offsetY - func(x0 - h) * scale);
            ctx.lineTo((x0 + h) * scale + offsetX, offsetY - func(x0 + h) * scale);
            ctx.stroke();

            // 绘制后向差分线段
            ctx.strokeStyle = '#00f';
            ctx.beginPath();
            ctx.moveTo((x0 - h) * scale + offsetX, offsetY - func(x0 - h) * scale);
            ctx.lineTo(x, y);
            ctx.stroke();

            requestAnimationFrame(animate);
        }

        hSlider.addEventListener('input', animate);
        animate();
    </script>
</body>

</html>