Skip to content

fps #22

@leno23

Description

@leno23
<title>FPS 计算器演示</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 20px;
    }

    .container {
        background: rgba(255, 255, 255, 0.95);
        border-radius: 20px;
        padding: 40px;
        box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
        max-width: 600px;
        width: 100%;
    }

    h1 {
        text-align: center;
        color: #333;
        margin-bottom: 30px;
        font-size: 32px;
    }

    .fps-display {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 15px;
        padding: 30px;
        margin-bottom: 30px;
        text-align: center;
        color: white;
    }

    .fps-value {
        font-size: 72px;
        font-weight: bold;
        margin-bottom: 10px;
        text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
    }

    .fps-label {
        font-size: 18px;
        opacity: 0.9;
    }

    .stats {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 15px;
        margin-bottom: 25px;
    }

    .stat-item {
        background: #f5f5f5;
        padding: 20px;
        border-radius: 10px;
        text-align: center;
    }

    .stat-value {
        font-size: 28px;
        font-weight: bold;
        color: #667eea;
        margin-bottom: 5px;
    }

    .stat-label {
        font-size: 14px;
        color: #666;
    }

    .controls {
        display: flex;
        gap: 10px;
        justify-content: center;
        flex-wrap: wrap;
    }

    button {
        padding: 12px 25px;
        border: none;
        border-radius: 8px;
        font-size: 16px;
        cursor: pointer;
        transition: all 0.3s ease;
        font-weight: 600;
    }

    .btn-primary {
        background: #667eea;
        color: white;
    }

    .btn-primary:hover {
        background: #5568d3;
        transform: translateY(-2px);
        box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
    }

    .btn-secondary {
        background: #e0e0e0;
        color: #333;
    }

    .btn-secondary:hover {
        background: #d0d0d0;
        transform: translateY(-2px);
    }

    .info {
        margin-top: 25px;
        padding: 15px;
        background: #f9f9f9;
        border-radius: 8px;
        font-size: 14px;
        color: #666;
        line-height: 1.6;
    }

    .canvas-container {
        margin-top: 20px;
        border-radius: 10px;
        overflow: hidden;
        box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
    }

    canvas {
        display: block;
        width: 100%;
        background: white;
    }
</style>

🎮 FPS 计算器

    <div class="fps-display">
        <div class="fps-value" id="fpsValue">0</div>
        <div class="fps-label">当前 FPS</div>
    </div>

    <div class="stats">
        <div class="stat-item">
            <div class="stat-value" id="avgFps">0</div>
            <div class="stat-label">平均 FPS</div>
        </div>
        <div class="stat-item">
            <div class="stat-value" id="minFps">0</div>
            <div class="stat-label">最低 FPS</div>
        </div>
        <div class="stat-item">
            <div class="stat-value" id="maxFps">0</div>
            <div class="stat-label">最高 FPS</div>
        </div>
    </div>

    <div class="controls">
        <button class="btn-primary" id="resetBtn">重置统计</button>
        <button class="btn-secondary" id="toggleLoad">增加负载</button>
    </div>

    <div class="canvas-container">
        <canvas id="animationCanvas" width="520" height="200"></canvas>
    </div>

    <div class="info">
        <strong>💡 说明:</strong><br>
        FPS(Frames Per Second)表示每秒渲染的帧数。点击"增加负载"可以看到性能变化。
        本示例使用 <code>requestAnimationFrame</code> 方法实现帧率计算。
    </div>
</div>

<script>
    // FPS 计算器类
    class FPSCounter {
        constructor() {
            this.fps = 0;
            this.frames = [];
            this.lastFrameTime = performance.now();
            this.allFps = [];
        }

        // 更新 FPS
        update() {
            const now = performance.now();
            const delta = now - this.lastFrameTime;
            this.lastFrameTime = now;

            // 计算当前帧率
            const currentFps = 1000 / delta;
            this.frames.push(currentFps);

            // 保持最近 60 帧的数据用于平滑计算
            if (this.frames.length > 60) {
                this.frames.shift();
            }

            // 计算平均 FPS(最近 60 帧)
            this.fps = Math.round(
                this.frames.reduce((a, b) => a + b, 0) / this.frames.length
            );

            // 记录所有 FPS 用于统计
            this.allFps.push(this.fps);

            return this.fps;
        }

        // 获取平均 FPS
        getAverage() {
            if (this.allFps.length === 0) return 0;
            const sum = this.allFps.reduce((a, b) => a + b, 0);
            return Math.round(sum / this.allFps.length);
        }

        // 获取最小 FPS
        getMin() {
            if (this.allFps.length === 0) return 0;
            return Math.min(...this.allFps);
        }

        // 获取最大 FPS
        getMax() {
            if (this.allFps.length === 0) return 0;
            return Math.max(...this.allFps);
        }

        // 重置统计
        reset() {
            this.frames = [];
            this.allFps = [];
            this.fps = 0;
        }
    }

    // 初始化
    const fpsCounter = new FPSCounter();
    const fpsElement = document.getElementById('fpsValue');
    const avgFpsElement = document.getElementById('avgFps');
    const minFpsElement = document.getElementById('minFps');
    const maxFpsElement = document.getElementById('maxFps');
    const resetBtn = document.getElementById('resetBtn');
    const toggleLoadBtn = document.getElementById('toggleLoad');
    const canvas = document.getElementById('animationCanvas');
    const ctx = canvas.getContext('2d');

    let highLoad = false;
    let particles = [];

    // 粒子类(用于演示动画)
    class Particle {
        constructor() {
            this.x = Math.random() * canvas.width;
            this.y = Math.random() * canvas.height;
            this.vx = (Math.random() - 0.5) * 3;
            this.vy = (Math.random() - 0.5) * 3;
            this.radius = Math.random() * 3 + 2;
            this.color = `hsl(${Math.random() * 360}, 70%, 60%)`;
        }

        update() {
            this.x += this.vx;
            this.y += this.vy;

            if (this.x < 0 || this.x > canvas.width) this.vx *= -1;
            if (this.y < 0 || this.y > canvas.height) this.vy *= -1;
        }

        draw() {
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
            ctx.fillStyle = this.color;
            ctx.fill();
        }
    }

    // 初始化粒子
    function initParticles(count) {
        particles = [];
        for (let i = 0; i < count; i++) {
            particles.push(new Particle());
        }
    }

    initParticles(50);

    // 主动画循环
    function animate() {
        // 更新 FPS
        const currentFps = fpsCounter.update();
        
        // 更新显示
        fpsElement.textContent = currentFps;
        avgFpsElement.textContent = fpsCounter.getAverage();
        minFpsElement.textContent = fpsCounter.getMin();
        maxFpsElement.textContent = fpsCounter.getMax();

        // 根据 FPS 更改颜色
        if (currentFps >= 50) {
            fpsElement.style.color = '#4ade80';
        } else if (currentFps >= 30) {
            fpsElement.style.color = '#fbbf24';
        } else {
            fpsElement.style.color = '#f87171';
        }

        // 清空画布
        ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // 更新和绘制粒子
        particles.forEach(particle => {
            particle.update();
            particle.draw();
        });

        // 如果启用高负载,执行额外计算
        if (highLoad) {
            for (let i = 0; i < 100000; i++) {
                Math.sqrt(Math.random() * 10000);
            }
        }

        // 继续动画循环
        requestAnimationFrame(animate);
    }

    // 重置按钮
    resetBtn.addEventListener('click', () => {
        fpsCounter.reset();
        fpsElement.textContent = '0';
        avgFpsElement.textContent = '0';
        minFpsElement.textContent = '0';
        maxFpsElement.textContent = '0';
    });

    // 切换负载按钮
    toggleLoadBtn.addEventListener('click', () => {
        highLoad = !highLoad;
        if (highLoad) {
            toggleLoadBtn.textContent = '减少负载';
            toggleLoadBtn.classList.remove('btn-secondary');
            toggleLoadBtn.classList.add('btn-primary');
            initParticles(200); // 增加粒子数量
        } else {
            toggleLoadBtn.textContent = '增加负载';
            toggleLoadBtn.classList.remove('btn-primary');
            toggleLoadBtn.classList.add('btn-secondary');
            initParticles(50); // 恢复粒子数量
        }
    });

    // 启动动画
    animate();
</script>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions