From 58134bc7c205e78c2098e95ca1c80417890ec4a7 Mon Sep 17 00:00:00 2001 From: Robert Long <robert@robertlong.me> Date: Fri, 13 Apr 2018 14:22:56 -0700 Subject: [PATCH] Stats panel component that collapses to an FPS counter --- src/components/stats-plus.css | 26 +++++++ src/components/stats-plus.js | 130 ++++++++++++++++++++++++++++++++++ src/hub.js | 7 +- 3 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 src/components/stats-plus.css create mode 100644 src/components/stats-plus.js diff --git a/src/components/stats-plus.css b/src/components/stats-plus.css new file mode 100644 index 000000000..fc4417bf5 --- /dev/null +++ b/src/components/stats-plus.css @@ -0,0 +1,26 @@ +:global(.rs-header) { + display: flex; + justify-content: space-between; + border-bottom: 1px rgba(255,255,255,0.1) solid; + margin-bottom: 8px; +} + +:global(.rs-collapse-btn) { + cursor: pointer; + font-size: 12px; +} + +:global(.rs-fps-counter) { + cursor: pointer; + position: absolute; + bottom: 0; + left: 0; + padding: 8px; + color: #aaa; + font-size: 10px; +} + +:global(.rs-mobile) { + bottom: auto; + top: 0; +} \ No newline at end of file diff --git a/src/components/stats-plus.js b/src/components/stats-plus.js new file mode 100644 index 000000000..c64100eea --- /dev/null +++ b/src/components/stats-plus.js @@ -0,0 +1,130 @@ +import "./stats-plus.css"; +// Adapted from https://github.com/aframevr/aframe/blob/master/src/components/scene/stats.js + +function createStats(scene) { + const threeStats = new window.threeStats(scene.renderer); + const aframeStats = new window.aframeStats(scene); + const plugins = scene.isMobile ? [] : [threeStats, aframeStats]; + return new window.rStats({ + css: [], // Our stylesheet is injected from AFrame. + values: { + fps: { caption: "fps", below: 30 } + }, + groups: [{ caption: "Framerate", values: ["fps", "raf"] }], + plugins: plugins + }); +} + +const HIDDEN_CLASS = "a-hidden"; + +AFRAME.registerComponent("stats-plus", { + // Whether or not the stats panel is expanded. + // Shows FPS counter when collapsed. + schema: { default: false }, + init() { + this.onExpand = this.onExpand.bind(this); + this.onCollapse = this.onCollapse.bind(this); + this.onEnterVr = this.onEnterVr.bind(this); + this.onExitVr = this.onExitVr.bind(this); + + const scene = this.el.sceneEl; + this.stats = createStats(scene); + this.statsEl = document.querySelector(".rs-base"); + + // Add header to stats panel so we can collapse it + const statsHeaderEl = document.createElement("div"); + statsHeaderEl.classList.add("rs-header"); + + const statsTitleEl = document.createElement("h1"); + statsTitleEl.innerHTML = "Stats"; + statsHeaderEl.appendChild(statsTitleEl); + + const collapseEl = document.createElement("div"); + collapseEl.classList.add("rs-collapse-btn"); + collapseEl.innerHTML = "X"; + collapseEl.addEventListener("click", this.onCollapse); + statsHeaderEl.appendChild(collapseEl); + + this.statsEl.insertBefore(statsHeaderEl, this.statsEl.firstChild); + + // Add fps counter to the page + this.fpsEl = document.createElement("div"); + this.fpsEl.addEventListener("click", this.onExpand); + this.fpsEl.classList.add("rs-fps-counter"); + document.body.appendChild(this.fpsEl); + this.lastFpsUpdate = performance.now(); + this.frameCount = 0; + + if (scene.isMobile) { + this.statsEl.classList.add("rs-mobile"); + this.fpsEl.classList.add("rs-mobile"); + } + + scene.addEventListener("enter-vr", this.onEnterVr); + scene.addEventListener("exit-vr", this.onExitVr); + }, + update(oldData) { + if (oldData !== this.data) { + if (this.data) { + this.statsEl.classList.remove(HIDDEN_CLASS); + this.fpsEl.classList.add(HIDDEN_CLASS); + } else { + this.statsEl.classList.add(HIDDEN_CLASS); + this.fpsEl.classList.remove(HIDDEN_CLASS); + } + } + }, + tick() { + if (this.data) { + // Update rStats + const stats = this.stats; + stats("rAF").tick(); + stats("FPS").frame(); + stats().update(); + } else { + // Update the fps counter + const now = performance.now(); + this.frameCount++; + + // Update the fps counter text once a second + if (now >= this.lastFpsUpdate + 1000) { + const fps = this.frameCount / ((now - this.lastFpsUpdate) / 1000); + this.fpsEl.innerHTML = Math.round(fps) + " FPS"; + this.lastFpsUpdate = now; + this.frameCount = 0; + } + } + }, + onEnterVr() { + // Hide all stats elements when entering VR on mobile + if (this.el.sceneEl.isMobile) { + this.statsEl.classList.add(HIDDEN_CLASS); + this.fpsEl.classList.add(HIDDEN_CLASS); + } + }, + onExitVr() { + // Revert to previous state whe exiting VR on mobile + if (this.el.sceneEl.isMobile) { + if (this.data) { + this.statsEl.classList.remove(HIDDEN_CLASS); + } else { + this.fpsEl.classList.remove(HIDDEN_CLASS); + } + } + }, + onExpand() { + this.el.setAttribute(this.name, true); + }, + onCollapse() { + this.el.setAttribute(this.name, false); + }, + remove() { + this.el.sceneEl.removeListener("enter-vr", this.hide); + this.el.sceneEl.removeListener("exit-vr", this.show); + + if (this.statsEl) { + this.statsEl.parentNode.removeChild(this.statsEl); + this.fpsEl.parentNode.removeChild(this.fpsEl); + } + } +}); diff --git a/src/hub.js b/src/hub.js index 9dc3247e3..081bc5442 100644 --- a/src/hub.js +++ b/src/hub.js @@ -46,6 +46,7 @@ import "./components/hand-poses"; import "./components/gltf-model-plus"; import "./components/gltf-bundle"; import "./components/hud-controller"; +import "./components/stats-plus"; import ReactDOM from "react-dom"; import React from "react"; @@ -133,6 +134,8 @@ async function enterScene(mediaStream, enterInVR, janusRoomId) { document.querySelector("a-scene canvas").classList.remove("blurred"); scene.render(); + scene.setAttribute("stats-plus", false); + if (enterInVR) { scene.enterVR(); } @@ -146,10 +149,6 @@ async function enterScene(mediaStream, enterInVR, janusRoomId) { serverURL: process.env.JANUS_SERVER }); - if (!qsTruthy("no_stats")) { - scene.setAttribute("stats", true); - } - if (isMobile || qsTruthy("mobile")) { playerRig.setAttribute("virtual-gamepad-controls", {}); } -- GitLab