Skip to content

Instantly share code, notes, and snippets.

@aaronbeall
Created June 14, 2018 19:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronbeall/34db0088585f911bd9131f3e158aaeba to your computer and use it in GitHub Desktop.
Save aaronbeall/34db0088585f911bd9131f3e158aaeba to your computer and use it in GitHub Desktop.
// ES6+TS port of mrdoob's stats.js
// Need this because lib.d.ts doesn't have Performance.memory
declare global {
interface Performance {
memory: any;
}
}
export class Stats {
REVISION = `16.ts`;
visiblePanelIndex = 0;
dom = document.createElement("div");
private beginTime = (performance || Date).now();
private prevTime = this.beginTime;
private frames = 0;
private fpsPanel: Panel;
private msPanel: Panel;
private memPanel: Panel;
constructor() {
this.dom.style.cssText = `position: fixed; top: 0; left: 0; cursor: pointer; opacity: 0.9; z-index: 10000`;
this.dom.addEventListener("click", event => {
event.preventDefault();
this.showPanel(++this.visiblePanelIndex % this.dom.children.length);
}, false);
this.fpsPanel = this.addPanel(new Panel("FPS", "#0ff", "#002"));
this.msPanel = this.addPanel(new Panel("MS", "#0f0", "#020"));
if (self.performance && self.performance.memory) {
this.memPanel = this.addPanel(new Panel("MB", "#f08", "#201"));
}
this.showPanel(0);
}
addPanel(panel: Panel) {
this.dom.appendChild(panel.dom);
return panel;
}
showPanel(index: number) {
for (let i = 0; i < this.dom.children.length; i++) {
(this.dom.children[i] as HTMLElement).style.display = i === index ? "block" : "none";
}
this.visiblePanelIndex = index;
}
begin = () => {
this.beginTime = (performance || Date).now();
}
end = () => {
this.frames++;
const time = (performance || Date).now();
this.msPanel.update(time - this.beginTime, 200);
if (time >= this.prevTime + 1000) {
this.fpsPanel.update((this.frames * 1000) / (time - this.prevTime), 100);
this.prevTime = time;
this.frames = 0;
if (this.memPanel) {
const memory = performance.memory;
this.memPanel.update(memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576);
}
}
return time;
}
update = () => {
this.beginTime = this.end();
}
}
export class Panel {
min = Infinity;
max = 0;
round = Math.round;
PR = this.round(window.devicePixelRatio || 1);
WIDTH = 80 * this.PR;
HEIGHT = 48 * this.PR;
TEXT_X = 3 * this.PR;
TEXT_Y = 2 * this.PR;
GRAPH_X = 3 * this.PR;
GRAPH_Y = 15 * this.PR;
GRAPH_WIDTH = 74 * this.PR;
GRAPH_HEIGHT = 30 * this.PR;
dom: HTMLCanvasElement;
context: CanvasRenderingContext2D;
constructor(private name: string, private fg: string, private bg: string) {
const canvas = document.createElement("canvas");
canvas.width = this.WIDTH;
canvas.height = this.HEIGHT;
canvas.style.cssText = `width: 80px; height: 48px`;
const context = canvas.getContext("2d");
if (!context) throw new Error(`DOM not ready for rendering`);
context.font = `bold ${9 * this.PR}px Helvetica,Arial,sans-serif`;
context.textBaseline = "top";
context.fillStyle = bg;
context.fillRect(0, 0, this.WIDTH, this.HEIGHT);
context.fillStyle = fg;
context.fillText(name, this.TEXT_X, this.TEXT_Y);
context.fillRect(this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH, this.GRAPH_HEIGHT);
context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect(this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH, this.GRAPH_HEIGHT);
this.dom = canvas;
this.context = context;
}
update(value: number, maxValue: number) {
this.min = Math.min(this.min, value);
this.max = Math.max(this.max, value);
this.context.fillStyle = this.bg;
this.context.globalAlpha = 1;
this.context.fillRect(0, 0, this.WIDTH, this.GRAPH_Y);
this.context.fillStyle = this.fg;
this.context.fillText(`${this.round(value)} ${this.name} (${this.round(this.min)}-${this.round(this.max)})`, this.TEXT_X, this.TEXT_Y);
this.context.drawImage(this.dom, this.GRAPH_X + this.PR, this.GRAPH_Y, this.GRAPH_WIDTH - this.PR, this.GRAPH_HEIGHT, this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH - this.PR, this.GRAPH_HEIGHT);
this.context.fillRect(this.GRAPH_X + this.GRAPH_WIDTH - this.PR, this.GRAPH_Y, this.PR, this.GRAPH_HEIGHT);
this.context.fillStyle = this.bg;
this.context.globalAlpha = 0.9;
this.context.fillRect(this.GRAPH_X + this.GRAPH_WIDTH - this.PR, this.GRAPH_Y, this.PR, this.round((1 - (value / maxValue)) * this.GRAPH_HEIGHT));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment