一:這段時(shí)間一直在學(xué)習(xí)微信小程序柱彻,近期也多有遇到小程序有關(guān)于圖片與canvas的坑骂澄,
二:說(shuō)明一下需求吧:首先要有兩張圖片,其中一張中間部分是透明的圖片A,另一張是完整的圖片B统刮;現(xiàn)在圖片A在上面匀奏,圖片B在下面,當(dāng)手指在圖片A上移動(dòng)時(shí),圖片B要跟著移動(dòng),同時(shí)還要做到可以雙指縮放;在調(diào)整好位置之后,還要用canvas把完成的結(jié)果圖片打印出來(lái);
三:解決問(wèn)題:
1:頁(yè)面布局
//移動(dòng)的事件最好還是用catch來(lái)
//因?yàn)樾〕绦蚧卣{(diào)的參數(shù)是用px來(lái)計(jì)算的,所以這里就不用rpx了,如果一定要用,請(qǐng)做好不同手機(jī)的適配
<view class='img' catchtouchstart='touchstart' catchtouchmove='touchmove' catchtouchend='touchend'>
<image mode='aspectFill' class='img zIndex' src='{{圖片A}}'></image>
//這里想用margin用margin,想用top饼记、left就用top、left,感覺(jué)是一樣的,transform應(yīng)該也可以,
<image style='margin-left:{{marginLeft}}px;margin-top:{{marginTop}}px;height:{{imgHeight}}px;width:{{imgWidth}}px' src='{{圖片B}}' class='img'></image>
</view>
.img{
height: 100vh;
width: 100%;
position: absolute;
top: 0;
left: 0;
display: flex;
box-sizing: border-box
}
.zIndex{
z-index: 5
}
2:移動(dòng),縮放的方法
// 開(kāi)始點(diǎn)擊
touchstart(e) {
this.setData({
lastTouchPoint: { x: 0, y: 0 },
oldDist: 0
})
},
/**
* 計(jì)算x軸上的雙指中心點(diǎn)比例
*/
_calcXRatio: function (event) {
let xRatio = ((event.touches[0].clientX + event.touches[1].clientX) / 2 - this.data.marginLeft) / this.data.imgWidth
return xRatio
},
/**
* 計(jì)算y軸上的雙指中心點(diǎn)比例
*/
_calcYRatio: function (event) {
let yRatio = ((event.touches[0].clientY + event.touches[1].clientY) / 2 - this.data.marginTop) / this.data.imgHeight
return yRatio
},
//移動(dòng)和放大
_zoom: function (f, event) {
let xRatio = this._calcXRatio(event)
let yRatio = this._calcYRatio(event)
let maxMultiple = this.data.maxMultiple
let minMultiple = this.data.minMultiple
//minMultiple是最小倍數(shù),可以自己設(shè)置
if (this.data.imgWidth <= this.data.windowWidth * minMultiple && f < 1) {
let ratio = this.data.windowWidth / this.data.imgWidth
this.setData({
imgWidth: this.data.imgWidth * ratio * minMultiple,
imgHeight: this.data.imgHeight * ratio * minMultiple
})
return;
}
if (this.data.imgHeight <= this.data.view_height * minMultiple && f < 1) {
let ratio = this.data.view_height / this.data.imgHeight
this.setData({
imgWidth: this.data.imgWidth * ratio * minMultiple,
imgHeight: this.data.imgHeight * ratio * minMultiple
})
return;
}
//maxMultiple是最大倍數(shù)薛窥,可以自己設(shè)置
if (this.data.imgWidth >= this.data.windowWidth * maxMultiple && f > 1) {
let ratio = this.data.windowWidth / this.data.imgWidth
this.setData({
imgWidth: this.data.imgWidth * ratio * maxMultiple,
imgHeight: this.data.imgHeight * ratio * maxMultiple,
})
return;
}
if (this.data.imgHeight >= this.data.windowHeight * maxMultiple && f > 1) {
let ratio = this.data.windowHeight / this.data.imgHeight
this.setData({
imgWidth: this.data.imgWidth * ratio * maxMultiple,
imgHeight: this.data.imgHeight * ratio * maxMultiple,
})
return;
}
this.setData({
//此處的ratio為雙指中心點(diǎn)在圖片的百分比
marginLeft: this.data.marginLeft + xRatio * this.data.imgWidth * (1 - f),
marginTop: this.data.marginTop + yRatio * this.data.imgHeight * (1 - f),
imgWidth: this.data.imgWidth * f,
imgHeight: this.data.imgHeight * f,
})
},
_spacing: function (event) {
let x = event.touches[0].clientX - event.touches[1].clientX;
let y = event.touches[0].clientY - event.touches[1].clientY;
return Math.sqrt(x * x + y * y);
},
//移動(dòng)距離
touchmove(e) {
let moveX = e.changedTouches[0].clientX
let moveY = e.changedTouches[0].clientY
let oldDist = this.data.oldDist;
let newDist = this.data.newDist;
let lastTouchPoint = this.data.lastTouchPoint
//單指移動(dòng)事件
if (e.touches.length == 1) {
if (lastTouchPoint.x == 0 && lastTouchPoint.y == 0) {
lastTouchPoint.x = e.touches[0].clientX
lastTouchPoint.y = e.touches[0].clientY
this.setData({
lastTouchPoint,
})
} else {
let xOffset = e.touches[0].clientX - lastTouchPoint.x
let yOffset = e.touches[0].clientY - lastTouchPoint.y
lastTouchPoint.x = e.touches[0].clientX
lastTouchPoint.y = e.touches[0].clientY
this.setData({
marginTop: this.data.marginTop + yOffset,
marginLeft: this.data.marginLeft + xOffset,
lastTouchPoint
})
}
} else if (e.touches.length == 2) {
if (oldDist == 0) {
oldDist = this._spacing(e);
this.setData({
oldDist
})
} else {
newDist = this._spacing(e);
if (newDist > oldDist + 1) {
this._zoom(newDist / oldDist, e);
oldDist = newDist;
this.setData({
oldDist,
newDist
})
}
if (newDist < oldDist - 1) {
this._zoom(newDist / oldDist, e);
oldDist = newDist;
this.setData({
oldDist,
newDist
})
}
}
}
},
//移動(dòng)結(jié)束
touchend(e) {
//移動(dòng)結(jié)束這個(gè)方法可以根據(jù)自己的需求來(lái)做,不是必要的
},
3:重頭戲來(lái)了,圖片的canvas打印,有些人會(huì)說(shuō)如果想用canvas打印你干嘛前面不用canvas來(lái)寫(xiě)呢;這里有個(gè)問(wèn)題,canvas上面如果想加?xùn)|西只能加cover-view,但是cover-view有各種限制和不足,所以當(dāng)你加的東西不影響到最后生成的圖的時(shí)候可以用用這個(gè),其他的確實(shí)直接canvas簡(jiǎn)單方便
// 因?yàn)閏anvas用的也是px镇防,如果前面用其他單位的話(huà),記得換算
let backImgWidth = this.data.backImgWidth//圖片A的寬度
let backImgHeight = this.data.backImgHeight//圖片A的高度
let imgWidth = this.data.imgWidth//圖片B的寬度
let imgHeight = this.data.imgHeight//圖片B的高度
let windowWidth = this.data.windowWidth//手機(jī)屏的寬度
let windowHeight = this.data.windowHeight//手機(jī)屏的高度
let marginTop = this.data.marginTop
let marginLeft = this.data.marginLeft
let that = this
//因?yàn)槠聊坏拈L(zhǎng)寬比實(shí)在是太多了胃榕,而且為了圖片不變形,一般都會(huì)用裁剪的功能,所以,我們要知道這里圖片A到底被裁了多少
let distance = backImgHeight * windowWidth / backImgWidth - windowHeight
//現(xiàn)在基本就是繪圖了
const ctx = wx.createCanvasContext('img')
//花型圖片因?yàn)榈讏D片裁剪,所以還有一段裁剪掉的對(duì)上距離要加上
ctx.drawImage(圖片B, marginLeft, marginTop + distance/2, imgWidth, imgHeight)
//底圖片高度應(yīng)為會(huì)自定義縮放换淆,所以必須在這里就將圖片按比例算好大小
ctx.drawImage('圖片A', 0, 0 , windowWidth, backImgHeight * e.windowWidth / backImgWidth)
//生成圖片是要把裁剪掉的距離給去掉的同時(shí),高度也要和前面的一樣
//這里要用false,用true會(huì)保留原來(lái)的圖片樣式,那就有的玩了
ctx.draw(false, (e) => {
wx.canvasToTempFilePath({
x: 0,
y: distance / 2,
width: windowWidth,
height: windowHeight ,
destWidth: windowWidth,
destHeight: windowHeight,
canvasId: 'img',
success: (res) => {
//圖片生成成功了
console.log(res)
},
fail:(res)=>{
console.log(res)
}
}, that)
})
//對(duì)了還留了一個(gè)坑梆砸,小程序你想要canvas正常使用狮暑,你就必須在布局的時(shí)候給它位置;
//還有canvas的canvas-id一定要和打印的一樣
<canvas class='canvas' canvas-id='img'></canvas>
這樣以來(lái)算可以正常使用