Qeepsake / react-native-images-collage

Robust interactive image collage component for React Native
MIT License
116 stars 30 forks source link

Pinch zooming not workjng #7

Closed dbarner1 closed 5 years ago

dbarner1 commented 5 years ago

Hi-

Love the module. Finding, though, that pinch to zoom doesn’t work. Curious if you or anyone else is experiencing this?

Thank you! Dave

lukebrandonfarrell commented 5 years ago

@dbarner1 I'm glad you like it!

I'll look into this. Would you please share your code and setup (React & RN versions)?

dbarner1 commented 5 years ago

Thanks Luke.

I hope this is the most helpful format. I tried to only include the relevant bits. If not, please let me know what would be better.

I'm on: RN: .52 R: 16.2

Walkthrough: We have a component called composeEntry. In it is an addAttachment component, which houses https://github.com/ivpusic/react-native-image-crop-picker. When a user selects an image from this library it gets passed to which gets a prop called 'attachment' sent to this.state.entry when a user selects a photo from it gets passed to onSelectAttachment. There we simply update the state to that attachment. Then, in the render of composeEntry we pass in the attachment's path 3 times, to mimic passing three photos to DynamicCollage. When attempting to pinch-to-zoom, nothing happens. It's worth noting that I can move the image around.

Here's the code:

//Native
import React, { Component } from 'react';
import {
  ActivityIndicator,
  Alert,
  Dimensions,
  Image,
  Keyboard,
  Platform,
  ScrollView,
  StyleSheet,
  Switch,
  TextInput,
  TouchableOpacity,
  View,
} from 'react-native';

//3rd party
import PropTypes from 'prop-types';
 import { LayoutData, DynamicCollage, StaticCollage } from 'react-native-images-collage';

//Helpers
import globalStyle from '@globalStyle';
import makeReduxContainer from '@lib/redux-container';

//Homegrown
import {
  Attachment,
  Container,
} from '@common';
import AddAttachment from './add-attachment';
import JournalEntryImageUploader from './journal-entry-image-uploader';
//Redux
import store from '@store';

const { height, width } = Dimensions.get('window');

class ComposeEntry extends Component {
  constructor(props) {
    super(props);

    const { question, showAddPhotoModal } = this.props;
    const {
      attachment,
    } = this.props.initialEntry;

    this.state = {
      pendingAttachment: null,
      entry: {
        attachment: attachment,
      },
      keyboard: {
        visible: false,
        height: 216,
        duration: 250,
      },
    };
  }

  onSelectAttachment(attachment) {
    const { network } = store.getState();

    if (network.available) {
      this.setState({ pendingAttachment: attachment }, () => {
        let entry = this.state.entry;
        entry.localAttachment = attachment;

        this.setState({ entry: entry });

        this.props.onPendingAttachment();
      });
    } else {
      alertHelper.noService();
    }
  }

  keyboardStyle() {
    const { height, visible } = this.state.keyboard;

    return {
      marginBottom: visible ? height : 0,
    };
  }

  render() {
    const { attachment } = this.state.entry;

    return (
      <Container style={[styles.container, this.keyboardStyle()]}>
        <View
          style={styles.composeWrapper}
          keyboardShouldPersistTaps="handled"
        >
          {pendingAttachment && (
            <JournalEntryImageUploader
              image={pendingAttachment}
              onFinish={image => this.onUploadFinish(image)}
              onUploadError={() => this.onUploadError()}
            />
          )}
          {attachment &&
            attachment.path && (
              <DynamicCollage
                 width={400}
                 height={400}
                 imageStyle={{width: 100, height: 100}}
                 matrix={ LayoutData[3][3].matrix }
                 direction={ LayoutData[3][3].direction }
                 panningTopPadding={50}
                 panningRightPadding={50}
                 panningLeftPadding={50}
                 panningBottomPadding={50}
                 scaleAmplifier={500}
                 imageSelectedStyle={{borderColor: 'red', borderWidth: 2}}
                 imageSwapStyle={{borderColor: 'blue', borderWidth: 2}}

                 images={ [attachment.path, attachment.path, attachment.path] }
                  />
              )}
        </View>
        <View style={styles.toolsInner}>
          <AddAttachment
            canAddPhoto={() => this.canAddPhoto()}
            showAddPhotoModal={this.props.showAddPhotoModal}
            attachment={attachment}
            style={styles.tool}
            onSelect={attachment => this.onSelectAttachment(attachment)}
          />
        </View>
      </Container>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'flex-start',
  },
  loading: {
    backgroundColor: globalStyle.color.overlayDarker,
    alignItems: 'center',
    justifyContent: 'center',
    position: 'absolute',
    top: 0,
    right: 0,
    bottom: 0,
    left: 0,
  },
  datePicker: {
    borderColor: globalStyle.color.purple,
    borderRadius: globalStyle.border.radius,
    borderWidth: 1,
    flexDirection: 'row',
    flex: 0,
    alignSelf: 'flex-start',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 10,
  },
  calendar: {
    alignSelf: 'flex-start',
    marginRight: 10,
    marginTop: 2,
  },
  receivedAtDate: {
    color: globalStyle.color.purple,
  },
  scrollContainer: {
    flex: 1,
    justifyContent: 'flex-start',
    alignItems: 'center',
    backgroundColor: 'transparent',
  },
  composeWrapper: {
    flex: 1,
    alignSelf: 'stretch',
    backgroundColor: globalStyle.color.white,
  },
  textArea: {
    alignSelf: 'stretch',
    fontFamily: globalStyle.fontFamily.regular,
    color: globalStyle.color.darkGray,
    backgroundColor: globalStyle.color.white,
    paddingHorizontal: globalStyle.spacing.normal,
    paddingTop: globalStyle.spacing.normal,
    paddingBottom: globalStyle.spacing.tiny,
  },
  toolsWrapper: {
    alignSelf: 'stretch',
    backgroundColor: 'transparent',
    overflow: 'hidden',
  },
  toolsInner: {
    height: globalStyle.size.toolsInner,
    elevation: 2,
    alignSelf: 'stretch',
    paddingHorizontal: globalStyle.spacing.normal,
    overflow: 'visible',
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    backgroundColor: globalStyle.color.white,
    borderTopLeftRadius: globalStyle.border.wideRadius,
    borderTopRightRadius: globalStyle.border.wideRadius,
    ...globalStyle.shadow.wide,
  },
  tool: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  icon: {
    marginHorizontal: globalStyle.spacing.narrow,
  },
  questionWrapper: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  metaDataWrapper: {
    padding: globalStyle.spacing.metaDataWrapper,
    backgroundColor: globalStyle.color.lightBackground,
    flexDirection: 'column',
    flex: 0,
  },
  question: {
    marginHorizontal: 0,
    marginBottom: 0,
    padding: globalStyle.spacing.tiny,
    flex: 1,
  },
  clearQuestion: {
    width: 32,
    height: 32,
    backgroundColor: globalStyle.color.darkBlue,
    borderRadius: 16,
    alignItems: 'center',
    justifyContent: 'center',
    marginLeft: globalStyle.spacing.narrow,
  },
  clearQuestionTitle: {
    color: globalStyle.color.white,
  },
  attachmentWrapper: {
    alignSelf: 'stretch',
  },
  attachment: {
    backgroundColor: globalStyle.color.midGray,
  },
  deleteAttachment: {
    position: 'absolute',
    top: globalStyle.spacing.narrow,
    right: globalStyle.spacing.narrow,
    width: 32,
    height: 32,
    backgroundColor: globalStyle.color.darkBlue,
    borderRadius: 16,
    alignItems: 'center',
    justifyContent: 'center',
  },
  deleteText: {
    color: globalStyle.color.white,
    backgroundColor: 'transparent',
  },
});

export default makeReduxContainer(
  ComposeEntry,
  { ...questionActions },
  (state, props) => {
    return {
      permissions: state.currentUser.app_permissions,
      currentUser: state.currentUser,
      ...props,
    };
  },
);

Thanks again, Dave

lukebrandonfarrell commented 5 years ago

Hey @dbarner1,

I suggest you modifying the CollageImage file in your project and adding console.log() in various places. The only thing I can think of is that for some reason your image URLs are being resolved as 0 width and 0 height, which would indeed break scaling, but I don't think it would break panning. The Collage component would still work as the width and height fallback to the container if they are less then than the container size.

Put your logs in this file:

  1. Line 187 - console.log({ width, height })
  2. Line 168 - console.log({ newWidth, newHeight, relativeContainerWidth, relativeContainerHeight })

If the log on Line 168 isn't executed when you use two fingers to scale then the problem lies in the PanResponder detecting 2 touch gestures or the scaling flag not switching back to false.

If you could paste your logs in here, that would help me debug the issue.

Let me know how you get on.

dbarner1 commented 5 years ago

Thanks @lukebrandonfarrell . No luck so far :(

The result of the first console.log: {width: 2400, height: 1601}

The second console.log doesn't return. Pinching to zoom does nothing - aka, the image stays put as it is. So, looks like its just not recognizing the pinch.

Also, it looks like the swapping of photos isn't working either :/. The first picture does get the red border. The second does get the blue border. But, on release the photos go back to their original containers.

Thanks for the help here! Dave

lukebrandonfarrell commented 5 years ago

@dbarner1

It looks like it could be a problem with the PanResponder not detecting multiple touches (This could be due to your version of react-native. I had the same problem when developing the component. Try RN 0.54.0).

If you set up a sample project on Github which I can clone and run I will be able to look into these two issues further for you.

dhanababum commented 5 years ago

@lukebrandonfarrell I found the issue, https://github.com/lukebrandonfarrell/react-native-images-collage/blob/master/src/CollageImage.js#L140

and it should be,

const touchOne = evt.touchHistory.touchBank[0];
const touchTwo = evt.touchHistory.touchBank[1];

not

const touchOne = evt.touchHistory.touchBank[1];
const touchTwo = evt.touchHistory.touchBank[2];
Pamu2018 commented 5 years ago

Great @dhanababum , keep it up

lukebrandonfarrell commented 5 years ago

@dhanababum Thanks for helping out! I'll give it a test this weekend. Would you be able to submit a pull request for this?

dhanababum commented 5 years ago

Yep I will do it

lukebrandonfarrell commented 5 years ago

@dbarner1 @dhanababum

I think I've solved your issues. After some further investigation this weekend, I've found that the scaling and movement issues can be caused by setting the collage component width and height with a percentage e.g. "80%". This is because the width and height are used to calculate image scaling and movement, and the percentage (which is a string), resolve to NaN.

Percentages are now supported in v3.0.4.

Let me know if you have any problems.

dhanababum commented 5 years ago

Hi @lukebrandonfarrell , I am using V3.1.1 and not resolved my issue

dbarner1 commented 5 years ago

Same here :(

Sent from my iPhone

On Dec 27, 2018, at 12:30 PM, Dhana Babu notifications@github.com wrote:

Hi @lukebrandonfarrell , I am using V3.1.1 and not resolved my issue

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

lukebrandonfarrell commented 5 years ago

@dhanababum @dbarner1 Swapping should now be working on v3.1.2. The issue was being caused by getDerivedStateFromProps, see CHANGELOG.

As for the scaling, I think it is an issue with RN 57.0, because two touch gestures are not being detected. I will do some further exploration into this issue.

lukebrandonfarrell commented 5 years ago

@dbarner1 @dhanababum I can confirm that the scaling issue is not RN 57.0. It is due to the PanResponder being wrapped in certain components. These components include <TouchableOpacity /> and <ScrollView /> I believe... This is something I will flag with the RN repository when I get to the core of the issue.

As for now, I am going to close this issue as most of the swapping issues experienced should be fixed in 3.1.7+.

I've opened another issue which will address the scaling issue in more detail #12