| 1787 | } |
| 1788 | |
| 1789 | class FpsMonitor { |
| 1790 | constructor() { |
| 1791 | this.frameCount = 0; |
| 1792 | this.accumulatedTime = 0; |
| 1793 | this.lastTimestamp = 0; |
| 1794 | this.lastFrameTimestamp = 0; |
| 1795 | this.currentFps = null; |
| 1796 | |
| 1797 | this.root = document.createElement("div"); |
| 1798 | this.root.className = "fps-overlay"; |
| 1799 | |
| 1800 | this.valueElement = document.createElement("span"); |
| 1801 | this.valueElement.className = "fps-overlay__value"; |
| 1802 | this.valueElement.textContent = "— fps"; |
| 1803 | |
| 1804 | this.root.appendChild(this.valueElement); |
| 1805 | document.body.appendChild(this.root); |
| 1806 | this.refreshDisplay = this.refreshDisplay.bind(this); |
| 1807 | this.displayTimer = window.setInterval(this.refreshDisplay, 250); |
| 1808 | this.refreshDisplay(); |
| 1809 | } |
| 1810 | |
| 1811 | update(time) { |
| 1812 | if (!Number.isFinite(time)) return; |
| 1813 | if (this.lastTimestamp === 0) { |
| 1814 | this.lastTimestamp = time; |
| 1815 | this.lastFrameTimestamp = time; |
| 1816 | return; |
| 1817 | } |
| 1818 | const delta = time - this.lastTimestamp; |
| 1819 | this.lastTimestamp = time; |
| 1820 | if (delta < 0) return; |
| 1821 | |
| 1822 | this.accumulatedTime += delta; |
| 1823 | this.frameCount += 1; |
| 1824 | this.lastFrameTimestamp = time; |
| 1825 | |
| 1826 | if (this.accumulatedTime >= 250) { |
| 1827 | const fps = Math.round((this.frameCount * 1000) / this.accumulatedTime); |
| 1828 | this.currentFps = fps; |
| 1829 | this.accumulatedTime = 0; |
| 1830 | this.frameCount = 0; |
| 1831 | this.refreshDisplay(); |
| 1832 | } |
| 1833 | } |
| 1834 | |
| 1835 | refreshDisplay() { |
| 1836 | const now = typeof performance !== "undefined" ? performance.now() : Date.now(); |
| 1837 | const timeSinceLastFrame = |
| 1838 | this.lastFrameTimestamp > 0 ? now - this.lastFrameTimestamp : Number.POSITIVE_INFINITY; |
| 1839 | |
| 1840 | if (!Number.isFinite(timeSinceLastFrame) || timeSinceLastFrame > 600) { |
| 1841 | this.valueElement.textContent = "idle"; |
| 1842 | this.currentFps = null; |
| 1843 | return; |
| 1844 | } |
| 1845 | |
| 1846 | if (this.currentFps !== null) { |
nothing calls this directly
no outgoing calls
no test coverage detected