Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize the function of Mobile Image clipping component based on Vue

2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)05/31 Report--

Today, the editor will share with you the relevant knowledge points about how to achieve the mobile image clipping component based on Vue. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article. Let's take a look at it.

Let's see the effect first:

I. initialization parameters of the component

1. Picture img (url or base64 data-url)

2. Wide clipperImgWidth of screenshot

3. High clipperImgHeight of screenshot

Props: {img: String, / / url or dataUrl clipperImgWidth: {type: Number, default: 500}, clipperImgHeight: {type: Number, default: 200}}

II. Layout

In the direction of Z axis, it is mainly composed of four layers. The first layer is a canvas that occupies the entire container (called cCanvas); the second layer is a transparent mask layer; the third layer is the cropped area (the white box in the example figure), which contains a canvas equal to the size of the cropping region (called pCanvas); and the fourth layer is a transparent layer gesture-mask, which is used to bind touchstart,touchmove,touchend events. Both of the canvas will load the same image, but the starting coordinates are different. Why do I need two canvas? Because you want to make the effect of a mask layer on the part of the surface outside the crop region when the finger leaves the screen, which highlights the contents of the crop region.

Cancel confirmation

Initialize canvas

The picture drawn by canvas will appear blurred on the hdpi display screen, the specific reason is not analyzed here, you can refer to here. What I'm doing here is to multiply the width and height of canvas by devicePixelRatio times its css width/height, and multiply the parameters passed in when calling canvas api by window.devicePixelRatio. Finally, record the x, y difference (originXDiff and originYDiff) of the two canvas coordinate origins. As follows

_ ratio (size) {return parseInt (window.devicePixelRatio * size);}, _ initCanvas () {let $canvas = this.$refs.canvas, $pCanvas = this.$refs.pCanvas, clipperClientRect = this.$refs.clipper.getBoundingClientRect (), clipperWidth = parseInt (this.clipperImgWidth / window.devicePixelRatio), clipperHeight = parseInt (this.clipperImgHeight / window.devicePixelRatio); this.ctx = $canvas.getContext ('2d'); this.pCtx = $pCanvas.getContext (' 2d') / / determine whether clipperWidth and clipperHeight exceed the container value if (clipperWidth)

< 0 || clipperWidth >

ClipperClientRect.width) {clipperWidth = 250} if (clipperHeight

< 0 || clipperHeight >

ClipperClientRect.height) {clipperHeight = 100} / / because the canvas will be magnified on the phone, so the contents will be blurred. Here, enlarge the canvas according to the phone's devicePixelRatio, and then shrink by setting css, so all values or coordinates about canvas should be multiplied by devicePixelRatio $canvas.style.width + 'px'; $canvas.style.height = clipperClientRect.height +' px'; $canvas.width = this._ratio (clipperClientRect.width). $canvas.height = this._ratio (clipperClientRect.height); $pCanvas.style.width = clipperWidth + 'px'; $pCanvas.style.height = clipperHeight +' px'; $pCanvas.width = this._ratio (clipperWidth); $pCanvas.height = this._ratio (clipperHeight); / / calculate the x y difference between the two canvas origins let cClientRect = $canvas.getBoundingClientRect (), pClientRect = $pCanvas.getBoundingClientRect (); this.originXDiff = pClientRect.left-cClientRect.left; this.originYDiff = pClientRect.top-cClientRect.top This.cWidth = cClientRect.width; this.cHeight = cClientRect.height;}

4. Load pictures

Loading a picture is relatively simple, first creating an Image object and listening for the onload event (because the loaded image may be cross-domain, so set its crossOrigin property to Anonymous, and then set the Access-Control-Allow-Origin response header on the server). If the width and height of the loaded picture is greater than the width and height of the container, it should be reduced. Finally, the vertical horizontal center display () (note here that you want to save the width and height value before the picture is drawn, because the image will be scaled based on this value and multiplied by the magnification, imgStartWidth,imgStartHeight here)

_ loadImg () {if (this.imgLoading | | this.loadImgQueue.length = 0) {return;} let img = this.loadImgQueue.shift (); if (! img) {return;} let $img = new Image (), onLoad = e = > {$img.removeEventListener ('load', onLoad, false); this.$img = $img; this.imgLoaded = true; this.imgLoading = false; this._initImg ($img.width, $img.height) This.$emit ('loadSuccess', e); this.$emit (' loadComplete', e); this._loadImg ();}, onError = e = > {$img.removeEventListener ('error', onError, false); this.$img = $img = null; this.imgLoading = false; this.$emit (' loadError', e); this.$emit ('loadComplete', e); this._loadImg ();} This.$emit ('beforeLoad'); this.imgLoading = true; this.imgLoaded = false; $img.src = this.img; $img.crossOrigin =' Anonymous'; / / because canvas toDataUrl cannot manipulate unauthorized cross-domain images, this requires the server to set the Access-Control-Allow-Origin header $img.addEventListener ('load', onLoad, false); $img.addEventListener (' error', onError, false) } _ initImg (w, h) {let eW = null, eH = null, maxW = this.cWidth, maxH = this.cHeight-this.actionBarHeight; / / if the width and height of the picture is less than the width and height of the container, do not process if (w {if (! this.imgLoaded) {return;} if (e.touches.length = 1) {let finger = e.touches [0]; scx = finger.pageX Scy = finger.pageY; iX = this.imgX; iY = this.imgY; fingers [finger.identifier] = finger } else if (e.touches.length = 2) {let finger1 = e.touches [0], finger2 = e.touches [1], f1x = finger1.pageX-cClientRect.left, f1y = finger1.pageY-cClientRect.top, f2x = finger2.pageX-cClientRect.left, f2y = finger2.pageY-cClientRect.top; scx = parseInt ((f1x + f2x) / 2); scy = parseInt ((f1y + f2y) / 2) FigureDistance = this._pointDistance (f1x, f1y, f2x, f2y); fingers [finger1.identifier] = finger1; fingers [finger2.identifier] = finger2; / / determine whether the midpoint of the transformation is in the picture, and if not, go to the nearest point if (scx)

< this.imgX) { scx = this.imgX; } if (scx >

This.imgX + this.imgCurrentWidth) {scx = this.imgX + this.imgCurrentHeight;} if (scy

< this.imgY) { scy = this.imgY; } if (scy >

This.imgY + this.imgCurrentHeight) {scy = this.imgY + this.imgCurrentHeight;}, false); $gesture.addEventListener ('touchmove', e = > {e.preventDefault (); if (! this.imgLoaded) {return;} this.maskShowTimer & & clearTimeout (this.maskShowTimer); this.maskShow = false) If (e.touches.length = 1) {let f1x = e.touches [0] .pageX, f1y = e.touches [0] .pageY; this._drawImage (iX + f1x-scx, iY + f1y-scy, this.imgCurrentWidth, this.imgCurrentHeight) } else if (e.touches.length = 2) {let finger1 = e.touches [0], finger2 = e.touches [1], f1x = finger1.pageX-cClientRect.left, f1y = finger1.pageY-cClientRect.top, f2x = finger2.pageX-cClientRect.left, f2y = finger2.pageY-cClientRect.top, newFigureDistance = this._pointDistance (f1x, f1y, f2x, f2y) Scale = this.imgScale + parseFloat ((newFigureDistance-figureDistance) / this.imgScaleStep) .toFixed (1)) Fingers [finger1.identifier] = finger1; fingers [finger2.identifier] = finger2; if (scale! = = pinchScale) {/ / currently the minimum scale is 1 and the maximum is 5 if (scale

< this.imgMinScale) { scale = this.imgMinScale; } else if (scale >

This.imgMaxScale) {scale = this.imgMaxScale;} pinchScale = scale; this._scale (scx, scy, scale);}}, false); $gesture.addEventListener ('touchend', e = > {if (! this.imgLoaded) {return;} this.imgScale = pinchScale) / / delete the fingers that have left let touches = Array.prototype.slice.call (e.changedTouches, 0) from finger; touches.forEach (item = > {delete fingers [item.identifier];}); / / iterate fingers, update scx,scy,iX,iY if finger exists, because drag let I, fingerArr = [] immediately after zooming For (i in fingers) {if (fingers.hasOwnProperty (I)) {fingerArr.push (thanks [I]);}} if (fingerArr.length > 0) {scx = fingerArr [0] .pageX; scy = fingerArr [0] .pageY; iX = this.imgX; iY = this.imgY;} else {this.maskShowTimer = setTimeout (() = > {this.maskShow = true Let x = this.imgX, y = this.imgY, pClientRect = this.$refs.pCanvas.getBoundingClientRect (); if (x > pClientRect.left + pClientRect.width) {x = pClientRect.left} else if (x + this.imgCurrentWidth)

< pClientRect.left) { x = pClientRect.left + pClientRect.width - this.imgCurrentWidth; } if (y >

PClientRect.top + pClientRect.height) {y = pClientRect.top;} else if (y + this.imgCurrentHeight < pClientRect.top) {y = pClientRect.top + pClientRect.height-this.imgCurrentHeight;} if (this.imgX! = = x | this.imgY! = = y) {this._drawImage (x, y, this.imgCurrentWidth, this.imgCurrentHeight);}}) }, _ scale (x, y, scale) {let newPicWidth = parseInt (this.imgStartWidth * scale), newPicHeight = parseInt (this.imgStartHeight * scale), newIX = parseInt (x-newPicWidth * (x-this.imgX) / this.imgCurrentWidth), newIY = parseInt (y-newPicHeight * (y-this.imgY) / this.imgCurrentHeight); this._drawImage (newIX, newIY, newPicWidth, newPicHeight) }, _ pointDistance (x1, y1, x2, y2) {return parseInt (Math.sqrt ((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2));}

Explain what fingers does, and it is used to record how many fingers are currently touching on the screen. It is possible that when both fingers are zoomed, one finger moves out of the display while the other moves on the display. In this case, the finger that has left the display screen in the fingers is removed according to the e.changedTouches on the touchend event. If there is only one finger left in the fingers, update the scx,scy,iX,iY to initialize the moving image.

8. Cropping pictures

It's simple here, just call the toDataURL method of pCanvas.

_ clipper () {let imgData = null; try {imgData = this.$refs.pCanvas.toDataURL ();} catch (e) {console.error ('Please add Access-Control-Allow-Origin to response header, otherwise canvas cannot crop unauthorized cross-domain images');} this.$emit ('sure', imgData) } these are all the contents of this article entitled "how to realize the function of Mobile Image clipping component based on Vue". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report