• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

小程序canvas动画解决方案,绘制一个塔罗牌动画

原作者: [db:作者] 来自: [db:来源] 收藏 邀请


wxml


<canvas style='width:{{windowWidth}}px;height:{{height}}px;  position: fixed;' canvas-id="secondCanvas0">
</canvas>
<canvas style='width:{{windowWidth}}px;height:{{height}}px;  position: fixed;' canvas-id="secondCanvas1"></canvas>
<view class='receivenow_view'>
  <view class="receivenow_button_view" bindtap='{{!start_state?"shuffle_func":"card_selection_func"}}' style='margin-top:{{height+10}}px' animation="{{animation3}}">
    <text>{{!start_state?"开始洗牌":"开始选牌"}}</text>
  </view>
</view>

wxss

.receivenow_view {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding-bottom: 80rpx;
}

.receivenow_button_view {
  font-size: 30rpx;
  color: #fff;
  padding: 35rpx 190rpx;
  border-radius: 60rpx;
  background: linear-gradient(to right, #ff5846, #ff067a);
  line-height: normal;
}

js

const animationFrame = require('../../utils/requestAnimationFrame.js')
const ctx0 = wx.createCanvasContext('secondCanvas0')
const ctx = wx.createCanvasContext('secondCanvas1')

Page({

  /**
   * 
   */
  data: {
    //默认canvas高度
    height: 375,
    //默认canvas宽度
    windowWidth: 375,
    //背景资源
    bg: "",
    //卡片资源
    card: "",
    //是否开始洗牌
    start_state: false,
    //开场动画是否结束
    kaichang: false,
    // 是否开始选牌
    card_selection: false,
    //20张卡开场动画过后的所在位置x坐标
    xarrs: [],
    //20张卡开场动画过后的所在位置y坐标
    yarrs: [],
    //开场动画执行时间
    start_time: 1500,
    card_width: 46,
    card_height: 76.3
  },
  onLoad: function(options) {
    var that = this
    //获取手机屏幕宽度
    wx.getSystemInfo({
      success(res) {
        let windowWidth = res.windowWidth
        let height = windowWidth
        that.setData({
          height: height,
          windowWidth: windowWidth
        })
      }
    })
    // const ctx = wx.createCanvasContext('secondCanvas')

    // ctx.clearRect(0, 0, that.data.windowWidth, that.data.height)
    // ctx.draw()

    this.init();
  },
  //初始化数据,获取绘图所需图片
  init() {

    var doAnimationFrame = animationFrame.doAnimationFrame
    this.setData({
      bg: "/img/bg.jpg",
      card: "/img/card.png"
    })
    this.draw();
  },
  //开始画图    
  draw() {
    var that = this
    let width = that.data.windowWidth
    let height = that.data.height
    let nowtime = new Date().getTime()
    let time = that.data.start_time
    let card_width = that.data.card_width
    let card_height = that.data.card_height
    //用来存储所有卡片的x坐标和移动距离
    let xarrs = []
    //设置所有卡片的x坐标和移动距离
    for (let i = 0; i < 20; i++) {
      xarrs.push([width / 18, card_width * (i * 0.5)])
    }
    console.log(xarrs)
    //用来存储所有卡片的y坐标和移动距离
    let yarrs = [
      [height / 2 - card_height / 2, 0]
    ]
    //画一个背景
    ctx0.drawImage(that.data.bg, 0, 0, width, height);

    ctx0.draw()
    // animationFrame.doAnimationFrame,e为回调执行时间
    var rander = function(e) {
      e = e ? e : nowtime
      ctx.clearRect(0, 0, width, height) //清空所有的内容
      //绘制卡片  
      for (let i = 0; i < xarrs.length; i++) {
        ctx.drawImage(that.data.card, xarrs[i][0], yarrs[0][0], card_width, card_height);
        //从新设置卡片的x坐标和剩余移动距离
        xarrs[i] = that.move_x_func(xarrs[i][0], xarrs[i][1], time)
      }
      // console.log(arrs[0])      
      ctx.draw()
      //如果开始执行动画时间到最后一次的时间大于动画执行时间则停止动画
      if (e - nowtime < time) {
        var id = animationFrame.doAnimationFrame(rander);
      } else {
        //开场动画结束保存其位置
        that.setData({
          xarrs: xarrs,
          yarrs: yarrs,
          kaichang: true
        })
      }
    }
    rander()
  },
  //x坐标位置,以及移动距离(px),两秒移动s,16ms移动多少;time动画持续时间返回一个arr
  move_x_func(position, s, time) {
    // console.log(position)
    //动画持续时长两秒
    position = parseFloat(position.toFixed(2))
    //16ms移动的距离
    let time_distance = parseFloat((s * 16 / time).toFixed(2))
    s = parseFloat(s.toFixed(2))
    if (s === 0) {
      return [position, s];
    } else {
      return [position + time_distance, s - time_distance]
    }
  },
  //y坐标位置,以及移动距离
  move_y_func(position, s) {

  },
  //洗牌开始
  shuffle_func() {
    let that = this
    let width = that.data.windowWidth
    let height = that.data.height
    let nowtime = new Date().getTime()
    let time = that.data.start_time
    let card_width = that.data.card_width
    let card_height = that.data.card_height
    let xarrs = that.data.xarrs
    let yarrs = that.data.yarrs
    let time1 = 0
    //如果还未开场,不进行洗牌
    if (!that.data.kaichang | that.data.start_state) {
      return false;
    }
    var animation3 = wx.createAnimation({
      duration: 300,
      timingFunction: 'ease',
    })
    animation3.scale3d(0.1, 0.1, 0.1).step().scale3d(1, 1, 1).step();
    that.setData({
      animation3: animation3,
      //洗牌开始了,改变是否洗牌的状态
      start_state: true
    })

    let x = that.rnd(1, height / 2)
    let ys = []
    let xs = []
    let centers = []
    for (let i = 0; i < xarrs.length; i++) {
      ys.push(that.rnd(height / 10, height / 8))
      // xs.push(that.rnd(width / 8, width / 4))
      xs.push(width / 10)
      centers.push([that.rnd(width / 4, width / 2), that.rnd(height / 4, height / 2)])
    }

    //用户点击洗牌,执行另一个动画
    var rander = function(e) {
      ctx.clearRect(0, 0, width, height) //清空所有的内容 
      //设置中心点
      ctx.translate(width / 2, height / 2);
      for (let i = 0; i < xarrs.length; i++) {
        //设定每次旋转的度数
        // ctx.save()
        ctx.rotate(time1 * Math.PI / 540);
        ctx.drawImage(that.data.card, xs[i], ys[i], card_width, card_height);
        // ctx.restore()  
      }
      ctx.draw()
      time1++
      if (!that.data.card_selection) {
        var id = animationFrame.doAnimationFrame(rander);
      }
    }
    rander()
  },
  /**
   * 选牌开始
   * 所有当前卡牌归位
   */
  card_selection_func() {
    let that = this
    //设置开始选牌为true
    that.setData({
      card_selection: true
    })
  },
  //在min和max之间取随机
  rnd(min, max) {
    return min + Math.floor(Math.random() * (max - min + 1));
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function(options) {
    var that = this;
    return {
      title: "塔罗牌测试",
      path: '/pages/start/start',
      imageUrl: "/img/share.png",
      success: function(res) {
        var shareTickets = res.shareTickets;
        //如果分享不成功,或者不是到群
        if (shareTickets.length == 0) {
          return false;
        }
      }
    }
  },
})

requestAnimationFrame.js

// 模拟 web端的requestAnimationFrame

// lastFrameTime为上次更新时间
var lastFrameTime = 0;
var doAnimationFrame = function(callback) {
  //当前毫秒数
  var currTime = new Date().getTime();
  //设置执行该函数的等待时间,如果上次执行时间和当前时间间隔大于16ms,则设置timeToCall=0立即执行,否则则取16-(currTime - lastFrameTime),确保16ms后执行动画更新的函数
  var timeToCall = Math.max(0, 16 - (currTime - lastFrameTime));
  // console.log(timeToCall)
  var id = setTimeout(function() {
    callback(currTime + timeToCall);
    //确保每次动画执行时间间隔为16ms
  }, timeToCall);
  //timeToCall小于等于16ms,lastFrameTime为上次更新时间
  lastFrameTime = currTime + timeToCall;
  return id;
};
// 模拟 cancelAnimationFrame
var abortAnimationFrame = function(id) {
  clearTimeout(id)
}
module.exports = {
  doAnimationFrame: doAnimationFrame,
  abortAnimationFrame: abortAnimationFrame
}

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
小程序开发中的一些坑和技巧发布时间:2022-07-18
下一篇:
vue.js 小程序_vue.js上的支持拖放调度程序发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap