GoogleChromeLabs / pinch-zoom

Apache License 2.0
372 stars 54 forks source link

Allow setting bounds #1

Open kenchris opened 5 years ago

kenchris commented 5 years ago

I admit that I didn't look at the code in detail to see if this is already possible, but I know from having implemented this on mobile platforms before that it is common that you have a max and min scale, and still allow pinching beyond that, but then when letting go, it would just bounce back with a nice animation.

It might make sense doing something similar.

The Safari browser on iOS does this (or used to, as I don't use any iOS devices for a while)

There are some CSS properties for overscroll scrolling, so might make sense to minic that for this as well

https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior https://developers.google.com/web/updates/2017/11/overscroll-behavior

jakearchibald commented 5 years ago

Yeah, this is a good idea.

valpet commented 5 years ago

It's not only a good idea, it's an excellent idea. I miss this function very much.

WernerRaath commented 4 years ago

@kenchris did you ever find a fix for this? Or should one search for alternatives?

streamtw commented 3 years ago

Bounds can be achieved by adding custom event listeners:

HTML:

<pinch-zoom class="my-pinch-zoom">
  <img>
</pinch-zoom>

Javascript:

const pinchZoom = document.querySelector('.my-pinch-zoom')
pinchZoom.addEventListener('touchend', moveToSafeArea)
pinchZoom.addEventListener('wheel', moveToSafeArea)

Event listener moveToSafeArea will calculate proper position for content, according to width and height of both wrapper and content:

const moveToSafeArea = function () {
  const wrapper = document.querySelector('.my-pinch-zoom')
  const wrapperWidth = wrapper.clientWidth
  const wrapperHeight = wrapper.clientHeight

  const content = wrapper.children[0]
  const contentWidth = content.clientWidth * wrapper.scale
  const contentHeight = content.clientHeight * wrapper.scale

  content.classList.add('moving')

  let safeX
  let safeY

  const safeRangeX = wrapperWidth - contentWidth
  if (safeRangeX > 0) {
    safeX = Math.min(Math.max(wrapper.x, 0), safeRangeX)
  } else {
    safeX = Math.max(Math.min(wrapper.x, 0), safeRangeX)
  }

  const safeRangeY = wrapperHeight - contentHeight
  if (safeRangeY > 0) {
    safeY = Math.min(Math.max(wrapper.y, 0), safeRangeY)
  } else {
    safeY = Math.max(Math.min(wrapper.y, 0), safeRangeY)
  }

  wrapper.setTransform({
    scale: wrapper.scale,
    x: safeX,
    y: safeY
  })

  setTimeout(() => {
    content.classList.remove('moving')
  }, 250)
}

And remember to add a nice bounce animation:

.my-pinch-zoom > .moving {
  transition: all .25s;
}