import Cropper from "react-easy-crop"; import { useState, useCallback, useRef } from "react"; import Slider from "./Slider"; export default function ImageUploader({target, id, buttonMsg, handleAvatarChange, imageRef}){ const imageFileRef = useRef(); const [imageDataUrl, setImageDataUrl] = useState(); const [croppedAreaPixels, setCroppedAreaPixels] = useState(); const [rotation] = useState(1); const [crop, setCrop] = useState({ x: 0, y: 0 }); const [zoom, setZoom] = useState(1); const [imageLoaded, setImageLoaded] = useState(false); const [isImageShown, setIsImageShown] = useState(false); const [shownImage, setShownImage] = useState(); const [imageUploadModalOpen, setImageUploadModalOpen] = useState(false); const openUploaderModal = () => { imageRef ? (setIsImageShown(true), setShownImage(imageRef)) : setIsImageShown(false); setImageUploadModalOpen(!imageUploadModalOpen) } const closeImageUploadModal = () => { setImageUploadModalOpen(false); }; async function ImageUploadHandler() { const img = await readFile(imageFileRef.current.files[0]); setImageDataUrl(img); CropHandler(); } const readFile = (file) => { return new Promise((resolve) => { const reader = new FileReader(); reader.addEventListener('load', () => resolve(reader.result), false); reader.readAsDataURL(file) }) } const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => { setCroppedAreaPixels(croppedAreaPixels); }, []) const CropHandler = () => { setCrop({ x: 0, y: 0 }); setZoom(1); setImageLoaded(true); } const handleZoomSliderChange = ([value]) => { value < 1 ? setZoom(1) : setZoom(value); // setZoom(e[0]); } const createImage = (url) => new Promise((resolve, reject) => { const image = new Image(); image.addEventListener('load', () => resolve(image)); image.addEventListener('error', error => reject(error)); image.setAttribute('crossOrigin', 'anonymous'); // needed to avoid cross-origin issues on CodeSandbox image.src = url; }) function getRadianAngle(degreeValue) { return (degreeValue * Math.PI) / 180; } async function getCroppedImg(imageSrc, pixelCrop, rotation = 0) { const image = await createImage(imageSrc); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const maxSize = Math.max(image.width, image.height); const safeArea = 2 * ((maxSize / 2) * Math.sqrt(2)); // set each dimensions to double largest dimension to allow for a safe area for the // image to rotate in without being clipped by canvas context canvas.width = safeArea; canvas.height = safeArea; // translate canvas context to a central location on image to allow rotating around the center. ctx.translate(safeArea / 2, safeArea / 2); ctx.rotate(getRadianAngle(rotation)); ctx.translate(-safeArea / 2, -safeArea / 2); // draw rotated image and store data. ctx.drawImage( image, safeArea / 2 - image.width * 0.5, safeArea / 2 - image.height * 0.5 ); const data = ctx.getImageData(0, 0, safeArea, safeArea); // set canvas width to final desired crop size - this will clear existing context canvas.width = pixelCrop.width; canvas.height = pixelCrop.height; // paste generated rotate image with correct offsets for x,y crop values. ctx.putImageData( data, Math.round(0 - safeArea / 2 + image.width * 0.5 - pixelCrop.x), Math.round(0 - safeArea / 2 + image.height * 0.5 - pixelCrop.y) ); // As Base64 string return canvas.toDataURL('image/jpeg'); } const showCroppedImage = useCallback(async () => { try { const croppedImage = await getCroppedImg( imageDataUrl, croppedAreaPixels, rotation ) setIsImageShown(true) setShownImage(croppedImage) setImageLoaded(false) handleAvatarChange(croppedImage) closeImageUploadModal() } catch (e) { console.error(e) } }, [croppedAreaPixels, rotation]); return (
{ imageUploadModalOpen &&
{!imageLoaded &&
{!isImageShown &&

No {target}

} {isImageShown && {target} }
} {imageLoaded &&
}
}
) }