From 2211017411334e3e7f1afad23e420a8ac99eed5e Mon Sep 17 00:00:00 2001 From: David Jerleke Date: Thu, 4 Jul 2024 21:43:08 +0200 Subject: [PATCH] Bug fix for #928. --- .../src/components/AutoScroll.ts | 15 ++-- .../Examples/examplesCarouselStyles.ts | 1 + .../InfiniteScroll/EmblaCarousel.jsx | 8 +- .../InfiniteScroll/EmblaCarousel.tsx | 6 +- .../InfiniteScroll/EmblaCarousel.tsx | 6 +- .../EmblaCarouselInfiniteScroll.js | 8 +- .../EmblaCarouselInfiniteScroll.ts | 2 + .../EmblaCarouselInfiniteScroll.ts | 2 + .../src/content/pages/api/events.mdx | 2 +- .../src/content/pages/api/methods.mdx | 2 +- .../src/components/Fade.ts | 7 +- .../src/__tests__/loop-ltr.test.ts | 1 + .../src/__tests__/scrollBounds-ltr.test.ts | 5 +- .../src/__tests__/scrollBounds-rtl.test.ts | 5 +- .../__tests__/scrollBounds-vertical.test.ts | 5 +- .../src/components/Animations.ts | 27 +++++-- .../embla-carousel/src/components/Engine.ts | 81 ++++++++++++++----- .../src/components/ScrollBody.ts | 17 ++-- .../embla-carousel/src/components/ScrollTo.ts | 12 ++- .../src/main.ts | 2 +- 20 files changed, 158 insertions(+), 56 deletions(-) diff --git a/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts b/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts index 587ae5c12..4e49d81a2 100644 --- a/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts +++ b/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts @@ -148,6 +148,8 @@ function AutoScroll(userOptions: AutoScrollOptionsType = {}): AutoScrollType { function createAutoScrollBehaviour(engine: EngineType): ScrollBodyType { const { location, + previousLocation, + offsetLocation, target, scrollTarget, index, @@ -164,12 +166,15 @@ function AutoScroll(userOptions: AutoScrollOptionsType = {}): AutoScrollType { let rawLocationPrevious = 0 let hasSettled = false - function seek(): ScrollBodyType { + function seek(timeStep: number): ScrollBodyType { + const fixedDeltaTimeSeconds = timeStep / 1000 let directionDiff = 0 - bodyVelocity = directionSign * options.speed + previousLocation.set(location) + + bodyVelocity = directionSign * options.speed * 55 rawLocation += bodyVelocity - location.add(bodyVelocity) + location.add(bodyVelocity * fixedDeltaTimeSeconds) target.set(location) directionDiff = rawLocation - rawLocationPrevious @@ -186,8 +191,8 @@ function AutoScroll(userOptions: AutoScrollOptionsType = {}): AutoScrollType { const reachedEnd = options.direction === 'forward' - ? reachedMin(location.get()) - : reachedMax(location.get()) + ? reachedMin(offsetLocation.get()) + : reachedMax(offsetLocation.get()) if (!loop && reachedEnd) { hasSettled = true diff --git a/packages/embla-carousel-docs/src/components/Examples/examplesCarouselStyles.ts b/packages/embla-carousel-docs/src/components/Examples/examplesCarouselStyles.ts index cd92460c6..c6b951ee9 100644 --- a/packages/embla-carousel-docs/src/components/Examples/examplesCarouselStyles.ts +++ b/packages/embla-carousel-docs/src/components/Examples/examplesCarouselStyles.ts @@ -144,6 +144,7 @@ export const SLIDE_NUMBER_STYLES = css` align-items: center; justify-content: center; height: __replace_slide_height__; + user-select: none; } ` diff --git a/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.jsx b/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.jsx index 297aadd14..d9e465bb0 100644 --- a/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.jsx +++ b/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.jsx @@ -30,7 +30,13 @@ const EmblaCarousel = (props) => { emblaApi.reInit() const newEngine = emblaApi.internalEngine() - const copyEngineModules = ['location', 'target', 'scrollBody'] + const copyEngineModules = [ + 'scrollBody', + 'location', + 'offsetLocation', + 'previousLocation', + 'target' + ] copyEngineModules.forEach((engineModule) => { Object.assign(newEngine[engineModule], oldEngine[engineModule]) }) diff --git a/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.tsx b/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.tsx index 8afb77e56..e2285dde4 100644 --- a/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.tsx +++ b/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesDist/InfiniteScroll/EmblaCarousel.tsx @@ -42,9 +42,11 @@ const EmblaCarousel: React.FC = (props) => { emblaApi.reInit() const newEngine = emblaApi.internalEngine() const copyEngineModules: (keyof EngineType)[] = [ + 'scrollBody', 'location', - 'target', - 'scrollBody' + 'offsetLocation', + 'previousLocation', + 'target' ] copyEngineModules.forEach((engineModule) => { Object.assign(newEngine[engineModule], oldEngine[engineModule]) diff --git a/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesSrc/InfiniteScroll/EmblaCarousel.tsx b/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesSrc/InfiniteScroll/EmblaCarousel.tsx index 8afb77e56..e2285dde4 100644 --- a/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesSrc/InfiniteScroll/EmblaCarousel.tsx +++ b/packages/embla-carousel-docs/src/components/Sandbox/React/SandboxFilesSrc/InfiniteScroll/EmblaCarousel.tsx @@ -42,9 +42,11 @@ const EmblaCarousel: React.FC = (props) => { emblaApi.reInit() const newEngine = emblaApi.internalEngine() const copyEngineModules: (keyof EngineType)[] = [ + 'scrollBody', 'location', - 'target', - 'scrollBody' + 'offsetLocation', + 'previousLocation', + 'target' ] copyEngineModules.forEach((engineModule) => { Object.assign(newEngine[engineModule], oldEngine[engineModule]) diff --git a/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.js b/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.js index 0e065e799..f1994cf94 100644 --- a/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.js +++ b/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.js @@ -47,7 +47,13 @@ export const setupInfiniteScroll = (emblaApi, loadMoreCallback) => { emblaApi.reInit() const newEngine = emblaApi.internalEngine() - const copyEngineModules = ['scrollBody', 'location', 'target'] + const copyEngineModules = [ + 'scrollBody', + 'location', + 'offsetLocation', + 'previousLocation', + 'target' + ] copyEngineModules.forEach((engineModule) => Object.assign(newEngine[engineModule], oldEngine[engineModule]) ) diff --git a/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.ts b/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.ts index eb0718c4c..87f653a43 100644 --- a/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.ts +++ b/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesDist/InfiniteScroll/EmblaCarouselInfiniteScroll.ts @@ -66,6 +66,8 @@ export const setupInfiniteScroll = ( const copyEngineModules: (keyof EngineType)[] = [ 'scrollBody', 'location', + 'offsetLocation', + 'previousLocation', 'target' ] copyEngineModules.forEach((engineModule) => diff --git a/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesSrc/InfiniteScroll/EmblaCarouselInfiniteScroll.ts b/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesSrc/InfiniteScroll/EmblaCarouselInfiniteScroll.ts index eb0718c4c..87f653a43 100644 --- a/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesSrc/InfiniteScroll/EmblaCarouselInfiniteScroll.ts +++ b/packages/embla-carousel-docs/src/components/Sandbox/Vanilla/SandboxFilesSrc/InfiniteScroll/EmblaCarouselInfiniteScroll.ts @@ -66,6 +66,8 @@ export const setupInfiniteScroll = ( const copyEngineModules: (keyof EngineType)[] = [ 'scrollBody', 'location', + 'offsetLocation', + 'previousLocation', 'target' ] copyEngineModules.forEach((engineModule) => diff --git a/packages/embla-carousel-docs/src/content/pages/api/events.mdx b/packages/embla-carousel-docs/src/content/pages/api/events.mdx index 819738053..4e8c57a43 100644 --- a/packages/embla-carousel-docs/src/content/pages/api/events.mdx +++ b/packages/embla-carousel-docs/src/content/pages/api/events.mdx @@ -394,7 +394,7 @@ export function EmblaCarousel() { console.log(`Embla just triggered ${eventName}!`) } - function onInit(event): void { + function onInit(event: CustomEvent): void { emblaApi = event.detail emblaApi.on('slidesInView', logEmblaEvent) } diff --git a/packages/embla-carousel-docs/src/content/pages/api/methods.mdx b/packages/embla-carousel-docs/src/content/pages/api/methods.mdx index c33c4217b..a21138d16 100644 --- a/packages/embla-carousel-docs/src/content/pages/api/methods.mdx +++ b/packages/embla-carousel-docs/src/content/pages/api/methods.mdx @@ -239,7 +239,7 @@ export function EmblaCarousel() { console.log(emblaApi.slidesInView()) } - function onInit(event): void { + function onInit(event: CustomEvent): void { emblaApi = event.detail emblaApi.on('slidesInView', logSlidesInView) } diff --git a/packages/embla-carousel-fade/src/components/Fade.ts b/packages/embla-carousel-fade/src/components/Fade.ts index 98d5b4dea..1bf972a89 100644 --- a/packages/embla-carousel-fade/src/components/Fade.ts +++ b/packages/embla-carousel-fade/src/components/Fade.ts @@ -20,6 +20,7 @@ function Fade(userOptions: FadeOptionsType = {}): FadeType { const fullOpacity = 1 const noOpacity = 0 const fadeFriction = 0.68 + const timeStep = 1000 / 60 let emblaApi: EmblaCarouselType let opacities: number[] = [] @@ -28,6 +29,7 @@ function Fade(userOptions: FadeOptionsType = {}): FadeType { let fadeVelocity = 0 let progress = 0 let shouldFadePair = false + let defaultSettledBehaviour: ScrollBodyType['settled'] let defaultProgressBehaviour: EmblaCarouselType['scrollProgress'] @@ -214,10 +216,11 @@ function Fade(userOptions: FadeOptionsType = {}): FadeType { return distanceSign === directionSign ? nextSnap : selectedSnap } - const fade = (emblaApi: EmblaCarouselType): void => { + function fade(emblaApi: EmblaCarouselType): void { const { dragHandler, scrollBody } = emblaApi.internalEngine() + const fixedDeltaTimeSeconds = timeStep / 1000 const pointerDown = dragHandler.pointerDown() - const velocity = scrollBody.velocity() + const velocity = scrollBody.velocity() * fixedDeltaTimeSeconds const duration = scrollBody.duration() const fadeIndex = getFadeIndex() const noFadeIndex = !isNumber(fadeIndex) diff --git a/packages/embla-carousel/src/__tests__/loop-ltr.test.ts b/packages/embla-carousel/src/__tests__/loop-ltr.test.ts index 4f9cfcd67..1e90d4777 100644 --- a/packages/embla-carousel/src/__tests__/loop-ltr.test.ts +++ b/packages/embla-carousel/src/__tests__/loop-ltr.test.ts @@ -13,6 +13,7 @@ export const scrollToLocationInstant = ( engine.target.set(location) engine.scrollBody.useDuration(0) engine.animation.update() + engine.animation.render(1) } describe('➡️ Loop - Horizontal LTR', () => { diff --git a/packages/embla-carousel/src/__tests__/scrollBounds-ltr.test.ts b/packages/embla-carousel/src/__tests__/scrollBounds-ltr.test.ts index 18d3cd4e5..10ee47c09 100644 --- a/packages/embla-carousel/src/__tests__/scrollBounds-ltr.test.ts +++ b/packages/embla-carousel/src/__tests__/scrollBounds-ltr.test.ts @@ -7,6 +7,7 @@ export const setLocationOutOfBounds = ( engine: EngineType, outOfBoundsLocation: number ): void => { + engine.offsetLocation.set(outOfBoundsLocation) engine.location.set(outOfBoundsLocation) engine.target.set(outOfBoundsLocation) } @@ -21,7 +22,7 @@ describe('➡️ ScrollBounds - Horizontal LTR', () => { emblaApi.on('settle', settleCallback) setLocationOutOfBounds(engine, engine.limit.max + 1) - engine.animation.update() + engine.animation.render(1) expect(settleCallback).toHaveBeenCalledTimes(0) }) @@ -46,7 +47,7 @@ describe('➡️ ScrollBounds - Horizontal LTR', () => { emblaApi.on('settle', settleCallback) setLocationOutOfBounds(engine, engine.limit.min - 1) - engine.animation.update() + engine.animation.render(1) expect(settleCallback).toHaveBeenCalledTimes(0) }) diff --git a/packages/embla-carousel/src/__tests__/scrollBounds-rtl.test.ts b/packages/embla-carousel/src/__tests__/scrollBounds-rtl.test.ts index 4dcdd1b0b..f268c77eb 100644 --- a/packages/embla-carousel/src/__tests__/scrollBounds-rtl.test.ts +++ b/packages/embla-carousel/src/__tests__/scrollBounds-rtl.test.ts @@ -7,6 +7,7 @@ export const setLocationOutOfBounds = ( engine: EngineType, outOfBoundsLocation: number ): void => { + engine.offsetLocation.set(outOfBoundsLocation) engine.location.set(outOfBoundsLocation) engine.target.set(outOfBoundsLocation) } @@ -23,7 +24,7 @@ describe('➡️ ScrollBounds - Horizontal RTL', () => { emblaApi.on('settle', settleCallback) setLocationOutOfBounds(engine, engine.limit.max + 1) - engine.animation.update() + engine.animation.render(1) expect(settleCallback).toHaveBeenCalledTimes(0) }) @@ -52,7 +53,7 @@ describe('➡️ ScrollBounds - Horizontal RTL', () => { emblaApi.on('settle', settleCallback) setLocationOutOfBounds(engine, engine.limit.min - 1) - engine.animation.update() + engine.animation.render(1) expect(settleCallback).toHaveBeenCalledTimes(0) }) diff --git a/packages/embla-carousel/src/__tests__/scrollBounds-vertical.test.ts b/packages/embla-carousel/src/__tests__/scrollBounds-vertical.test.ts index 05ac692d1..1daddfaa0 100644 --- a/packages/embla-carousel/src/__tests__/scrollBounds-vertical.test.ts +++ b/packages/embla-carousel/src/__tests__/scrollBounds-vertical.test.ts @@ -7,6 +7,7 @@ export const setLocationOutOfBounds = ( engine: EngineType, outOfBoundsLocation: number ): void => { + engine.offsetLocation.set(outOfBoundsLocation) engine.location.set(outOfBoundsLocation) engine.target.set(outOfBoundsLocation) } @@ -23,7 +24,7 @@ describe('➡️ ScrollBounds - Vertical', () => { emblaApi.on('settle', settleCallback) setLocationOutOfBounds(engine, engine.limit.max + 1) - engine.animation.update() + engine.animation.render(1) expect(settleCallback).toHaveBeenCalledTimes(0) }) @@ -52,7 +53,7 @@ describe('➡️ ScrollBounds - Vertical', () => { emblaApi.on('settle', settleCallback) setLocationOutOfBounds(engine, engine.limit.min - 1) - engine.animation.update() + engine.animation.render(1) expect(settleCallback).toHaveBeenCalledTimes(0) }) diff --git a/packages/embla-carousel/src/components/Animations.ts b/packages/embla-carousel/src/components/Animations.ts index 5097f7c54..7980a2ca1 100644 --- a/packages/embla-carousel/src/components/Animations.ts +++ b/packages/embla-carousel/src/components/Animations.ts @@ -2,7 +2,14 @@ import { EngineType } from './Engine' import { EventStore } from './EventStore' import { WindowType } from './utils' -export type AnimationsUpdateType = (engine: EngineType) => void +export type AnimationsUpdateType = ( + engine: EngineType, + timeStep: number +) => void +export type AnimationsRenderType = ( + engine: EngineType, + lagOffset: number +) => void export type AnimationsType = { init: () => void @@ -10,18 +17,20 @@ export type AnimationsType = { start: () => void stop: () => void update: () => void + render: (lagOffset: number) => void } export function Animations( ownerDocument: Document, ownerWindow: WindowType, - update: AnimationsType['update'] + update: (timeStep: number) => void, + render: (lagOffset: number) => void ): AnimationsType { const documentVisibleHandler = EventStore() const timeStep = 1000 / 60 let lastTimeStamp: number | null = null - let animationFrame = 0 let lag = 0 + let animationFrame = 0 function init(): void { documentVisibleHandler.add(ownerDocument, 'visibilitychange', () => { @@ -38,15 +47,18 @@ export function Animations( if (!animationFrame) return if (!lastTimeStamp) lastTimeStamp = timeStamp - const timeElapsed = timeStamp - lastTimeStamp + const elapsed = timeStamp - lastTimeStamp lastTimeStamp = timeStamp - lag += timeElapsed + lag += elapsed while (lag >= timeStep) { - update() + update(timeStep) lag -= timeStep } + const lagOffset = lag / timeStep + render(lagOffset) + if (animationFrame) ownerWindow.requestAnimationFrame(animate) } @@ -73,7 +85,8 @@ export function Animations( destroy, start, stop, - update + update: () => update(timeStep), + render } return self } diff --git a/packages/embla-carousel/src/components/Engine.ts b/packages/embla-carousel/src/components/Engine.ts index aeff9c682..f2a7d3626 100644 --- a/packages/embla-carousel/src/components/Engine.ts +++ b/packages/embla-carousel/src/components/Engine.ts @@ -1,5 +1,10 @@ import { Alignment } from './Alignment' -import { Animations, AnimationsType, AnimationsUpdateType } from './Animations' +import { + Animations, + AnimationsType, + AnimationsUpdateType, + AnimationsRenderType +} from './Animations' import { Axis, AxisType } from './Axis' import { Counter, CounterType } from './Counter' import { DragHandler, DragHandlerType } from './DragHandler' @@ -44,6 +49,8 @@ export type EngineType = { indexPrevious: CounterType limit: LimitType location: Vector1DType + offsetLocation: Vector1DType + previousLocation: Vector1DType options: OptionsType percentOfView: PercentOfViewType scrollBody: ScrollBodyType @@ -149,21 +156,30 @@ export function Engine( const slideIndexes = arrayKeys(slides) // Animation - const update: AnimationsUpdateType = ({ - dragHandler, - eventHandler, - scrollBody, - scrollBounds, - scrollLooper, - slideLooper, - translate, - location, - animation, - options: { loop } - }) => { + const update: AnimationsUpdateType = ( + { dragHandler, scrollBody, scrollBounds, options: { loop } }, + timeStep + ) => { if (!loop) scrollBounds.constrain(dragHandler.pointerDown()) - scrollBody.seek() + scrollBody.seek(timeStep) + } + const render: AnimationsRenderType = ( + { + scrollBody, + translate, + location, + offsetLocation, + scrollLooper, + slideLooper, + dragHandler, + animation, + eventHandler, + scrollBounds, + options: { loop } + }, + lagOffset + ) => { const shouldSettle = scrollBody.settled() const withinBounds = !scrollBounds.shouldConstrain() const hasSettled = loop ? shouldSettle : shouldSettle && withinBounds @@ -174,22 +190,40 @@ export function Engine( } if (!hasSettled) eventHandler.emit('scroll') + const interpolatedLocation = + location.get() * lagOffset + previousLocation.get() * (1 - lagOffset) + + offsetLocation.set(interpolatedLocation) + if (loop) { scrollLooper.loop(scrollBody.direction()) slideLooper.loop() } - translate.to(location.get()) + translate.to(offsetLocation.get()) } - - const animation = Animations(ownerDocument, ownerWindow, () => update(engine)) + const animation = Animations( + ownerDocument, + ownerWindow, + (timeStep) => update(engine, timeStep), + (lagOffset: number) => render(engine, lagOffset) + ) // Shared const friction = 0.68 const startLocation = scrollSnaps[index.get()] const location = Vector1D(startLocation) + const previousLocation = Vector1D(startLocation) + const offsetLocation = Vector1D(startLocation) const target = Vector1D(startLocation) - const scrollBody = ScrollBody(location, target, duration, friction) + const scrollBody = ScrollBody( + location, + offsetLocation, + previousLocation, + target, + duration, + friction + ) const scrollTarget = ScrollTarget( loop, scrollSnaps, @@ -201,6 +235,7 @@ export function Engine( animation, index, indexPrevious, + scrollBody, scrollTarget, target, eventHandler @@ -267,6 +302,8 @@ export function Engine( indexPrevious, limit, location, + offsetLocation, + previousLocation, options, resizeHandler: ResizeHandler( container, @@ -280,13 +317,15 @@ export function Engine( scrollBody, scrollBounds: ScrollBounds( limit, - location, + offsetLocation, target, scrollBody, percentOfView ), - scrollLooper: ScrollLooper(contentSize, limit, location, [ + scrollLooper: ScrollLooper(contentSize, limit, offsetLocation, [ location, + offsetLocation, + previousLocation, target ]), scrollProgress, @@ -302,7 +341,7 @@ export function Engine( slideSizesWithGaps, snaps, scrollSnaps, - location, + offsetLocation, slides ), slideFocus, diff --git a/packages/embla-carousel/src/components/ScrollBody.ts b/packages/embla-carousel/src/components/ScrollBody.ts index d14d23a5b..2eb117ac6 100644 --- a/packages/embla-carousel/src/components/ScrollBody.ts +++ b/packages/embla-carousel/src/components/ScrollBody.ts @@ -5,7 +5,7 @@ export type ScrollBodyType = { direction: () => number duration: () => number velocity: () => number - seek: () => ScrollBodyType + seek: (timeStep: number) => ScrollBodyType settled: () => boolean useBaseFriction: () => ScrollBodyType useBaseDuration: () => ScrollBodyType @@ -15,6 +15,8 @@ export type ScrollBodyType = { export function ScrollBody( location: Vector1DType, + offsetLocation: Vector1DType, + previousLocation: Vector1DType, target: Vector1DType, baseDuration: number, baseFriction: number @@ -26,21 +28,26 @@ export function ScrollBody( let rawLocation = location.get() let rawLocationPrevious = 0 - function seek(): ScrollBodyType { + function seek(timeStep: number): ScrollBodyType { + const fixedDeltaTimeSeconds = timeStep / 1000 + const duration = scrollDuration * fixedDeltaTimeSeconds const diff = target.get() - location.get() const isInstant = !scrollDuration let directionDiff = 0 if (isInstant) { bodyVelocity = 0 + previousLocation.set(target) location.set(target) directionDiff = diff } else { - bodyVelocity += diff / scrollDuration + previousLocation.set(location) + + bodyVelocity += diff / duration bodyVelocity *= scrollFriction rawLocation += bodyVelocity - location.add(bodyVelocity) + location.add(bodyVelocity * fixedDeltaTimeSeconds) directionDiff = rawLocation - rawLocationPrevious } @@ -51,7 +58,7 @@ export function ScrollBody( } function settled(): boolean { - const diff = target.get() - location.get() + const diff = target.get() - offsetLocation.get() return mathAbs(diff) < 0.001 } diff --git a/packages/embla-carousel/src/components/ScrollTo.ts b/packages/embla-carousel/src/components/ScrollTo.ts index 0f03e801d..bdd6e406e 100644 --- a/packages/embla-carousel/src/components/ScrollTo.ts +++ b/packages/embla-carousel/src/components/ScrollTo.ts @@ -1,6 +1,7 @@ import { AnimationsType } from './Animations' import { CounterType } from './Counter' import { EventHandlerType } from './EventHandler' +import { ScrollBodyType } from './ScrollBody' import { ScrollTargetType, TargetType } from './ScrollTarget' import { Vector1DType } from './Vector1d' @@ -13,6 +14,7 @@ export function ScrollTo( animation: AnimationsType, indexCurrent: CounterType, indexPrevious: CounterType, + scrollBody: ScrollBodyType, scrollTarget: ScrollTargetType, targetVector: Vector1DType, eventHandler: EventHandlerType @@ -23,7 +25,15 @@ export function ScrollTo( targetVector.add(distanceDiff) - if (distanceDiff) animation.start() + if (distanceDiff) { + if (scrollBody.duration()) { + animation.start() + } else { + animation.update() + animation.render(1) + animation.update() + } + } if (indexDiff) { indexPrevious.set(indexCurrent.get()) diff --git a/playgrounds/embla-carousel-playground-vanilla/src/main.ts b/playgrounds/embla-carousel-playground-vanilla/src/main.ts index fd51359d1..a611f14ec 100644 --- a/playgrounds/embla-carousel-playground-vanilla/src/main.ts +++ b/playgrounds/embla-carousel-playground-vanilla/src/main.ts @@ -24,7 +24,7 @@ import './main.css' const injectBaseStyles = (): void => { const styleElement = document.createElement('style') const carouselStyles = examplesCarouselDefaultStyles( - '100%', + '70%', '1rem', 'x', styledComponentsStylesToString(