-
Notifications
You must be signed in to change notification settings - Fork 3k
/
Copy pathThumbnailImage.js
98 lines (85 loc) · 3.84 KB
/
ThumbnailImage.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import lodashClamp from 'lodash/clamp';
import React, {useCallback, useState} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import ImageWithSizeCalculation from './ImageWithSizeCalculation';
import styles from '../styles/styles';
import * as StyleUtils from '../styles/StyleUtils';
import useWindowDimensions from '../hooks/useWindowDimensions';
const propTypes = {
/** Source URL for the preview image */
previewSourceURL: PropTypes.string.isRequired,
/** Any additional styles to apply */
// eslint-disable-next-line react/forbid-prop-types
style: PropTypes.any,
/** Whether the image requires an authToken */
isAuthTokenRequired: PropTypes.bool.isRequired,
/** Width of the thumbnail image */
imageWidth: PropTypes.number,
/** Height of the thumbnail image */
imageHeight: PropTypes.number,
};
const defaultProps = {
style: {},
imageWidth: 200,
imageHeight: 200,
};
/**
* Compute the thumbnails width and height given original image dimensions.
*
* @param {Number} width - Width of the original image.
* @param {Number} height - Height of the original image.
* @param {Number} windowHeight - Height of the device/browser window.
* @returns {Object} - Object containing thumbnails width and height.
*/
function calculateThumbnailImageSize(width, height, windowHeight) {
// Width of the thumbnail works better as a constant than it does
// a percentage of the screen width since it is relative to each screen
// Note: Clamp minimum width 40px to support touch device
let thumbnailScreenWidth = lodashClamp(width, 40, 250);
const imageHeight = height / (width / thumbnailScreenWidth);
let thumbnailScreenHeight = lodashClamp(imageHeight, 40, windowHeight * 0.4);
const aspectRatio = height / width;
// If thumbnail height is greater than its width, then the image is portrait otherwise landscape.
// For portrait images, we need to adjust the width of the image to keep the aspect ratio and vice-versa.
if (thumbnailScreenHeight > thumbnailScreenWidth) {
thumbnailScreenWidth = Math.round(thumbnailScreenHeight * (1 / aspectRatio));
} else {
thumbnailScreenHeight = Math.round(thumbnailScreenWidth * aspectRatio);
}
return {thumbnailWidth: Math.max(40, thumbnailScreenWidth), thumbnailHeight: Math.max(40, thumbnailScreenHeight)};
}
function ThumbnailImage(props) {
const {windowHeight} = useWindowDimensions();
const initialDimensions = calculateThumbnailImageSize(props.imageWidth, props.imageHeight, windowHeight);
const [imageWidth, setImageWidth] = useState(initialDimensions.thumbnailWidth);
const [imageHeight, setImageHeight] = useState(initialDimensions.thumbnailHeight);
/**
* Update the state with the computed thumbnail sizes.
*
* @param {{ width: number, height: number }} Params - width and height of the original image.
*/
const updateImageSize = useCallback(
({width, height}) => {
const {thumbnailWidth, thumbnailHeight} = calculateThumbnailImageSize(width, height, windowHeight);
setImageWidth(thumbnailWidth);
setImageHeight(thumbnailHeight);
},
[windowHeight],
);
return (
<View style={[props.style, styles.overflowHidden]}>
<View style={[StyleUtils.getWidthAndHeightStyle(imageWidth, imageHeight), styles.alignItemsCenter, styles.justifyContentCenter]}>
<ImageWithSizeCalculation
url={props.previewSourceURL}
onMeasure={updateImageSize}
isAuthTokenRequired={props.isAuthTokenRequired}
/>
</View>
</View>
);
}
ThumbnailImage.propTypes = propTypes;
ThumbnailImage.defaultProps = defaultProps;
ThumbnailImage.displayName = 'ThumbnailImage';
export default React.memo(ThumbnailImage);