// ==UserScript==
// @name 帧率检测器 - FPS Monitor
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 实时检测网页帧率(FPS) - 每秒更新一次
// @author Your Name
// @match *://*/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 等待页面加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
function init() {
// 创建悬浮窗容器
const floatingWindow = document.createElement('div');
floatingWindow.id = 'fps-monitor-root';
floatingWindow.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 999999;
width: 260px;
background: linear-gradient(135deg, #1a1e2c 0%, #141824 100%);
border-radius: 16px;
padding: 15px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
box-shadow: 0 8px 20px rgba(0,0,0,0.3);
border: 1px solid rgba(255,255,255,0.1);
color: white;
cursor: move;
`;
// 简单的 HTML 结构
floatingWindow.innerHTML = `
⚡ FPS 检测器
检测中
📊 平均帧率
-- fps
⬇️ 最低帧率
-- fps
⬆️ 最高帧率
-- fps
📈 采样次数
0
`;
document.body.appendChild(floatingWindow);
// 拖拽功能
let isDragging = false;
let dragStartX, dragStartY, startLeft, startTop;
floatingWindow.addEventListener('mousedown', (e) => {
if (e.target.tagName === 'BUTTON') return;
isDragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
startLeft = floatingWindow.offsetLeft;
startTop = floatingWindow.offsetTop;
floatingWindow.style.cursor = 'grabbing';
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
let newLeft = startLeft + (e.clientX - dragStartX);
let newTop = startTop + (e.clientY - dragStartY);
newLeft = Math.max(0, Math.min(window.innerWidth - floatingWindow.offsetWidth, newLeft));
newTop = Math.max(0, Math.min(window.innerHeight - floatingWindow.offsetHeight, newTop));
floatingWindow.style.left = newLeft + 'px';
floatingWindow.style.top = newTop + 'px';
floatingWindow.style.right = 'auto';
});
document.addEventListener('mouseup', () => {
isDragging = false;
floatingWindow.style.cursor = 'move';
});
// FPS 检测逻辑 - 每秒更新一次
let lastTime = performance.now();
let frameCount = 0;
let currentFps = 0;
let fpsHistory = [];
let totalFps = 0;
let minFps = Infinity;
let maxFps = -Infinity;
let sampleCount = 0;
let animationId = null;
const fpsValueEl = document.getElementById('fpsValue');
const avgValueEl = document.getElementById('avgValue');
const minValueEl = document.getElementById('minValue');
const maxValueEl = document.getElementById('maxValue');
const sampleCountEl = document.getElementById('sampleCount');
const fpsStatusEl = document.getElementById('fpsStatus');
const resetBtn = document.getElementById('resetFpsBtn');
function updateDisplay(fps) {
// 更新当前FPS显示
const roundedFps = Math.round(fps);
fpsValueEl.textContent = roundedFps;
// 更新状态文字和颜色
if (fps >= 55) {
fpsValueEl.style.color = '#4ade80';
fpsStatusEl.textContent = '✅ 流畅';
fpsStatusEl.style.background = 'rgba(74,222,128,0.2)';
} else if (fps >= 30) {
fpsValueEl.style.color = '#fbbf24';
fpsStatusEl.textContent = '⚠️ 一般';
fpsStatusEl.style.background = 'rgba(251,191,36,0.2)';
} else {
fpsValueEl.style.color = '#f87171';
fpsStatusEl.textContent = '❌ 卡顿';
fpsStatusEl.style.background = 'rgba(248,113,113,0.2)';
}
}
function updateStats() {
if (sampleCount === 0) {
avgValueEl.textContent = '-- fps';
minValueEl.textContent = '-- fps';
maxValueEl.textContent = '-- fps';
return;
}
const avg = totalFps / sampleCount;
avgValueEl.textContent = avg.toFixed(1) + ' fps';
minValueEl.textContent = Math.round(minFps) + ' fps';
maxValueEl.textContent = Math.round(maxFps) + ' fps';
sampleCountEl.textContent = sampleCount;
}
function recordFps(fps) {
if (fps <= 0 || !isFinite(fps)) return;
totalFps += fps;
if (fps < minFps) minFps = fps;
if (fps > maxFps) maxFps = fps;
sampleCount++;
fpsHistory.push(fps);
if (fpsHistory.length > 200) fpsHistory.shift();
updateStats();
}
function resetStats() {
totalFps = 0;
minFps = Infinity;
maxFps = -Infinity;
sampleCount = 0;
fpsHistory = [];
updateStats();
fpsStatusEl.textContent = '重置完成';
setTimeout(() => {
if (currentFps >= 55) fpsStatusEl.textContent = '✅ 流畅';
else if (currentFps >= 30) fpsStatusEl.textContent = '⚠️ 一般';
else if (currentFps > 0) fpsStatusEl.textContent = '❌ 卡顿';
else fpsStatusEl.textContent = '检测中';
}, 1000);
}
// 帧率统计函数 - 每秒执行一次
function tick(now) {
frameCount++;
const delta = now - lastTime;
// 每秒钟计算一次帧率
if (delta >= 1000) {
// 计算这一秒内的平均帧率
currentFps = (frameCount * 1000) / delta;
currentFps = Math.min(144, Math.max(0, currentFps));
// 更新显示
updateDisplay(currentFps);
// 记录到统计数据
if (currentFps > 0 && isFinite(currentFps)) {
recordFps(currentFps);
}
// 重置计数器
frameCount = 0;
lastTime = now;
}
animationId = requestAnimationFrame(tick);
}
function startMonitoring() {
if (animationId) cancelAnimationFrame(animationId);
lastTime = performance.now();
frameCount = 0;
animationId = requestAnimationFrame(tick);
}
resetBtn.addEventListener('click', resetStats);
// 页面可见性变化处理
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
lastTime = performance.now();
frameCount = 0;
}
});
startMonitoring();
// 清理函数
window.addEventListener('beforeunload', () => {
if (animationId) cancelAnimationFrame(animationId);
});
console.log('FPS 检测器已启动 - 每秒更新一次');
}
})();