Search code examples
javascriptimagereactjscrop

CropperJS incorrect scaling canvas after browser resize



I'm using ReactCropper witch uses CropperJs. I'm using crop and rotate functions. I got a problem with the responsive feature. When resizing browser to smaller and then to bigger size image becomes too big (like much scaled). Here is uploaded image, as you see it is not centered, but main problem is not in that.
enter image description here

Here resizing the browser
enter image description here

And after making browser window bigger again, the image is shifted and scaled. enter image description here

I'm using such options for configure Cropper:

            <Cropper
                    ref='cropper'
                    src={image}
                    style={{height: '100%', width: '100%'}}
                    background={false}
                    viewMode={1}
                    zoomOnTouch={false}
                    zoomOnWheel={false}
                    aspectRatio={1}
                    guides={false}
                    restore={true}
                />

When I delete viewMode={1} there are no scaling or shifting issues but crop-box is moving over all container (I don't need such crop-box-behaviour, I need it be moving inside image).

Any ideas what is the problem?

Thank's for any help


Solution

  • So,

    for now, I found such solution as manual updating size and position of the image

    1) Configuration of the cropper:

     <Cropper
                        ref='cropper'
                        src={image}
                        style={{height: '100%', width: '100%'}}
                        viewMode={1}
                        background={false}
                        aspectRatio={1}
                        guides={false}
                        dragMode="none"
                        movable={false}
                        zoomable={false}
                        minCanvasWidth={320}
                        minCanvasHeight={320}
                        minCropBoxWidth={160}
                        minCropBoxHeight={160}
                        checkOrientation={true}
                        restore={true}
                        autoCropArea={0.5}
                    />
    

    2) Bind listener to window resize event and perform an action of updating canvas size and centering the image. I need updating canvas size because image should be smaller than window size in my case.

    Here is updating the canvas size:

        updateCanvasSize() {
        let koef = 0.9, // how smaller than window viewport image should be
            container = this.refs.cropper.getContainerData(),
            allowedSize = Math.min(container.width, container.height) * koef,
            image = this.refs.cropper.getImageData(),
            imgW = Math.round(image.width),
            imgH = Math.round(image.height),
            originalW = Math.round(image.naturalWidth),
            originalH = Math.round(image.naturalHeight),
            newH, newW, scale = 1;
    
        if (Math.abs((this.degrees / 90) % 2) > 0) { //if image was rotated
            let t = imgW;
            imgW = imgH;
            imgH = t;
        }
    
        if (allowedSize < imgH || imgW > allowedSize) {
            if (imgW > imgH) {
                scale = allowedSize / imgW;
                if (imgH * scale > allowedSize) {
                    scale = allowedSize / imgH;
                }
            }
            else {
                scale = allowedSize / imgH;
                if (imgW * scale > allowedSize) {
                    scale = allowedSize / imgW;
                }
            }
        }
    
        newW = Math.round(scale * imgW);
        newH = Math.round(scale * imgH);
    
    /* this part is needed if you want to keep size of small images */
            if (Math.abs((this.degrees / 90) % 2) > 0) {
                if (newW >= originalH && newH >= originalW) {
                    newW = originalH;
                    newH = originalW;
                }
            } else {
                if (newW >= originalW && newH >= originalH) {
                    newW = originalW;
                    newH = originalH;
                }
            }
    /* end */
    
        this.refs.cropper.setCanvasData({
            width: newW,
            height: newH
        });
    }
    

    And the centering inside the window:

     centerImage() {
            let container = this.refs.cropper.getContainerData(),
                canvas = this.refs.cropper.getCanvasData(),
                height = canvas.height,
                width = canvas.width;
    
            let top = Math.abs((container.height - height) / 2),
                left = Math.abs((container.width - width) / 2);
    
            this.refs.cropper.setCanvasData({
                top,
                left
            });
        }
    

    Also, I'm using this update after image rotation.

    Hope, it helps