效果圖
GIF
微信小程序
項(xiàng)目地址
主要實(shí)現(xiàn)
為了可以兼容多種小程序和h5慕淡,這里使用uni-app來開發(fā)
1.帽子標(biāo)簽
<view class='user-hat'
@touchstart='handleTouchStart'
@touchmove.stop='handleTouchMove'
@touchEnd='handleTouchEnd'
:style='hatStyleStr'>
<image class='hat' id='hat' src='/static/img/hat.png' :style='hatImgStyleStr'></image>
<view class='rotate' id='rotate' :style='rotateStyleStr'>
<image class='rotate-icon' id='rotate' src='/static/img/icon-rotate.png'></image>
</view>
</view>
帽子的組成:
class='hat'
的帽子圖片和class='rotate'
的帽子旋轉(zhuǎn)按鈕
2.綁定touch事件
1.touchstart 事件
handleTouchStart(e){
// 當(dāng)前帽子 top 值
this.currentHatTop = this.hatTop
// 當(dāng)前帽子 left 值
this.currentHatLeft = this.hatLeft
// 當(dāng)前旋轉(zhuǎn)按鈕 top 值
this.currentRotateTop = this.rotateTop
// 當(dāng)前旋轉(zhuǎn)按鈕 left 值
this.currentRotateLeft = this.rotateLeft
// 當(dāng)前target的id
this.touchTarget = e.target.id
// 當(dāng)前touch的x值和y值
this.currentPos = {x:e.touches[0].clientX,y:e.touches[0].clientY}
}
在 touchstart
中,首先獲取帽子和旋轉(zhuǎn)按鈕的當(dāng)前偏移值并賦值給相應(yīng)變量在跳,然后記錄下當(dāng)前 target 的 id 和當(dāng)前 touch 事件的 XY 值
2.touchmove 事件
handleTouchMove(e){
if(this.touchTarget){
// 當(dāng)前touch的x值和y值
const pos = {x:e.touches[0].clientX,y:e.touches[0].clientY}
// 對(duì)比touchstart時(shí)的x值的偏移量
const moveX = pos.x - this.currentPos.x
// 對(duì)比touchstart時(shí)的x值的偏移量
const moveY = pos.y - this.currentPos.y
// 如果移動(dòng)的是帽子圖片
if(this.touchTarget === 'hat'){
// 將帽子進(jìn)行位移
this.hatLeft = this.hatLeft + moveX
this.hatTop = this.hatTop + moveY
}
// 如果移動(dòng)的是旋轉(zhuǎn)按鈕
else if(this.touchTarget === 'rotate'){
// 將旋轉(zhuǎn)按鈕進(jìn)行位移
this.rotateLeft = this.rotateLeft + moveX
this.rotateTop = this.rotateTop + moveY
// 當(dāng)前旋轉(zhuǎn)按鈕中心點(diǎn)相對(duì)于初始的帽子中心點(diǎn)的x偏移量
const nowWidth = this.rotateLeft + this.hatHalfWidth
// 當(dāng)前旋轉(zhuǎn)按鈕中心點(diǎn)相對(duì)于初始的帽子中心點(diǎn)的y偏移量
const nowHeight = this.rotateTop + this.hatHalfWidth
// 當(dāng)前旋轉(zhuǎn)按鈕中心點(diǎn)相對(duì)于初始的帽子中心點(diǎn)的直線距離(新的半徑)
const nowRadius = Math.sqrt(nowWidth * nowWidth + nowHeight * nowHeight)
// 新的半徑與舊的半徑的比例
this.hatScale = nowRadius / this.hatRadius
// 當(dāng)前的旋轉(zhuǎn)按鈕中心點(diǎn)與x軸的角度
const nowAngel = Math.atan2(nowHeight,nowWidth) / Math.PI * 180
// 這里this.beforeAngel默認(rèn)設(shè)置為45
this.hatRotate = nowAngel - this.beforeAngel + this.hatRotate
// 重新賦值this.beforeAngel
this.beforeAngel = nowAngel
}
// 重新賦值this.currentPos
this.currentPos = pos
}
}
在 touchmove
中,根據(jù)target的不同進(jìn)行了不同的處理焦人,旋轉(zhuǎn)按鈕move會(huì)對(duì)帽子進(jìn)行一個(gè)旋轉(zhuǎn)+放大的處理别凹,其中放大計(jì)算主要是計(jì)算前后半徑的比例。
3.保存圖片
現(xiàn)在已經(jīng)完成對(duì)帽子進(jìn)行位移昔园,旋轉(zhuǎn)和放大了,最后只需要將變化后的圖片進(jìn)行保存闹炉。
const wrapperWidth = uni.getSystemInfoSync().windowWidth
const context = uni.createCanvasContext('avatarCanvas')
const hatSize = this.hatHalfWidth * 2 * this.hatScale
context.clearRect(0, 0, wrapperWidth, wrapperWidth)
context.drawImage(path, 0, 0, wrapperWidth, wrapperWidth)
context.translate(this.hatLeft + this.hatHalfWidth,this.hatTop + this.hatHalfWidth)
context.rotate(this.hatRotate * Math.PI / 180)
console.log(-hatSize/2)
context.drawImage("/static/img/hat.png", -hatSize/2, -hatSize/2, hatSize, hatSize)
context.draw()
canvas的處理比較簡單蒿赢,繪制圖片并進(jìn)行位移旋轉(zhuǎn)和縮放即可,需要注意的是微信小程序中需要配置下安全域名渣触,不然頭像是無法繪制出來的。
其他關(guān)于授權(quán)等內(nèi)容不同小程序平臺(tái)也有一些差異壹若,可以查看源碼嗅钻,這里就不詳細(xì)描述了。