From 3fef7795681c405322aed6e1c876948ebc2cc932 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 29 Oct 2020 23:53:13 +0300 Subject: refactor: separate ImageCropAreaSelect component --- src/containers/AvatarCropModal/AvatarCropModal.tsx | 57 ++++++++++++++++++++++ src/containers/AvatarCropModal/canvasUtils.js | 54 ++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 src/containers/AvatarCropModal/AvatarCropModal.tsx create mode 100644 src/containers/AvatarCropModal/canvasUtils.js (limited to 'src/containers/AvatarCropModal') diff --git a/src/containers/AvatarCropModal/AvatarCropModal.tsx b/src/containers/AvatarCropModal/AvatarCropModal.tsx new file mode 100644 index 0000000..a24d2b4 --- /dev/null +++ b/src/containers/AvatarCropModal/AvatarCropModal.tsx @@ -0,0 +1,57 @@ +import React, { useState } from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import SendIcon from "@material-ui/icons/Send"; +import { getCroppedImg } from './canvasUtils' + +import ImageCropAreaSelect from '../../components/ImageCropAreaSelect/ImageCropAreaSelect'; +import ModalScreen from '../../components/ModalScreen/ModalScreen'; + +interface Area { + x: number; + y: number; + width?: number; + height?: number; +} + +interface PropTypes { + avatar: string; + callback: (file: File) => void; +} + +const useStyles = makeStyles(theme => ({ + cropContainer: { + position: 'relative', + width: '100%', + height: '100vh', + background: '#333', + [theme.breakpoints.up('sm')]: { + height: 400, + }, + } +})); + +const AvatarCropModal: React.FC = ({ avatar, callback }) => { + const classes = useStyles(); + const [area, setArea] = useState({ x: 0, y: 0 }); + + const handleAction = async () => getCroppedImg(avatar, area) + .then(croppedImage => callback(croppedImage)); + + return ( + } + handleAction={handleAction} + isActionDisabled={false} + > +
+ +
+
+ ) +}; + +export default AvatarCropModal; diff --git a/src/containers/AvatarCropModal/canvasUtils.js b/src/containers/AvatarCropModal/canvasUtils.js new file mode 100644 index 0000000..b01aadc --- /dev/null +++ b/src/containers/AvatarCropModal/canvasUtils.js @@ -0,0 +1,54 @@ +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 + }); + +export async function getCroppedImg(imageSrc, pixelCrop) { + 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.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'); + + // As a blob + + return new Promise(resolve => { + canvas.toBlob(file => resolve(file)) + }) +} -- cgit v1.2.3 From 99b4e4aa53d3ade389fc270f9ba9b02904da93f6 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Tue, 17 Nov 2020 15:19:39 +0300 Subject: Make responsive avatar crop component --- src/containers/AvatarCropModal/AvatarCropModal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/containers/AvatarCropModal') diff --git a/src/containers/AvatarCropModal/AvatarCropModal.tsx b/src/containers/AvatarCropModal/AvatarCropModal.tsx index a24d2b4..4decdfb 100644 --- a/src/containers/AvatarCropModal/AvatarCropModal.tsx +++ b/src/containers/AvatarCropModal/AvatarCropModal.tsx @@ -22,10 +22,10 @@ const useStyles = makeStyles(theme => ({ cropContainer: { position: 'relative', width: '100%', - height: '100vh', - background: '#333', + // height: '100vh', + // background: '#333', [theme.breakpoints.up('sm')]: { - height: 400, + // height: 400, }, } })); -- cgit v1.2.3