Jadual Kandungan
知识点和求解参考图
canvas画时钟效果的代码编写
Rumah hujung hadapan web Tutorial H5 使用h5 canvas实现时钟的动态效果

使用h5 canvas实现时钟的动态效果

Jul 17, 2018 pm 02:37 PM
canvas html5

canvas 绘制好时钟界面,使用定时器定时重绘整个canvas,就实现了仿真动态时钟的效果。

难点在于:

  • 秒钟刻度和时钟刻度的绘制

  • 整点文字沿着内边圆形环绕

其中刻度的环绕并不难计算,文字的环绕就比较坑爹了,canvas绘制的文字是在绘制坐标之上的(文字基线和对齐方式影响),需要进行偏移的计算,使之文字中点正好落在圆上。
这一步相当淡疼,由于api中并没有测量字高的办法,而使用fontSize,其实也并不是字的准确高度,因此,y坐标+二分之一行高向下偏移,使之垂直居中,却总是不够准确的。而x坐标+二分之一行宽向左偏移,使之水平居中,则没有这个问题,因为api提供了测量行宽的方法。

一切都是因为 ctx.measureText(text).width 存在,但 ctx.measureText(numText).height 不存在。打印测量结果,也只有一个宽度属性。文档中说canvas对于绘制文字的支持比较弱,从这一点上看 何止是弱。

直接设置基线和对齐方式为居中,似乎也存在一定误差,看起来总不是那么赏心悦目。下面的代码中两种方式都写了。

会走的时钟预览:

这里写图片描述

时间显示可能略有误差。

知识点和求解参考图

主要知识点为圆的坐标公式,和三角函数sin,cos计算。实际上,圆的坐标公式使用的并不多,引入求值反而可能复杂化。

下图是计算刻度线坐标和整点文字绘制坐标的参考图:

这里写图片描述

canvas画时钟效果的代码编写

下面是全部代码:

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=1024, height=768,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
    <title>时钟</title></head><body><p style="margin: 50px">
    <canvas width="300" height="300"></canvas>
    <canvas width="200" height="200" style="background-color: #bbbbbb"></canvas>
    <canvas width="200" height="200"></canvas>
    <canvas width="200" height="200"></canvas></p><script>

    var clockHelper = function (canvas, config) {
        if (!config) {
            config = {}
        }        var ctx = canvas.getContext(&#39;2d&#39;);        var deColor = config.deColor ? config.deColor : &#39;#333333&#39;;        var deConfig = {
            ringWidth: config.ringWidth ? config.ringWidth : 6,//圆环宽度
            ringColor: config.ringColor ? config.ringColor : deColor,//圆环颜色
            hSaleL: config.hSaleL ? config.hSaleL : 8,//时刻度线长
            hScaleWidth: config.hScaleWidth ? config.hScaleWidth : 4,//时刻度线宽
            hScaleColor: config.hScaleColor ? config.hScaleColor : deColor,//时刻度颜色
            msSaleL: config.msSaleL ? config.msSaleL : 4,//分秒刻度线长
            msScaleWidth: config.msScaleWidth ? config.msScaleWidth : 2,//分秒刻度线宽
            msScaleColor: deColor,//分秒刻度颜色
            hFontSize: config.hFontSize ? config.hFontSize : 18,//整点文字大小
            hHandWidth: config.hHandWidth ? config.hHandWidth : 10,//时针宽度
            mHandWidth: config.mHandWidth ? config.mHandWidth : 5,//分针宽度
            sHandWidth: config.sHandWidth ? config.sHandWidth : 2,//秒针宽度

            hHandColor: config.hHandColor ? config.hHandColor : deColor,//时针颜色
            mHandColor: config.mHandColor ? config.mHandColor : deColor,//分针颜色
            sHandColor: config.sHandColor ? config.sHandColor : &#39;#bb3333&#39;,//秒针颜色
            handMode: [&#39;ms&#39;, &#39;s&#39;].indexOf("" + config.handMode) !== -1 ? config.handMode : &#39;s&#39;,//指针读秒模式,ms:毫秒,s:秒。
            clockFaceColor: config.clockFaceColor ? config.clockFaceColor : &#39;&#39;,
        };        var ox = canvas.width / 2;        var oy = canvas.height / 2;        var width = canvas.width;        var height = canvas.height;

        ctx.font = deConfig.hFontSize + "px 黑体";        //中线圆环半径
        var ringR = (width < height) ? (width / 2 - deConfig.ringWidth / 2) : (height / 2 - deConfig.ringWidth / 2);        //内圆环半径
        var ringInnerR = (width < height) ? (width / 2 - deConfig.ringWidth) : (height / 2 - deConfig.ringWidth);        var timer;        var timeSleep = 100;        var isStart = false;        function start() {
            if (isStart) {                return;
            }
            isStart = true;            if (deConfig.handMode == &#39;ms&#39;) {
                timeSleep = 100;
            } else {
                timeSleep = 1000;
            }

            ctx.clearRect(0, 0, width, height);
            draw();

            timer = setInterval(function () {
                if (isStart) {
                    ctx.clearRect(0, 0, width, height);
                    draw();
                }
            }, timeSleep);

        }        function stop() {
            isStart = false;
            clearInterval(timer)
        }        function draw() {

            beforeDraw();

            drawCircleFace();
            drawHands();

            afterDraw();

        }        function drawCircleFace() {

            ctx.fillStyle = deConfig.ringColor;
            ctx.strokeStyle = deConfig.ringColor;

            ctx.lineWidth = deConfig.ringWidth;
            ctx.beginPath();
            ctx.arc(ox, oy, ringR, 0, Math.PI * 2);
            ctx.stroke();            if (deConfig.clockFaceColor) {
                ctx.fillStyle = deConfig.clockFaceColor;
                ctx.fill();
            }            var x1 = ox;            var y1 = oy;            var x2 = ox;            var y2 = oy;            var radin = 0;
            ctx.lineWidth = deConfig.hScaleWidth;            // ctx.beginPath();
            for (var i = 1; i <= 60; i++) {
                radin = i * 6 * Math.PI / 180;
                x1 = ox + ringInnerR * Math.sin(radin);
                y1 = oy - ringInnerR * Math.cos(radin);                if (i % 5 === 0) {
                    ctx.lineWidth = deConfig.hScaleWidth;
                    x2 = ox + (ringInnerR - deConfig.hSaleL) * Math.sin(radin);
                    y2 = oy - (ringInnerR - deConfig.hSaleL) * Math.cos(radin);

                    ctx.fillStyle = deConfig.hScaleColor;                    var numText = i / 5 + "";                    var textWidth = ctx.measureText(numText).width;                    var x3 = ox + (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.sin(radin);                    var y3 = oy - (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.cos(radin);
                    ctx.textAlign = &#39;center&#39;;
                    ctx.textBaseline = &#39;middle&#39;;                    //不设置文字居中,基线居中,自己计算。貌似都有误差。因为旋转过程中,角度变化,且文字宽高不尽相同
                    // var x3 = ox + (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.sin(radin) - textWidth / 2;
                    // var y3 = oy - (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.cos(radin) + deConfig.hFontSize/ 2;
                    //x2,y2已经求过,化简为:
                    // var x3 = x2 - deConfig.hFontSize * Math.sin(radin) - textWidth / 2;
                    // var y3 = y2 + deConfig.hFontSize * Math.cos(radin) + textWidth / 2;
                    //文字x轴向左偏移一半文字宽,使之水平居中;向下偏移一半高度,使之垂直居中。
                    // 实际中发现,字高没法测(api无),而使用fontSize不准。但y轴加上字宽,位置倒是更对齐一些。

                    // var x3 = x2 + textWidth / 2;
                    // var y3 = y2 - deConfig.hFontSize / 2;

                    ctx.fillText(numText, x3, y3);

                } else {
                    ctx.lineWidth = deConfig.msScaleWidth;
                    x2 = ox + (ringInnerR - deConfig.msSaleL) * Math.sin(radin);
                    y2 = oy - (ringInnerR - deConfig.msSaleL) * Math.cos(radin);
                }


                ctx.beginPath();
                ctx.moveTo(x1, y1);
                ctx.lineTo(x2, y2);
                ctx.stroke();

            }

        }        //改变坐标中点,并旋转画布也许是更好的选择。
        function drawHands() {
            var date = new Date();            var h = date.getHours() % 12;            var m = date.getMinutes();            var s = date.getSeconds();            var ms = date.getMilliseconds();            // console.log(h + ":" + m + ":" + s);
            //    时针

            var hRadin = (h + m / 60 + s / 3600) * Math.PI * 2 / 12;            var mRadin = (m + s / 60) * Math.PI * 2 / 60;            var sRadin;            if (deConfig.handMode == &#39;ms&#39;) {
                sRadin = (s + ms / 1000) * Math.PI * 2 / 60;
            } else {
                sRadin = s * Math.PI * 2 / 60;
            }            var x = 0;            var y = 0;            var hDotR = deConfig.hHandWidth + 2;            var mDotR = 0.6 * hDotR            var sDotR = 0.5 * hDotR            //秒针半径
            var sHandR = ringInnerR - deConfig.hSaleL * 2
            //分针半径
            var mHandR = 0.8 * sHandR;            //时针半径
            var hHandR = 0.7 * mHandR;            //时针
            ctx.beginPath();
            ctx.lineWidth = deConfig.hHandWidth;
            ctx.strokeStyle = deConfig.hHandColor;
            ctx.strokeStyle = deConfig.hHandColor;
            ctx.moveTo(ox, oy);
            x = ox + hHandR * Math.cos(hRadin - Math.PI / 2);
            y = oy + hHandR * Math.sin(hRadin - Math.PI / 2);
            ctx.lineTo(x, y);
            ctx.stroke();            //针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。)
            ctx.beginPath();
            ctx.lineWidth = 0;
            ctx.arc(x, y, deConfig.hHandWidth / 2, 0, 2 * Math.PI);
            ctx.fill();            //中心
            ctx.beginPath();            // ctx.lineWidth = hDotR;
            ctx.arc(ox, oy, hDotR / 2, 0, Math.PI * 2);
            ctx.fill();
            ctx.stroke();            //分针
            ctx.beginPath();
            ctx.lineWidth = deConfig.mHandWidth;
            ctx.strokeStyle = deConfig.mHandColor;
            ctx.fillStyle = deConfig.mHandColor;
            ctx.moveTo(ox, oy);
            x = ox + mHandR * Math.cos(mRadin - Math.PI / 2);
            y = oy + mHandR * Math.sin(mRadin - Math.PI / 2);
            ctx.lineTo(x, y);
            ctx.stroke();            //针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。)
            ctx.beginPath();
            ctx.lineWidth = 0;
            ctx.arc(x, y, deConfig.mHandWidth / 2, 0, 2 * Math.PI);
            ctx.fill();            //中心
            ctx.beginPath();
            ctx.arc(ox, oy, mDotR / 2, 0, Math.PI * 2);
            ctx.stroke();            //秒针
            ctx.beginPath();
            ctx.strokeStyle = deConfig.sHandColor;
            ctx.fillStyle = deConfig.sHandColor;
            ctx.lineWidth = deConfig.sHandWidth;            //秒针有长短两线
            x = ox - sHandR / 4 * Math.cos(sRadin - Math.PI / 2);
            y = oy - sHandR / 4 * Math.sin(sRadin - Math.PI / 2);
            ctx.moveTo(x, y);
            x = ox + sHandR * Math.cos(sRadin - Math.PI / 2);
            y = oy + sHandR * Math.sin(sRadin - Math.PI / 2);
            ctx.lineTo(x, y);
            ctx.stroke();            //针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。)
            ctx.beginPath();
            ctx.lineWidth = 0;
            ctx.arc(x, y, deConfig.sHandWidth / 2, 0, 2 * Math.PI);
            ctx.fill();            //中心
            ctx.beginPath();
            ctx.fillStyle = deColor;
            ctx.arc(ox, oy, sDotR, 0, Math.PI * 2);
            ctx.fill();
            ctx.stroke();

        }        function beforeDraw() {
            if (typeof exp.beforeDraw === &#39;function&#39;) {
                exp.beforeDraw(ctx, deConfig);
            }
        }        function afterDraw() {
            if (typeof exp.afterDraw === &#39;function&#39;) {
                exp.afterDraw(ctx, deConfig);
            }
        }        var exp = {
            start: start,
            stop: stop,
            beforeDraw: null,
            afterDraw: null,
        }        return exp;


    }    var clockCanvas1 = document.getElementsByTagName(&#39;canvas&#39;)[0];    var clockCanvas2 = document.getElementsByTagName(&#39;canvas&#39;)[1];    var clockCanvas3 = document.getElementsByTagName(&#39;canvas&#39;)[2];    var clockCanvas4 = document.getElementsByTagName(&#39;canvas&#39;)[3];    var clock = clockHelper(clockCanvas1, {mHandColor: &#39;#3333bb&#39;, sHandColor: &#39;#bb3333&#39;});
    clock.start();
    setTimeout(function () {
        clock.stop()
    }, 5000)
    setTimeout(function () {
        clock.start();
    }, 8000)

    clockHelper(clockCanvas2, {
        mHandColor: &#39;green&#39;,
        hHandWidth: 6,
        mHandWidth: 4,
        hFontSize: 14,
        hScaleWidth: 2,
        handMode: &#39;ms&#39;
    }).start();


    clockHelper(clockCanvas2, {
        mHandColor: &#39;green&#39;,
        hHandWidth: 6,
        mHandWidth: 4,
        hFontSize: 14,
        hScaleWidth: 2,
        handMode: &#39;ms&#39;
    }).start();


    clockHelper(clockCanvas3, {
        deColor: &#39;#bbbbbb&#39;,
        sHandColor: &#39;#bbbbbb&#39;,
        clockFaceColor: &#39;#112233&#39;,//钟面
        hHandWidth: 6,
        mHandWidth: 4,
        hFontSize: 14,
        hScaleWidth: 2,
        handMode: &#39;s&#39;
    }).start();    var clock4 = clockHelper(clockCanvas4, {
        deColor: &#39;#bbbbbb&#39;,
        sHandColor: &#39;#bbbbbb&#39;,        // clockFaceColor: &#39;#112233&#39;,
        hHandWidth: 6,
        mHandWidth: 4,
        hFontSize: 14,
        hScaleWidth: 2,
        handMode: &#39;s&#39;
    });

    clock4.afterDraw = function (ctx, deConfig) {
        var grd = ctx.createLinearGradient(0, 0, clockCanvas4.width, clockCanvas4.height);
        grd.addColorStop(0, "rgba(255,0,0,0.3)");
        grd.addColorStop(1, "rgba(0,0,255,0.5)");
        ctx.fillStyle = grd;
        ctx.arc(clockCanvas4.width/2,clockCanvas4.height/2,clockCanvas4.width/2,0,Math.PI*2);        // ctx.fillRect(0, 0, clockCanvas4.width, clockCanvas4.height);
        ctx.fill();

        ctx.fillText(&#39;时钟绘制完成后,自定义其他绘制&#39;,clockCanvas4.width/2,clockCanvas4.height - deConfig.hFontSize);
    };

    clock4.start();</script></body></html>
Salin selepas log masuk

说明:

1、clockHelper第一个参数传入画布。第二个参数传入时钟界面的配置对象,包括指针、刻度的颜色、大小等,配置项和clockHelper中的deConfig默认对象是相对的,参考deConfig的属性传入参数即可。

2、clockHelper的封装性略差,仅是基本能用型。但属性不多,改造应该并不困难。

3、提供了时钟界面绘制之前和之后的方法,可以在beforeDraw和afterDraw这两个方法中执行自己的逻辑。但是由于事先设计没有留出足够的空白像素,用处不大。只能进行一些简单的再绘制。比如给钟面添加色彩、渐变。

相关推荐:

H5+C3实现时钟效果

使用Canvas制作时钟动画的方法

Atas ialah kandungan terperinci 使用h5 canvas实现时钟的动态效果. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Sempadan Jadual dalam HTML Sempadan Jadual dalam HTML Sep 04, 2024 pm 04:49 PM

Panduan untuk Sempadan Jadual dalam HTML. Di sini kita membincangkan pelbagai cara untuk menentukan sempadan jadual dengan contoh Sempadan Jadual dalam HTML.

Jadual Bersarang dalam HTML Jadual Bersarang dalam HTML Sep 04, 2024 pm 04:49 PM

Ini ialah panduan untuk Nested Table dalam HTML. Di sini kita membincangkan cara membuat jadual dalam jadual bersama-sama dengan contoh masing-masing.

HTML jidar-kiri HTML jidar-kiri Sep 04, 2024 pm 04:48 PM

Panduan untuk HTML margin-kiri. Di sini kita membincangkan gambaran keseluruhan ringkas tentang HTML margin-left dan Contoh-contohnya bersama-sama dengan Pelaksanaan Kodnya.

Susun Atur Jadual HTML Susun Atur Jadual HTML Sep 04, 2024 pm 04:54 PM

Panduan untuk Susun Atur Jadual HTML. Di sini kita membincangkan Nilai Susun Atur Jadual HTML bersama-sama dengan contoh dan output n perincian.

Pemegang Tempat Input HTML Pemegang Tempat Input HTML Sep 04, 2024 pm 04:54 PM

Panduan untuk Pemegang Tempat Input HTML. Di sini kita membincangkan Contoh Pemegang Tempat Input HTML bersama-sama dengan kod dan output.

Memindahkan Teks dalam HTML Memindahkan Teks dalam HTML Sep 04, 2024 pm 04:45 PM

Panduan untuk Memindahkan Teks dalam HTML. Di sini kita membincangkan pengenalan, cara teg marquee berfungsi dengan sintaks dan contoh untuk dilaksanakan.

Senarai Tertib HTML Senarai Tertib HTML Sep 04, 2024 pm 04:43 PM

Panduan kepada Senarai Tertib HTML. Di sini kami juga membincangkan pengenalan senarai dan jenis Tertib HTML bersama-sama dengan contoh mereka masing-masing

Butang onclick HTML Butang onclick HTML Sep 04, 2024 pm 04:49 PM

Panduan untuk Butang onclick HTML. Di sini kita membincangkan pengenalan, kerja, contoh dan onclick Event masing-masing dalam pelbagai acara.

See all articles