Day 24 - 用 canvas 画个时钟

前述

今天来画个时钟~!一样利用 requestAnimationFrame,再判断当前时间,每一秒往前进,就完成啦!

codesendBox

import React, { useEffect, useRef } from "react";

const Clock = () => {
  const clockRef = useRef(null);

  useEffect(() => {
    const clock = () => {
      const canvas = clockRef.current;
      const ctx = canvas.getContext("2d");
      let now = new Date(),
        sec = now.getSeconds(),
        min = now.getMinutes(),
        hr = now.getHours();
      hr = hr > 12 ? hr - 12 : hr;

      // 底盘颜色
      ctx.save();
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.translate(canvas.width / 2, canvas.height / 2);
      ctx.rotate(-Math.PI / 2); // 将座标轴逆时针转90度,x轴正方向对准12点位置
      var lingrad = ctx.createLinearGradient(150, 0, -150, 0);
      lingrad.addColorStop(0, "#242f37"); // 制造渐层感的底色
      lingrad.addColorStop(1, "#48585c");
      ctx.fillStyle = lingrad;
      ctx.beginPath();
      ctx.arc(0, 0, 150, 0, Math.PI * 2, true);
      ctx.fill();

      // 小时刻度
      ctx.save();
      for (var i = 0; i < 12; i++) {
        ctx.beginPath();
        ctx.strokeStyle = "#fff";
        ctx.lineWidth = 3;
        ctx.rotate(Math.PI / 6);
        ctx.moveTo(140, 0);
        ctx.lineTo(120, 0);
        ctx.stroke();
      }
      ctx.restore();

      // 分钟刻度
      ctx.save();
      ctx.beginPath();
      for (i = 0; i < 60; i++) {
        if (i % 5 !== 0) {
          ctx.beginPath();
          ctx.strokeStyle = "#eee";
          ctx.lineWidth = 2;
          ctx.moveTo(140, 0);
          ctx.lineTo(130, 0);
          ctx.stroke();
        }
        ctx.rotate(Math.PI / 30);
      }
      ctx.restore();

      // 时间文字
      ctx.save();
      ctx.rotate(Math.PI / 2);
      ctx.beginPath();
      ctx.fillStyle = "#01bBC2";
      ctx.font = "32px Microsoft yahei";
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.fillText("3", 100, 0);
      ctx.fillText("6", 0, 100);
      ctx.fillText("9", -100, 0);
      ctx.fillText("12", 0, -100);
      ctx.restore();

      // 时针
      ctx.save();
      ctx.rotate(
        hr * (Math.PI / 6) + min * (Math.PI / 360) + sec * (Math.PI / 21600)
      );
      ctx.lineWidth = 10;
      ctx.strokeStyle = "#fff";
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.lineTo(110, 0);
      ctx.stroke();
      ctx.fillStyle = "#34434c";
      ctx.arc(102, 0, 3, 0, Math.PI * 2, true);
      ctx.fill();
      ctx.restore();

      // 分针
      ctx.save();
      ctx.rotate(min * (Math.PI / 30) + sec * (Math.PI / 1800));
      ctx.lineWidth = 6;
      ctx.strokeStyle = "#fff";
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.lineTo(135, 0);
      ctx.stroke();

      ctx.lineWidth = 3;
      ctx.strokeStyle = "#34434c";
      ctx.beginPath();
      ctx.moveTo(130, 0);
      ctx.lineTo(115, 0);
      ctx.stroke();
      ctx.restore();

      // 秒针
      ctx.save();
      ctx.rotate(sec * (Math.PI / 30));
      ctx.beginPath();
      ctx.lineWidth = 4;
      ctx.strokeStyle = "#fff";
      ctx.moveTo(0, 0);
      ctx.lineTo(141, 0);
      ctx.stroke();

      ctx.beginPath();
      ctx.lineWidth = 12;
      ctx.strokeStyle = "#fff";
      ctx.moveTo(0, 0);
      ctx.lineTo(-38, 0);
      ctx.stroke();

      ctx.beginPath();
      ctx.fillStyle = "#fff";
      ctx.arc(0, 0, 15, 0, Math.PI * 2, true);
      ctx.fill();

      ctx.beginPath();
      ctx.strokeStyle = "#cdd2d5";
      ctx.lineWidth = 1;
      ctx.arc(0, 0, 8, 0, Math.PI * 2, true);
      ctx.stroke();
      ctx.restore();

      // 外框
      ctx.beginPath();
      ctx.lineWidth = 7;
      var lingrad2 = ctx.createLinearGradient(150, 0, -150, 0);
      lingrad2.addColorStop(0, "#adb9c5");
      lingrad2.addColorStop(1, "#e9eced");
      ctx.strokeStyle = lingrad2;
      ctx.arc(0, 0, 152, 0, Math.PI * 2, true);
      ctx.stroke();
      ctx.restore();

      window.requestAnimationFrame(clock); // loop 时间
    };

    if (clockRef.current) clock();
  }, [clockRef]);

  return <canvas ref={clockRef} width={500} height={500}></canvas>;
};

export default Clock;


<<:  用 Python 畅玩 Line bot - 05:MessageEvent

>>:  [ Day 24 ] - 阵列资料处理 - filter

Day 16. Hashicorp Vault: Upgrade

Hashicorp Vault: Upgrade 升级方式: Vault是binary的档案,所以更...

[Day - 29] - 深透 Spring Actuator 创造系统服务监视神之眼

Abstract 大家好,我是游戏王怪兽之决斗小编威斯~~丁,想必大家都知道游戏王的贝卡斯的千年眼可...

[Day19] 第十九章-今天来开双B (blade与bootstrap 安装手册)

前言 昨天把简单的view切出来後 我们当然要上 css框架阿!! 我们今天就想办法把blade v...

不只懂 Vue 语法:为何元件里的 data 必须是函式?建立 data 时能否使用箭头函式?

问题回答 元件里的 data 必须是函式是为了确保元件里的资料不会被别的元件资料所污染。如果 dat...

Day 13 - 非同步元件

在大型专案中,我们会需要注入大量的元件,每次都要把所有的元件载入有时相对耗效能,这时候就可以使用非同...