From 81477f0ed8e85b4834cb419fb37205a609a82d95 Mon Sep 17 00:00:00 2001 From: Spedon Date: Tue, 14 Mar 2023 23:31:20 +0800 Subject: [PATCH] add lazyload background --- assets/ts/overlay.ts | 11 ++++---- assets/ts/trackMouse.ts | 27 ++++++++++++------- assets/ts/utils.ts | 59 ++++++++++++++++++++++++++++++++--------- 3 files changed, 70 insertions(+), 27 deletions(-) diff --git a/assets/ts/overlay.ts b/assets/ts/overlay.ts index de85661..5463def 100644 --- a/assets/ts/overlay.ts +++ b/assets/ts/overlay.ts @@ -1,14 +1,14 @@ import { delay, removeAllEventListeners, - layersPosSet, + layersStyleSet, center, createImgElement, calcImageIndex, FIFO } from './utils' import { - posArray, + layersStyleArray, layers, handleOnMove, globalIndex, @@ -64,7 +64,7 @@ export function overlayDisable(): void { // handle close click async function handleCloseClick(): Promise { overlayDisable() - layersPosSet(posArray, layers) + layersStyleSet(layersStyleArray, layers, true, false) for (let i: number = 4; i >= 0; i--) { layers[i].dataset.status = `r${4 - i}` } @@ -72,20 +72,21 @@ async function handleCloseClick(): Promise { for (let i: number = 4; i >= 0; i--) { layers[i].dataset.status = 'null' } + layersStyleSet(layersStyleArray, layers, false, true) window.addEventListener('mousemove', handleOnMove) } function handlePrevClick(): void { globalIndexDec() const imgIndex = calcImageIndex(globalIndex, imagesArrayLen) - FIFO(createImgElement(imagesArray[imgIndex]), layers) + FIFO(createImgElement(imagesArray[imgIndex], false).image, layers) imgIndexSpanUpdate(imgIndex + 1, imagesArrayLen) } function handleNextClick(): void { globalIndexInc() const imgIndex = calcImageIndex(globalIndex, imagesArrayLen) - FIFO(createImgElement(imagesArray[imgIndex]), layers) + FIFO(createImgElement(imagesArray[imgIndex], false).image, layers) imgIndexSpanUpdate(imgIndex + 1, imagesArrayLen) } diff --git a/assets/ts/trackMouse.ts b/assets/ts/trackMouse.ts index 7bd8b65..097c13b 100644 --- a/assets/ts/trackMouse.ts +++ b/assets/ts/trackMouse.ts @@ -1,17 +1,19 @@ import { overlayEnable } from './overlay' import { - posCache, + styleCache, FIFO, - layersPosSet, + layersStyleSet, center, type position, createImgElement, calcImageIndex, - delay + delay, + type imgElement } from './utils' import { thresholdSensitivityArray, thresholdIndex } from './thresholdCtl' import { imgIndexSpanUpdate } from './indexDisp' import { imagesArrayLen, imagesArray } from './dataFetch' +import { preloader } from './imageCache' // get layer divs export const layers: HTMLDivElement[] = [ @@ -23,9 +25,10 @@ export const layers: HTMLDivElement[] = [ ] // layers position caching -export const posArray: string[][] = [ +export const layersStyleArray: string[][] = [ ['0px', '0px', '0px', '0px', '0px'], - ['0px', '0px', '0px', '0px', '0px'] + ['0px', '0px', '0px', '0px', '0px'], + ['', '', '', '', ''] ] // global index for "activated" @@ -36,9 +39,10 @@ let last: position = { x: 0, y: 0 } // activate top image const activate = (index: number, x: number, y: number): void => { - posCache(x, y, posArray) - layersPosSet(posArray, layers) - FIFO(createImgElement(imagesArray[index]), layers) + const imgElem: imgElement = createImgElement(imagesArray[index], true) + styleCache(x, y, imgElem.bgStyle, layersStyleArray) + layersStyleSet(layersStyleArray, layers) + FIFO(imgElem.image, layers) last = { x, y } } @@ -60,11 +64,14 @@ export const handleOnMove = (e: MouseEvent): void => { activate(imageIndex, e.clientX, e.clientY) imgIndexSpanUpdate(imageIndex + 1, imagesArrayLen) // self increment - globalIndex++ + globalIndexInc() } } async function enterOverlay(): Promise { + layers[4].style.backgroundImage = '' + const topLayerImage = layers[4].lastElementChild as HTMLImageElement + topLayerImage.style.transition = '' // stop images animation window.removeEventListener('mousemove', handleOnMove) // set top image @@ -95,8 +102,10 @@ export function trackMouseInit(): void { export function globalIndexDec(): void { globalIndex-- + preloader(globalIndex) } export function globalIndexInc(): void { globalIndex++ + preloader(globalIndex) } diff --git a/assets/ts/utils.ts b/assets/ts/utils.ts index 58008a7..befa564 100644 --- a/assets/ts/utils.ts +++ b/assets/ts/utils.ts @@ -3,6 +3,8 @@ export interface ImageData { url: string imgH: string imgW: string + pColor: string + sColor: string } export interface position { @@ -10,14 +12,26 @@ export interface position { y: number } +export interface imgElement { + image: HTMLImageElement + bgStyle: string +} + // cache a xy position to array -export const posCache = (x: number, y: number, xyArray: string[][]): void => { +export const styleCache = ( + x: number, + y: number, + bg: string, + styleArray: string[][] +): void => { // pop element if length surpass limitation - xyArray[0].shift() - xyArray[1].shift() + styleArray[0].shift() + styleArray[1].shift() + styleArray[2].shift() // push new element - xyArray[0].push(`${x}px`) - xyArray[1].push(`${y}px`) + styleArray[0].push(`${x}px`) + styleArray[1].push(`${y}px`) + styleArray[2].push(bg) } // 0 to 0001, 25 to 0025 @@ -47,13 +61,18 @@ export const FIFO = ( } // set position for 5 image display layers -export const layersPosSet = ( - xyArray: string[][], - layersArray: HTMLDivElement[] +export const layersStyleSet = ( + styleArray: string[][], + layersArray: HTMLDivElement[], + posOut: boolean = true, + styleOut: boolean = true ): void => { function posSet(layer: HTMLDivElement, index: number): void { - layer.style.left = xyArray[0][index] - layer.style.top = xyArray[1][index] + if (posOut) { + layer.style.left = styleArray[0][index] + layer.style.top = styleArray[1][index] + } + if (styleOut) layer.style.backgroundImage = styleArray[2][index] } for (let i = 4; i >= 0; i--) { posSet(layersArray[i], i) @@ -80,13 +99,22 @@ export const center = (e: HTMLDivElement): void => { } } -export function createImgElement(input: ImageData): HTMLImageElement { +export function createImgElement(input: ImageData, returnBgStyle: boolean): imgElement { const img = document.createElement('img') img.setAttribute('src', input.url) - img.setAttribute('alt', input.index) + img.setAttribute('alt', '') img.setAttribute('height', input.imgH) img.setAttribute('width', input.imgW) - return img + img.setAttribute('loading', 'eager') + img.style.opacity = '0' + img.onload = async () => { + img.style.opacity = '1' + img.style.transition = 'opacity 0.5s ease-in' + await delay(500) + img.style.transition = '' + } + const style: string = `linear-gradient(15deg, ${input.pColor}, ${input.sColor})` + return returnBgStyle ? { image: img, bgStyle: style } : { image: img, bgStyle: '' } } export function calcImageIndex(index: number, imgCounts: number): number { @@ -96,3 +124,8 @@ export function calcImageIndex(index: number, imgCounts: number): number { return (imgCounts + (index % imgCounts)) % imgCounts } } + +export function preloadImage(src: string): void { + const cache = new Image() + cache.src = src +}