Skip to content

Instantly share code, notes, and snippets.

@chy4egg
Created March 5, 2020 07:40
Show Gist options
  • Save chy4egg/7c21a85ecace2ba9643aa40c89e3d081 to your computer and use it in GitHub Desktop.
Save chy4egg/7c21a85ecace2ba9643aa40c89e3d081 to your computer and use it in GitHub Desktop.
An example of image uploader and cropper written on react
import React, { useCallback, useState, useRef } from 'react'
import { useDropzone } from 'react-dropzone'
import styles from './ImageUploader.module.scss';
import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';
import axios from 'axios';
import { Button } from 'components/buttons/button/Button';
import { DialogWindow } from 'components/dialogWindow/DialogWindow';
import { optimizeImage } from './helpers/optimizeImage';
export interface IImageUploaderProps {
onChange: (url: string) => void
url: string
size: { width: number, height: number }
aspectRatio?: number // (16 / 9)
}
const UPDATE_IMG_URL = 'api/some_api_method_url';
/**
* Компонент-виджет для загрузки и обрезки изображений
* @param props
*/
export const ImageUploader: React.FC<IImageUploaderProps> = (props) => {
const onDrop = useCallback(acceptedFiles => {
const reader = new FileReader();
const aImage = acceptedFiles[0];
reader.readAsDataURL(aImage);
reader.addEventListener("load", (e) => {
const base64url = reader.result;
setPreview(base64url);
setIsModalOpen(true);
}, false);
}, [])
// в useDropzone есть доп. параметры. См. документацию
const { getRootProps, getInputProps } = useDropzone({ onDrop })
let cropperRef = useRef(null) as any;
const [loading, setLoading] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [preview, setPreview] = useState<any>(undefined);
const [initialUrl] = useState<any>(props.url);
const aspectRatio = +props.size.width / +props.size.height;
const handleRemoveImg = (event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
event.stopPropagation();
setPreview(undefined);
props.onChange(initialUrl)
}
const handleCrop = () => {
const cropper = cropperRef.current;
if (cropper) {
const canvas = cropper.getCroppedCanvas();
canvas.toBlob((blob: Blob) => {
setLoading(true);
optimizeImage(blob, props.size.width, props.size.height)
.then((optimizedBlob) => {
props.onChange(URL.createObjectURL(optimizedBlob));
})
});
}
}
const handleOpenModal = (event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
event.stopPropagation();
setIsModalOpen(true)
}
return (
<>
<div {...getRootProps()}>
<input {...getInputProps()} />
<div className={styles.wrapper}>
<div className={styles.imageNameField}>
<img className={styles.image} src={props.url} alt={props.url}/>
</div>
<div>
{preview &&
<span className={styles.crop} onClick={handleOpenModal}>обрезать</span>
}
{preview &&
<span className={styles.remove} onClick={handleRemoveImg}>удалить</span>
}
</div>
</div>
</div>
<DialogWindow
paperWidth="1024px"
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
>
<>
<Cropper
ref={cropperRef}
src={preview && preview}
style={{ height: 600, width: '100%' }}
aspectRatio={aspectRatio}
guides={false}
/>
<div className={styles.cropBtnWrapper}>
<Button onClick={handleCrop} styleClass={'blue'} loading={loading}>Обрезать</Button>
</div>
</>
</DialogWindow>
</>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment