stats.js
stats.js 是 javascript
性能监视器.
- FPS:上一秒渲染的 FPS 帧。数字越高越好
- MS:渲染帧需要毫秒。数字越低越好
- MB:MB 的已分配内存。(Run Chrome with --enable-precise-memory-info)
Usage
js
ar stats = new Stats();
stats.showPanel( 1 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );
function animate() {
stats.begin();
// monitored code goes here
stats.end();
requestAnimationFrame( animate );
}
requestAnimationFrame( animate );
// or
javascript:(function(){var script=document.createElement('script');script.onload=function(){var stats=new Stats();document.body.appendChild(stats.dom);requestAnimationFrame(function loop(){stats.update();requestAnimationFrame(loop)});};script.src='//mrdoob.github.io/stats.js/build/stats.min.js';document.head.appendChild(script);})()
源码解析
js
var Stats = function () {
var mode = 0; // 默认显示 fps。0: fps, 1: ms, 2: mb, 3+: custom
// 展示在页面的监控面板容器
var container = document.createElement("div");
container.style.cssText =
"position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";
container.addEventListener(
"click",
function (event) {
event.preventDefault();
// 点击循环切换展示的性能监控面板
showPanel(++mode % container.children.length);
},
false
);
// 添加性能监控面板到容器中
function addPanel(panel) {
container.appendChild(panel.dom);
return panel;
}
// 展示当前 mode 对应的面板
function showPanel(id) {
for (var i = 0; i < container.children.length; i++) {
container.children[i].style.display = i === id ? "block" : "none";
}
mode = id;
}
var beginTime = (performance || Date).now(),
prevTime = beginTime,
frames = 0;
// fps 监控面板
var fpsPanel = addPanel(new Stats.Panel("FPS", "#0ff", "#002"));
// ms 监控面板
var msPanel = addPanel(new Stats.Panel("MS", "#0f0", "#020"));
if (self.performance && self.performance.memory) {
// mb 监控面板
var memPanel = addPanel(new Stats.Panel("MB", "#f08", "#201"));
}
// 展示 fps 监控面板
showPanel(0);
return {
REVISION: 16,
dom: container,
addPanel: addPanel,
showPanel: showPanel,
// 开始监控
begin: function () {
beginTime = (performance || Date).now();
},
// 结束监控
end: function () {
frames++;
var time = (performance || Date).now();
// ms 计算公式:(结束时间 - 开始时间)
msPanel.update(time - beginTime, 200);
if (time >= prevTime + 1000) {
// fps 计算公式:执行次数 - (结束时间 - 开始时间)
fpsPanel.update((frames * 1000) / (time - prevTime), 100);
prevTime = time;
frames = 0;
if (memPanel) {
var memory = performance.memory;
// jsHeapSizeLimit:上下文内可用堆的最大体积,以字节计算
// usedJSHeapSize:当前 JS 堆活跃段(segment)的体积,以字节计算
// 1048576 === 1M
memPanel.update(
memory.usedJSHeapSize / 1048576,
memory.jsHeapSizeLimit / 1048576
);
}
}
return time;
},
// 更新监控
update: function () {
beginTime = this.end();
},
// Backwards Compatibility
domElement: container,
setMode: showPanel,
};
};
// 绘制监控面板
Stats.Panel = function (name, fg, bg) {
var min = Infinity,
max = 0,
round = Math.round;
var PR = round(window.devicePixelRatio || 1);
var WIDTH = 80 * PR,
HEIGHT = 48 * PR,
TEXT_X = 3 * PR,
TEXT_Y = 2 * PR,
GRAPH_X = 3 * PR,
GRAPH_Y = 15 * PR,
GRAPH_WIDTH = 74 * PR,
GRAPH_HEIGHT = 30 * PR;
var canvas = document.createElement("canvas");
canvas.width = WIDTH;
canvas.height = HEIGHT;
canvas.style.cssText = "width:80px;height:48px";
var context = canvas.getContext("2d");
context.font = "bold " + 9 * PR + "px Helvetica,Arial,sans-serif";
context.textBaseline = "top";
context.fillStyle = bg;
context.fillRect(0, 0, WIDTH, HEIGHT);
context.fillStyle = fg;
context.fillText(name, TEXT_X, TEXT_Y);
context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
return {
dom: canvas,
// 更新监控面板数值
update: function (value, maxValue) {
min = Math.min(min, value);
max = Math.max(max, value);
context.fillStyle = bg;
context.globalAlpha = 1;
context.fillRect(0, 0, WIDTH, GRAPH_Y);
context.fillStyle = fg;
context.fillText(
round(value) + " " + name + " (" + round(min) + "-" + round(max) + ")",
TEXT_X,
TEXT_Y
);
context.drawImage(
canvas,
GRAPH_X + PR,
GRAPH_Y,
GRAPH_WIDTH - PR,
GRAPH_HEIGHT,
GRAPH_X,
GRAPH_Y,
GRAPH_WIDTH - PR,
GRAPH_HEIGHT
);
context.fillRect(GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT);
context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect(
GRAPH_X + GRAPH_WIDTH - PR,
GRAPH_Y,
PR,
round((1 - value / maxValue) * GRAPH_HEIGHT)
);
},
};
};
export { Stats as default };