Skip to content

Commit 41aa986

Browse files
Item browser performance improvements (mcmonkeyprojects#908)
* image browser performance improvement - set initial aspect ratio of thumbnails In most cases, we know the aspect ratio of the image we will be using as the thumbnail. By setting this aspect ratio when creating the thumbnail element, we can avoid the reflow that occurs when the image loads. In my test where I click Refresh while viewing folder c (in the a/b/c tree) where c has 635 files and I have the profiler running (which slows things down) this reduces the time from click to finish by about 20% (from 8s to 6.5s). With debugger closed, the click-to-finish time is about 5s. * Avoid repetitive reflow when triggering lazyload elements * Defer adding title to an item until the mouse enters the item. Converting HTML to text is expensive, and 99% of the time not needed. * only set scrollOffset if the user had been scrolled. * Optimize the fetching and updating during initial load and on refresh. * Only render the files once after the folder tree has been fetched and expanded (original code was rendering files each fetch...so could be many many times) * Only fetch the folders/files once if refreshing the root folder (original code was fetching 2x) * Only fetch the folders/files twice if refreshing a subfolder (original code was fetching (1 + 1 * subfolderDepth). * clean and simplify * remove stray css edits --------- Co-authored-by: Alex "mcmonkey" Goodwin <[email protected]>
1 parent abfa807 commit 41aa986

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed

src/wwwroot/css/genpage.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ body {
366366
}
367367
.image-preview-text {
368368
font-family: var(--font-monospace);
369+
min-width: 100%;
370+
max-width: 0;
369371
}
370372
.current_model_view {
371373
display: inline-block;

src/wwwroot/js/genpage/gentab/imagehistory.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ function describeImage(image) {
149149
let imageSrc = image.data.src.endsWith('.html') ? 'imgs/html.jpg' : `${image.data.src}?preview=true${allowAnimToggle}`;
150150
let searchable = `${image.data.name}, ${image.data.metadata}, ${image.data.fullsrc}`;
151151
let detail_list = [escapeHtml(image.data.name), formattedMetadata.replaceAll('<br>', '&emsp;')];
152-
return { name, description, buttons, 'image': imageSrc, 'dragimage': dragImage, className: parsedMeta.is_starred ? 'image-block-starred' : '', searchable, display: name, detail_list };
152+
let aspectRatio = parsedMeta.sui_image_params?.width && parsedMeta.sui_image_params?.height ? parsedMeta.sui_image_params.width / parsedMeta.sui_image_params.height : null;
153+
return { name, description, buttons, 'image': imageSrc, 'dragimage': dragImage, className: parsedMeta.is_starred ? 'image-block-starred' : '', searchable, display: name, detail_list, aspectRatio };
153154
}
154155

155156
function selectImageInHistory(image, div) {

src/wwwroot/js/genpage/helpers/browsers.js

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ class BrowserUtil {
55
* Make any visible images within a container actually load now.
66
*/
77
makeVisible(elem) {
8-
for (let subElem of elem.querySelectorAll('.lazyload')) {
9-
let top = subElem.getBoundingClientRect().top;
10-
if (top >= window.innerHeight + 512 || top == 0) { // Note top=0 means not visible
11-
continue;
12-
}
8+
let elementsToLoad = Array.from(elem.querySelectorAll('.lazyload')).filter(e => {
9+
let top = e.getBoundingClientRect().top;
10+
return top != 0 && top < window.innerHeight + 512; // Note top=0 means not visible
11+
});
12+
for (let subElem of elementsToLoad) {
1313
subElem.classList.remove('lazyload');
1414
if (subElem.tagName == 'IMG') {
1515
if (!subElem.dataset.src) {
@@ -95,6 +95,7 @@ class GenPageBrowserClass {
9595
this.rerenderPlanned = false;
9696
this.updatePendingSince = null;
9797
this.wantsReupdate = false;
98+
this.noContentUpdates = false;
9899
this.checkIsSmall();
99100
}
100101

@@ -142,6 +143,7 @@ class GenPageBrowserClass {
142143
* Clicks repeatedly into a path to fully open it.
143144
*/
144145
clickPath(path) {
146+
this.noContentUpdates = true;
145147
let tree = this.tree;
146148
if (!tree.isOpen) {
147149
tree.clickme(() => {
@@ -150,6 +152,8 @@ class GenPageBrowserClass {
150152
return;
151153
}
152154
if (path.length == 0) {
155+
this.noContentUpdates = false;
156+
this.rerender();
153157
return;
154158
}
155159
let split = path.split('/');
@@ -158,6 +162,8 @@ class GenPageBrowserClass {
158162
continue;
159163
}
160164
if (!(part in tree.children)) {
165+
this.noContentUpdates = false;
166+
this.rerender();
161167
return;
162168
}
163169
tree = tree.children[part];
@@ -168,6 +174,8 @@ class GenPageBrowserClass {
168174
return;
169175
}
170176
}
177+
this.noContentUpdates = false;
178+
this.rerender();
171179
}
172180

173181
/**
@@ -177,6 +185,9 @@ class GenPageBrowserClass {
177185
refreshParameterValues(true, () => {
178186
this.chunksRendered = 0;
179187
let path = this.folder;
188+
this.folder = '';
189+
let depth = this.depth;
190+
this.noContentUpdates = true;
180191
this.update(true, () => {
181192
this.clickPath(path);
182193
});
@@ -326,7 +337,7 @@ class GenPageBrowserClass {
326337
span.onclick = (e) => {
327338
this.select(tree.fileData, null);
328339
};
329-
tree.clickme = (callback) => span.onclick(null);
340+
tree.clickme = (callback) => this.select(tree.fileData, callback);
330341
}
331342
else {
332343
let clicker = (isSymbol, callback) => {
@@ -431,11 +442,16 @@ class GenPageBrowserClass {
431442
if (this.format.startsWith('Big')) { factor = 15; div.classList.add('image-block-big'); }
432443
else if (this.format.startsWith('Giant')) { factor = 25; div.classList.add('image-block-giant'); }
433444
else if (this.format.startsWith('Small')) { factor = 5; div.classList.add('image-block-small'); }
434-
div.style.width = `${factor + 1}rem`;
435-
img.addEventListener('load', () => {
436-
let ratio = img.width / img.height;
437-
div.style.width = `${(ratio * factor) + 1}rem`;
438-
});
445+
if (desc.aspectRatio) {
446+
div.style.width = `${(desc.aspectRatio * factor) + 1}rem`;
447+
}
448+
else {
449+
div.style.width = `${factor + 1}rem`;
450+
img.addEventListener('load', () => {
451+
let ratio = img.width / img.height;
452+
div.style.width = `${(ratio * factor) + 1}rem`;
453+
});
454+
}
439455
let textBlock = createDiv(null, 'image-preview-text');
440456
textBlock.innerText = desc.display || desc.name;
441457
if (this.format == "Small Thumbnails" || textBlock.innerText.length > 40) {
@@ -486,7 +502,7 @@ class GenPageBrowserClass {
486502
div.appendChild(menu);
487503
}
488504
if (!this.format.includes('Cards')) {
489-
div.title = stripHtmlToText(desc.description);
505+
div.addEventListener('mouseenter', () => div.title = stripHtmlToText(desc.description), { once: true });
490506
}
491507
div.dataset.name = file.name;
492508
img.classList.add('lazyload');
@@ -717,14 +733,18 @@ class GenPageBrowserClass {
717733
this.headerCount.innerText = files.length;
718734
this.headerBar.appendChild(this.headerCount);
719735
this.buildTreeElements(this.folderTreeDiv, '', this.tree);
720-
this.buildContentList(this.contentDiv, files);
721-
this.folderTreeDiv.scrollTop = folderScroll;
722-
browserUtil.makeVisible(this.contentDiv);
723-
if (scrollOffset) {
724-
this.contentDiv.scrollTop = scrollOffset;
725-
}
726736
applyTranslations(this.headerBar);
727-
applyTranslations(this.contentDiv);
737+
if (!this.noContentUpdates) {
738+
this.buildContentList(this.contentDiv, files);
739+
browserUtil.makeVisible(this.contentDiv);
740+
if (scrollOffset) {
741+
this.contentDiv.scrollTop = scrollOffset;
742+
}
743+
applyTranslations(this.contentDiv);
744+
}
745+
if (folderScroll) {
746+
this.folderTreeDiv.scrollTop = folderScroll;
747+
}
728748
this.everLoaded = true;
729749
if (this.builtEvent) {
730750
this.builtEvent();

0 commit comments

Comments
 (0)