效果图
GIF
微信小程序
项目地址
主要实现
为了可以兼容多种小程序和h5,这里使用uni-app来开发
1.帽子标签
<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'
的帽子旋转按钮
2.绑定touch事件
1.touchstart 事件
handleTouchStart(e){
// 当前帽子 top 值
this.currentHatTop = this.hatTop
// 当前帽子 left 值
this.currentHatLeft = this.hatLeft
// 当前旋转按钮 top 值
this.currentRotateTop = this.rotateTop
// 当前旋转按钮 left 值
this.currentRotateLeft = this.rotateLeft
// 当前target的id
this.touchTarget = e.target.id
// 当前touch的x值和y值
this.currentPos = {x:e.touches[0].clientX,y:e.touches[0].clientY}
}
在 touchstart
中,首先获取帽子和旋转按钮的当前偏移值并赋值给相应变量,然后记录下当前 target 的 id 和当前 touch 事件的 XY 值
2.touchmove 事件
handleTouchMove(e){
if(this.touchTarget){
// 当前touch的x值和y值
const pos = {x:e.touches[0].clientX,y:e.touches[0].clientY}
// 对比touchstart时的x值的偏移量
const moveX = pos.x - this.currentPos.x
// 对比touchstart时的x值的偏移量
const moveY = pos.y - this.currentPos.y
// 如果移动的是帽子图片
if(this.touchTarget === 'hat'){
// 将帽子进行位移
this.hatLeft = this.hatLeft + moveX
this.hatTop = this.hatTop + moveY
}
// 如果移动的是旋转按钮
else if(this.touchTarget === 'rotate'){
// 将旋转按钮进行位移
this.rotateLeft = this.rotateLeft + moveX
this.rotateTop = this.rotateTop + moveY
// 当前旋转按钮中心点相对于初始的帽子中心点的x偏移量
const nowWidth = this.rotateLeft + this.hatHalfWidth
// 当前旋转按钮中心点相对于初始的帽子中心点的y偏移量
const nowHeight = this.rotateTop + this.hatHalfWidth
// 当前旋转按钮中心点相对于初始的帽子中心点的直线距离(新的半径)
const nowRadius = Math.sqrt(nowWidth * nowWidth + nowHeight * nowHeight)
// 新的半径与旧的半径的比例
this.hatScale = nowRadius / this.hatRadius
// 当前的旋转按钮中心点与x轴的角度
const nowAngel = Math.atan2(nowHeight,nowWidth) / Math.PI * 180
// 这里this.beforeAngel默认设置为45
this.hatRotate = nowAngel - this.beforeAngel + this.hatRotate
// 重新赋值this.beforeAngel
this.beforeAngel = nowAngel
}
// 重新赋值this.currentPos
this.currentPos = pos
}
}
在 touchmove
中,根据target的不同进行了不同的处理,旋转按钮move会对帽子进行一个旋转+放大的处理,其中放大计算主要是计算前后半径的比例。
3.保存图片
现在已经完成对帽子进行位移,旋转和放大了,最后只需要将变化后的图片进行保存。
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的处理比较简单,绘制图片并进行位移旋转和缩放即可,需要注意的是微信小程序中需要配置下安全域名,不然头像是无法绘制出来的。
其他关于授权等内容不同小程序平台也有一些差异,可以查看源码,这里就不详细描述了。