canvas版人体时钟的实现示例


Posted in HTML / CSS onJanuary 29, 2021

不知道老网民们还记不记得这个魔性的时钟插件:

canvas版人体时钟的实现示例

作为网上冲浪十数载的网虫,不久前看到这个图瞬间破防,直接梦回10年前的QQ空间,感叹一下岁月蹉跎、时光荏苒、青春不在、不胜唏嘘。

十年后的今天,flash在各个浏览器都已经不再支持,已经是个不再那个只会用脚本打扮QQ空间的我,自然得用青春换来得技术还原一下自己的青春记忆。

首先感谢原作者提供的如此优秀好玩的插件: http://chabudai.org/blog/?p=59

这次为了图方便,就直接那pixi.js来上手做动画了,动画素材来源于油管视频,拿到PS逐帧抠图并导出,这个过程就不再详细介绍了。合成后的精灵图以及对应的json文件我会放在文章末尾。

核心的API是PIXI.AnimatedSprite。

代码也是很短,就直接放到下面了

<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>HoneHoneClock</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }
    html, body {
      width: 100%;
      height: 100%;
    }
    body {
      background-color: lightcyan;
    }
    canvas {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
    }
  </style>
</head>
<body>
<canvas class="canvas"></canvas>
<script src="pixi_5.3.4.min.js"></script>
<script src="Stats.min.js"></script>
<script>

  (async function () {
    const stats = new Stats()
    document.body.appendChild(stats.domElement)

    let pageWidth = 0
    let pageHeight = 0

    let clockHour1, clockHour2
    let clockMin1, clockMin2
    let clockSec1, clockSec2
    const $canvas = document.querySelector('canvas')
    const renderer = new PIXI.Renderer({
      view: $canvas,
      width: pageWidth,
      height: pageHeight,
      transparent: true,
      autoDensity: true,
      antialias: true
    })

    // 人体时钟
    class Clock extends PIXI.Container {
      constructor (name) {
        super()
        const textures = loader.resources[honeHoneClockJson].textures
        let frames = []
        let aniData = []
        if (this.frames) {
          frames = this.frames
          aniData = this.aniData
        }
        else {
          aniData = [
            {
              prefix: '0',
              count: 6,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '1',
              count: 9,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '2',
              count: 7,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '3',
              count: 6,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '4',
              count: 9,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '5',
              count: 14,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '6',
              count: 7,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '7',
              count: 10,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '8',
              count: 7,
              frameFrom: -1,
              frameTo: -1,
            },
            {
              prefix: '9',
              count: 9,
              frameFrom: -1,
              frameTo: -1,
            },
          ]
          let k = 0
          for (let i = 0; i < aniData.length; i++) {
            const data = aniData[i]
            data.frameFrom = k
            for (let j = 1; j <= data.count; j++) {
              k++
              frames.push(textures[`${data.prefix}(${j}).png`])
            }
            data.frameTo = k - 1
          }
          this.frames = frames
          this.aniData = aniData
        }
        const ani = new PIXI.AnimatedSprite(frames)
        ani.anchor.set(0.5, 1)
        ani.animationSpeed = 0.4

        this.stopAt = -1
        ani.onFrameChange = () => {
          if (ani.currentFrame === this.stopAt) {
            ani.stop()
          }
        }
        this.addChild(ani)
        this.name = name
        this.ani = ani
        this.num = -1
      }

      set number (number) {
        if (this.num !== number) {
          this.num = number
          this.stopAt = this.aniData[number].frameTo
          this.ani.gotoAndPlay(this.aniData[number].frameFrom)
        }
      }
    }

    const stage = new PIXI.Container()
    stage.name = 'stage'
    let clockWrap

    const ticker = new PIXI.Ticker()
    let now = new Date()
    let lastTime = now.getTime()
    const loop = function () {
      stats.begin()
      now = new Date()
      if (now.getTime() - lastTime >= 1000) {
        let hours = now.getHours()
        if (hours > 9) {
          clockHour1.number = Math.floor(hours / 10)
          clockHour2.number = hours % 10
        }
        else {
          clockHour1.number = 0
          clockHour2.number = hours
        }

        let minutes = now.getMinutes()
        if (minutes > 9) {
          clockMin1.number = Math.floor(minutes / 10)
          clockMin2.number = minutes % 10
        }
        else {
          clockMin1.number = 0
          clockMin2.number = minutes
        }

        let seconds = now.getSeconds()
        if (seconds > 9) {
          clockSec1.number = Math.floor(seconds / 10)
          clockSec2.number = seconds % 10
        }
        else {
          clockSec1.number = 0
          clockSec2.number = seconds
        }
        lastTime = now.getTime()
      }
      renderer.render(stage)
      stats.end()
    }

    ticker.add(loop)

    const honeHoneClockJson = 'HoneHoneClock.json'
    const loader = new PIXI.Loader()
    loader.add([honeHoneClockJson])
    loader.onComplete.add(async (res) => {
      clockWrap = new PIXI.Container()
      clockWrap.position.set((pageWidth - 630) * 0.5, (pageHeight + 150) * 0.5)

      clockHour1 = new Clock('hour')
      clockHour2 = new Clock('hour')
      clockMin1 = new Clock('min')
      clockMin2 = new Clock('min')
      clockSec1 = new Clock('sec')
      clockSec2 = new Clock('sec')
      clockHour1.position.set(0, 0)
      clockHour2.position.set(100, 0)
      clockMin1.position.set(250, 0)
      clockMin2.position.set(350, 0)
      clockSec1.position.set(500, 0)
      clockSec2.position.set(600, 0)
      clockWrap.addChild(clockHour1)
      clockWrap.addChild(clockHour2)
      clockWrap.addChild(clockMin1)
      clockWrap.addChild(clockMin2)
      clockWrap.addChild(clockSec1)
      clockWrap.addChild(clockSec2)
      stage.addChild(clockWrap)

      // 开始动画循环
      ticker.start()
    })
    loader.load()

    const onResize = (e) => {
      pageWidth = document.body.clientWidth
      pageHeight = document.body.clientHeight
      if (clockWrap) {
        clockWrap.position.set((pageWidth - 630) * 0.5, (pageHeight + 150) * 0.5)
      }
      renderer.resize(pageWidth, pageHeight)
    }

    onResize()

    window.onresize = onResize
  })()
</script>
</body>
</html>

完整代码戳这里

在线演示1 、 在线演示2

到此这篇关于canvas版人体时钟的实现示例的文章就介绍到这了,更多相关canvas人体时钟内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!

HTML / CSS 相关文章推荐
CSS3——齿轮转动关键代码
May 02 HTML / CSS
详解CSS3中nth-child与nth-of-type的区别
Jan 05 HTML / CSS
css3实现书本翻页效果的示例代码
Mar 08 HTML / CSS
HTML5 拖拽批量上传文件的示例代码
Mar 28 HTML / CSS
Canvas与Image互相转换示例代码
Aug 09 HTML / CSS
HTML5 在canvas中绘制文本附效果图
Jun 23 HTML / CSS
HTML5和CSS3实例教程总结(推荐)
Jul 18 HTML / CSS
HTML5去掉输入框type为number时的上下箭头的实现方法
Jan 03 HTML / CSS
Html5在手机端调用相机的方法实现
May 13 HTML / CSS
浅析HTML5页面元素及属性
Jan 20 HTML / CSS
利用html+css实现菜单栏缓慢下拉效果的示例代码
Mar 30 HTML / CSS
clear 万能清除浮动(clearfix:after)
May 21 HTML / CSS
h5页面背景图很长要有滚动条滑动效果的实现
Jan 27 #HTML / CSS
ivx平台开发之不用代码实现一个九宫格抽奖功能
Jan 27 #HTML / CSS
详解如何将 Canvas 绘制过程转为视频
Jan 25 #HTML / CSS
HTML5适合的情人节礼物有纪念日期功能
Jan 25 #HTML / CSS
html table呈现个人简历以及单元格宽度失效的问题解决
Jan 22 #HTML / CSS
浅析HTML5页面元素及属性
Jan 20 #HTML / CSS
详解如何解决H5开发使用wx.hideMenuItems无效果不生效
Jan 20 #HTML / CSS
You might like
php字符串截取问题
2006/11/28 PHP
几种有用的变型 PHP中循环语句的用法介绍
2012/01/30 PHP
PHP浮点比较大小的方法
2016/02/14 PHP
验证token、回复图文\文本、推送消息的实用微信类php代码
2016/06/28 PHP
jquery中交替点击事件的实现代码
2014/02/14 Javascript
js兼容pc端浏览器并有多种弹出小提示的手机端浮层控件实例
2015/04/29 Javascript
基于Jquery实现焦点图淡出淡入效果
2015/11/30 Javascript
高效的jquery数字滚动特效
2015/12/17 Javascript
jQuery弹层插件jquery.fancybox.js用法实例
2016/01/22 Javascript
AngularJS中的按需加载ocLazyLoad示例
2017/01/11 Javascript
jquery实现静态搜索功能(可输入搜索文字)
2017/03/28 jQuery
vue中实现methods一个方法调用另外一个方法
2018/02/08 Javascript
解决使用vue.js路由后失效的问题
2018/03/17 Javascript
vue实现引入本地json的方法分析
2018/07/12 Javascript
vue-cli基础配置及webpack配置修改的完整步骤
2019/10/20 Javascript
React.js组件实现拖拽排序组件功能过程解析
2020/04/27 Javascript
JavaScript 事件代理需要注意的地方
2020/09/08 Javascript
解决antd Form 表单校验方法无响应的问题
2020/10/27 Javascript
[41:37]DOTA2北京网鱼队选拔赛——冲击职业之路
2015/04/13 DOTA
[01:27:30]LGD vs Newbee 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/19 DOTA
sublime text 3配置使用python操作方法
2017/06/11 Python
python梯度下降法的简单示例
2018/08/31 Python
python获取微信小程序手机号并绑定遇到的坑
2018/11/19 Python
pyqt弹出新对话框,以及关闭对话框获取数据的实例
2019/06/18 Python
python飞机大战pygame游戏之敌机出场实现方法详解
2019/12/17 Python
sklearn+python:线性回归案例
2020/02/24 Python
Python Pandas 对列/行进行选择,增加,删除操作
2020/05/17 Python
python 爬虫如何正确的使用cookie
2020/10/27 Python
python 装饰器的基本使用
2021/01/13 Python
戴森英国官网:Dyson英国
2019/05/07 全球购物
酒吧创业计划书
2014/01/18 职场文书
怎样写好创业计划书的内容
2014/02/06 职场文书
关爱留守儿童倡议书
2014/04/15 职场文书
员工试用期自我鉴定范文
2014/09/15 职场文书
小程序教您怎样你零成本推广获取数万用户的方法
2019/07/30 职场文书
react如何快速设置文件路径别名
2021/04/28 Javascript