canvas 学习

142 阅读2分钟

为了更加熟悉canvas,跟着网上的一些案例,写了一个时钟,随便玩玩,说实话感觉还挺开心,就是个玩。哈哈

代码如下(纯HTML,可以直接运行在浏览器)。

image.png

  • clock.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <style>
    .clock-box {
      width: 300px;
      margin: 100px auto;
    }

    #dateStr {
      text-align: center;
    }
  </style>
</head>

<body>
  <div class="clock-box">
    <h1 id="dateStr"></h1>
    <canvas id="love_clock_img"></canvas>
  </div>
</body>
<script type="text/javascript">
  window.onload = function () {
    let canvas = document.getElementById('love_clock_img');
    let dateStr = document.getElementById('dateStr');
    dateStr.innerText = `${new Date().getFullYear()}-${new Date().getMonth() + 1}-${new Date().getDate()}`;
    let ctx = canvas.getContext("2d");
    let makeClockFun = () => {
      // 获取当前时间
      let dateMap = new Map(
        [
          ['year', new Date().getFullYear()],
          ['month', new Date().getMonth() + 1],
          ['day', new Date().getDate()],
          ['hour', new Date().getHours()],
          ['min', new Date().getMinutes()],
          ['sec', new Date().getSeconds()],
        ]
      );
      // 设置 画布大小
      canvas.width = 300;
      canvas.height = 300;
      // 设置 表盘圆心和半径并清理画布
      let r = 144;
      let pos = [r + 6, r + 6];
      ctx.clearRect(0, 0, 300, 300);
      // 画大表盘
      ctx.beginPath()
      ctx.arc(...pos, r, 0, 2 * Math.PI);
      ctx.lineWidth = 10;
      ctx.strokeStyle = 'black';
      ctx.stroke();
      ctx.closePath()
      ctx.restore();
      // 画表芯的装饰 ❤
      ctx.beginPath();
      ctx.arc(122, 125, 45, 0.8 * Math.PI, 1.9 * Math.PI, false);
      ctx.arc(178, 125, 45, 1.1 * Math.PI, 0.2 * Math.PI, false);
      ctx.lineTo(150, 220);
      ctx.fillStyle = 'red';
      ctx.fill();
      ctx.closePath();
      ctx.restore();
      // 装饰文字
      ctx.fillStyle = '#fff';
      ctx.font = '16px Microsoft Yahei';
      ctx.beginPath();
      ctx.fillText('I love u', 128, 120);
      ctx.fill();
      ctx.closePath();
      // 重新存储 合并画布
      ctx.restore();

      // 画表盘 刻度
      // hourI
      let hourI = 0;
      while (hourI < 12) {
        // 每次都保存
        ctx.save();
        // 刻度宽度为 4
        ctx.lineWidth = 4;
        ctx.strokeStyle = "#000";
        // 每次把 画布原点的位置 位移到圆心上 并主轴旋转 30度
        ctx.translate(...pos);
        ctx.rotate(hourI * 30 * Math.PI / 180);
        // 开始画刻度
        ctx.beginPath();
        // 来到纵轴 距离原点 115的位置上,连线画到 135为止。
        ctx.moveTo(0, 115);
        ctx.lineTo(0, 135);
        ctx.stroke();
        ctx.closePath();
        // 重新存储
        ctx.restore();
        hourI++;
      }

      // 画秒针刻度
      let secI = 0;
      while (secI < 60) {
        ctx.save();
        ctx.lineWidth = 2;
        ctx.strokeStyle = "#000";
        ctx.translate(...pos);
        ctx.rotate(secI * 6 * Math.PI / 180);
        ctx.beginPath();
        ctx.moveTo(0, 125);
        ctx.lineTo(0, 135);
        ctx.stroke();
        ctx.closePath();
        // 重新存储
        ctx.restore();
        secI++;
      }

      // 给小时的刻度标上数字
      let num = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
      // 刻度数字位置微调数据
      let numAdjust = new Map(
        [
          [3, { x: 0, y: 7 },],
          [4, { x: -3, y: 10 }],
          [5, { x: -3, y: 9 }],
          [6, { x: -6, y: 10 }],
          [7, { x: -6, y: 9 }],
          [8, { x: -9, y: 8 }],
          [9, { x: -12, y: 7 }],
          [10, { x: -12, y: 8 }],
          [11, { x: -13, y: 7 }],
          [12, { x: -11, y: 5 }],
          [1, { x: -6, y: 6 }],
          [2, { x: -3, y: 4 }],
        ]
      )

      let numI = 0;
      while (numI < 12) {
        // 每次都保存
        ctx.save();
        ctx.translate(...pos);
        ctx.fillStyle = 'red';
        ctx.font = '20px Microsoft Yahei';
        ctx.beginPath();
        let x = (Math.cos((Math.PI / 6) * numI)) * 100 + numAdjust.get(num[numI]).x;
        let y = (Math.sin((Math.PI / 6) * numI)) * 100 + numAdjust.get(num[numI]).y;
        ctx.fillText(num[numI], x, y);
        ctx.fill();
        ctx.closePath();
        ctx.restore();
        numI++;
      }
      // 根据正常时间画时针,
      let hourTemp = dateMap.get('hour') + dateMap.get('min') / 60;
      hourTemp = hourTemp > 12 ? hourTemp - 12 : hourTemp;
      ctx.save();
      ctx.beginPath();
      ctx.lineWidth = 1;
      ctx.fillStyle = '#000';
      ctx.translate(...pos);
      ctx.rotate(hourTemp * Math.PI / 6);
      ctx.beginPath();
      ctx.moveTo(1, 10);
      ctx.lineTo(1, -40);
      ctx.lineTo(5, -40);
      ctx.lineTo(0, -50);
      ctx.lineTo(-5, -40);
      ctx.lineTo(-1, -40);
      ctx.lineTo(-1, 10);
      ctx.lineTo(1, 10);
      ctx.fill();
      ctx.closePath();
      // 将之前画的合并起来
      ctx.restore();

      // 画分针
      ctx.save();
      ctx.beginPath();
      ctx.lineWidth = 1;
      ctx.fillStyle = '#000';
      ctx.translate(...pos);
      ctx.rotate(dateMap.get('min') * Math.PI / 30);
      ctx.beginPath();
      ctx.moveTo(1, 10);
      ctx.lineTo(1, -70);
      ctx.lineTo(5, -70);
      ctx.lineTo(0, -80);
      ctx.lineTo(-5, -70);
      ctx.lineTo(-1, -70);
      ctx.lineTo(-1, 10);
      ctx.lineTo(1, 10);
      ctx.fill();
      ctx.closePath();
      // 将之前画的合并起来
      ctx.restore();

      // 画秒针
      ctx.save();
      ctx.beginPath();
      ctx.lineWidth = 2;
      ctx.strokeStyle = 'green';
      ctx.translate(...pos);
      ctx.rotate(dateMap.get('sec') * Math.PI / 30);
      ctx.beginPath();
      ctx.moveTo(0, 25);
      ctx.lineTo(1, -105);
      ctx.stroke();
      ctx.closePath();
      // 装饰 秒针
      ctx.beginPath();
      ctx.lineWidth = 2;
      ctx.fillStyle = 'green';
      ctx.arc(1, -95, 4, 0, 2 * Math.PI, false);
      ctx.fill();
      ctx.closePath();
      // 将之前画的合并起来
      ctx.restore();

    }
    setInterval(makeClockFun, 1000);
  }
</script>

</html>