Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: Give animation variables more descriptive names and round rendered position #1057

Merged
merged 1 commit into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Implement #1056.
  • Loading branch information
davidjerleke committed Nov 9, 2024
commit 9ce102378946d6a9d99902e68f45672f6f9a9e4d
10 changes: 5 additions & 5 deletions packages/embla-carousel/src/__tests__/loop-ltr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('➡️ Loop - Horizontal LTR', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(0.09000000000000001px,0px,0px)'
'translate3d(0.09px,0px,0px)'
)
})
})
Expand Down Expand Up @@ -274,7 +274,7 @@ describe('➡️ Loop - Horizontal LTR', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(-1209.8899999999999px,0px,0px)'
'translate3d(-1209.89px,0px,0px)'
)
})

Expand All @@ -285,7 +285,7 @@ describe('➡️ Loop - Horizontal LTR', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(450.09000000000003px,0px,0px)'
'translate3d(450.09px,0px,0px)'
)
})
})
Expand Down Expand Up @@ -940,7 +940,7 @@ describe('➡️ Loop - Horizontal LTR', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(-1419.8899999999999px,0px,0px)'
'translate3d(-1419.89px,0px,0px)'
)
})

Expand All @@ -951,7 +951,7 @@ describe('➡️ Loop - Horizontal LTR', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(440.09000000000003px,0px,0px)'
'translate3d(440.09px,0px,0px)'
)
})
})
Expand Down
10 changes: 5 additions & 5 deletions packages/embla-carousel/src/__tests__/loop-rtl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('➡️ Loop - Horizontal RTL', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(-0.09000000000000001px,0px,0px)'
'translate3d(-0.09px,0px,0px)'
)
})
})
Expand Down Expand Up @@ -267,7 +267,7 @@ describe('➡️ Loop - Horizontal RTL', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(1209.8899999999999px,0px,0px)'
'translate3d(1209.89px,0px,0px)'
)
})

Expand All @@ -278,7 +278,7 @@ describe('➡️ Loop - Horizontal RTL', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(-450.09000000000003px,0px,0px)'
'translate3d(-450.09px,0px,0px)'
)
})
})
Expand Down Expand Up @@ -939,7 +939,7 @@ describe('➡️ Loop - Horizontal RTL', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(1419.8899999999999px,0px,0px)'
'translate3d(1419.89px,0px,0px)'
)
})

Expand All @@ -950,7 +950,7 @@ describe('➡️ Loop - Horizontal RTL', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(-440.09000000000003px,0px,0px)'
'translate3d(-440.09px,0px,0px)'
)
})
})
Expand Down
10 changes: 5 additions & 5 deletions packages/embla-carousel/src/__tests__/loop-vertical.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('➡️ Loop - Vertical', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(0px,0.09000000000000001px,0px)'
'translate3d(0px,0.09px,0px)'
)
})
})
Expand Down Expand Up @@ -267,7 +267,7 @@ describe('➡️ Loop - Vertical', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(0px,-1209.8899999999999px,0px)'
'translate3d(0px,-1209.89px,0px)'
)
})

Expand All @@ -278,7 +278,7 @@ describe('➡️ Loop - Vertical', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(0px,450.09000000000003px,0px)'
'translate3d(0px,450.09px,0px)'
)
})
})
Expand Down Expand Up @@ -939,7 +939,7 @@ describe('➡️ Loop - Vertical', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(0px,-1419.8899999999999px,0px)'
'translate3d(0px,-1419.89px,0px)'
)
})

Expand All @@ -950,7 +950,7 @@ describe('➡️ Loop - Vertical', () => {
)

expect(emblaApi.containerNode().style.transform).toBe(
'translate3d(0px,440.09000000000003px,0px)'
'translate3d(0px,440.09px,0px)'
)
})
})
Expand Down
69 changes: 41 additions & 28 deletions packages/embla-carousel/src/components/Animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { EngineType } from './Engine'
import { EventStore } from './EventStore'
import { WindowType } from './utils'

export type AnimationsUpdateType = (
engine: EngineType,
timeStep: number
) => void
export type AnimationsUpdateType = (engine: EngineType) => void
export type AnimationsRenderType = (
engine: EngineType,
lagOffset: number
Expand All @@ -23,14 +20,14 @@ export type AnimationsType = {
export function Animations(
ownerDocument: Document,
ownerWindow: WindowType,
update: (timeStep: number) => void,
update: () => void,
render: (lagOffset: number) => void
): AnimationsType {
const documentVisibleHandler = EventStore()
const timeStep = 1000 / 60
const fixedTimeStep = 1000 / 60
let lastTimeStamp: number | null = null
let lag = 0
let animationFrame = 0
let accumulatedTime = 0
let animationId = 0

function init(): void {
documentVisibleHandler.add(ownerDocument, 'visibilitychange', () => {
Expand All @@ -43,49 +40,65 @@ export function Animations(
documentVisibleHandler.clear()
}

function animate(timeStamp: DOMHighResTimeStamp): void {
if (!animationFrame) return
if (!lastTimeStamp) lastTimeStamp = timeStamp
function shouldUpdate(): boolean {
return accumulatedTime >= fixedTimeStep
}

const elapsed = timeStamp - lastTimeStamp
lastTimeStamp = timeStamp
lag += elapsed
function updateAndRemoveAccumulatedTime(): void {
update()
accumulatedTime -= fixedTimeStep
if (shouldUpdate()) updateAndRemoveAccumulatedTime()
}

function renderWithAlpha(): void {
const alpha = accumulatedTime / fixedTimeStep
render(alpha)
}

function animate(timeStamp: DOMHighResTimeStamp): void {
if (!animationId) return

while (lag >= timeStep) {
update(timeStep)
lag -= timeStep
if (!lastTimeStamp) {
lastTimeStamp = timeStamp
update()
renderWithAlpha()
}

const lagOffset = lag / timeStep
render(lagOffset)
const timeElapsed = timeStamp - lastTimeStamp
lastTimeStamp = timeStamp
accumulatedTime += timeElapsed

if (animationFrame) ownerWindow.requestAnimationFrame(animate)
if (shouldUpdate()) updateAndRemoveAccumulatedTime()
renderWithAlpha()

if (animationId) {
animationId = ownerWindow.requestAnimationFrame(animate)
}
}

function start(): void {
if (animationFrame) return

animationFrame = ownerWindow.requestAnimationFrame(animate)
if (animationId) return
animationId = ownerWindow.requestAnimationFrame(animate)
}

function stop(): void {
ownerWindow.cancelAnimationFrame(animationFrame)
ownerWindow.cancelAnimationFrame(animationId)
lastTimeStamp = null
lag = 0
animationFrame = 0
accumulatedTime = 0
animationId = 0
}

function reset(): void {
lastTimeStamp = null
lag = 0
accumulatedTime = 0
}

const self: AnimationsType = {
init,
destroy,
start,
stop,
update: () => update(timeStep),
update,
render
}
return self
Expand Down
22 changes: 13 additions & 9 deletions packages/embla-carousel/src/components/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,14 @@ export function Engine(
const slideIndexes = arrayKeys(slides)

// Animation
const update: AnimationsUpdateType = (
{ dragHandler, scrollBody, scrollBounds, options: { loop } },
timeStep
) => {
const update: AnimationsUpdateType = ({
dragHandler,
scrollBody,
scrollBounds,
options: { loop }
}) => {
if (!loop) scrollBounds.constrain(dragHandler.pointerDown())
scrollBody.seek(timeStep)
scrollBody.seek()
}

const render: AnimationsRenderType = (
Expand All @@ -171,6 +173,7 @@ export function Engine(
translate,
location,
offsetLocation,
previousLocation,
scrollLooper,
slideLooper,
dragHandler,
Expand All @@ -179,7 +182,7 @@ export function Engine(
scrollBounds,
options: { loop }
},
lagOffset
alpha
) => {
const shouldSettle = scrollBody.settled()
const withinBounds = !scrollBounds.shouldConstrain()
Expand All @@ -192,7 +195,7 @@ export function Engine(
if (!hasSettled) eventHandler.emit('scroll')

const interpolatedLocation =
location.get() * lagOffset + previousLocation.get() * (1 - lagOffset)
location.get() * alpha + previousLocation.get() * (1 - alpha)

offsetLocation.set(interpolatedLocation)

Expand All @@ -203,11 +206,12 @@ export function Engine(

translate.to(offsetLocation.get())
}

const animation = Animations(
ownerDocument,
ownerWindow,
(timeStep) => update(engine, timeStep),
(lagOffset: number) => render(engine, lagOffset)
() => update(engine),
(alpha: number) => render(engine, alpha)
)

// Shared
Expand Down
30 changes: 14 additions & 16 deletions packages/embla-carousel/src/components/ScrollBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export type ScrollBodyType = {
direction: () => number
duration: () => number
velocity: () => number
seek: (timeStep: number) => ScrollBodyType
seek: () => ScrollBodyType
settled: () => boolean
useBaseFriction: () => ScrollBodyType
useBaseDuration: () => ScrollBodyType
Expand All @@ -21,38 +21,36 @@ export function ScrollBody(
baseDuration: number,
baseFriction: number
): ScrollBodyType {
let bodyVelocity = 0
let scrollVelocity = 0
let scrollDirection = 0
let scrollDuration = baseDuration
let scrollFriction = baseFriction
let rawLocation = location.get()
let rawLocationPrevious = 0

function seek(timeStep: number): ScrollBodyType {
const fixedDeltaTimeSeconds = timeStep / 1000
const duration = scrollDuration * fixedDeltaTimeSeconds
const diff = target.get() - location.get()
function seek(): ScrollBodyType {
const displacement = target.get() - location.get()
const isInstant = !scrollDuration
let directionDiff = 0
let scrollDistance = 0

if (isInstant) {
bodyVelocity = 0
scrollVelocity = 0
previousLocation.set(target)
location.set(target)

directionDiff = diff
scrollDistance = displacement
} else {
previousLocation.set(location)

bodyVelocity += diff / duration
bodyVelocity *= scrollFriction
rawLocation += bodyVelocity
location.add(bodyVelocity * fixedDeltaTimeSeconds)
scrollVelocity += displacement / scrollDuration
scrollVelocity *= scrollFriction
rawLocation += scrollVelocity
location.add(scrollVelocity)

directionDiff = rawLocation - rawLocationPrevious
scrollDistance = rawLocation - rawLocationPrevious
}

scrollDirection = mathSign(directionDiff)
scrollDirection = mathSign(scrollDistance)
rawLocationPrevious = rawLocation
return self
}
Expand All @@ -71,7 +69,7 @@ export function ScrollBody(
}

function velocity(): number {
return bodyVelocity
return scrollVelocity
}

function useBaseDuration(): ScrollBodyType {
Expand Down
Loading
Loading