最近正在弄一个微信小程序,涉及一个切图的工具,由此写一个切图组件,实现功能:手指滑动选取切图区域、单指拖动选框、旋转、缩放。
切图界面:
QQ图片20200928110353.png切图效果:
image.png思路:
1、手指滑动选择区域:
切图用到canvas,在微信小程序中canvas的层级太高,直接在canvas上实现手指滑动选择区域不好实现,所以把canvas隐藏起来,直接在image标签上实现手指滑动选择区域,手指第一次点击设为起点,再记录手指滑动路径,由此计算滑动的水平长和宽,起点设为image标签上滑动区域view的位置,计算出的长和宽作为view的长度和宽度。
代码实现:
<view class="g-cont">
<!-- 手指滑动区域 -->
<view class="cont-view"
id="contView"
bindtouchmove="_jkCutViewMove" bindtouchstart="_jkCutViewStart">
<image
id="cutImg"
src="{{cutImgInfo.src}}"
style="width: {{cutImgInfo.picWidth}}px;height: {{cutImgInfo.picHeight}}px;transform:rotate({{rotateImgandCanvas}}deg) scale({{scaleImgandCanvas}});" alt=""></image>
</view>
</view>
<!-- image上的滑动区域 -->
<view
class="cut_view"
style="top: {{cut_viewTop}}px;left: {{cut_viewLeft}}px;width: {{cut_viewWidth}}px;height: {{cut_viewHeight}}px"
>
<view class="cut_view_cont"
bindtouchmove="_jkCut_ViewMove" bindtouchstart="_jkCut_ViewStart"
>
<view class="btn left-top"
wx:if="{{cut_viewWidth>0}}"
catchtouchmove="_jkCut_ViewMove_angle"
data-info="left_top"></view>
<view class="btn right-bot"
wx:if="{{cut_viewWidth>0}}"
catchtouchmove="_jkCut_ViewMove_angle"
data-info="right_bot"></view>
</view>
</view>
<!-- 隐藏的canvas -->
<canvas class="cut-canvas" canvas-id="cutCanvas"
width="{{cutCanvasInfo.Width}}"
height="{{cutCanvasInfo.Height}}"
style="width: {{cutCanvasInfo.Width}}px;height: {{cutCanvasInfo.Height}}px;" alt=""></canvas>
_jkCutViewStart: function(e) {
let { globalCanvasDom } = this.data;
if( globalCanvasDom ) {
this.setData({
cut_viewWidth: 0,
cut_viewHeight: 0,
cut_viewTop: e.touches[0].pageY,
cut_viewLeft: e.touches[0].pageX
})
} else {
app.globalData.webapi.goShowToast(`请选择图片`,null,null,false);
}
},
_jkCutViewMove: function(e) {
let { globalCanvasDom } = this.data;
if ( globalCanvasDom ) {
this.setData({
cut_viewWidth: e.touches[0].pageX-this.data.cut_viewLeft,
cut_viewHeight: e.touches[0].pageY-this.data.cut_viewTop
})
} else {
app.globalData.webapi.goShowToast(`请选择图片`,null,null,false);
}
},
2、单指拖动选框:
手指点中选框区域,手指点中的点设为起点,计算起点相对于选中区域的左上角的相对位置。
image.png
手指拖着选框移动时,修改选框居左和居上的位置,该位置的计算通过手指移动过的位置坐标减去相对位置的宽和高
代码实现:
_jkCut_ViewStart: function(e) {
let { globalCanvasDom } = this.data;
if( globalCanvasDom ) {
this.setData({
curClickCutViewInfo: {
x: e.touches[0].pageX -this.data.cut_viewLeft,
y: e.touches[0].pageY -this.data.cut_viewTop,
}
})
}else {
app.globalData.webapi.goShowToast(`请选择图片`,null,null,false);
}
},
_jkCut_ViewMove: function(e) {
let { globalCanvasDom } = this.data;
if(globalCanvasDom) {
this.setData({
cut_viewTop: e.touches[0].pageY-this.data.curClickCutViewInfo.y,
cut_viewLeft: e.touches[0].pageX-this.data.curClickCutViewInfo.x
})
}else {
app.globalData.webapi.goShowToast(`请选择图片`,null,null,false);
}
},
3、旋转和缩放:
旋转和缩放是在使用组件页面实现的
image.png
这里的问题主要是对canvas的旋转缩放,在页面中拖动旋转和缩放,传到组件中。
以canvas的中心点为基准缩放和旋转
/*
小滑块滑动结束
*/
_jkSlideViewEnd(e) {
let {cutImgInfo,cutCanvasInfo} = this.data;
cutImgInfo.picScale = e.picScale;
cutImgInfo.picRotate = e.picRotate;
this.setData({
cutImgInfo
})
const context = wx.createCanvasContext('cutCanvas',this);
context.clearRect(0, 0, cutCanvasInfo.Width, cutCanvasInfo.Height);
context.translate(cutCanvasInfo.Width/2, cutCanvasInfo.Height/2);
context.scale(cutImgInfo.picScale,cutImgInfo.picScale);
context.rotate(cutImgInfo.picRotate);
context.drawImage(cutImgInfo.src, cutImgInfo.picLeft, cutImgInfo.picTop, cutImgInfo.picWidth*3, cutImgInfo.picHeight*3);
context.clearRect(0, 0, cutCanvasInfo.Width, cutCanvasInfo.Height);
context.translate(-(cutCanvasInfo.Width/2), -(cutCanvasInfo.Height/2));
context.drawImage(cutImgInfo.src, cutImgInfo.picLeft, cutImgInfo.picTop, cutImgInfo.picWidth*3, cutImgInfo.picHeight*3);
context.draw();
}
4、选择图片
选择需要切的图片,对图片进行缩放,使图片能够在可视区域显示。
首先获取图片的宽和高,计算图片的缩放比,然后获取可视区域的宽和高,如果图片的宽超出了可视区域的宽则去可视区域的百分之就是作为图片的宽,根据图片缩放比计算图片的高,如果高度超出可视区域的高,和计算高度一样进行相应的计算。
query.select('#contView').boundingClientRect()
.exec((data) => {
let contView_width = data[0].width
, contView_height = data[0].height
, curImgWidth = res.width
, curImgHeight = res.height;
let imgRoate = curImgWidth/curImgHeight;
// 对图片的缩放
if (res.width > contView_width) {
curImgWidth = contView_width*0.9;
curImgHeight = curImgWidth/imgRoate;
}
if(curImgHeight>contView_height) {
curImgHeight = contView_height*0.9;
curImgWidth = (curImgHeight * imgRoate);
}
_this.setData({
[ imgWidth ]: curImgWidth,
[ imgHeight ]: curImgHeight,
[ canWidth ]: contView_width*3,
[ canHeight ]: contView_height*3
})
let imgPicLeft = (contView_width - curImgWidth)/2
, imgPicTop = (contView_height - curImgHeight)/2;
_this.setData({
[ imgLeft ]: imgPicLeft*3,
[ imgTop ]: imgPicTop*3
})
globalCanvasDom = wx.createCanvasContext('cutCanvas',_this);
_this.setData({ globalCanvasDom });
globalCanvasDom.drawImage(tempFilePaths, imgPicLeft*3, imgPicTop*3, curImgWidth*3, curImgHeight*3);
globalCanvasDom.draw();
_this.triggerEvent('jkGetnoreadcount', {globalCanvasDom,cutCanvasInfo});
})
网友评论