Naughty Program Manipulator

    react-multi-cropper

    0.1.16-fabric • Public • Published

    React Multi Cropper

    A component for allowing multiple cropping regions on a single image, powered by fabric.

    build version size downloads

    WIP: Certain aspects are in development, and may be incomplete or buggy.
    It should be fine for most purposes.

    screenshot

    Installation

    yarn add react-multi-cropper fabric

    Development

    yarn install
    yarn start # in one terminal
    yarn serve # in another

    Then open http://localhost:3000 in your browser.
    If 3000 is occupied, the terminal output will show you what URL the serve command is serving on.

    Usage

    See the examples/index.tsx file.

    Functionality

    Draw rectangular regions on an image to obtain the selected area as a base64 encoded data URL.
    Multiple regions can be obtained by drawing multiple boxes.

    The component is responsive, so the image dimensions can use relative units (like %), and the cropping regions/rectangles should stay in place w.r.t. the image.

    The cropping logic is aware of the device pixel ratio, so you won't get blurry crops on a MacBook or phone.

    Documentation

    Default Usage

    const Cropper = ({ imageUrl }: { imageUrl: string ) => {
      const [boxes, setBoxes] = useState<CropperBox[]>([]);
      const [imageMap, setImageMap] = useState<CropperBoxDataMap>({});
    
      const updateBoxes = (_, __, _boxes) => setBoxes(_boxes);
    
      return (
        <div>
          <MultiCrops
            src={imageUrl}
            zoom={1}
            boxes={boxes}
            onChange={updateBoxes}
            onCrop={(e, map) => setImageMap(map)}
            onLoad={(map) => setImageMap(map)}
          />
          {boxes.map((box, i) =>
            !!imageMap[box.id] && <img src={imageMap[box.id]} key={i} />
          )}
        </div>
      );
    };

    How to reset zoom, rotation, and pan?

    In examples/index.tsx, you'll see an implementation of reset.

    const reset = () => {
      setRotation(0);
      setZoom(1);
      resetCenter();
    };

    setRotation, and setZoom are simple state setting functions obtained from a useState.
    resetCenter needs a few more lines.
    Note: Due to the current implementation, when resetting the component you must reset rotation before zoom to avoid bugs. It would be changed in the future to use a different update mechanism.

    The second argument of onLoad provides the reset handler. To call this from anywhere, you may want to assign this to a ref.

    // Initialize a ref to store the function
    const resetCenterRef = useRef(() => {});
    const resetCenter = resetCenterRef.current;
    
    // Call function anywhere
    resetCenter();
    
    // Obtain the function from onLoad
    onLoad={(map, reset) => {
      setImageMap(map);
      resetCenterRef.current = reset;
    }}

    Props for the MultiCrops component

    type CropperProps = {
      cropperRef?: MutableRefObject<fabric.Canvas | null>;
      src: string;
      zoom?: number;
      rotation?: number; // degrees
      cropScale?: number; // the scale of the resultant cropped images
      boxes: CropperBox[];
      onChange?: UpdateFunction;
      onDelete?: UpdateFunction;
      onBoxMouseEnter?: UpdateFunction;
      onBoxMouseLeave?: UpdateFunction;
      onBoxClick?: UpdateFunction;
      onLoad?: ImgOnLoadWithImageData;
      onCrop?: CropTriggerFunctionWithImageData;
      onZoomGesture?: (newZoom: number) => any;
      containerClassName?: string;
      containerStyles?: CSSProperties;
      imageStyles?: CSSProperties;
      cursorMode?: CropperCursorMode;
      disableKeyboard?: boolean;
      disableMouse?: {
        all?: boolean;
        zoom?: boolean;
        pan?: boolean;
        draw?: boolean;
      };
      boxInView?: { id?: string; rotate?: boolean; panInView?: boolean };
    };

    All the above types have been exported from the module.

    Notes:

    • The onLoad prop is optional, but useful for a few things.
      1. To determine that the image has indeed loaded, same as an img tag.
      2. Get access to the internal fabric object.
      3. To get a resetCenter handler to reset the panned position of the image.
    • You need to pass a function the onCrop prop if you want the default functionality to work out of the box. It will be called when a drawing operation was completed. This will be needed if you want to receive the image payload after a cropping action was done.
      • It is however optional, in case you want the box drawing to be controlled externally.
    • The function supplied to onCrop will be called when a drawing operation was completed. This will be needed if you want to receive the image payload after a cropping action was done.
      • The first argument is a CropperEvent event that tells you all you need to know about the event that was triggered to cause this function to fire.
      • The second argument is a dictionary of box.id's and their respective base64 encoded image contents.
    • Removed the ability to change a box after drawing it. The existing functionality was not stable enough to leave it, and leaving it in caused more issues than were manageable.
    • Mouse/Touchpad wheel to pan/zoom is supported. Example for wheel zoom is present in the examples/index.tsx.
    • Arrow Keys based pan/zoom is supported.
    • It would be advisable to memoize the functions passed to the component.
    • If you want to pass a box for reasons other than getting the imageData out of it, add the noImage: true key-val to it.

    Install

    npm i react-multi-cropper

    DownloadsWeekly Downloads

    264

    Version

    0.1.16-fabric

    License

    MIT

    Unpacked Size

    39.2 kB

    Total Files

    11

    Last publish

    Collaborators

    • jayantbh