react-native-reanimated-zoom icon indicating copy to clipboard operation
react-native-reanimated-zoom copied to clipboard

Enhancement proposal: avoid scrolling zoomed image beyond the borders

Open ManuViola77 opened this issue 2 years ago • 9 comments

Hi!

I loved this library and the only thing I found that could make it better is to have the option of not scrolling beyond the zoomed image borders, meaning that it doesn't leave black spaces horizontally or vertically (except the image is actually smaller than the height/width).

In case Im not being clear, what I mean is that if the image is this:

it could only let scroll upto the borders like this:

without letting have empty black space between the image and the borders.

This requires lots of math 😅 I managed to make a version but is not perfect at all, I would love to have a more official code for doing that 😅 In my case, for example, all math is broken if the user turns the phone horizontally 😂

ManuViola77 avatar May 30 '22 19:05 ManuViola77

it's bindToBorders from https://github.com/openspacelabs/react-native-zoomable-view i tried to look into the code but hard for me since i don't know typescript also they are not using reanimated

putuoka avatar Jun 06 '22 09:06 putuoka

Yeah, you are right, basically is this code:

image

I think it doesn't really matter Typescript or Reanimated. The issue here is if the offset is greater than what it should be to avoid scrolling over the boundaries, so basically assuming 0 is in the middle of the image (which it is), you can calculate the biggest offset accepted according to the current zoom scale, and, if the offset is greater than that, you assign the maximum allowed, otherwise you assign the offset you have. Also, if the image is smaller than the window's width/height, in those cases the offset should be 0.

This implies a lot of math, like you can see here for example.

What I did for this case, you have inside the pan gesture that the offset X is this:

const offsetX = prevTranslationX.value + e.translationX - panTranslateX.value;

so what I do with that is, instead of assigning that directly to translationX.value, I call a getPanTranslation I created with these parameters: getPanTranslation(offsetX, IMAGE_WIDTH, screenWidth, scale.value) and the function has this code:

const getPanTranslation = (offset, imageOriginalDimension, screenDimension, scale) => {
    const imageDimension = imageOriginalDimension * scale;

    if (imageDimension <= screenDimension) {
      return 0; // if the image is smaller than the screen dimension, the offset is 0
    }

    const max = (imageDimension - screenDimension) / 2;  // this is the max offset accepted
    const sign = offset < 0 ? -1 : 1;
    const absoluteOffset = Math.abs(offset);

    return Math.min(absoluteOffset, max) * sign;
  };

I think this is not perfect but is the way I managed to do it 😅

ManuViola77 avatar Jun 07 '22 05:06 ManuViola77

+1 for this enhancement - this is a rather critical UX feature for any zoom/pan system to prevent the content from being panned outside of the view.

This is a great library and I'd love to see a solution built in for this, like bindToBorders from react-native-zoomable-view

Davidson-Mike avatar Jun 09 '22 19:06 Davidson-Mike

Thanks for the suggestions! Just pushed a fix in 0.1.4. https://github.com/intergalacticspacehighway/react-native-reanimated-zoom/pull/7. Can you try and let me know if it works as expected?

Closing as it's solved in 0.2.0. Let me know if you still face any issues.

Hi! Thanks for the quick response! I cloned this and run the example and horizontal works perfect as expected, vertical I see it still scrolls more than the borders. But maybe is just because of how the example is implemented, I didn't check in my particular project.

https://user-images.githubusercontent.com/8755889/176504358-2af596a2-64b6-4f03-b202-9221ec499e71.mp4

ManuViola77 avatar Jun 29 '22 18:06 ManuViola77

Yes, right. I missed checking the vertical. Thanks for reporting. I'll look into it!

Thanks for being so attentive 😄

ManuViola77 avatar Jul 04 '22 15:07 ManuViola77

@ManuViola77 i just checked and it kind of works as expected 😅. In the above example, the image is less in height, so it allows a bit of scrolling. Try the below example, it won't allow scrolling out of image borders. Let me know if this is expected!

 <Zoom>
      <Image
        source={{
          uri: 'https://images.unsplash.com/photo-1536152470836-b943b246224c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1038&q=80',
        }}
        style={{
          width: Dimensions.get('window').width,
          height: Dimensions.get('window').height,
        }}
      />
</Zoom>