All files / src/components/AvatarUpload/modal/hooks useImageCropper.ts

85.29% Statements 29/34
69.23% Branches 9/13
77.77% Functions 7/9
87.5% Lines 28/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104                                  1x             1x                             33x   33x 33x   33x   33x 16x 16x   16x 16x   16x     33x 14x 14x 14x     33x 14x 14x     33x         33x                 33x 2x 2x     33x                         1x 16x 16x    
import { isArray } from "lodash";
import { useRef, useState } from "react";
import { ReactCropperElement } from "react-cropper";
 
interface StateType {
  zoom: number;
  rotation: number;
  croppedAreaPixels: any;
  file: File | null;
}
 
type TZoomParams = {
  minZoom: number;
  maxZoom: number;
  step: number;
};
 
const initialState: StateType = {
  zoom: 0,
  rotation: 0,
  croppedAreaPixels: null,
  file: null,
};
 
const useImageCropper = (
  zoomParams: TZoomParams,
  handleUpdateImage: (
    url: HTMLCanvasElement,
    data?: {
      x?: string | number;
      y?: string | number;
      width?: string | number;
      height?: string | number;
      rotate?: string | number;
      scaleX?: string | number;
      scaleY?: string | number;
    },
  ) => void,
) => {
  const { minZoom, maxZoom, step } = zoomParams;
 
  const cropperRef = useRef<ReactCropperElement>(null);
  const [{ zoom, rotation }, setCustomize] = useState<StateType>(initialState);
 
  const zoomValue = Math.round((zoom / maxZoom) * 100);
 
  const handleZoomCanvas = (zoom: number) => {
    const cropper = cropperRef.current?.cropper;
    Iif (!cropper) return;
 
    const scale = normalizeScale(zoom);
    cropper.scale(scale);
 
    setCustomize((p) => ({ ...p, zoom }));
  };
 
  const getNewZoomValue = (value: number, isAdd: boolean) => {
    const addValue = value + step >= maxZoom ? maxZoom : value + step;
    const subtractValue = value - step <= minZoom ? minZoom : value - step;
    return isAdd ? addValue : subtractValue;
  };
 
  const handleZoom = (isAdd = false) => {
    const newValue = getNewZoomValue(zoom, isAdd);
    handleZoomCanvas(newValue);
  };
 
  const rotate = () => {
    const cropper = cropperRef.current?.cropper;
    cropper?.rotate(-90);
  };
 
  const getCropData = () => {
    if (typeof cropperRef.current?.cropper !== "undefined") {
      handleUpdateImage(
        cropperRef.current?.cropper.getCroppedCanvas(),
        cropperRef.current?.cropper?.getData(),
      );
    }
  };
 
  const handleUpdateSlider = (event: Event, zoom: number | number[]) => {
    const newZoomValue = isArray(zoom) ? zoom[0] : zoom;
    handleZoomCanvas(newZoomValue);
  };
 
  return {
    cropperRef,
    handleUpdateSlider,
    getCropData,
    rotate,
    handleZoom,
    zoomValue,
    rotation,
  };
};
 
export default useImageCropper;
 
const normalizeScale = (zoom: number) => {
  const newVal = Math.min(100, Math.max(0, zoom));
  return 1 + newVal / 100;
};