基于Vue的移动端图片裁剪组件功能(2)
三、初始化canvas
canvas绘制的图片在hdpi显示屏上会出现模糊,具体原因这里不作分析,可以参考下这里。我这里的做法是让canvas的width与height为其css width/height的devicePixelRatio倍,以及调用canvas api时所传入的参数都要乘以window.devicePixelRatio。最后还要记录一下两个canvas坐标原点的x, y差值(originXDiff与originYDiff)。如下
_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'); //判断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(clipperWidth); $pCanvas.height = this._ratio(clipperHeight); //计算两个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; }
四、加载图片
加载图片比较简单,首先是创建一个Image对象并监听器onload事件(因为加载的图片有可能是跨域的,因此要设置其crossOrigin属性为Anonymous,然后服务器上要设置Access-Control-Allow-Origin响应头)。加载的图片如果宽高大于容器的宽高,要对其进行缩小处理。最后垂直水平居中显示()(这里注意的是要保存图片绘制前的宽高值,因为日后缩放图片是以该值为基础再乘以缩放倍率,这里取imgStartWidth,imgStartHeight)如下
_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'; //因为canvas toDataUrl不能操作未经允许的跨域图片,这需要服务器设置Access-Control-Allow-Origin头 $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 (w <= maxW && h <= maxH) { eW = w; eH = h; } else if (w > maxW && h <= maxH) { eW = maxW; eH = parseInt(h / w * maxW); } else if (w <= maxW && h > maxH) { eW = parseInt(w / h * maxH); eH = maxH; } else { //判断是横图还是竖图 if (h > w) { eW = parseInt(w / h * maxH); eH = maxH; } else { eW = maxW; eH = parseInt(h / w * maxW); } } if (eW <= maxW && eH <= maxH) { //记录其初始化的宽高,日后的缩放功能以此值为基础 this.imgStartWidth = eW; this.imgStartHeight = eH; this._drawImage((maxW - eW) / 2, (maxH - eH) / 2, eW, eH); } else { this._initImg(eW, eH); } }
内容版权声明:除非注明,否则皆为本站原创文章。