微信小程序营销之大转盘(二)

前言

大转盘营销活动大家应该都不陌生那如何用小程序实现呢?
第一个版本的大转盘都是用图片做的,奖品等信息都是不无法修改的,说白了就是没啥实际用途,作者我就直接用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();
};

完整代码

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

关注我们

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 好久没有写过年终总结这种东西,可能是觉得随着自己的成长成熟,只要把眼前的事情把今天做好就可以了,过往的一切没有什么...
    sagittario阅读 194评论 0 0
  • 她来自一个偏僻的农村。 朴实。简单。 杏仁眼,总喜欢瞪大了眼睛看着你,眼神里满满都是对你的信赖。而且,她笑起来非常...
    秋笏笑月阅读 312评论 0 0
  • 总是看不见您对我的付出 直到做了妈妈才想到您不容易 每次打电话您总是报喜不报忧 开心地说老爸还在打...
    赫颖阅读 185评论 0 0