UNPKG

pixi-stats

Version:

WebGL stats for pixi.js or/and three.js

195 lines (160 loc) 4.65 kB
import { PIXIHooks } from './pixi-hooks' import { RenderPanel } from './stats-panel' import { StatStorage } from './stat-storage' import { IStats, IPanelConfig, IStatsJSAdapter, Renderer, PIXITicker } from './model' import { StatsJSAdapter } from './stats-adapter' import { DOM_ELEMENT_ID } from './stats-constants' export class Stats implements IStats { mode = -1 frames = 0 beginTime: number prevTime: number pixiHooks: PIXIHooks adapter: IStatsJSAdapter fpsStat: StatStorage msStat: StatStorage memStat?: StatStorage panels: IPanelConfig[] = [] domElement: HTMLDivElement | null = null containerElement: HTMLElement | null = null renderPanel: RenderPanel | null = null /** * in document/html/dom context returns document's body */ static getContainerElement(): HTMLElement | undefined { if (typeof document === 'undefined') { return undefined } return document?.body } constructor( renderer: Renderer, ticker?: PIXITicker, containerElement = Stats.getContainerElement(), autoStart = true ) { this.beginTime = (performance || Date).now() this.prevTime = this.beginTime this.fpsStat = this.createStat('FPS', '#3ff', '#002') this.msStat = this.createStat('MS', '#0f0', '#020') if ('memory' in performance) { this.memStat = this.createStat('MB', '#f08', '#200') } this.pixiHooks = new PIXIHooks(renderer) this.adapter = new StatsJSAdapter(this.pixiHooks, this) if (typeof renderer?.animations !== 'undefined') { renderer.animations.push(() => { this.adapter.update() }) } else if (typeof ticker !== 'undefined') { ticker.add(() => { this.adapter.update() }) } else if (typeof requestAnimationFrame !== 'undefined') { const frame = () => { this.adapter.update() requestAnimationFrame(frame) } frame() } if (containerElement) { this.containerElement = containerElement } if (this.containerElement && autoStart) { this.showPanel() } } initDomElement(): void { if (this.containerElement && !this.domElement) { this.domElement = document.createElement('div') this.domElement.id = DOM_ELEMENT_ID this.domElement.addEventListener('click', this.handleClickPanel, false) this.containerElement.appendChild(this.domElement) } } handleClickPanel = (event: MouseEvent): void => { event.preventDefault() this.showPanel(++this.mode % this.panels.length) } createStat(name: string, fg: string, bg: string): StatStorage { const statStorage = new StatStorage() this.panels.push({ name, fg, bg, statStorage }) return statStorage } showPanel(id = 0) { const panel = this.panels[id] if (panel) { this.initDomElement() this.removeDomRenderPanel() this.createRenderPanel(panel) this.mode = id } else { this.hidePanel() } } hidePanel() { this.removeDomRenderPanel() this.removeDomElement() this.mode = -1 } createRenderPanel({ name, fg, bg, statStorage }: IPanelConfig): void { if (!this.domElement) { return } this.renderPanel = new RenderPanel(name, fg, bg, statStorage) if (this.renderPanel.dom) { this.domElement.appendChild(this.renderPanel.dom) } } removeDomRenderPanel(): void { if (!this.domElement) { return } if (this.renderPanel?.dom) { this.domElement.removeChild(this.renderPanel.dom) this.renderPanel.destroy() this.renderPanel = null } } removeDomElement(): void { if (!this.domElement || !this.containerElement) { return } this.containerElement.removeChild(this.domElement) this.domElement.removeEventListener('click', this.handleClickPanel, false) this.domElement = null } begin(): void { this.beginTime = (performance || Date).now() } end(): number { const time: number = (performance || Date).now() this.frames++ this.msStat.update(time - this.beginTime, 200) if (time > this.prevTime + 1000) { this.fpsStat.update((this.frames * 1000) / (time - this.prevTime), 100) this.prevTime = time this.frames = 0 if ('memory' in performance && this.memStat) { const memory = performance.memory as { usedJSHeapSize: number jsHeapSizeLimit: number } this.memStat.update( memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576 ) } } return time } update(): void { this.beginTime = this.end() } }