// luckRoll.wxml
<view class="canvas-container" style="transform: rotate({{isRotate}}deg)">
<canvas disable-scroll="true" canvas-id='canvas' id="canvas-bg" class='canvas'></canvas>
<image src="{{tempFilePath}}"></image>
</view>
须要定义的数据
// luckRoll.js
data: {
trunBtn: false,// 抽奖按钮是否能够点击
itemsNum: 3, // 大转盘等分数, 可依据后盾配置加载
itemsArc: 0, // 大转盘每等分角度
coupons: [],// 每个扇形中的文字填充
isRotate: -180, // 初始旋转角度
}
创立一个 canvas 对象, 因为它是个组件,所以在传入转盘数据的时候,初始化 canvas
properties: {
rollOptions: {
type: Array,
observer(val) {if(val.length > 0) {
this.setData({
coupons: val,
itemsNum: val.length
})
const ctx = wx.createCanvasContext("canvas", this); // 创立 id 为 canvas 的绘图
this.getGiftList(ctx)
}
}
}
},
getGiftList(ctx) {
let that = this;
let itemsArc = 360/that.data.itemsNum
that.setData({itemsArc}, function () {const query = wx.createSelectorQuery().in(that)
query.select('#canvas-bg').boundingClientRect()
query.exec(function (rect) {w1 = parseInt(rect[0].width / 2);
h1 = parseInt(rect[0].height / 2);
that.drawRegion(itemsArc, ctx);// 每一份扇形的外部绘制。})
})
}
绘制扇形
drawRegion(e, ctx) {
let that = this;
let itemsArc = e;// 每一份扇形的角度
let num = that.data.itemsNum;// 等分数量
let itemArr = that.data.coupons.map(item=>item.name);// 放文字的数组
for (let i = 0; i < num; i++) {ctx.beginPath();
ctx.moveTo(w1, h1);
ctx.arc(w1, h1, w1 - 2, itemsArc * i * Math.PI / 180, (itemsArc + itemsArc * i) * Math.PI / 180);// 绘制扇形,默认从第四象限开始画,所以区域编号 1 的中央为三点钟开始地位
ctx.closePath();
const colorList = ['#7cd8e3', '#ffffff']
ctx.setFillStyle(colorList[i % 2]);
ctx.fill();
ctx.save();
ctx.beginPath();
ctx.translate(w1, h1);// 将原点移至圆形圆心地位
ctx.rotate((itemsArc * (i + 1 + (num - 2) * 0.25)) * Math.PI / 180);// 旋转文字
if (num >= 6) {ctx.setFontSize(18);// 设置文字字号大小
} else {ctx.setFontSize(20);// 设置文字字号大小
}
if (i % 2 == 0) {ctx.setFillStyle("#ffffff");// 设置文字色彩
} else {ctx.setFillStyle("#7cd8e3");// 设置文字色彩
}
ctx.setTextAlign("center");// 使文字垂直居中显示
ctx.setTextBaseline("middle");// 使文字水平居中显示
if (itemArr[i].length < 7) {ctx.setFontSize(12);// 设置文字字号大小
ctx.fillText(itemArr[i], 0, -(h1 * 0.75));
} else if (itemArr[i].length >= 7 && itemArr[i].length <= 10) {let len = Math.ceil(itemArr[i].length / 2)
ctx.fillText(itemArr[i].slice(0, len), 0, -(h1 * 0.80));
ctx.fillText(itemArr[i].slice(len), 0, -(h1 * 0.65));
ctx.setFontSize(20);// 设置文字字号大小
} else {let mainInfo = itemArr[i].slice(0, 10) + '...'
ctx.fillText(mainInfo.slice(0, 6), 0, -(h1 * 0.80));
ctx.fillText(mainInfo.slice(6, 13), 0, -(h1 * 0.65));
ctx.setFontSize(20);// 设置文字字号大小
}
ctx.restore();// 保留绘图上下文,使上一个绘制的扇形保留住。}
ctx.draw();
setTimeout(()=>{
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: 2 * w1,
height: 2 * h1,
destWidth: 8 * w1,
destHeight: 8 * h1,
fileType: 'jpg',
quality: 1,// 图片的品质,目前仅对 jpg 无效。取值范畴为 (0, 1],不在范畴内时当作 1.0 解决。canvasId: 'canvas',
success: function (res) {
var tempFilePath = res.tempFilePath;
that.setData({tempFilePath: res.tempFilePath})
},
fail: function (res) {console.log('----------', res)
}
}, that)
},1000)
ctx.draw(true);// 参数为 true 的时候,保留以后画布的内容,持续绘制
}
wx.canvasToTempFilePath 特地重要,必须将 canvas 转换为图片在页面上渲染,不然会呈现各种问题,canvas 用 translateY 移出页面显示
另外 wx.canvasToTempFilePath 必须写在 setTimeout 外面,不然安卓机的图片是黑屏
下面转盘曾经画成,上面就要转动起来
startRoll(index) {
let that = this;
let turntableRegionId = index+1
let rotate = that.data.isRotate - that.data.isRotate % 360 + (720 - Number(turntableRegionId - 1) * that.data.itemsArc - 0.5 * that.data.itemsArc - 90)
// 转动过程写在 css 动画外面,时长 3s
that.setData({isRotate: rotate + 2160})
let cur = that.data.coupons[index]
let isBingo = !!cur.isPrize
let award = cur.name
that.setData({
isBingo: isBingo, // 是否中奖
award: award // 奖品
})
setTimeout(()=>{
//3S 后显示最终后果弹窗
that.setData({dialogShow: true})
},3000)
}
其余细节,我的项目不同再另外写
外围 css
.canvas-container {
width: 550rpx;
height: 550rpx;
transition:all 3s ease;
position: absolute;
top: 45rpx;
left: 110rpx;
z-index: 1;
border-radius: 50%;
overflow: hidden;
}
.canvas{
width: 550rpx;
height: 550rpx;
display: block;
position: fixed;
left: -5000px;
}