微信小程序实现转盘抽奖,可以自定义编辑奖项列表

这个功能可以分几步实现:

1. 界面设计:

转盘区域: 使用 canvas 绘制转盘,可配置扇形数量、颜色、文字等。
按钮: "开始/停止" 按钮控制转盘转动。
编辑按钮: 点击弹出弹窗,编辑转盘项目。
中奖弹窗: 显示中奖结果。
2. 数据结构:

使用数组存储转盘项目数据,例如:

const prizeList = [
  { name: '一等奖', color: '#FFD700' },
  { name: '二等奖', color: '#C0C0C0' },
  { name: '三等奖', color: '#CD7F32' },
  // ... 其他奖项
];


3. 功能实现:

绘制转盘:
根据 prizeList 数据计算每个扇形的角度。
使用 canvas API 绘制扇形、文字、边框等。

drawPrizeWheel() {
    // 创建离屏 2D canvas 实例,创建canvas元素
    const canvas = wx.createOffscreenCanvas({type: '2d', width: 300, height: 300});
    // 获取 context。注意这里必须要与创建时的 type 一致const ctx = canvas.getContext('2d');
    const centerX = 150;
    const centerY = 150;
    const radius = 130;
    const prizeCount = this.data.prizeList.length;
    const anglePerItem = 360 / prizeCount;
    // 记录当前角度,初始为 0/90 度
    let currentAngle = 90; 
    for (let i = 0; i < prizeCount; i++) {
      ctx.beginPath();
      ctx.moveTo(centerX, centerY);
      ctx.arc(
        centerX,
        centerY,
        radius,
        (i * anglePerItem * Math.PI) / 180,
        ((i + 1) * anglePerItem * Math.PI) / 180,
      );
      ctx.closePath();
      ctx.fillStyle = this.data.prizeList[i].color;
      ctx.fill();
      // --- 绘制文字 ---
      ctx.save(); 
      // 保存当前画布状态
      ctx.font = '12px sans-serif';
      ctx.fillStyle = '#fff';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      const textAngle = (i * anglePerItem + anglePerItem / 2) * (Math.PI) / 180;
      const textX = centerX + radius * 0.7 * Math.cos(textAngle);
      const textY = centerY + radius * 0.7 * Math.sin(textAngle);
      ctx.fillText(this.data.prizeList[i].name, textX, textY);
      ctx.restore(); 
      // 恢复之前的画布状态// --- 文字绘制结束 ---
      // 计算当前奖项区域的结束角度
      let endAngle = currentAngle + anglePerItem;
      if(endAngle > 360){
        endAngle %= 360;
      }
      // 计算当前奖项区域的起始角度和结束角度
      // 将角度信息存储到 prizeList 数组中
      this.data.prizeList[i].startAngle = currentAngle;
      this.data.prizeList[i].endAngle = endAngle;
      // 更新 currentAngle,准备绘制下一个区域
      currentAngle = endAngle; 
    }
    // 将canvas转换为DataURL格式的图片var dataURL = canvas.toDataURL('image/png', 1);this.setData({wheelImg: dataURL});
  },

代码解释:

初始化 currentAngle: 在循环开始之前,将 currentAngle 初始化为 90,表示从 90 度开始绘制。因为canvas 绘制圆弧的起始角度是水平向右的 x 轴正方向,而不是竖直向上的 y 轴正方向。所以这里实际起始角度是从90度开始。
计算结束角度: 在每次循环中,根据 currentAngle 和 anglePerItem 计算当前奖项区域的结束角度 endAngle。
绘制扇形: 使用 currentAngle 和 endAngle 绘制当前奖项区域的扇形。将 currentAngle 和 endAngle 存储到 prizeList 数组中,方便后续判断中奖区域。更新 currentAngle: 将 currentAngle 更新为 endAngle,以便绘制下一个奖项区域。最后把canvas转换为base64图片地址。 
记录角度信息: 在 drawPrizeWheel 方法中,我们为prizeList数组中每个奖项对象添加了 startAngle 和 endAngle 属性,用来存储该奖项区域的起始和结束角度。
判断指针位置: 在 stopRotate 方法中,我们循环遍历 prizeList 数组,并根据每个奖项的 startAngle 和 endAngle 判断指针是否落在该区域内。
注意处理了跨越 0 度的情况,如果 startAngle 大于 endAngle,则表示该区域跨越了 0 度,需要分别判断指针是否大于等于 startAngle 或者小于 endAngle。
通过以上修改,奖项区域将从 0 度开始绘制,并且每个区域的角度信息会被正确记录在 prizeList 数组中,然后在 stopRotate方法中准确判断指针落在哪个区域,从而确定中奖结果。

转盘转动:
使用 setInterval/setTimeout 或 requestAnimationFrame 实现动画效果。
控制转速和停止位置。

<view class="pointer" style="transform: rotate({
  {pointerAngle}}deg)"></view>
//开始旋转
startRotate() {
    if (this.data.isRotating) return;
    this.setData({ isRotating: true });
    // 生成随机旋转圈数(至少旋转 6 圈)
    const randomRounds = 6 + Math.floor(Math.random() * 3); 
    // 生成随机停止角度
    const finalAngle = Math.floor(Math.random() * 360);
    // 计算总旋转角度
    const totalRotation = randomRounds * 360 + finalAngle;
    // 使用 setInterval 实现动画
    const startTime = Date.now();const frameRate = 80; 
    const rotateAnimation = () => {
      const currentTime = Date.now();
      const elapsed = currentTime - startTime;
      const progress = Math.min(elapsed / this.data.animationDuration, 1);
      // 使用 ease-out 动画曲线
      const easeOut = (t) => 1 - Math.pow(1 - t, 3);
      // 计算当前角度
      const currentAngle = easeOut(progress) * totalRotation;
      this.setData({ pointerAngle: currentAngle });
      i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值