项目要求有个拍照后剪切功能,然而发现小程序他居然没有剪切的原生api
冷静,百度搜了下,发现有写好的demo
看起来好像也不是特别麻烦,要不自己写一个?
那就写吧
Three days later ........
着急用的话有我自己写好的demo, git地址 https://gitee.com/singlever/applet_demo
用法,在json文件中引入组件后(路径自己定好,这里只是我的路径)
"usingComponents": {
"img-shear": "./components/img_shear/index",
},
在页面中加入下面代码 shear控制组件加载,剪切后的图片数据会传入 showimg方法中
<view wx:if="{{shear}}">
<img-shear bind:imgdata="showimg" />
</view>
步入正题
1.通过 wx.chooseImage 拿到需要处理的图片
wx.chooseImage({
success: function(res){}
})
2.通过 wx.getImageInfo 拿到图片的全部数据
wx.chooseImage({
success: function(res){
wx.getImageInfo({
src:res.tempFilePaths[0],
success(data){
}
})
}
})
3.容器页面,这里我选用 scroll-view 组件来对选择好的图片进行滑动,内嵌 canvas 来绘制图片
<scroll-view scroll-x="true" scroll-y="true">
<canvas id="canvas" canvas-id="mycanvas"/>
</scroll-view>
4.确定容器宽高,并且绘制图片,设置scroll-view的宽高决定切图视角的宽高,canvas的宽高为绘制图片的宽高,通过 wx.createCanvasContext 读取到被渲染的canvas,setData 把图片的数据和绑定好的canvas节点上传到data中,再通过节点绑定data中的数据进行渲染
data: {
ctx:'',
cnavasimg:{},
},
const ctx = wx.createCanvasContext('mycanvas',this)
this.setData({ctx})
let _this = this
wx.chooseImage({
success: function(res){
wx.getImageInfo({
src:res.tempFilePaths[0],
success(data){
_this.setData({
cnavasimg:{...data,src:res.tempFilePaths[0]}})
ctx.drawImage(res.tempFilePaths[0], 0, 0,data.width, data.height)
ctx.draw()
}
})
}
})
<scroll-view scroll-x="true" scroll-y="true" class="con">
<canvas style="width:{{cnavasimg.width}}px;height:{{cnavasimg.height}}px" canvas-id="mycanvas" id="canvas" />
</scroll-view>
这里初步的渲染已经完成
5.通过用户双指的距离来对图片进行缩放,并且及时渲染到节点中去,这里用到 bindtouchstart 和 bindtouchmove 来确定两指之间的位置
<scroll-view scroll-x="true" scroll-y="true" bindtouchstart="touchstart" bindtouchmove="touchmove" class="con">
好累,接下来不放完整代码了,我就说说流程和思路吧
(1).两手指刚触碰屏幕时,触发 bindtouchstart 绑定的方法,在data中记录下两手指的 clientX 和 clientY,通过勾股定理计算出此时两指的距离
let x = res.touches[0].clientX - res.touches[1].clientX
let y = res.touches[0].clientY - res.touches[1].clientY
x = x > 0 ? x : -x
y = y > 0 ? y : -y
// console.log('x',x,'y',y)
let z = Math.sqrt(Math.pow(x,2)+Math.pow(y,2))
return z
(2)手指滑动的时候,同样计算两指距离,给个if判定,两者的差 的正负来判断是否缩放 ,drawImage 函数是用来绘制图形的
touchmove(res){
if (res.touches.length === 1) {return}
let bei = this.compute_z(res) - this.data.now_length
if(bei > 0){
this.drawImage(bei)
}
if(bei < -0){
this.drawImage(bei)
}
},
(3)drawImage ,绘制图形,思路 首先 先用 ctx.clearRect() 来清屏,然后通过传入的参数 bei 的大小正负来对图片进行缩放,我这里的算法是
let img = this.data.cnavasimg
let width,height;
let limit = 1000
if(bei > 0){
width = ((bei/limit)+1)*img.width
height = ((bei/limit)+1)*img.height
}else{
bei = -bei
width = (limit/(limit+bei))*img.width
height = (limit/(limit+bei))*img.height
}
(4)canvas容器的大小要随图片大小改变
this.setData({['cnavasimg.width']:width,['cnavasimg.height']:height})
(5)绘制图片
ctx.drawImage(img.src, 0, 0,this.data.cnavasimg.width, this.data.cnavasimg.height)
ctx.draw()
6.这里对于图片的放大缩小逻辑已经完了,现在是开始切图
使用 scroll-view 的 bindscroll 绑定的方法,及时传递图片所切位置的left和top
location(e){
this.data.view_left = e.detail.scrollLeft
this.data.view_top = e.detail.scrollTop
},
切图
qie(){
let w = 500*(this.data.w/750)
let _this = this
wx.canvasToTempFilePath({
canvasId: 'mycanvas',
height: w,
width: w,
x: _this.data.view_left,
y: _this.data.view_top,
success(res){
_this.triggerEvent('imgdata',res.tempFilePath)
}
}, _this)
},
通过点击按钮触发函数 qie 数据 ,w 是所切的图片宽高这里默认是 500rpx ,切图的api是 wx.canvasToTempFilePath()
再通过 this.triggerEvent 方法,将获得的图片数据传给调用页面。