perf(import): throttle photo rendering
This commit is contained in:
@@ -993,6 +993,11 @@ function htmlPage(): string {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let activeImportController = null;
|
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);
|
const map = L.map("map", { zoomControl: true }).setView([52.5208, 13.4095], 13);
|
||||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
@@ -1376,6 +1381,7 @@ function htmlPage(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearGallery() {
|
function clearGallery() {
|
||||||
|
cancelScheduledRender();
|
||||||
state.photos = [];
|
state.photos = [];
|
||||||
state.visiblePhotos = [];
|
state.visiblePhotos = [];
|
||||||
state.activePhotoId = null;
|
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 timelinePointerState = null;
|
||||||
let timelineClickSuppressed = false;
|
let timelineClickSuppressed = false;
|
||||||
|
|
||||||
@@ -1792,7 +1852,7 @@ function htmlPage(): string {
|
|||||||
|
|
||||||
function appendPhoto(photo) {
|
function appendPhoto(photo) {
|
||||||
state.photos.push(photo);
|
state.photos.push(photo);
|
||||||
renderVisiblePhotos({ fitMap: state.photos.length === 1 });
|
scheduleVisiblePhotoRender({ fitMap: state.photos.length === 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
function textContent(node, namespace, localName) {
|
function textContent(node, namespace, localName) {
|
||||||
@@ -1938,8 +1998,10 @@ function htmlPage(): string {
|
|||||||
"Import complete: " + loaded + " images imported" + (skipped ? ", " + skipped + " skipped" : "") + "."
|
"Import complete: " + loaded + " images imported" + (skipped ? ", " + skipped + " skipped" : "") + "."
|
||||||
);
|
);
|
||||||
setProgress(listing.length, listing.length, "complete");
|
setProgress(listing.length, listing.length, "complete");
|
||||||
|
flushVisiblePhotoRender({ fitMap: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (controller.signal.aborted) {
|
if (controller.signal.aborted) {
|
||||||
|
flushVisiblePhotoRender();
|
||||||
setImportStatus("Import stopped.");
|
setImportStatus("Import stopped.");
|
||||||
setProgress(state.processed, state.total, "canceled");
|
setProgress(state.processed, state.total, "canceled");
|
||||||
return;
|
return;
|
||||||
@@ -1950,6 +2012,7 @@ function htmlPage(): string {
|
|||||||
"Import failed: " + (error instanceof Error ? error.message : "unknown error"),
|
"Import failed: " + (error instanceof Error ? error.message : "unknown error"),
|
||||||
"error"
|
"error"
|
||||||
);
|
);
|
||||||
|
flushVisiblePhotoRender();
|
||||||
} finally {
|
} finally {
|
||||||
activeImportController = null;
|
activeImportController = null;
|
||||||
setImporting(false);
|
setImporting(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user