软件之家基于Vue的移动端图片裁剪组件功能_vue.js_脚本之家

第一定义两个变量scx, scy,iX,iY。

2、touchmove

三、初始化canvas

六、移动图片

坚持到底…继续看看代码吧

证实一下fingers是干嘛的,是用来记录当前有微微只手指在显示屏上触摸。大概会并发这种气象,双指缩放后,在那之中壹只手指移出荧屏,而除此以外多少个手指在显示屏上移动。针对这种意况,要在touchend事件上依据e.changedTouches来移除fingers里早就离开显示屏的finger,纵然此刻fingers里只剩余多个finger,则更新scx,scy,iX,iY为移动图片做最初化准备。

五、绘制图片

绘图缩放后的图形无非必要4个参数,缩放后图片左上角的坐标以致宽高。求宽高相对好办,宽高级于imgStartWidth
* 缩放比率与imgstartHeight * 缩放倍率(imgStartWidth ,imgstartHeight
上文首节有提到)。接下来正是求缩放倍率的标题了,首先在touchstart事件上求取两只手指间的相距d1;然后在touchmove事件上三番四遍求取两只手指间的间距d2,当前缩放倍率=
开始缩放倍率 + / 步长,touchend事件上让开头缩放倍率=当前缩放倍率。

下面的_drawImage有多个参数,分别是图片对应cCanvas的x,y坐标以至图片目前的宽高w,h。函数首先会清空多少个canvas的内容,方法是再一次安装canvas的宽高。然后更新组件实例中对应的值,最后再调用八个canvas的drawImage去绘制图片。对于pCanvas来讲,其绘制的图样坐标值为x,y减去相应的originXDiff与originYDiff(其实一定于切换坐标系展现而已,因而只需求减去八个坐标系原点的x,y差值就可以)。看看代码

前段时间项目上要做三个车牌识其他意义。本来觉得不会细小略,只供给将图片扔给后台就足以了,然而经测量检验后识别率独有20-五分二。由此付加物提议摄影图片后,能够对图纸张开拖拽和缩放,然后裁剪车牌部分上传给后台来加强识别率。刚初始的话依旧百度了一下探问有未有现有的机件,可是找来找去都尚未找到一个不为已甚的,幸亏那个功能不是很着急,因而自个儿周天就在家里商量一下。

在Z轴方向重视大是由4层组成。第1层是三个占满整个容器的canvas;第2层是二个有反射率的遮罩层;第3层是裁剪的区域,里面含有三个与裁剪区域大小也等于的canvas;第4层是二个透明层gesture-mask,用作绑定touchstart,touchmove,touchend事件。在那之中三个canvas都会加载同一张图纸,只是起先坐标不平等。为何须求四个canvas?因为想做出当手指离开荧屏时,裁剪区域外的部分表面会有叁个遮罩层的效果,这样能非凡裁剪区域的开始和结果。

1、touchstart

艺术很简短,正是收获touches[0]的pageX,pageY来更新scx与scy以至更新iX与iY

七、缩放图片(这里不作非常表明的坐标都是周旋于cCanvas坐标系)

          取消 确认     

加载图片比较轻巧,首先是制造叁个Image对象并监听器onload事件(因为加载的图片有异常的大恐怕是跨域的,由此要安装其crossOrigin属性为Anonymous,然后服务器上要设置Access-Control-Allow-Origin响应头)。加载的图形假设宽高大于容器的宽高,要对其进展压缩管理。最后垂直水平居中显示(卡塔尔(قطر‎(这里注意的是要保存图片绘制前的宽高值,因为从此未来缩放图片是以该值为底蕴再乘以缩放倍率,这里取imgStartWidth,imgStartHeight)如下

接下去看看下边那些例子(在visio找了比较久都还没画坐标系的效益,所以一定要手工业画了)

canvas绘制的图片在hdpi荧屏上会现身模糊,具体原因这里不作解析,能够参见下这里。小编这里的做法是让canvas的width与height为其css
width/height的devicePixelRatio倍,以致调用canvas
api时所盛传的参数都要加倍window.devicePixelRatio。最后还要记下一下八个canvas坐标原点的x,
y差值(originXDiff与originYDiff)。如下

总结

获取touches[0]的pageX,注解变量f1x贮存,移动后的x坐标等于iX + f1x –
scx,y坐标同理,最终调用_drawImage来更新图片。

_clipper() { let imgData = null; try { imgData = this.$refs.pCanvas.toDataURL { console.error('请在response header加上Access-Control-Allow-Origin,否则canvas无法裁剪未经许可的跨域图片'); } this.$emit;}

二、布局

_loadImg() { if (this.imgLoading || this.loadImgQueue.length === 0) { return; } let img = this.loadImgQueue.shift { 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; this.$emit; this._loadImg(); }, onError = e => { $img.removeEventListener('error', onError, false); this.$img = $img = null; this.imgLoading = false; this.$emit; this.$emit; this._loadImg(); }; this.$emit; this.imgLoading = true; this.imgLoaded = false; $img.src = this.img; $img.crossOrigin = 'Anonymous'; //因为canvas toDataUrl不能操作未经允许的跨域图片,这需要服务器设置Access-Control-Allow-Origin头 $img.addEventListener('load', onLoad, false); $img.addEventListener('error', onError, false);}_initImg { let eW = null, eH = null, maxW = this.cWidth, maxH = this.cHeight - this.actionBarHeight; //如果图片的宽高都少于容器的宽高,则不做处理 if (w <= maxW && h <= maxH) { eW = w; eH = h; } else if (w > maxW && h <= maxH) { eW = maxW; eH = parseInt; } else if (w <= maxW && h > maxH) { eW = parseInt; eH = maxH; } else { //判断是横图还是竖图 if  { eW = parseInt; eH = maxH; } else { eW = maxW; eH = parseInt; } } if (eW <= maxW && eH <= maxH) { //记录其初始化的宽高,日后的缩放功能以此值为基础 this.imgStartWidth = eW; this.imgStartHeight = eH; this._drawImage / 2,  / 2, eW, eH); } else { this._initImg; }}

如上所述是笔者给我们介绍的基于Vue的位移端图片裁剪组件效率,希望对大家全部利于,假诺大家有任何疑问请给自身留言,小编会及时苏醒我们的。在这里也极其谢谢我们对台本之家网站的支撑!

因为移动端是用vue,所以就写成了二个vue组件,上边就说说本身的部分完毕思路(自身本领有限,各位大神请体谅。此外显示的代码不必然是有些意义的一体化代码),先看看效果:

_drawImage { this._clearCanvas(); this.imgX = parseInt; this.imgY = parseInt; this.imgCurrentWidth = parseInt; this.imgCurrentHeight = parseInt; //更新canvas this.ctx.drawImage(this.$img, this._ratio, this._ratio; //更新pCanvas,只需要减去两个canvas坐标原点对应的差值即可 this.pCtx.drawImage(this.$img, this._ratio, this._ratio, this._ratio;},_clearCanvas() { let $canvas = this.$refs.canvas, $pCanvas = this.$refs.pCanvas; $canvas.width = $canvas.width; $canvas.height = $canvas.height; $pCanvas.width = $pCanvas.width; $pCanvas.height = $pCanvas.height;}

赫色框是一张10*5的图纸,莲红框是宽高放大两倍后的图形20*10,根据地点的公式推算的x2
= sx – w2 / w1,y2 = sy – h2 / h1。

四、加载图片

(缩放中央x坐标 – 缩放后图片左上角x坐标)/ 缩放后图片的升幅 =
(缩放大旨x坐标 – 缩放前图片左上角x坐标)/ 缩放前图片的拉长率;

这边很简短,就调用pCanvas的toDataU酷威L方法就能够了

Demo地址:

2、截图的宽clipperImgWidth

3、截图的高clipperImgHeight

至于什么求取缩放后图片左上角的坐标值,在草稿纸上画来画去,画了十分久……终于有一点点眉目。首先要找到贰个缩放中央(这里做法是取双指的中式点心坐标,可是那几个坐标必定要放在图片上,假使不在图片上,则取图片上离该中式茶食坐标近年来的点),然后存在上面这么些等式

下载地址:

_initEvent() { let $gesture = this.$refs.gesture, cClientRect = this.$refs.canvas.getBoundingClientRect(), scx = 0, //对于单手操作是移动的起点坐标,对于缩放是图片距离两手指的中点最近的图标。 scy = 0, fingers = {}; //记录当前有多少只手指在触控屏幕 //one finger let iX = this.imgX, iY = this.imgY; //two finger let figureDistance = 0, pinchScale = this.imgScale; $gesture.addEventListener('touchstart', e => { if  { 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; scy = parseInt; figureDistance = this._pointDistance; fingers[finger1.identifier] = finger1; fingers[finger2.identifier] = finger2; //判断变换中点是否在图片中,如果不是则去离图片最近的点 if  { scx = this.imgX; } if (scx > this.imgX + this.imgCurrentWidth) { scx = this.imgX + this.imgCurrentHeight; } if  { scy = this.imgY; } if (scy > this.imgY + this.imgCurrentHeight) { scy = this.imgY + this.imgCurrentHeight; } } }, false); $gesture.addEventListener('touchmove', e => { e.preventDefault(); if  { return; } this.maskShowTimer && clearTimeout; 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, scale = this.imgScale + parseFloat(((newFigureDistance - figureDistance) / this.imgScaleStep).toFixed; fingers[finger1.identifier] = finger1; fingers[finger2.identifier] = finger2; if  { //目前缩放的最小比例是1,最大是5 if (scale < this.imgMinScale) { scale = this.imgMinScale; } else if (scale > this.imgMaxScale) { scale = this.imgMaxScale; } pinchScale = scale; this._scale; } } }, false); $gesture.addEventListener('touchend', e => { if  { return; } this.imgScale = pinchScale; //从finger删除已经离开的手指 let touches = Array.prototype.slice.call; touches.forEach(item => { delete fingers[item.identifier]; }); //迭代fingers,如果存在finger则更新scx,scy,iX,iY,因为可能缩放后立即单指拖动 let i, fingerArr = []; for { if (fingers.hasOwnProperty { fingerArr.push; } } if  { scx = fingerArr[0].pageX; scy = fingerArr[0].pageY; iX = this.imgX; iY = this.imgY; } else { this.maskShowTimer = setTimeout => { this.maskShow = true; }, 300); } //做边界值检测 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 { let newPicWidth = parseInt(this.imgStartWidth * scale), newPicHeight = parseInt(this.imgStartHeight * scale), newIX = parseInt(x - newPicWidth *  / this.imgCurrentWidth), newIY = parseInt(y - newPicHeight *  / this.imgCurrentHeight); this._drawImage(newIX, newIY, newPicWidth, newPicHeight);},_pointDistance { return parseInt *  * ;}
props: { img: String, //url或dataUrl clipperImgWidth: { type: Number, default: 500 }, clipperImgHeight: { type: Number, default: 200 }}

一、组件的初阶化参数

八、裁剪图片

上边只是列出了一部分谈得来感觉比较关键的点,
假诺有意思味的,能够到本身的github上下载源码看看。

一抬手一动脚图片实现特别轻巧,首先给gesture-mask绑定touchstart,touchmove,touchend事件,下边分别介绍那八个事件的内容

_initEvent() { let $gesture = this.$refs.gesture, scx = 0, scy = 0; let iX = this.imgX, iY = this.imgY; $gesture.addEventListener('touchstart', e => { if  { return; } let finger = e.touches[0]; scx = finger.pageX; scy = finger.pageY; iX = this.imgX; iY = this.imgY; }, false); $gesture.addEventListener('touchmove', e => { e.preventDefault(); if  { return; } let f1x = e.touches[0].pageX, f1y = e.touches[0].pageY; this._drawImage(iX + f1x - scx, iY + f1y - scy, this.imgCurrentWidth, this.imgCurrentHeight); }, false);} 
_ratio { 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; this.pCtx = $pCanvas.getContext; //判断clipperWidth与clipperHeight有没有超过容器值 if (clipperWidth < 0 || clipperWidth > clipperClientRect.width) { clipperWidth = 250 } if (clipperHeight < 0 || clipperHeight > clipperClientRect.height) { clipperHeight = 100 } //因为canvas在手机上会被放大,因此里面的内容会模糊,这里根据手机的devicePixelRatio来放大canvas,然后再通过设置css来收缩,因此关于canvas的所有值或坐标都要乘以devicePixelRatio $canvas.style.width = clipperClientRect.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; $pCanvas.height = this._ratio; //计算两个canvas原点的x y差值 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;}

相关文章

发表评论