93 lines
2.2 KiB
TypeScript
93 lines
2.2 KiB
TypeScript
import { IS_IOS } from './browser/windowEnvironment';
|
|
import { animate } from './animation';
|
|
import { fastRaf } from './schedulers';
|
|
|
|
const TEST_INTERVAL = 5000; // 5 sec
|
|
const FRAMES_TO_TEST = 10;
|
|
const REDUCED_FPS = 35;
|
|
|
|
let isImproved = false;
|
|
|
|
export function betterView() {
|
|
if (!IS_IOS) return;
|
|
|
|
let interval: number | undefined;
|
|
let lastFocusAt = Date.now();
|
|
|
|
function setupInterval() {
|
|
if (interval || isImproved) return;
|
|
|
|
interval = window.setInterval(testAndImprove, TEST_INTERVAL);
|
|
}
|
|
|
|
window.addEventListener('focus', () => {
|
|
const now = Date.now();
|
|
if (now - lastFocusAt < 100) return; // iOS triggers two `focus` events for some reason
|
|
lastFocusAt = now;
|
|
|
|
setupInterval();
|
|
testAndImprove();
|
|
});
|
|
|
|
window.addEventListener('blur', () => {
|
|
clearInterval(interval);
|
|
interval = undefined;
|
|
});
|
|
|
|
if (document.hasFocus()) {
|
|
setupInterval();
|
|
testAndImprove();
|
|
}
|
|
}
|
|
|
|
async function testAndImprove() {
|
|
const fps = await testFps();
|
|
if (fps <= REDUCED_FPS) {
|
|
improveView();
|
|
}
|
|
}
|
|
|
|
function testFps() {
|
|
return new Promise<number>((resolve) => {
|
|
const frames: number[] = [];
|
|
let lastFrameAt = performance.now();
|
|
|
|
animate(() => {
|
|
const now = performance.now();
|
|
frames.push(now - lastFrameAt);
|
|
lastFrameAt = now;
|
|
|
|
if (frames.length === FRAMES_TO_TEST) {
|
|
const mean = frames.sort()[Math.floor(frames.length / 2)];
|
|
resolve(Math.round(1000 / mean));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}, fastRaf);
|
|
});
|
|
}
|
|
|
|
function improveView() {
|
|
isImproved = true;
|
|
|
|
const containerEl = document.createElement('div');
|
|
containerEl.style.cssText = 'position: absolute; top: 0; left: 0; width: 0; height: 100%; overflow: hidden;';
|
|
|
|
const boosterEl = document.createElement('div');
|
|
const height = window.screen.height * 1.5;
|
|
boosterEl.style.cssText = `width: 0; height: ${height}px; transform: translateX(100%); transition: transform 100ms;`;
|
|
boosterEl.innerHTML = ' ';
|
|
|
|
containerEl.appendChild(boosterEl);
|
|
document.body.appendChild(containerEl);
|
|
|
|
requestAnimationFrame(() => {
|
|
boosterEl.addEventListener('transitionend', () => {
|
|
containerEl.remove();
|
|
});
|
|
|
|
boosterEl.style.transform = '';
|
|
});
|
|
}
|