perf(import): throttle photo rendering
This commit is contained in:
@@ -993,6 +993,11 @@ function htmlPage(): string {
|
||||
}
|
||||
};
|
||||
let activeImportController = null;
|
||||
const IMPORT_RENDER_INTERVAL_MS = 180;
|
||||
let scheduledRenderFrame = null;
|
||||
let scheduledRenderTimer = null;
|
||||
let scheduledRenderOptions = { fitMap: false };
|
||||
let lastRenderAt = 0;
|
||||
|
||||
const map = L.map("map", { zoomControl: true }).setView([52.5208, 13.4095], 13);
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
@@ -1376,6 +1381,7 @@ function htmlPage(): string {
|
||||
}
|
||||
|
||||
function clearGallery() {
|
||||
cancelScheduledRender();
|
||||
state.photos = [];
|
||||
state.visiblePhotos = [];
|
||||
state.activePhotoId = null;
|
||||
@@ -1667,6 +1673,60 @@ function htmlPage(): string {
|
||||
}
|
||||
}
|
||||
|
||||
function runScheduledRender() {
|
||||
scheduledRenderFrame = null;
|
||||
const options = scheduledRenderOptions;
|
||||
scheduledRenderOptions = { fitMap: false };
|
||||
lastRenderAt = performance.now();
|
||||
renderVisiblePhotos(options);
|
||||
}
|
||||
|
||||
function scheduleVisiblePhotoRender(options = {}) {
|
||||
scheduledRenderOptions = {
|
||||
fitMap: Boolean(scheduledRenderOptions.fitMap || options.fitMap)
|
||||
};
|
||||
|
||||
if (scheduledRenderFrame !== null || scheduledRenderTimer !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elapsed = performance.now() - lastRenderAt;
|
||||
const delay = Math.max(0, IMPORT_RENDER_INTERVAL_MS - elapsed);
|
||||
const queueFrame = () => {
|
||||
scheduledRenderTimer = null;
|
||||
scheduledRenderFrame = requestAnimationFrame(runScheduledRender);
|
||||
};
|
||||
|
||||
if (delay === 0) {
|
||||
queueFrame();
|
||||
} else {
|
||||
scheduledRenderTimer = setTimeout(queueFrame, delay);
|
||||
}
|
||||
}
|
||||
|
||||
function cancelScheduledRender() {
|
||||
if (scheduledRenderFrame !== null) {
|
||||
cancelAnimationFrame(scheduledRenderFrame);
|
||||
scheduledRenderFrame = null;
|
||||
}
|
||||
|
||||
if (scheduledRenderTimer !== null) {
|
||||
clearTimeout(scheduledRenderTimer);
|
||||
scheduledRenderTimer = null;
|
||||
}
|
||||
|
||||
scheduledRenderOptions = { fitMap: false };
|
||||
}
|
||||
|
||||
function flushVisiblePhotoRender(options = {}) {
|
||||
const renderOptions = {
|
||||
fitMap: Boolean(scheduledRenderOptions.fitMap || options.fitMap)
|
||||
};
|
||||
cancelScheduledRender();
|
||||
lastRenderAt = performance.now();
|
||||
renderVisiblePhotos(renderOptions);
|
||||
}
|
||||
|
||||
let timelinePointerState = null;
|
||||
let timelineClickSuppressed = false;
|
||||
|
||||
@@ -1792,7 +1852,7 @@ function htmlPage(): string {
|
||||
|
||||
function appendPhoto(photo) {
|
||||
state.photos.push(photo);
|
||||
renderVisiblePhotos({ fitMap: state.photos.length === 1 });
|
||||
scheduleVisiblePhotoRender({ fitMap: state.photos.length === 1 });
|
||||
}
|
||||
|
||||
function textContent(node, namespace, localName) {
|
||||
@@ -1938,8 +1998,10 @@ function htmlPage(): string {
|
||||
"Import complete: " + loaded + " images imported" + (skipped ? ", " + skipped + " skipped" : "") + "."
|
||||
);
|
||||
setProgress(listing.length, listing.length, "complete");
|
||||
flushVisiblePhotoRender({ fitMap: true });
|
||||
} catch (error) {
|
||||
if (controller.signal.aborted) {
|
||||
flushVisiblePhotoRender();
|
||||
setImportStatus("Import stopped.");
|
||||
setProgress(state.processed, state.total, "canceled");
|
||||
return;
|
||||
@@ -1950,6 +2012,7 @@ function htmlPage(): string {
|
||||
"Import failed: " + (error instanceof Error ? error.message : "unknown error"),
|
||||
"error"
|
||||
);
|
||||
flushVisiblePhotoRender();
|
||||
} finally {
|
||||
activeImportController = null;
|
||||
setImporting(false);
|
||||
|
||||
Reference in New Issue
Block a user