canvas版人体时钟的实现示例

作者:袖梨 2025-07-10

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

作为网上冲浪十数载的网虫,不久前看到这个图瞬间破防,直接梦回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人体时钟内容请搜索一聚教程网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持一聚教程网!

相关文章

精彩推荐