美文网首页
Canvas制作滚动的数字时钟

Canvas制作滚动的数字时钟

作者: ohityes | 来源:发表于2022-05-08 23:20 被阅读0次

    这是一款滚动的数字时钟,使用 canvas 制作,采用 12 小时制,右上角显示 AM 或 PM,时钟以秒为单位,从上往下滚动。

    滚动的数字时钟
    查看效果:滚动的数字时钟演示

    制作过程

    1、HTML

    由于是把时钟绘制到 canvas 里,所以 html 机构就比较简单了。另外,还使用到了 lightning.js,所以 html 结构如下:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="utf-8" />
        <title>滚动的数字时钟演示_dowebok</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
        <link rel="stylesheet" href="style.css" />
    </head>
    <body>
        <div class="app"></div>
        <script src="lightning.min.js"></script>
        <script src="script.js"></script>
    </body>
    </html>
    

    2、CSS

    CSS 也很简单,代码如下:

    html,
    body {
        padding: 0;
        margin: 0;
        font-size: 16px;
        background: #000;
    }
    
    body {
        font-family: 'peacock';
    }
    
    canvas {
        display: block;
        object-fit: contain;
        width: 100vw;
        height: 100vh;
    }
    

    3、Javascript

    因为是用 canvas 绘制数字时钟,所以主要的代码都有 JS 实现:

    const width = window.innerWidth < 450 ? 450 : window.innerWidth
    const height = window.innerHeight
    const lineHeight = 80
    const commonFont = {
        fontFace: 'peacock',
        fontSize: lineHeight,
        lineHeight: lineHeight,
        textColor: 0xffffffff
    }
    class App extends lng.Application {
        static _template() {
            return {
                TimeWrapper: {
                    flex: { direction: 'row' },
                    mount: 0.5,
                    x: width * 0.5,
                    y: height * 0.5,
                    Hours: {
                        w: 100,
                        children: [{ type: ChangeValue }, { type: ChangeValue, x: 50 }]
                    },
                    ColonOne: {
                        text: Object.assign({ text: ':' }, commonFont)
                    },
                    Minutes: {
                        w: 100,
                        children: [{ type: ChangeValue }, { type: ChangeValue, x: 50 }]
                    },
                    ColonTwo: {
                        text: Object.assign({ text: ':' }, commonFont)
                    },
                    Seconds: {
                        w: 100,
                        children: [{ type: ChangeValue }, { type: ChangeValue, x: 50 }]
                    },
                    AmPm: {
                        w: 61,
                        x: 10,
                        y: 10,
                        type: ChangeValue,
                        fontSize: 40,
                        lineHeight: 40
                    }
                }
            }
        }
        setTime(lastTime) {
            const currentDate = new Date()
            currentDate.setSeconds(currentDate.getSeconds() - 1)
            if (!lastTime || currentDate.toString() !== lastTime.toString()) {
                const nextDate = new Date()
                this.setCurrentNext(
                    'Hours',
                    this.set12Hours(currentDate.getHours()),
                    this.set12Hours(nextDate.getHours()),
                    false
                )
                this.setCurrentNext('Minutes', currentDate.getMinutes(), nextDate.getMinutes())
                this.setCurrentNext('Seconds', currentDate.getSeconds(), nextDate.getSeconds())
                this.tag('AmPm').patch({
                    currentValue: this.getAmPm(currentDate.getHours()),
                    nextValue: this.getAmPm(nextDate.getHours())
                })
            }
            window.requestAnimationFrame(() => this.setTime(currentDate))
        }
        getAmPm(hours) {
            let ampm = 'AM'
            if (hours >= 12 && hours < 24) {
                ampm = 'PM'
            }
            return ampm
        }
        set12Hours(hours) {
            return hours % 12 || 12
        }
        doubleZero(val) {
            return val < 10 ? '0' + val : val.toString()
        }
        setCurrentNext(tagName, currentValue = '', nextValue = '', leading = true) {
            const tag = this.tag(tagName)
            currentValue = this.doubleZero(currentValue).split('')
            nextValue = this.doubleZero(nextValue).split('')
            if (!leading) {
                currentValue[0] = currentValue[0] === '0' ? '' : currentValue[0]
                nextValue[0] = nextValue[0] === '0' ? '' : nextValue[0]
            }
            tag.children = tag.children.map((child, i) => {
                child.patch({
                    currentValue: currentValue[i],
                    nextValue: nextValue[i]
                })
                return child
            })
        }
        _init() {
            this.setTime()
        }
    }
    class ChangeValue extends lng.Component {
        _construct() {
            this.duration = 0.7
            this.commonFont = commonFont
        }
        _init() {
            this.tag('Group').children.forEach((child) => {
                child.patch({
                    text: {
                        fontSize: this.fontSize || this.commonFont.fontSize,
                        lineHeight: this.lineHeight || this.commonFont.lineHeight
                    }
                })
            })
        }
        static _template(that) {
            return {
                Group: {
                    Current: {
                        text: Object.assign(
                            {
                                text: this.bindProp(['currentValue', 'nextValue'], (ctx) => {
                                    const currentValue = ctx.currentValue
                                    const nextValue = ctx.nextValue
                                    if (currentValue !== nextValue) {
                                        ctx.changePosition(ctx)
                                    }
                                    return currentValue
                                })
                            },
                            that.commonFont
                        )
                    },
                    Next: {
                        y: that.commonFont.lineHeight * -1,
                        alpha: 1,
                        scale: 0.5,
                        text: Object.assign({ text: this.bindProp(['nextValue']) }, that.commonFont)
                    }
                }
            }
        }
        changePosition(ctx) {
            ctx.tag('Group').setSmooth('y', ctx.commonFont.lineHeight, { duration: ctx.duration })
            ctx.tag('Current').setSmooth('alpha', 0, { duration: ctx.duration })
            ctx.tag('Current').setSmooth('scale', 0.5, { duration: ctx.duration })
            ctx.tag('Next').setSmooth('alpha', 1, { duration: ctx.duration })
            ctx.tag('Next').setSmooth('scale', 1, { duration: ctx.duration })
            ctx.tag('Next')
                .transition('scale')
                .on('finish', () => {
                    ctx.resetPosition(ctx)
                })
        }
        resetPosition(ctx) {
            ctx.tag('Current').patch({
                text: { text: ctx.nextValue },
                alpha: 1,
                scale: 1
            })
            ctx.tag('Group').patch({ y: 0 })
            ctx.tag('Next').patch({ alpha: 0, scale: 0.5 })
        }
    }
    const StartApp = new App({
        stage: {
            w: adjustDevicePixelRatio(width),
            h: adjustDevicePixelRatio(height),
            precision: adjustDevicePixelRatio(),
            clearColor: '0x00ff0000',
            useImageWorker: false
        },
        debug: true
    })
    const canvasApp = StartApp.stage.getCanvas()
    document.querySelector('.app').appendChild(canvasApp)
    function adjustDevicePixelRatio(val = 1) {
        return val * (window.devicePixelRatio || 1)
    }
    

    到这里就制作完了,如需下载代码,请点击:滚动的数字时钟

    相关文章

      网友评论

          本文标题:Canvas制作滚动的数字时钟

          本文链接:https://www.haomeiwen.com/subject/bpycurtx.html