mirror of
https://github.com/Sped0n/bridget.git
synced 2026-04-14 10:09:31 -07:00
initial version of transition toward image elements
This commit is contained in:
@@ -97,4 +97,52 @@
|
||||
&#layer1 {
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
|
||||
.images {
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: contain;
|
||||
max-height: 55vmin;
|
||||
max-width: 100vw;
|
||||
|
||||
&[data-status='null'] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&[data-status='top'] {
|
||||
opacity: 1;
|
||||
max-height: calc(100vh - var(--footer-height));;
|
||||
transition-property: transform, max-height;
|
||||
transition-timing-function: ease-in-out;
|
||||
transition-duration: 0.5s, 0.5s;
|
||||
}
|
||||
|
||||
&[data-status='trail'] {
|
||||
opacity: 0;
|
||||
margin-top: 40px;
|
||||
transition-property: opacity, margin-top;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
&[data-status='resumeTop'] {
|
||||
opacity: 1;
|
||||
max-height: 55vmin;
|
||||
transition-property: max-height, transform;
|
||||
transition-timing-function: ease-in-out;
|
||||
transition-duration: 0.7s, 0.5s;
|
||||
}
|
||||
|
||||
&[data-status='resume'] {
|
||||
opacity: 1;
|
||||
margin-top: 0;
|
||||
transition-property: opacity, margin-top;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,9 @@
|
||||
import { overlayEnable } from './overlay'
|
||||
import {
|
||||
calcImageIndex,
|
||||
center,
|
||||
createImgElement,
|
||||
delay,
|
||||
FIFO,
|
||||
layerPosSet,
|
||||
type position
|
||||
} from './utils'
|
||||
import { calcImageIndex, center, delay, mouseToTransform, type position } from './utils'
|
||||
import { thresholdIndex, thresholdSensitivityArray } from './thresholdCtl'
|
||||
import { imgIndexSpanUpdate } from './indexDisp'
|
||||
import { imagesArray, imagesArrayLen } from './dataFetch'
|
||||
import { layers } from './elemGen'
|
||||
|
||||
// top layer position caching
|
||||
let topLayerPos: number[] = [0, 0]
|
||||
|
||||
// set top layer position
|
||||
export const topLayerPosSet = (): void => {
|
||||
layerPosSet(topLayerPos[0], topLayerPos[1], layers[0])
|
||||
}
|
||||
import { imagesArrayLen } from './dataFetch'
|
||||
import { imagesDivNodes as images } from './elemGen'
|
||||
|
||||
// global index for "activated"
|
||||
export let globalIndex: number = 0
|
||||
@@ -27,13 +11,79 @@ export let globalIndex: number = 0
|
||||
// last position set as "activated"
|
||||
let last: position = { x: 0, y: 0 }
|
||||
|
||||
export let trailingImageIndexes: number[] = []
|
||||
|
||||
export let transformCache: string[] = []
|
||||
|
||||
let EnterOverlayClickAbCtl = new AbortController()
|
||||
|
||||
export const stackDepth: number = 5
|
||||
|
||||
export const pushIndex = (
|
||||
index: number,
|
||||
invert: boolean = false,
|
||||
autoHide: boolean = true
|
||||
): number => {
|
||||
let indexesNum: number = trailingImageIndexes.length
|
||||
let overflow: number
|
||||
if (!invert) {
|
||||
// push the tail index out and hide the image
|
||||
if (indexesNum === stackDepth) {
|
||||
trailingImageIndexes.push(index)
|
||||
overflow = trailingImageIndexes.shift() as number
|
||||
if (autoHide) {
|
||||
images[overflow].style.display = 'none'
|
||||
images[overflow].dataset.status = 'trail'
|
||||
}
|
||||
} else {
|
||||
trailingImageIndexes.push(index)
|
||||
indexesNum += 1
|
||||
}
|
||||
} else {
|
||||
if (indexesNum === stackDepth) {
|
||||
trailingImageIndexes.unshift(
|
||||
calcImageIndex(index - stackDepth + 1, imagesArrayLen)
|
||||
)
|
||||
overflow = trailingImageIndexes.pop() as number
|
||||
if (autoHide) {
|
||||
images[overflow].style.display = 'none'
|
||||
images[overflow].dataset.status = 'trail'
|
||||
}
|
||||
} else {
|
||||
trailingImageIndexes.unshift(
|
||||
calcImageIndex(index - indexesNum + 1, imagesArrayLen)
|
||||
)
|
||||
indexesNum += 1
|
||||
}
|
||||
}
|
||||
return indexesNum
|
||||
}
|
||||
|
||||
// activate top image
|
||||
const activate = (index: number, x: number, y: number): void => {
|
||||
const imgElem: HTMLImageElement = createImgElement(imagesArray[index])
|
||||
topLayerPos = [x, y]
|
||||
FIFO(imgElem, layers, true)
|
||||
topLayerPosSet()
|
||||
last = { x, y }
|
||||
const activate = (index: number, mouseX: number, mouseY: number): void => {
|
||||
EnterOverlayClickAbCtl.abort()
|
||||
EnterOverlayClickAbCtl = new AbortController()
|
||||
const indexesNum: number = pushIndex(index)
|
||||
// set img position
|
||||
images[index].style.transform = mouseToTransform(mouseX, mouseY, true, true)
|
||||
images[index].dataset.status = 'null'
|
||||
// reset z index
|
||||
for (let i = 0; i < indexesNum; i++) {
|
||||
images[trailingImageIndexes[i]].style.zIndex = `${i}`
|
||||
}
|
||||
images[index].style.display = 'block'
|
||||
images[index].addEventListener(
|
||||
'click',
|
||||
() => {
|
||||
void enterOverlay()
|
||||
},
|
||||
{
|
||||
passive: true,
|
||||
once: true,
|
||||
signal: EnterOverlayClickAbCtl.signal
|
||||
}
|
||||
)
|
||||
last = { x: mouseX, y: mouseY }
|
||||
}
|
||||
|
||||
// Compare the current mouse position with the last activated position
|
||||
@@ -61,10 +111,18 @@ export const handleOnMove = (e: MouseEvent): void => {
|
||||
async function enterOverlay(): Promise<void> {
|
||||
// stop images animation
|
||||
window.removeEventListener('mousemove', handleOnMove)
|
||||
// set top image
|
||||
center(layers[0])
|
||||
for (let i = 0; i <= 4; i++) {
|
||||
layers[i].dataset.status = `t${i}`
|
||||
const indexesNum: number = trailingImageIndexes.length
|
||||
for (let i = 0; i < indexesNum; i++) {
|
||||
const e: HTMLImageElement = images[trailingImageIndexes[i]]
|
||||
transformCache.push(e.style.transform)
|
||||
if (i === indexesNum - 1) {
|
||||
e.style.transitionDelay = `${0.1 * i + 0.2}s, ${0.1 * i + 0.2 + 0.5}s`
|
||||
e.dataset.status = 'top'
|
||||
center(e)
|
||||
} else {
|
||||
e.dataset.status = 'trail'
|
||||
e.style.transitionDelay = `${0.1 * i}s`
|
||||
}
|
||||
}
|
||||
await delay(1600)
|
||||
// Offset previous self increment of global index (by handleOnMove)
|
||||
@@ -76,15 +134,6 @@ async function enterOverlay(): Promise<void> {
|
||||
// initialization
|
||||
export const trackMouseInit = (): void => {
|
||||
window.addEventListener('mousemove', handleOnMove)
|
||||
layers[0].addEventListener(
|
||||
'click',
|
||||
() => {
|
||||
void enterOverlay()
|
||||
},
|
||||
{
|
||||
passive: true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const globalIndexDec = (): void => {
|
||||
@@ -94,3 +143,11 @@ export const globalIndexDec = (): void => {
|
||||
export const globalIndexInc = (): void => {
|
||||
globalIndex++
|
||||
}
|
||||
|
||||
export const emptyTransformCache = (): void => {
|
||||
transformCache = []
|
||||
}
|
||||
|
||||
export const emptyTrailingImageIndexes = (): void => {
|
||||
trailingImageIndexes = []
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { imagesArray, imagesArrayLen } from './dataFetch'
|
||||
import { createImgElement } from './utils'
|
||||
|
||||
// get components of overlay
|
||||
export let overlayCursor: HTMLDivElement
|
||||
export let cursorInnerContent: HTMLDivElement
|
||||
export let layers: HTMLDivElement[]
|
||||
export let imagesDivNodes: NodeListOf<HTMLImageElement>
|
||||
|
||||
const passDesktopElements = (): void => {
|
||||
overlayCursor = document
|
||||
@@ -10,21 +13,8 @@ const passDesktopElements = (): void => {
|
||||
cursorInnerContent = document
|
||||
.getElementsByClassName('cursor_innerText')
|
||||
.item(0) as HTMLDivElement
|
||||
layers = [
|
||||
document.getElementById('layer1') as HTMLDivElement,
|
||||
document.getElementById('layer2') as HTMLDivElement,
|
||||
document.getElementById('layer3') as HTMLDivElement,
|
||||
document.getElementById('layer4') as HTMLDivElement,
|
||||
document.getElementById('layer5') as HTMLDivElement
|
||||
]
|
||||
}
|
||||
|
||||
const createLayerDiv = (layerID: number): HTMLDivElement => {
|
||||
const layerDiv: HTMLDivElement = document.createElement('div')
|
||||
layerDiv.className = 'image_container'
|
||||
layerDiv.id = `layer${layerID}`
|
||||
layerDiv.dataset.status = 'null'
|
||||
return layerDiv
|
||||
imagesDivNodes = document.getElementsByClassName('images')[0]
|
||||
.childNodes as NodeListOf<HTMLImageElement>
|
||||
}
|
||||
|
||||
const createCursorDiv = (): HTMLDivElement => {
|
||||
@@ -39,11 +29,11 @@ const createCursorDiv = (): HTMLDivElement => {
|
||||
export const createDesktopElements = (): void => {
|
||||
const mainDiv = document.getElementById('main') as HTMLDivElement
|
||||
mainDiv.appendChild(createCursorDiv())
|
||||
const desktopWrapper: HTMLDivElement = document.createElement('div')
|
||||
desktopWrapper.className = 'desktopWrapper'
|
||||
for (let i = 0; i < 15; i++) {
|
||||
desktopWrapper.appendChild(createLayerDiv(i))
|
||||
const imagesDiv: HTMLDivElement = document.createElement('div')
|
||||
imagesDiv.className = 'images'
|
||||
for (let i = 0; i < imagesArrayLen; i++) {
|
||||
imagesDiv.appendChild(createImgElement(imagesArray[i]))
|
||||
}
|
||||
mainDiv.appendChild(desktopWrapper)
|
||||
mainDiv.appendChild(imagesDiv)
|
||||
passDesktopElements()
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import {
|
||||
delay,
|
||||
center,
|
||||
createImgElement,
|
||||
calcImageIndex,
|
||||
FIFO,
|
||||
mouseToTransform
|
||||
} from './utils'
|
||||
import { delay, center, calcImageIndex, mouseToTransform } from './utils'
|
||||
import {
|
||||
handleOnMove,
|
||||
globalIndex,
|
||||
globalIndexDec,
|
||||
globalIndexInc,
|
||||
topLayerPosSet
|
||||
trailingImageIndexes,
|
||||
transformCache,
|
||||
pushIndex,
|
||||
emptyTransformCache,
|
||||
emptyTrailingImageIndexes
|
||||
} from './desktop'
|
||||
import { imagesArray, imagesArrayLen } from './dataFetch'
|
||||
import { imagesArrayLen } from './dataFetch'
|
||||
import { imgIndexSpanUpdate } from './indexDisp'
|
||||
import { overlayCursor, cursorInnerContent, layers } from './elemGen'
|
||||
import { overlayCursor, cursorInnerContent, imagesDivNodes as images } from './elemGen'
|
||||
|
||||
let oneThird: number = Math.round(window.innerWidth / 3)
|
||||
|
||||
// set cursor text
|
||||
const setCursorText = (text: string): void => {
|
||||
@@ -35,7 +34,7 @@ const disableListener = (): void => {
|
||||
|
||||
// enable overlay
|
||||
export const overlayEnable = (): void => {
|
||||
overlayCursor.style.zIndex = '7'
|
||||
overlayCursor.style.zIndex = '100'
|
||||
setListener()
|
||||
}
|
||||
|
||||
@@ -44,41 +43,62 @@ export const overlayDisable = (): void => {
|
||||
overlayCursor.style.zIndex = '-1'
|
||||
setCursorText('')
|
||||
disableListener()
|
||||
// Add back previous self increment of global index (by handleOnMove)
|
||||
globalIndexInc()
|
||||
}
|
||||
|
||||
// handle close click
|
||||
async function handleCloseClick(): Promise<void> {
|
||||
overlayDisable()
|
||||
topLayerPosSet()
|
||||
for (let i: number = 0; i <= 4; i++) {
|
||||
layers[i].dataset.status = `r${i}`
|
||||
const indexesNum = trailingImageIndexes.length
|
||||
emptyTrailingImageIndexes()
|
||||
for (let i: number = 0; i < indexesNum; i++) {
|
||||
const e: HTMLImageElement = images[calcImageIndex(globalIndex - i, imagesArrayLen)]
|
||||
trailingImageIndexes.unshift(calcImageIndex(globalIndex - i, imagesArrayLen))
|
||||
if (i === 0) {
|
||||
e.style.transitionDelay = '0s, 0.7s'
|
||||
} else {
|
||||
e.style.transitionDelay = `${1.2 + 0.1 * i - 0.1}s`
|
||||
e.style.display = 'block'
|
||||
}
|
||||
e.style.transform = transformCache[indexesNum - i - 1]
|
||||
e.style.zIndex = `${indexesNum - i - 1}`
|
||||
e.dataset.status = i === 0 ? 'resumeTop' : 'resume'
|
||||
}
|
||||
await delay(1700)
|
||||
for (let i: number = 0; i <= 4; i++) {
|
||||
layers[i].dataset.status = 'null'
|
||||
for (let i: number = 0; i < indexesNum; i++) {
|
||||
images[calcImageIndex(globalIndex - i, imagesArrayLen)].dataset.status = 'null'
|
||||
}
|
||||
// Add back previous self increment of global index (by handleOnMove)
|
||||
globalIndexInc()
|
||||
window.addEventListener('mousemove', handleOnMove, { passive: true })
|
||||
emptyTransformCache()
|
||||
}
|
||||
|
||||
const handlePrevClick = (): void => {
|
||||
const imgIndex: number = calcImageIndex(globalIndex, imagesArrayLen)
|
||||
globalIndexDec()
|
||||
const imgIndex = calcImageIndex(globalIndex, imagesArrayLen)
|
||||
FIFO(createImgElement(imagesArray[imgIndex]), layers, false)
|
||||
imgIndexSpanUpdate(imgIndex + 1, imagesArrayLen)
|
||||
const prevImgIndex = calcImageIndex(globalIndex, imagesArrayLen)
|
||||
pushIndex(prevImgIndex, true, false)
|
||||
images[imgIndex].style.display = 'none'
|
||||
center(images[prevImgIndex])
|
||||
images[prevImgIndex].dataset.status = 'top'
|
||||
images[prevImgIndex].style.display = 'block'
|
||||
imgIndexSpanUpdate(prevImgIndex + 1, imagesArrayLen)
|
||||
}
|
||||
|
||||
const handleNextClick = (): void => {
|
||||
const imgIndex: number = calcImageIndex(globalIndex, imagesArrayLen)
|
||||
globalIndexInc()
|
||||
const imgIndex = calcImageIndex(globalIndex, imagesArrayLen)
|
||||
FIFO(createImgElement(imagesArray[imgIndex]), layers, false)
|
||||
imgIndexSpanUpdate(imgIndex + 1, imagesArrayLen)
|
||||
const nextImgIndex = calcImageIndex(globalIndex, imagesArrayLen)
|
||||
pushIndex(nextImgIndex, false, false)
|
||||
images[imgIndex].style.display = 'none'
|
||||
center(images[nextImgIndex])
|
||||
images[nextImgIndex].dataset.status = 'top'
|
||||
images[nextImgIndex].style.display = 'block'
|
||||
imgIndexSpanUpdate(nextImgIndex + 1, imagesArrayLen)
|
||||
}
|
||||
|
||||
const handleOverlayMouseMove = (e: MouseEvent): void => {
|
||||
setTextPos(e)
|
||||
const oneThird: number = Math.round(window.innerWidth / 3)
|
||||
if (e.clientX < oneThird) {
|
||||
setCursorText('PREV')
|
||||
overlayCursor.dataset.status = 'PREV'
|
||||
@@ -114,6 +134,7 @@ export const vwRefreshInit = (): void => {
|
||||
window.addEventListener(
|
||||
'resize',
|
||||
() => {
|
||||
oneThird = Math.round(window.innerWidth / 3)
|
||||
// reset footer height
|
||||
const r = document.querySelector(':root') as HTMLStyleElement
|
||||
if (window.innerWidth > 768) {
|
||||
@@ -122,7 +143,8 @@ export const vwRefreshInit = (): void => {
|
||||
r.style.setProperty('--footer-height', '31px')
|
||||
}
|
||||
// recenter image (only in overlay)
|
||||
if (layers[0].dataset.status === 't0') center(layers[0])
|
||||
const i: HTMLImageElement = images[calcImageIndex(globalIndex, imagesArrayLen)]
|
||||
if (i.dataset.status === 'top') center(i)
|
||||
},
|
||||
{ passive: true }
|
||||
)
|
||||
|
||||
@@ -23,29 +23,6 @@ export const duper = (num: number): string => {
|
||||
return ('0000' + num.toString()).slice(-4)
|
||||
}
|
||||
|
||||
// FIFO data array for image display
|
||||
export const FIFO = (
|
||||
element: HTMLImageElement,
|
||||
layersArray: HTMLDivElement[],
|
||||
passPosition: boolean = true
|
||||
): void => {
|
||||
function layerProcess(layerL: HTMLDivElement, layerH: HTMLDivElement): void {
|
||||
if (layerL.childElementCount !== 0)
|
||||
layerL.removeChild(layerL.lastElementChild as HTMLImageElement)
|
||||
if (layerH.childElementCount !== 0) {
|
||||
const layerHNode = layerH.lastElementChild as HTMLImageElement
|
||||
layerL.appendChild(layerHNode.cloneNode(true))
|
||||
if (passPosition) layerL.style.transform = layerH.style.transform
|
||||
}
|
||||
}
|
||||
for (let i: number = 4; i >= 1; i--) {
|
||||
layerProcess(layersArray[i], layersArray[i - 1])
|
||||
}
|
||||
if (layersArray[0].childElementCount !== 0)
|
||||
layersArray[0].removeChild(layersArray[0].lastElementChild as HTMLImageElement)
|
||||
layersArray[0].appendChild(element)
|
||||
}
|
||||
|
||||
export const mouseToTransform = (
|
||||
x: number,
|
||||
y: number,
|
||||
@@ -57,11 +34,6 @@ export const mouseToTransform = (
|
||||
}, ${centerCorrection ? `calc(${y}px - 50%)` : `${y}px`}${accelerate ? ', 0' : ''})`
|
||||
}
|
||||
|
||||
// set position for layer
|
||||
export const layerPosSet = (x: number, y: number, layer: HTMLDivElement): void => {
|
||||
layer.style.transform = mouseToTransform(x, y)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
||||
export function delay(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
@@ -73,7 +45,7 @@ export const removeAllEventListeners = (e: Node): Node => {
|
||||
}
|
||||
|
||||
// center top div
|
||||
export const center = (e: HTMLDivElement): void => {
|
||||
export const center = (e: HTMLElement): void => {
|
||||
const x: number = window.innerWidth / 2
|
||||
let y: number
|
||||
if (window.innerWidth > 768) {
|
||||
@@ -90,7 +62,9 @@ export const createImgElement = (input: ImageData): HTMLImageElement => {
|
||||
img.setAttribute('alt', '')
|
||||
img.setAttribute('height', input.imgH)
|
||||
img.setAttribute('width', input.imgW)
|
||||
img.style.backgroundImage = `linear-gradient(15deg, ${input.pColor}, ${input.sColor})`
|
||||
img.style.display = 'none'
|
||||
img.dataset.status = 'trail'
|
||||
// img.style.backgroundImage = `linear-gradient(15deg, ${input.pColor}, ${input.sColor})`
|
||||
return img
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user