Skip to content
128 changes: 40 additions & 88 deletions src/components/ImageView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class ImageView extends PureComponent {
this.onContainerLayoutChanged = this.onContainerLayoutChanged.bind(this);
this.onContainerPressIn = this.onContainerPressIn.bind(this);
this.onContainerPress = this.onContainerPress.bind(this);
this.onContainerPressOut = this.onContainerPressOut.bind(this);
this.imageLoadingStart = this.imageLoadingStart.bind(this);
this.imageLoadingEnd = this.imageLoadingEnd.bind(this);
this.state = {
Expand All @@ -40,10 +39,6 @@ class ImageView extends PureComponent {
imgWidth: 0,
imgHeight: 0,
zoomScale: 0,
imageLeft: 0,
imageTop: 0,
imageRight: 0,
imageBottom: 0,
};
}

Expand Down Expand Up @@ -98,85 +93,51 @@ class ImageView extends PureComponent {
* @param {SyntheticEvent} e
*/
onContainerPress(e) {
if (this.state.isZoomed && !this.state.isDragging) {
let scrollX;
let scrollY;
if (!this.state.isZoomed && !this.state.isDragging) {
const {offsetX, offsetY} = e.nativeEvent;
const delta = this.getScrollOffset(offsetX, offsetY);
const sX = delta.offsetX;
const sY = delta.offsetY;
this.scrollableRef.scrollTop = sY * this.state.zoomScale;
this.scrollableRef.scrollLeft = sX * this.state.zoomScale;

// Dividing clicked positions by the zoom scale to get coordinates
// so that once we zoom we will scroll to the clicked location.
const delta = this.getScrollOffset(offsetX / this.state.zoomScale, offsetY / this.state.zoomScale);
scrollX = delta.offsetX;
scrollY = delta.offsetY;
}

if (this.state.isZoomed && this.state.isDragging && this.state.isMouseDown) {
this.setState({isDragging: false, isMouseDown: false});
} else {
// We first zoom and once its done then we scroll to the location the user clicked.
this.setState(prevState => ({
isZoomed: !prevState.isZoomed,
isMouseDown: false,
}), () => {
this.scrollableRef.scrollTop = scrollY;
this.scrollableRef.scrollLeft = scrollX;
});
}
}

onContainerPressOut() {
if (this.state.isDragging) {
return;
}

this.setState(prevState => ({
isZoomed: !prevState.isZoomed,
isMouseDown: false,
}));
}

/**
* When open image, set image left/right/top/bottom point and width, height
* When open image, set image width, height and zoomScale.
* @param {Number} imageWidth
* @param {Number} imageHeight
*/
setImageRegion(imageWidth, imageHeight) {
let width = imageWidth;
let height = imageHeight;
const containerHeight = this.state.containerHeight;
const containerWidth = this.state.containerWidth;

// return if image not loaded yet
if (imageHeight <= 0 || containerHeight <= 0) {
if (imageHeight <= 0) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need containerHeight check?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned in the comment below (#8809 (comment)) , it can sometimes be called last. therefore it is still necessary for the calculations we use below.

return;
}

// Fit the image to container size if image small than container.
const aspectRatio = Math.min(containerHeight / imageHeight, containerWidth / imageWidth);
if (aspectRatio > 1) {
width *= (aspectRatio);
height *= (aspectRatio);
}
let imgLeft = (this.props.windowWidth - width) / 2;
let imgRight = ((this.props.windowWidth - width) / 2) + width;
let imgTop = (this.props.windowHeight - height) / 2;
let imgBottom = ((this.props.windowHeight - height) / 2) + height;
const isScreenWiderThanImage = (this.props.windowWidth / width) > 1;
const isScreenTallerThanImage = (this.props.windowHeight / height) > 1;
const aspect = width / height;
if (aspect > 1 && !isScreenWiderThanImage) {
// In case Width fit Screen width and Height not fit the Screen height
const fitRate = this.props.windowWidth / width;
imgLeft = 0;
imgRight = this.props.windowWidth;
imgTop = (this.props.windowHeight - (fitRate * height)) / 2;
imgBottom = imgTop + (fitRate * height);
} else if (aspect <= 1 && !isScreenTallerThanImage) {
// In case Height fit Screen height and Width not fit the Screen width
const fitRate = this.props.windowHeight / height;
imgTop = 0;
imgBottom = this.props.windowHeight;
imgLeft = (this.props.windowWidth - (fitRate * width)) / 2;
imgRight = imgLeft + (fitRate * width);
}

const containerHeight = this.state.containerHeight;
const containerWidth = this.state.containerWidth;
const width = imageWidth;
const height = imageHeight;
const newZoomScale = Math.min(containerWidth / width, containerHeight / height);

this.setState({
imgWidth: width,
zoomScale: newZoomScale,
imgHeight: height,
imageLeft: imgLeft,
imageTop: imgTop,
imageRight: imgRight,
imageBottom: imgBottom,
zoomScale: newZoomScale,
});
}

Expand All @@ -187,31 +148,23 @@ class ImageView extends PureComponent {
* @returns {Object} converted touch point
*/
getScrollOffset(x, y) {
let fitRatio = 1;
if (this.state.imageTop === 0) {
// Fit Height
fitRatio = this.props.windowHeight / this.state.imgHeight;
} else if (this.state.imageLeft === 0) {
// Fit Width
fitRatio = this.props.windowWidth / this.state.imgWidth;
}
let sx = (x - this.state.imageLeft) / fitRatio;
let sy = (y - this.state.imageTop) / fitRatio;
let offsetX;
let offsetY;

// White blank touch
if (x < this.state.imageLeft) {
sx = 0;
}
if (x > this.state.imageRight) {
sx = this.state.imgWidth;
}
if (y < this.state.imageTop) {
sy = 0;
// Container size bigger than clicked position offset
if (x <= this.state.containerWidth / 2) {
offsetX = 0;
} else if (x > this.state.containerWidth / 2) {
// Minus half of container size because we want to be center clicked position
offsetX = x - (this.state.containerWidth / 2);
}
if (y > this.state.imageBottom) {
sy = this.state.imgHeight;
if (y <= this.state.containerHeight / 2) {
offsetY = 0;
} else if (y > this.state.containerHeight / 2) {
// Minus half of container size because we want to be center clicked position
offsetY = y - (this.state.containerHeight / 2);
}
return {offsetX: sx, offsetY: sy};
return {offsetX, offsetY};
}

trackMovement(e) {
Expand Down Expand Up @@ -284,7 +237,6 @@ class ImageView extends PureComponent {
}}
onPressIn={this.onContainerPressIn}
onPress={this.onContainerPress}
onPressOut={this.onContainerPressOut}
>
<Image
source={{uri: this.props.url}}
Expand Down