diff --git a/src/components/Lightbox.vue b/src/components/Lightbox.vue index 306edec..51ff847 100644 --- a/src/components/Lightbox.vue +++ b/src/components/Lightbox.vue @@ -38,6 +38,7 @@ export default { gMouseDownOffsetX: 0, gMouseDownOffsetY: 0, resizeTimer: null, + mediaLoadId: 0, containerPadding: null, imageBorderWidth: null, videoBorderWidth: null, @@ -93,7 +94,6 @@ export default { }, methods: { open(album, startId, source) { - this.sizeOverlay(); this.album = album.map((options) => this.mapMedia(options, source)); const startIndex = Math.max(this.album.findIndex((media) => media.id == startId), 0); @@ -106,6 +106,7 @@ export default { this.changeImage(startIndex); }, end(dispose = false) { + this.mediaLoadId++; //Drop any pending image/video load this.disableKeyboardNav(); this.$refs.video?.pause(); this.$refs.video?.removeAttribute('src'); @@ -242,6 +243,7 @@ export default { changeImage(index) { const media = this.album[index]; if(!media) return; + const loadId = ++this.mediaLoadId; this.updateDetails(media, false); this.hideElements([this.$refs.dataContainer]); @@ -260,6 +262,7 @@ export default { this.$refs.image.removeAttribute('src'); this.$refs.container.classList.add('lb-video-nav'); this.$refs.video.onloadedmetadata = () => { + if(loadId !== this.mediaLoadId) return; media.width = this.$refs.video.videoWidth; media.height = this.$refs.video.videoHeight; this.$refs.video.onloadedmetadata = null; @@ -269,10 +272,15 @@ export default { } else { this.$refs.video.pause(); this.$refs.video.removeAttribute('src'); - this.$refs.image.onload = () => { - this.$refs.image.alt = media.alt; - let width = this.$refs.image.naturalWidth; - let height = this.$refs.image.naturalHeight; + //Load & decode in a detached image, so that neither the placeholder nor the previous picture can be measured or painted + const loader = new Image(); + loader.src = media.link; + loader.decode().then(() => { + //A previous request may still resolve after a new one started: only the latest one counts + if(loadId !== this.mediaLoadId) return; + + let width = loader.naturalWidth; + let height = loader.naturalHeight; if(Math.abs(media.orientation) === 90 && width > height) { const tmp = width; width = height; @@ -280,10 +288,12 @@ export default { } media.width = width; media.height = height; - this.$refs.image.onload = null; + this.$refs.image.alt = media.alt; + this.$refs.image.src = media.link; this.updateSize(index); - }; - this.$refs.image.src = media.link; + }).catch((error) => { + if(loadId === this.mediaLoadId) console.error('Lightbox: unable to load image', media.link, error); + }); } }, sizeOverlay() {