Skip to content

Commit

Permalink
Add aspectRatio to ProductSummaryImage
Browse files Browse the repository at this point in the history
  • Loading branch information
iaron committed Feb 4, 2020
1 parent f0cc795 commit 9f0334a
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 15 deletions.
63 changes: 48 additions & 15 deletions react/components/ProductSummaryImage/ProductImage.js
Expand Up @@ -13,9 +13,13 @@ import { useProductSummary } from 'vtex.product-summary-context/ProductSummaryCo
import productSummary from '../../productSummary.css'

import { changeImageUrlSize } from '../../utils/normalize'
import { imageUrl } from '../../utils/aspectRatioUtil'

const CSS_HANDLES = ['image', 'imageContainer', 'product', 'imagePlaceholder']

const MAX_SIZE = 300
const DEFAULT_SIZE = 200

const maybeBadge = ({ listPrice, price, label }) => shouldShow => component => {
if (shouldShow) {
return (
Expand Down Expand Up @@ -46,7 +50,38 @@ const findImageByLabel = (images, selectedLabel) => {
return images.find(({ imageLabel }) => imageLabel === selectedLabel)
}

const Image = ({ src, width, height, onError, alt, className }) => {
const getImageSrc = (src, width, height, dpi, aspectRatio) => {
if (width || height) {
return changeImageUrlSize(src, width * dpi, height * dpi)
} else if (aspectRatio !== 'auto' && width) {
return imageUrl(src, width, MAX_SIZE, aspectRatio)
} else {
return src
}
}

const getStyle = (width, height, aspectRatio, maxHeight) => {
if (width && height) {
return {
width: '100%',
height,
objectFit: 'contain',
maxHeight: 'unset',
maxWidth: width,
}
} else if (aspectRatio !== 'auto' && width) {
return {
width: '100%',
height: '100%',
objectFit: 'contain',
maxHeight: maxHeight || 'unset',
}
} else {
return null
}
}

const Image = ({ src, width, height, onError, alt, className, aspectRatio, maxHeight }) => {
const { isMobile } = useDevice()

const dpi = window.devicePixelRatio || (isMobile ? 2 : 1)
Expand All @@ -55,20 +90,8 @@ const Image = ({ src, width, height, onError, alt, className }) => {

return (
<img
src={
shouldResize ? changeImageUrlSize(src, width * dpi, height * dpi) : src
}
style={
shouldResize
? {
width: '100%',
height,
objectFit: 'contain',
maxHeight: 'unset',
maxWidth: width,
}
: null
}
src = { getImageSrc(src, width, height, dpi, aspectRatio) }
style={ getStyle(width, height, aspectRatio, maxHeight) }
loading={shouldResize ? 'lazy' : 'auto'}
alt={alt}
className={className}
Expand All @@ -89,6 +112,8 @@ const ProductImageContent = ({
showCollections,
width: widthProp,
height: heightProp,
aspectRatio,
maxHeight,
}) => {
const { productClusters, productName: name } = product || {}

Expand Down Expand Up @@ -168,6 +193,8 @@ const ProductImageContent = ({
src={imageUrl}
width={width}
height={height}
aspectRatio={aspectRatio}
maxHeight={maxHeight}
alt={name}
className={imageClassname}
onError={onError}
Expand All @@ -177,6 +204,8 @@ const ProductImageContent = ({
src={hoverImage.imageUrl}
width={width}
height={height}
aspectRatio={aspectRatio}
maxHeight={maxHeight}
alt={name}
className={hoverImageClassname}
onError={onError}
Expand All @@ -200,6 +229,8 @@ const ProductImage = ({
showCollections,
width: widthProp,
height: heightProp,
aspectRatio,
maxHeight,
}) => {
const { product } = useProductSummary()

Expand All @@ -219,6 +250,8 @@ const ProductImage = ({
<ProductImageContent
width={width}
height={height}
aspectRatio={aspectRatio}
maxHeight={maxHeight}
hasError={error}
product={product}
badgeText={badgeText}
Expand Down
62 changes: 62 additions & 0 deletions react/utils/aspectRatioUtil.js
@@ -0,0 +1,62 @@
import { changeImageUrlSize } from './normalize'


/** Parses ratio values into a multiplier to set the image height.
* For example, turns "3:4" into 1.333, so the image height will be
* 1.333 times its width.
*/
const parseAspectRatio = (input) => {
if (!input) {
return null
}
if (typeof input === 'string') {
if (input === 'auto') {
return null
}
const separator = ':'
const data = input.split(separator)
if (data.length !== 2) {
return null
}

const [ width, height ] = data
const ratio = parseFloat(height) / parseFloat(width)

if (typeof ratio !== 'number' || isNaN(ratio)) {
return null
}

return ratio
}

if (typeof input === 'number') {
return input
}

return null
}

export const imageUrl = (src, size, maxSize, aspectRatio) => {
let width = size
let height = 'auto'

if (aspectRatio && aspectRatio !== 'auto') {
height = size * (parseAspectRatio(aspectRatio) || 1)

if (width > maxSize) {
height = height / (width / maxSize)
width = maxSize
}

if (height > maxSize) {
width = width / (height / maxSize)
height = maxSize
}

width = Math.round(width)
height = Math.round(height)
} else {
width = Math.min(maxSize, width)
}
return changeImageUrlSize(src, width, height)
}

0 comments on commit 9f0334a

Please sign in to comment.