Performance: stop iPhone freezes (blur over live map, runaway animation, eager charts)
Publish Container / publish (push) Successful in 2m57s
Publish Container / publish (push) Successful in 2m57s
Main app - No backdrop-filter over the live map, animated sky, or sticky headings (it re-blurs every frame; on iPhone that is a classic stutter/lock-up); top/bottom bars keep a light 8px blur - Sky effect only draws while the hero is on screen and the Now tab is active, ~30fps cap, fewer particles on phones; fixed a stale animation-frame id that could stop restarts Dashboard - Charts are built only when the Charts tab is opened (was ~11 charts on every page load), and the 2-minute refresh no longer rebuilds them in the background - On phones: max 360 points per chart (was 720), no entry animation, device pixel ratio capped at 2 - Lighter header blur, none on small buttons/cards Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dde59e3865
commit
fda8dca435
5 files changed
+53
-13
No files matched your search
@@ -614,6 +614,18 @@ const RANGE_LABELS = {
|
||||
};
|
||||
|
||||
let currentRange = '24h';
|
||||
|
||||
// ── Phone-friendly charts ──
|
||||
// Fewer points, no entry animation and a capped pixel ratio keep 11 charts cheap on an iPhone, and charts
|
||||
// are only built while the Charts tab is actually on screen.
|
||||
const NARROW_SCREEN = window.innerWidth < 700;
|
||||
const MAX_PTS = NARROW_SCREEN ? 360 : 720;
|
||||
let chartsDirty = true;
|
||||
const chartsPaneActive = () => !!document.querySelector('.tab-pane[data-pane="charts"].active');
|
||||
if (typeof Chart !== 'undefined') {
|
||||
if (window.matchMedia('(pointer: coarse)').matches) Chart.defaults.animation = false;
|
||||
Chart.defaults.devicePixelRatio = Math.min(window.devicePixelRatio || 1, 2);
|
||||
}
|
||||
let charts = {};
|
||||
|
||||
// ── Formatting helpers ──────────────────────────────────────────────────────
|
||||
@@ -807,7 +819,7 @@ async function drawPresTend(pagePts, pageRange) {
|
||||
if (hit && Date.now() - hit.at < 120000) pts = hit.data;
|
||||
else {
|
||||
try {
|
||||
const bucket = ['7d', '30d', 'all'].includes(range) ? '&points=720' : '';
|
||||
const bucket = ['7d', '30d', 'all'].includes(range) ? '&points=' + MAX_PTS : '';
|
||||
const r = await fetch(`/api/station/history?range=${range}${bucket}`);
|
||||
pts = r.ok ? await r.json() : [];
|
||||
} catch { pts = []; }
|
||||
@@ -815,7 +827,7 @@ async function drawPresTend(pagePts, pageRange) {
|
||||
}
|
||||
if (document.getElementById('cPresTend') !== canvas) return; // charts were re-rendered meanwhile
|
||||
}
|
||||
if (pts.length > 900) { const step = Math.ceil(pts.length / 720); pts = pts.filter((_, i) => i % step === 0); }
|
||||
if (pts.length > MAX_PTS * 1.25) { const step = Math.ceil(pts.length / MAX_PTS); pts = pts.filter((_, i) => i % step === 0); }
|
||||
// Bucketed (long) ranges can't resolve changes shorter than one bucket: widen the window to fit
|
||||
const bucketMs = pts.length > 1 ? (pts[pts.length - 1].dateutc - pts[0].dateutc) / (pts.length - 1) : 0;
|
||||
const effHours = Math.max(presTendWin, Math.ceil(bucketMs / 3600000));
|
||||
@@ -892,8 +904,8 @@ function renderCharts(readings, range, yoy = null, nws = null) {
|
||||
|
||||
// downsample for 30d to keep chart manageable
|
||||
let pts = readings;
|
||||
if (readings.length > 720) {
|
||||
const step = Math.ceil(readings.length / 720);
|
||||
if (readings.length > MAX_PTS) {
|
||||
const step = Math.ceil(readings.length / MAX_PTS);
|
||||
pts = readings.filter((_, i) => i % step === 0);
|
||||
}
|
||||
const lbls = pts.map(r => fmtTime(r.dateutc, range));
|
||||
@@ -990,7 +1002,7 @@ function renderCharts(readings, range, yoy = null, nws = null) {
|
||||
const addNws = (sets, key, suffix, dashed) => { const a = nwsAlign(pts, nws, key); if (a) sets.push(nwsDataset(`${nwsLab} ${suffix}`, a, dashed)); };
|
||||
addNws(tempDatasets, 'tempf', 'temp');
|
||||
if (yoy?.prior?.length) {
|
||||
const yoyPts = yoy.prior.length > 720 ? yoy.prior.filter((_, i) => i % Math.ceil(yoy.prior.length / 720) === 0) : yoy.prior;
|
||||
const yoyPts = yoy.prior.length > MAX_PTS ? yoy.prior.filter((_, i) => i % Math.ceil(yoy.prior.length / MAX_PTS) === 0) : yoy.prior;
|
||||
tempDatasets.push({ ...lineDataset('Last Year', yoyPts.map(r => r.tempf), c.accent + '55', true), borderWidth: 1 });
|
||||
}
|
||||
makeChart('cTemp', 'line', tempDatasets, lbls, '°F', { plugins: { legend: { labels: { filter: i => !['Max', 'Min'].includes(i.text) } } } });
|
||||
@@ -1164,10 +1176,12 @@ async function updateLatest() {
|
||||
|
||||
// ── Load history ─────────────────────────────────────────────────────────────
|
||||
async function loadHistory(range) {
|
||||
if (!chartsPaneActive()) { chartsDirty = true; return; } // build charts when the Charts tab is opened
|
||||
chartsDirty = false;
|
||||
const area = document.getElementById('chartsArea');
|
||||
area.innerHTML = '<div class="status" id="loadingMsg">Loading…</div>';
|
||||
try {
|
||||
const pts = ['7d','30d','90d','1y','2y','3y','all'].includes(range) ? '&points=720' : '';
|
||||
const pts = ['7d','30d','90d','1y','2y','3y','all'].includes(range) ? '&points=' + MAX_PTS : '';
|
||||
const nwsP = nwsOverlay ? fetch(`/api/nws/history?range=${range}`).then(x => (x.ok ? x.json() : [])).catch(() => []) : Promise.resolve([]);
|
||||
const r = await fetch(`/api/station/history?range=${range}${pts}`);
|
||||
if (r.status === 401) { location.href = '/dashboard/login'; return; }
|
||||
|
||||
Reference in new issue
Block a user