Created
June 14, 2018 19:38
-
-
Save aaronbeall/34db0088585f911bd9131f3e158aaeba to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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