最近正在弄一個(gè)微信小程序炫隶,涉及一個(gè)切圖的工具,由此寫一個(gè)切圖組件阎曹,實(shí)現(xiàn)功能:手指滑動(dòng)選取切圖區(qū)域伪阶、單指拖動(dòng)選框、旋轉(zhuǎn)处嫌、縮放望门。
切圖界面:
切圖效果:
思路:
1、手指滑動(dòng)選擇區(qū)域:
切圖用到canvas锰霜,在微信小程序中canvas的層級太高筹误,直接在canvas上實(shí)現(xiàn)手指滑動(dòng)選擇區(qū)域不好實(shí)現(xiàn),所以把canvas隱藏起來癣缅,直接在image標(biāo)簽上實(shí)現(xiàn)手指滑動(dòng)選擇區(qū)域厨剪,手指第一次點(diǎn)擊設(shè)為起點(diǎn),再記錄手指滑動(dòng)路徑友存,由此計(jì)算滑動(dòng)的水平長和寬祷膳,起點(diǎn)設(shè)為image標(biāo)簽上滑動(dòng)區(qū)域view的位置,計(jì)算出的長和寬作為view的長度和寬度屡立。
代碼實(shí)現(xiàn):
<view class="g-cont">
<!-- 手指滑動(dòng)區(qū)域 -->
<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上的滑動(dòng)區(qū)域 -->
<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直晨、單指拖動(dòng)選框:
手指點(diǎn)中選框區(qū)域,手指點(diǎn)中的點(diǎn)設(shè)為起點(diǎn)膨俐,計(jì)算起點(diǎn)相對于選中區(qū)域的左上角的相對位置勇皇。
手指拖著選框移動(dòng)時(shí),修改選框居左和居上的位置焚刺,該位置的計(jì)算通過手指移動(dòng)過的位置坐標(biāo)減去相對位置的寬和高
代碼實(shí)現(xiàn):
_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敛摘、旋轉(zhuǎn)和縮放:
旋轉(zhuǎn)和縮放是在使用組件頁面實(shí)現(xiàn)的
這里的問題主要是對canvas的旋轉(zhuǎn)縮放,在頁面中拖動(dòng)旋轉(zhuǎn)和縮放乳愉,傳到組件中兄淫。
以canvas的中心點(diǎn)為基準(zhǔn)縮放和旋轉(zhuǎn)
/*
小滑塊滑動(dòng)結(jié)束
*/
_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、選擇圖片
選擇需要切的圖片蔓姚,對圖片進(jìn)行縮放捕虽,使圖片能夠在可視區(qū)域顯示。
首先獲取圖片的寬和高坡脐,計(jì)算圖片的縮放比泄私,然后獲取可視區(qū)域的寬和高,如果圖片的寬超出了可視區(qū)域的寬則去可視區(qū)域的百分之就是作為圖片的寬,根據(jù)圖片縮放比計(jì)算圖片的高挖滤,如果高度超出可視區(qū)域的高崩溪,和計(jì)算高度一樣進(jìn)行相應(yīng)的計(jì)算。
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});
})