I have an element:
<div ref={scrollRef}>
<div ref={containerRef} style={{ width: width * zoomCoef }}>
</div>
</div>
Where “width” is a constant and “zoomCoef” is a dynamic numerical value.
So when “zoomCoef” value changed, div shrink or expand. I want zoom to behave smooth and relative to cursor position.
To do it I have such calculations (written by chatGPT)
const zoomCallback = ({ prevZoom, newZoom, event }: { prevZoom: number, newZoom: number, event: WheelEvent }) => {
const scrollDiv = scrollRef.current;
const container = containerRef.current;
if (!scrollDiv || !container) return;
const rect = container.getBoundingClientRect();
const scrollRect = scrollDiv.getBoundingClientRect();
const zoomDif = newZoom / prevZoom;
const cursorPositionOnView = event.clientX - scrollRect.left;
const cursorX = event.clientX - rect.left;
const newCursorX = cursorX * zoomDif;
const newScrollLeft = newCursorX - cursorPositionOnView;
const animationDuration = 400;
const initialWidth = container.offsetWidth;
const initialScrollLeft = scrollDiv.scrollLeft;
const newWidth = container.offsetWidth * zoomDif;
const startTime = performance.now();
const animate = (currentTime: number) => {
const elapsedTime = currentTime - startTime;
const progress = Math.min(elapsedTime / animationDuration, 1);
const interpolatedWidth = initialWidth + progress * (newWidth - initialWidth);
const interpolatedScrollLeft = initialScrollLeft + progress * (newScrollLeft - initialScrollLeft);
container.style.width = `${interpolatedWidth}px`;
scrollDiv.scrollLeft = interpolatedScrollLeft;
if (progress < 1) {
requestAnimationFrame(animate);
}
};
requestAnimationFrame(animate);
};
I use it with animation styles:
transition: 0.5s;
transition: width 0.5 linear;
It kinda work, but very poor (jerks and drives back and forth).
How can I fix it to achieve smooth and precisious behavior?
The example of what I want to achieve can be found in browser devtools>performance>profile timeline, which can be scrolled in/out relative to a cursor position: