How to scale the contents of overflown container while preserving scroll position?

  animation, css, javascript, reactjs, zoom-sdk

Context:

I’m working on the PDF viewer using react-pdf and one of the issues I’ve stumbled upon is zooming. Let’s say we’ve rendered 3 pages (800x1100px), our initial scale factor is 1 and we’ve scrolled to the middle of the overflown container.

Each page is being rendered within a wrapper that takes into account current scale factor like this.

  return (
    <div ref={ref} css={styles.page} style={{
      width: viewerScale * initialPageWidth,
      height: viewerScale * initialPageHeight,
      left: '50%',
      transition: 'all .2s ease-in`,
      transform: `translate(-50%, ${topOffset}px)`,
      marginBottom: 12,
      bottom: 0,
      position: 'absolute',
      top: 0
    }}>
      {pdfPage}
    </div>
  )
})

Wrappers reside within overflown div with the following styles:

  height: 100%;
  padding: 80px 0;
  width: 100%;
  overflow: auto;
  position: absolute;

I’m not using scale prop provided by react-pdfs Page component as rerendering is quite slow once you have more than 100 pages. Instead I render page once in the highest resolution and rely on the combination of width & height making it sort of responsive.

Once scale factor changes each page is being re-rendered and animated to imitate scaling experience. That being said, I’m experiencing couple of issues:

  1. Initial scrolling position is not preserved due to the change to the total height of overflow container.
  2. Pages are not being scaled with respect to the scroll position which causes scroll jumps.

Question

How does one scale content while preserving scroll position in a Google-like fashion?
I’ve been trying to reverse-engineer their solution to some extent and I’ve managed to get ​pretty close by sing transform: scale on the overflow container and changing its transform-origin dynamically based on the scroll position.

That being said, it causes flickering once the user scroll fast and causes a lot of repaints which are quite expensive. My understanding is that Google’s viewer relies on a combination of container width and padding-bottom attributes in conjunction with absolutely positioned items but I’m absolutely clueless as to how they achieve their scaling effect.

Please let me know if you need me to provide any additional details and thanks in advance!

Source: Ask Javascript Questions

LEAVE A COMMENT