Skip to content

king0222/bigwheel-miniapp

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

前言

大转盘营销活动大家应该都不陌生那如何用小程序实现呢? 第一个版本的大转盘都是用图片做的,奖品等信息都是不无法修改的,说白了就是没啥实际用途,作者我就直接用canvas撸了一个全手工绘制的大转盘分享给大家。此处应有掌声 : )

效果图

因为gif动态效果图实在是太大了,就截取了两张图片给大家看

项目结构

运行流程

  • 获取所有奖品列表
  • 绘制指针和转盘
  • 绑定指针区域点击事件
  • 点击指针开始转动
  • 请求后端获取抽中的奖品
  • 调用大转盘停止方法把奖品传进去
  • 大转盘停止转动
  • 展示奖品和信息

关键代码

绘制大转盘和绑定指针点击事件

 // 启用事件
    point.inputEvent = true;
    point.onInputDown = run;
// 更新动画
    var update = function () {
      // 清空
      context.clearRect(0, 0, w, h);
      // 画转盘
      wheel.draw(context);
      // 画指针
      point.draw(context);

      // 更新数据
      animation.draw(context);
      // 更新数据
      animation.update();

      // 获取手指点击
      var touch = that.data.touch;
      if (point.inputEvent && touch.isPressed && point.onInputDown) {
        // 如果点击到了指针
        if (point.contains(touch)) {
          // 调用点击回调方法
          point.onInputDown();
        }
      }

      // 绘图   
      context.draw()

    };
    setInterval(update, 1000 / fps, 1000 / fps);

点击指针之后的回调处理 使用setTimeout 模拟后端返回结果 使用stopTo 方法来让大转盘停止到某一个奖品

 // 开始转
    function run() {
      // 避免重复调用
      if (animation.isRun) return;
      // 当动画完成时
      animation.onComplete = function (prize) {
        wx.showToast({
          image: prize.img,
          title: prize.text,
          duration: 3000,
          mask: true,
        })
      };

      // 开始转
      animation.run();

      // 模拟后台返回数据
      setTimeout(function () {
        // 随机一个奖品
        var prizeIndex = utils.getRandom(slicePrizes.length - 1);
        // 计算奖品角度
        animation.stopTo(prizeIndex);
      }, 3000);
    }

转动处理的构造方法

function Animation(circle, screen) {
  this.circle = circle;
  this.screen = screen;
  // 角速度
  this.speed = 0;
  // 最大速度
  this.maxSpeed = 10;
  // 摩擦力
  this.friction = 0.98;
  // 加速度
  this.acceleration = 0.5;
  // 是否开始运行
  this.isRun = false;
  // 圈数
  this.rounds = 5;
  // 角度
  this.degrees = 0;
  // 当前角度
  this.angle = -90;
  // 开始减速
  this.speedDown = false;
  // 开始加速
  this.speedUp = true;
  // 顺时针还是逆时针
  this.anticlockwise = false;
  // 完成
  this.onComplete = null;
  // debug
  this.isDebug = false;
}

转动效果,先加速》匀速一段时间》调用stopTo方法后》减速》停止

Animation.prototype.update = function () {
  if (this.isRun) {
    // 到达奖品区
    var isJoin = this.prize && this.angle > this.minAngle && this.angle < this.maxAngle;
    // 是否要减速
    if (isJoin) {
      this.speedDown = true;
    }

    // 是否要停止加速
    if (this.speed >= this.maxSpeed) {
      this.speedUp = false;
    }

    // 加速
    if (this.speedUp) {
      this.speed += this.acceleration;
    }

    // 减速
    if (this.speedDown) {
      if (this.speed <= 2 && isJoin) {
        this.isRun = false;
        this.speed = 0;
        if (this.onComplete) this.onComplete(this.prize);
      } else if (this.speed <= 1) {
        this.speed = 1;
      } else {
        this.speed *= this.friction;
      }
    }

    this.angle += this.speed;
    // 转动角度
    if (Math.abs(this.angle) > 360) {
      this.angle -= 360;
    }
    // 旋转方向
    if (this.anticlockwise) {
      this.circle.rotation += (Math.PI / 180) * this.speed;
    } else {
      this.circle.rotation -= (Math.PI / 180) * this.speed;
    }
  }
};

大转盘的绘制

Circle.prototype.draw = function (context) {
  // 保存
  context.save();
  // 移动到圆心
  context.translate(this.x, this.y);
  // 旋转
  context.rotate(this.rotation);
  // 缩放
  // context.scale(this.scaleX, this.scaleY);

  if (this.img) {
    var imgX = -this.width / 2;
    var imgY = -this.height / 2;
    context.drawImage(this.img, imgX, imgY);
  }
  var colors = this.colors;
  var size = this.size;
  var angle = this.angle;

  var r = this.radius;

  // 画扇形
  for (var i = 0; i < size; i++) {
    context.beginPath()
    context.moveTo(0, 0)
    context.arc(0, 0, r, 0, angle * Math.PI / 180)
    context.setFillStyle(colors[i % colors.length])
    context.fill()
    context.rotate(angle * Math.PI / 180);
  }

  // 画图案
  // 计算圆上任意一点
  var offset = this.radius / 2;
  var offsetA = angle / 2;
  var offsetX = Math.cos(offsetA * Math.PI / 180) * offset;
  var offsetY = Math.sin(offsetA * Math.PI / 180) * offset;
  for (var i = 0; i < size; i++) {
    var prize = this.slicePrizes[i]
    context.save();

    context.translate(offsetX, offsetY);

    context.rotate((180 - ((180 - angle) / 2)) * Math.PI / 180);
    context.drawImage(prize.img, -10, -30, this.prizeWidth, this.prizeHeight);

    // 写文字
    context.setFontSize(this.prizeFontSize)
    context.setFillStyle(this.prizeFontStyle)
    context.textAlign = "center";
    context.fillText(prize.text, 0, (offset - 25) * -1)

    // 话圆点参考
    // context.beginPath()
    // context.arc(0, 0, 2, 0, 2 * Math.PI)
    // context.setFillStyle('red')
    // context.fill()

    context.restore()
    context.rotate(angle * Math.PI / 180);
  }

  // 还原
  context.restore();
};

指针和跑马灯的绘制

Circle.prototype.draw = function (context) {
  // 保存
  context.save();
  // 移动到圆心
  context.translate(this.x, this.y);
  // 旋转
  context.rotate(this.rotation);
  // 缩放
  // context.scale(this.scaleX, this.scaleY);

  if (this.img) {
    var imgX = -this.width / 2;
    var imgY = -this.height / 2;
    context.drawImage(this.img, imgX, imgY);
  }

  // 指针
  context.beginPath()
  context.setFillStyle('#ffffff')
  context.moveTo(0, (this.radius + 50) * -1);
  context.lineTo(-10, 0);
  context.lineTo(10, 0);
  context.fill()

  // 圆盘
  context.beginPath()
  context.setFillStyle('#ffffff')
  context.arc(0, 0, this.radius, 0, 2 * Math.PI)
  context.fill()

  // 文字
  context.setFontSize(30)
  context.setFillStyle('#ff2244')
  context.setTextAlign("center");
  context.fillText('抽奖', 0, 10)

  var r = this.wheel.radius;
  // 跑马灯外框  F6D000  FFA200
  context.beginPath()
  context.setLineWidth(15);
  context.setStrokeStyle("#FFA200")
  context.arc(0, 0, r + 20, 0, 2 * Math.PI)
  context.stroke()

  // 跑马灯内框 F6D000
  context.beginPath()
  context.setLineWidth(10);
  context.setStrokeStyle("#F6D000")
  context.arc(0, 0, r + 8, 0, 2 * Math.PI)
  context.stroke()

  // 跑马灯灯  
  for (var i = 0; i < 32; i++) {
    context.beginPath()
    context.setFillStyle(i % 2 == 0 ? "#ffffff" : "#FF403A")
    context.arc(r + 20, 0, 4, 0, 2 * Math.PI)
    context.fill()
    context.rotate((360 / 32) * Math.PI / 180);
  }
  // 还原
  context.restore();
};

其他推荐

微信小程序-欢乐夹娃娃 https://blog.100boot.cn/post/3067

微信小程序-欢乐夹娃娃

完整代码

GitHub 地址: https://github.com/qiaohhgz/bigwheel-miniapp

关注我们

IT实战联盟是集产品、UI设计、前后端、架构、大数据和AI人工智能等为一体的实战交流服务平台!联盟嘉宾都为各互联网公司项目的核心成员,联盟主旨是“让实战更简单”,欢迎来撩~~~

我们的网站: http://100boot.cn

About

微信小程序大转盘

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 100.0%