I'm using Embla Carousels in a project and want to have a nice slide scaling effect as you scroll through. Slides should get bigger the more they reach the left edge of the carousel container, and scale down relative to their distance to that left edge.
I found this example on their website: https://www.embla-carousel.com/examples/predefined/#scale
The core logic goes like this:
const [embla, setEmbla] = useState<Embla | null>(null);
const [scaleValues, setScaleValues] = useState<number[]>([]);
useEffect(() => {
if (!embla) return;
const onScroll = () => {
const engine = embla.internalEngine();
const scrollProgress = embla.scrollProgress();
const styles = embla.scrollSnapList().map((scrollSnap, index) => {
let diffToTarget = scrollSnap - scrollProgress;
if (engine.options.loop) {
engine.slideLooper.loopPoints.forEach(loopItem => {
const target = loopItem.target().get();
if (index === loopItem.index && target !== 0) {
const sign = Math.sign(target);
if (sign === -1) diffToTarget = scrollSnap - (1 + scrollProgress);
if (sign === 1) diffToTarget = scrollSnap + (1 - scrollProgress);
}
});
}
const scaleValue = 1 - Math.abs(diffToTarget * scaleFactor);
return clamp(scaleValue, 0, 1);
});
setScaleValues(styles);
};
onScroll();
const syncScroll = () => flushSync(onScroll);
embla.on("scroll", syncScroll);
embla.on("reInit", onScroll);
return () => {
embla.off("scroll", syncScroll);
embla.off("reInit", onScroll);
};
}, [embla, scaleFactor]);
scaleValues gets then mapped onto the style property of the slides.
But they are several problems with this:
embla.scrollSnapList()is the list of "snap" anchors the carousel has, not the list of slides. Its length is the length of the list of slides only if the carousel is small enough to only show one full slide at a time. Otherwise it's smaller than the list of slides. So depending on how many slides can fit into the view, some slides towards the end may not get any scaling at all.- The scaling effect is dependent on the width of the Carousel, and the screen if the Carousel resizes according to it
- The scaling effect is dependent on the number of slides. The smaller the number of slides, the more dramatic the scaling effect.
Is it possible to implement this feature while fixing all of the above?
The scaling difference between two slides should only be a function of their distance in px to the left edge of the Carousel, regardless of the Carousel's width or number of slides.
I've updated the tween examples including the scale example you mention. The following things have been fixed in the new example (see code snippet below):
Here's a link to the updated example in the docs. I hope this helps.
I'm not sure what you mean regarding this:
Because there's no explicit correlation between them?