• Scotland team
  • Author: Bigben

In the current front-end project, the picture function can be said to be very common, picture display, picture cutting and editing, picture uploading, so our project will come to a demand.

At present, we need a function to edit pictures freely in our project. When the pictures may be frequently edited and need to be fine-tuned when we find that the cutting is not satisfied, we will find that if we process pictures in accordance with common habits, such as uploading them to the server after cutting or transferring them to Base64, it does not meet the requirements. So what’s the best way to deal with it? How to solve application scenarios with as few network requests as possible and less storage usage? So, we came up with the idea of using only pure data to deal with our features.

First amway a map cutting artifact CropperJS, I think is an easy to use, configuration and API methods quite complete a component library.

Be sure not to leave out reference styles for in-project introductions

import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
Copy the code

Let’s take react as an example

This. state = {width: 640, // imgWidth: 640, // imgHeight: 360, // ImgTop: 0, // editing:false} // Show the basic dom structure of the image, we use the outer div and the inner img form, {width, height, imgWidth, imgHeight, imgLeft, imgTop, editing} = this.state; const containerStyle = { width: `${width}px`,
  height: `${height}px`
}
const imgStyle = {
  width: `${imgWidth}px`,
  height: `${imgHeight}px`,
  left: `${imgLeft}px`,
  top: `${imgTop}px`
}

.img-container {
  overflow: hidden;
  position: relative;
}

.crop-img {
  position: absolute;
  left: 0;
  top: 0;
}
<div 
  className="img-container" 
  style={containerStyle}
>
  <img 
    className="crop-img"
    src={picture} 
    style={imgStyle} 
    alt="pic"
  ></img>
</div>
Copy the code

In simple terms, the outer element controls the width and height of the cropping display, while the element positioning based on project requirements is also hung here. The inner IMG mounts the actual size and offset of the image.

Cropperjs initializes the element at the same DOM level as the img object, which means that if we initialize the display IMG directly, the edit area display will be affected by the parent element, as shown in the image, and we will not be able to see beyond the image when zooming in

Therefore, for the freedom of image editing, it is recommended to display DOM separately from the DOM used to initialize cropper objects. For example, the editing area here is the full screen, which can be adjusted according to the actual functional area of the project

.edit-container {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}

<div 
  className="img-container" 
  style={containerStyle}
>
  <img 
    className="crop-img"
    src={picture} 
    style={imgStyle} 
    alt="pic"></img> </div> //cropper initializes this.myref = react.createref (); this.myCropper = new Cropper(this.myRef.current, options); //options configures const options = {dragMode:'move'// Enable the image to drag background while cropping:false} // There are also many common configuration items, such as edit box size ratio, etc., you can check the API by yourself // crop savesave() { const cropBoxData = this.myCropper.getCropBoxData(); / / data for cutting box const canvasData = this. MyCropper. GetCanvasData (); This. setState({width: cropboxData. width, height: cropboxData. height, imgLeft: canvasData.left - cropBoxData.left, imgTop: canvasData.top - cropBoxData.top, imgWidth: canvasData.width, imgHeight: canvasData.height }) }Copy the code

This way we can edit completely in the custom full screen, save as follows, we have finished the first part of the function, crop and save the data and display

Let’s focus on the two API methods we use getCropBoxData and getCanvasData. GetCanvasData is used to get the actual data of the image (the current width and height, and the offset of the visible area relative to the parent element). GetCropBoxData gets clipped data relative to the image region.

How can we restore the effect of the second edit? Well, in fact, when we record the clipping data, we can calculate the corresponding data relationship again, and add the configuration in the initialization options of cropper

const options = {
dragMode: 'move',
background: falseReady: () => {const {width, height, imgWidth, imgHeight, imgLeft, imgTop} = this.state; Const left = 50; const left = 50; const top = 50; this.myCropper.setCanvasData({ width: imgWidth, height: imgHeight, left: left, top: top }); this.myCropper.setCropBoxData({ left: left - imgLeft, top: top - imgTop, width: width, height: height }) } } this.myCropper = new Cropper(this.myRef.current, options);Copy the code

At this time, we click the clipping picture again, and it will be restored perfectly. The gaps on the left and top are the top and left of setCanvasData. According to the actual project, the left and top of setCropBoxData are relative to the positioning of Croper-Canvas, so the above calculation form is created.

At this point, the basic function ends here, if it is applied in H5 edit, design to scale, relevant data calculation should be scale value oh, otherwise there will be a display picture and edit picture size is not equal to the situation. At the same time there are many functions will not do the demonstration, set the clipping box proportion, edit zoom and so on, welcome to try.

Of course, if you want to save the image, there are ways to crop the image data everywhere

this.myCropper.getCroppedCanvas().toDataURL('image/jpeg')
Copy the code

Finally, we can see that in the whole function process, we only need to cut data, read and write fast, also do not need to carry out additional picture storage, reduce the overhead of file server storage and optimization.

Cropperjs github:github.com/fengyuanche…

Thanks for watching, and welcome to our discussion and corrections.