Skip to content

Commit

Permalink
Fix(web-react): Recalculate FileUploader image preview by crop values
Browse files Browse the repository at this point in the history
  * need to use additional dimensions - natural width and height to
    calculate dimensions of previewed image
  * also need to better calculate the scale of the entire image and also
    position when we need to display the possible crop

refs #DS-1038
  • Loading branch information
literat committed Nov 2, 2023
1 parent 1e23f86 commit 68321dc
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 21 deletions.
4 changes: 2 additions & 2 deletions packages/web-react/src/components/FileUploader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,13 +329,13 @@ const customUpdate = (_event: MouseEvent, file: File) => {
#### Updating Image Preview with cropped image

When you are using FileUploader with some kind of image cropper you want to also update the image preview on FileUploaderAttachment when image changes.
You can do this by passing a specific object in shape of coordinates (`{ x: number, y: number, width: number, height: number }`) to the `meta` argument.
You can do this by passing a specific object in shape of coordinates (`{ x: number, y: number, cropWidth: number, cropHeight: number, originalWidth: number, originalHeight: number }`) to the `meta` argument.
Then the coordinates will be applied to the preview image in the attachment.

```javascript
//
const customUpdate = (_event: MouseEvent, file: File) => {
const meta = { x: 30, y: 30, width: 150, height: 150 };
const meta = { x: 30, y: 30, cropWidth: 150, cropHeight: 150, originalWidth: 560, originalHeight: 330 };

return updateQueue(file.name, file, meta);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ describe('useFileUploaderStyleProps', () => {
it('should have CSS for crop image', () => {
const { result } = renderHook(() =>
useFileUploaderStyleProps({
meta: { x: 1, y: 2, width: 3, height: 4 },
meta: { x: 0, y: 0, cropWidth: 100, cropHeight: 100, originalWidth: 350, originalHeight: 200 },
}),
);

expect(result.current.classProps.imageCropStyles).toBeDefined();
expect(result.current.classProps.imageCropStyles).toStrictEqual({
'--file-uploader-attachment-image-height': '4px',
'--file-uploader-attachment-image-left': '-1px',
'--file-uploader-attachment-image-top': '-2px',
'--file-uploader-attachment-image-width': '3px',
'--file-uploader-attachment-image-height': '108px',
'--file-uploader-attachment-image-left': '-0px',
'--file-uploader-attachment-image-top': '-0px',
'--file-uploader-attachment-image-width': '189px',
});
});
});
3 changes: 2 additions & 1 deletion packages/web-react/src/components/FileUploader/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const DEFAULT_FILE_SIZE_LIMIT = 10000000; // = 10 MB
export const DEFAULT_FILE_QUEUE_LIMIT = 10;
export const IMAGE_DIMENSION = 54; // px
export const IMAGE_DIMENSION = 54; // px; @see: CSS class `.FileUploaderAttachment__image` in _FileUploaderAttachment.scss
export const IMAGE_PREVIEW_BASE64_MAX_WIDTH = 500; // px

export const DEFAULT_ERROR_MESSAGE_MAX_FILE_SIZE = 'The file size limit has been exceeded';
export const DEFAULT_ERROR_MESSAGE_QUEUE_DUPLICITY = 'This file already exists in the queue';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useState, MouseEvent } from 'react';
import React, { MouseEvent, useState } from 'react';
import { FileUploader, FileUploaderAttachment, FileUploaderInput, FileUploaderList, useFileQueue } from '..';
import { SpiritFileUploaderAttachmentProps } from '../../../types';
import { Button } from '../../Button';
import { Modal, ModalDialog, ModalBody, ModalFooter } from '../../Modal';
import { FileUploader, FileUploaderAttachment, FileUploaderInput, FileUploaderList, useFileQueue } from '..';
import { Modal, ModalBody, ModalDialog, ModalFooter } from '../../Modal';

const FileUploaderMetaData = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
Expand Down Expand Up @@ -34,7 +34,9 @@ const FileUploaderMetaData = () => {
};

const customUpdate = (_event: MouseEvent, file: File) => {
const newMeta = toggleMeta ? { x: 30, y: 30, width: 150, height: 150 } : { x: 22, y: 0, width: 110, height: 100 };
const newMeta = toggleMeta
? { x: 30, y: 30, cropWidth: 150, cropHeight: 150, originalWidth: 560, originalHeight: 330 }
: { x: 22, y: 0, cropWidth: 110, cropHeight: 100, originalWidth: 560, originalHeight: 330 };

setIsModalOpen(false);
setToggleMeta(!toggleMeta);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { CSSProperties } from 'react';
import classNames from 'classnames';
import { CSSProperties } from 'react';
import { FileUploaderCropCSS } from '../../constants/dictionaries';
import { useClassNamePrefix } from '../../hooks';
import { FileMetadata, FileUploaderQueueLimitBehaviorType, Validation } from '../../types';
import { IMAGE_DIMENSION } from './constants';

export interface FileUploaderStyleProps extends Validation {
imageObjectFit?: 'contain' | 'cover';
Expand All @@ -28,6 +29,15 @@ type ImageObjectFit = {
'--file-uploader-attachment-image-object-fit': string;
};

type ImageCropMeta = {
x: number;
y: number;
cropWidth: number;
cropHeight: number;
originalWidth: number;
originalHeight: number;
};

export interface FileUploaderStyleReturn {
/** className props */
classProps: {
Expand Down Expand Up @@ -88,16 +98,32 @@ export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileU
const { meta, imageObjectFit } = props || {};
let imageCropCSS: ImageCropCSS | undefined;
let imageObjectFitCSS: ImageObjectFit | undefined;
const hasCoords = meta && meta.x != null && meta.y != null && meta.width != null && meta.height != null;
const hasCoordsInMeta =
meta != null &&
['x', 'y', 'cropWidth', 'cropHeight', 'originalWidth', 'originalHeight'].every((coord) => meta[coord] != null);

if (hasCoordsInMeta) {
const { x, y, cropWidth, cropHeight, originalWidth, originalHeight } = meta as ImageCropMeta;
const previewHeight = IMAGE_DIMENSION;
let scale;
if (cropHeight > cropWidth) {
// scale for portrait images
scale = previewHeight / cropWidth;
} else {
// scale for landscape images
scale = previewHeight / cropHeight;
}

if (hasCoords) {
const { x, y, width, height } = meta;
const cropX = Math.round(x * scale);
const cropY = Math.round(y * scale);
const imageWidth = Math.round(originalWidth * scale);
const imageHeight = Math.round(originalHeight * scale);

imageCropCSS = {
[FileUploaderCropCSS.TOP]: `-${y}px`,
[FileUploaderCropCSS.LEFT]: `-${x}px`,
[FileUploaderCropCSS.WIDTH]: `${width}px`,
[FileUploaderCropCSS.HEIGHT]: `${height}px`,
[FileUploaderCropCSS.TOP]: `-${cropY}px`,
[FileUploaderCropCSS.LEFT]: `-${cropX}px`,
[FileUploaderCropCSS.WIDTH]: `${imageWidth}px`,
[FileUploaderCropCSS.HEIGHT]: `${imageHeight}px`,
};
}

Expand Down Expand Up @@ -141,7 +167,7 @@ export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileU
image: fileUploaderAttachmentImageClass,
slot: fileUploaderAttachmentSlotClass,
},
...(hasCoords && { imageCropStyles: imageCropCSS }),
...(hasCoordsInMeta && { imageCropStyles: imageCropCSS }),
...(imageObjectFit && { attachmentStyles: imageObjectFitCSS }),
},
};
Expand Down

0 comments on commit 68321dc

Please sign in to comment.