zoukankan      html  css  js  c++  java
  • Canvas 倒计时

    背景

    由于最近要做一个小程序倒计时功能,搜集了许多资料发现都是顺时针,要么就是差那么一点意思; 于是自己写了一个web版的,后续翻译成小程序版。

    思路

    1、三个canvas层,分为: bottom(底色圆圈)、center、top(由于canvas中圆形,没有类似clearReact的方法;重新画时界面会闪,这里用两个canvas来规避这个问题)

    2、center、top为每次倒计时的canvas,top比center小一帧

    3、每次重绘时,先把center 重置一次,再把top重置

    代码如下:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            .countdown-container {
                display: flex;
                justify-content: center;
                align-items: center;
                position: relative;
                width: 165px;
                height: 165px;
                margin: 0 auto;
            }
    
            .countdonw-time-container {
                display: flex;
                flex-direction: column;
                justify-content: center;
                align-items: center;
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
            }
    
            .countdown-time {
                font-size: 56px;
            }
    
            .countdown-tips {
                font-size: 12px;
            }
    
            .sign-btn {
                width: 120px;
                height: 32px;
                background: #4F8BFF;
                border-radius: 4px;
                color: white;
                display: flex;
                flex-direction: column;
                justify-content: center;
                margin: 20px auto;
                text-align: center;
            }
    
            #myCanvas1,
            #myCanvas2,
            #myCanvas3 {
                position: absolute;
                top: 0;
                left: 0;
            }
    
            #myCanvas1 {
                z-index: 0;
            }
    
            #myCanvas2 {
                z-index: 1;
            }
    
            #myCanvas3 {
                z-index: 2;
            }
    
            .hide {
                display: none;
                width: 0;
            }
        </style>
    </head>
    
    <body>
        <div class="countdown-container">
            <canvas id="myCanvas1" width="168" height="168"></canvas>
            <canvas id="myCanvas2" width="168" height="168"></canvas>
            <canvas id="myCanvas3" width="168" height="168"></canvas>
            <div class="countdonw-time-container">
                <div class="countdown-time">1</div>
                <div class="countdown-tips">倒计时( S )</div>
            </div>
        </div>
    
        <div class="sign-btn"></div>
    </body>
    
    </html>
    
    <script>
    
        const basePx = 168
        const toZoomPx = (pxValue) => {
            const width = document.documentElement.clientWidth;
            return pxValue * (width / 750)
        }
    
        const pxWidth = toZoomPx(basePx)
    
        const time = 30 // 可以随意设置
        let count = time // 倒计时剩余时间
        const percent = 2 / time // 每一秒需要的度数
        let timer
    
        const countTimeNode = document.querySelector('.countdown-time')
        const cvsNode1 = document.querySelector('#myCanvas1')
        const ctx1 = cvsNode1.getContext('2d')
    
        const cvsNode2 = document.querySelector('#myCanvas2')
        const ctx2 = cvsNode2.getContext('2d')
    
        const cvsNode3 = document.querySelector('#myCanvas3')
        const ctx3 = cvsNode3.getContext('2d')
        const btn = document.querySelector('.sign-btn')
    
        countTimeNode.innerHTML = time
    
    
        const drawBottom = () => {
            ctx1.beginPath()
            ctx1.lineWidth = 3
            ctx1.strokeStyle = '#d9d9d9'
            ctx1.arc((basePx - 2) / 2, (basePx - 6) / 2, (basePx - 10) / 2, 0, 2 * Math.PI, false)
            ctx1.stroke()
        }
    
        const getPercent = (count) => {
            const deg = (time - count) * percent
            console.log('count , deg:', count, deg)
            return deg <= 0 ? -0.5 * Math.PI : (1.5 - deg) * Math.PI
        }
    
        const drawCenter = () => {
            ctx2.beginPath()
            ctx2.lineWidth = 5
            ctx2.strokeStyle = '#4F8BFF'
            ctx2.lineCap = 'round'
            ctx2.arc((basePx - 2) / 2, (basePx - 6) / 2, (basePx - 10) / 2, 1.5 * Math.PI, getPercent(count), false)
            ctx2.stroke()
        }
    
        const drawTop = () => {
            ctx3.beginPath()
            ctx3.lineWidth = 5
            ctx3.strokeStyle = '#4F8BFF'
            ctx3.lineCap = 'round'
            ctx3.arc((basePx - 2) / 2, (basePx - 6) / 2, (basePx - 10) / 2, 1.5 * Math.PI, getPercent(count), false)
            ctx3.stroke()
        }
    
        const initCanvasPx = () => {
            cvsNode1.setAttribute('width', pxWidth)
            cvsNode1.setAttribute('height', pxWidth)
    
            cvsNode2.setAttribute('width', pxWidth)
            cvsNode2.setAttribute('height', pxWidth)
    
            cvsNode3.setAttribute('width', pxWidth)
            cvsNode3.setAttribute('height', pxWidth)
        }
    
        const startCountDown = () => {
            if (count <= 0) {
                clearInterval(timer)
                return
            }
            count--
            countTimeNode.innerHTML = count
            // 隐藏中间层,重置中间层 
            cvsNode2.setAttribute('width', 0)
            cvsNode2.setAttribute('width', basePx)
            setTimeout(() => {
                drawCenter()
    
                cvsNode3.setAttribute('width', 0)
                cvsNode3.setAttribute('width', basePx)
    
                setTimeout(() => {
                    cvsNode3.className = ' '
                    drawTop()
                }, 100)
            }, 200)
        }
    
        const initCanvas = () => {
    
            // 画底圆
            drawBottom()
    
            // 画倒计时圆
            drawCenter()
    
            // 画倒计时圆
            drawTop()
        }
    
        const initCircle = () => {
            // initCanvasPx()
            initCanvas()
            timer = setInterval(startCountDown, 1000)
        }
    
        const init = () => {
            initCircle()
            console.log('on init...', countTimeNode.innerHTML)
        }
    
        btn.addEventListener('click', () => {
            if (timer) {
                clearInterval(timer)
                timer = null
            } else {
                timer = setInterval(startCountDown, 1000)
            }
        })
        init()
    </script>

    遗留问题:

    1、暂未考虑移动端分辨率

    2、canvas 绘制的圆形会有锯齿

    效果:

  • 相关阅读:
    分布式数据库中间件Mycat百亿级数据存储(转)
    大文本字符串滤重的解决方案(转)
    java处理大文本2G以上
    Mysql binlog详解
    varnish squid nginx比较
    java运行时内存分类
    redis rdb aof比较
    LeetCode 94 ——二叉树的中序遍历
    线性代数之——向量空间
    线性代数之——A 的 LU 分解
  • 原文地址:https://www.cnblogs.com/307914070/p/15012122.html
Copyright © 2011-2022 走看看