Implement lazy image loading (copied from freefall reader)

This commit is contained in:
Saphire committed 2022-02-21 16:36:27 +07:00
1 parent 10ab7fa470
commit fc8bf49ad9
7 files changed
+123 -5

No files matched your search

+4 -2
View File
@@ -115,17 +115,19 @@ a:visited {
}
.post-image {
margin: 0;
margin: 0 0 1rem;
align-self: center;
/* Note: make sure to check this does not break main.ts if changed! */
max-width: 95%;
}
.post-image img {
max-width: 100%;
display: block;
}
.post-text {
padding: 16px 40px;
padding: 0 40px 16px;
}
+65 -1
View File
@@ -1,5 +1,9 @@
class VisitAnalytics {
landmarksObserver: IntersectionObserver;
lazyloadObserver: IntersectionObserver;
lastWidth: number = 0;
resizeTimeout: number | null = null;
images: HTMLImageElement[] = [];
constructor() {
window.plausible = window.plausible || function () { (window.plausible.q = window.plausible.q || []).push(arguments); };
@@ -20,6 +24,14 @@ class VisitAnalytics {
threshold: 1.0
}
);
this.lazyloadObserver = new IntersectionObserver(
(entries, observer) => this.handleLazyload(entries, observer),
{
root: null,
rootMargin: "75% 0px 75% 0px",
threshold: 0.1
}
);
{
var all = document.querySelectorAll(".chapter-announce");
@@ -27,7 +39,18 @@ class VisitAnalytics {
this.landmarksObserver.observe(document.querySelector("footer"));
}
console.log("Intersection observer ready");
{
var all = document.querySelectorAll(".image-post");
all.forEach(elem => {
this.lazyloadObserver.observe(elem);
this.images.push(elem.querySelector(".post-image > img"));
});
this.resizeTimeout = setTimeout(() => this.resizeDebounced(), 200);
window.addEventListener("resize", (event) => this.handleResize(event));
}
console.log("Event handlers and observers ready");
}
handleLandmarks(entries: IntersectionObserverEntry[], observer: IntersectionObserver) {
@@ -42,5 +65,46 @@ class VisitAnalytics {
}
);
}
resizeDebounced() {
clearTimeout(this.resizeTimeout);
this.resizeTimeout = null;
const elem = document.querySelector(".post-content");
// Note: depends on main.css
const elemWidth = Math.floor(elem.clientWidth * 0.95);
if (elemWidth != this.lastWidth) {
this.lastWidth = elemWidth;
this.images.forEach(img => {
const naturalHeight = +img.getAttribute("data-height");
const naturalWidth = +img.getAttribute("data-width");
img.height = Math.floor(naturalHeight * Math.min(1, elemWidth / naturalWidth));
})
}
}
handleResize(event) {
if (event && event.type == "resize") {
if (this.resizeTimeout != null)
clearTimeout(this.resizeTimeout);
this.resizeTimeout = setTimeout(() => this.resizeDebounced(), 200);
}
}
handleLazyload(entries: IntersectionObserverEntry[], observer: IntersectionObserver) {
entries.filter(e => e.isIntersecting).forEach(e => {
const imgElem = e.target.querySelector<HTMLImageElement>(`img`);
imgElem.addEventListener("load", () => {
imgElem.classList.add("loaded");
});
imgElem.src = imgElem.getAttribute("data-src");
observer.unobserve(e.target);
console.log(`Lazyloaded ${ e.target.id ? e.target.id : e.target.tagName }`);
}
);
}
}
new VisitAnalytics();