<!--
 * canvas 时钟
  -->
<script setup lang="ts">
import { onMounted, ref, reactive, onBeforeUnmount } from 'vue';

const isShowGrid = ref(false);
const state = reactive({
  center: {
    x: 300,
    y: 300,
  }, // 圆心
  r: 200, // 半径,
  timer: null as any,
  canvasSeconds: null as any,
});

onBeforeUnmount(() => {
  if (state.timer) {
    clearInterval(state.timer);
    state.timer = null;
  }
});

onMounted(() => {
  state.canvasSeconds = document.getElementById('canvas-seconds');
  let canvas: any = document.getElementById('canvas');
  let pen = canvas.getContext('2d');
  const { center, r } = state;

  let img = new Image();
  img.src = require('./imgs/clock-bg.jpg');
  img.onload = function () {
    // 背景色
    pen.save();
    pen.fillStyle = '#2d2d2d';
    pen.fillRect(0, 0, 600, 600);
    pen.restore();

    // 绘制图片
    pen.save();
    pen.beginPath();
    pen.arc(center.x, center.y, r, 0, 2 * Math.PI);
    // pen.fill();
    // 将上面的区域作为剪辑区域
    pen.clip();
    pen.drawImage(img, 241, 68, 300, 300, 100, 100, 2 * r, 2 * r);
    // pen.drawImage(img, -90, 80);
    pen.restore();

    pen.save();
    // 大刻度
    for (let i = 0; i < 12; i++) {
      pen.beginPath();
      const a1 = Math.sin(toArc(i * 30)) * (r - 10); // (r - 10) 10是刻度与圆弧边线的间隙
      const b1 = Math.cos(toArc(i * 30)) * (r - 10);
      const x0 = center.x + a1;
      const y0 = center.y - b1;
      const a2 = Math.sin(toArc(i * 30)) * 8; // 8是大刻度线的长度
      const b2 = Math.cos(toArc(i * 30)) * 8;
      const x1 = x0 - a2;
      const y1 = y0 + b2;
      pen.moveTo(x0, y0);
      pen.lineTo(x1, y1);
      pen.lineWidth = 4;
      pen.lineCap = 'round';
      pen.strokeStyle = '#5CD8F9';

      // pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
      // pen.shadowBlur = 10;
      // pen.shadowOffsetX = -8;
      // pen.shadowOffsetY = 10;

      pen.stroke();
    }
    pen.restore();

    // 小刻度
    pen.save();
    for (let i = 0; i < 60; i++) {
      pen.beginPath();
      const a1 = Math.sin(toArc(i * 6)) * (r - 10); // (r - 10) 10是刻度与圆弧边线的间隙
      const b1 = Math.cos(toArc(i * 6)) * (r - 10);
      const x0 = center.x + a1;
      const y0 = center.y - b1;
      const a2 = Math.sin(toArc(i * 6)) * 4; // 4是大刻度线的长度
      const b2 = Math.cos(toArc(i * 6)) * 4;
      const x1 = x0 - a2;
      const y1 = y0 + b2;
      pen.moveTo(x0, y0);
      pen.lineTo(x1, y1);
      pen.lineWidth = 1;
      pen.lineCap = 'round';
      pen.strokeStyle = '#48E6FE';

      pen.stroke();
    }
    pen.restore();

    // 绘制文本
    pen.save();
    for (let i = 0; i < 12; i++) {
      pen.beginPath();
      const a1 = Math.sin(toArc(i * 30)) * (r - 40);
      const b1 = Math.cos(toArc(i * 30)) * (r - 40);

      const num = i || 12;
      const x0 = center.x + a1;
      const y0 = center.y - b1;

      pen.font = '26px sans-serif';
      pen.textAlign = 'center';
      pen.textBaseline = 'middle';

      pen.fillStyle = '#5CD8F9';
      pen.fillText(`${num}`, x0, y0);
    }
    pen.restore();

    // 外圆
    pen.save();
    pen.beginPath();
    pen.arc(center.x, center.y, r, 0, 2 * Math.PI);
    pen.lineWidth = 10;
    pen.strokeStyle = '#0E4A6F';

    // 阴影
    pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
    pen.shadowBlur = 20;
    pen.shadowOffsetX = -12;
    pen.shadowOffsetY = 20;
    pen.stroke();
    pen.restore();

    // 圆心
    pen.save();
    pen.beginPath();
    pen.arc(center.x, center.y, 16, 0, 2 * Math.PI);
    pen.fillStyle = '#204969';
    pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
    pen.shadowBlur = 5;
    pen.shadowOffsetX = -10;
    pen.shadowOffsetY = 10;
    pen.fill();
    pen.restore();

    state.timer = setInterval(() => {
      drawSeconds();
    }, 1000);
  };
});

function drawSeconds() {
  let pen = state.canvasSeconds.getContext('2d');

  const { center, r } = state;

  const date = getDate();
  // console.log('---', date);

  const secondsDeg = date.seconds * 6 + 270;
  const minDeg = date.minutes * 6 + 270 + date.seconds * 0.1;
  const hoursDeg =
    date.hours * 30 + 270 + date.minutes * 0.5 + date.seconds * (1 / 120);
  pen.clearRect(0, 0, 600, 600);

  // 时间显示
  pen.save();
  pen.font = '26px sans-serif';
  pen.textAlign = 'center';
  pen.textBaseline = 'middle';
  pen.fillStyle = '#5CD8F9';
  const hStr = date.hours < 10 ? `0${date.hours}` : date.hours;
  const mStr = date.minutes < 10 ? `0${date.minutes}` : date.minutes;
  const sStr = date.seconds < 10 ? `0${date.seconds}` : date.seconds;

  const timeStr = `${hStr}:${mStr}:${sStr}`;
  pen.fillText(timeStr, center.x, center.y - (2 / 5) * r);
  pen.restore();

  // 时针
  pen.save();
  const offseHour = rotateOriginOffset(600, center, toArc(hoursDeg));
  pen.translate(offseHour.x, offseHour.y); // 改变旋转中心
  pen.rotate(toArc(hoursDeg));
  pen.beginPath();
  pen.moveTo(center.x - 20, center.y);
  pen.lineTo(center.x + r - 110, center.y);
  pen.lineWidth = 9;
  pen.lineCap = 'round';
  pen.strokeStyle = '#1E88D2';

  pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
  pen.shadowBlur = 5;
  pen.shadowOffsetX = -10;
  pen.shadowOffsetY = 10;
  pen.stroke();
  pen.restore();

  pen.save();
  pen.beginPath();
  pen.arc(center.x, center.y, 12, 0, 2 * Math.PI);
  pen.fillStyle = '#71C6F7';
  pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
  pen.shadowBlur = 2;
  pen.shadowOffsetX = -2;
  pen.shadowOffsetY = 2;
  pen.fill();
  pen.restore();

  // 分针
  pen.save();
  const offsetMin = rotateOriginOffset(600, center, toArc(minDeg));
  pen.translate(offsetMin.x, offsetMin.y); // 改变旋转中心
  pen.rotate(toArc(minDeg));
  pen.beginPath();
  pen.moveTo(center.x - 20, center.y);
  pen.lineTo(center.x + r - 80, center.y);
  pen.lineWidth = 5;
  pen.lineCap = 'round';
  pen.strokeStyle = '#71C6F7';

  pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
  pen.shadowBlur = 5;
  pen.shadowOffsetX = -10;
  pen.shadowOffsetY = 10;

  pen.stroke();
  pen.restore();

  // 秒针
  pen.save();
  const offset = rotateOriginOffset(600, center, toArc(secondsDeg));
  pen.translate(offset.x, offset.y); // 改变旋转中心
  pen.rotate(toArc(secondsDeg));
  pen.beginPath();
  pen.moveTo(center.x - 40, center.y);
  pen.lineTo(center.x + r - 10, center.y);
  pen.lineWidth = 2;
  pen.lineCap = 'round';
  pen.strokeStyle = '#71C6F7';

  pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
  pen.shadowBlur = 5;
  pen.shadowOffsetX = -10;
  pen.shadowOffsetY = 10;

  pen.stroke();
  pen.restore();

  pen.save();
  pen.beginPath();
  pen.arc(center.x, center.y, 5, 0, 2 * Math.PI);
  pen.fillStyle = '#204969';
  pen.shadowColor = 'rgba(0, 0, 0, 0.35)';
  pen.shadowBlur = 2;
  pen.shadowOffsetX = -2;
  pen.shadowOffsetY = 2;
  pen.fill();
  pen.restore();
}

// 绘制网格
function drawGrid(color: string, w: number, h: number, pen: any) {
  const step = 100;
  const w_l = w / step;
  const h_l = h / step;

  pen.save();
  // 横着的线
  for (let i = 0; i <= h_l; i++) {
    pen.beginPath();
    pen.strokeStyle = color;
    pen.moveTo(0, i * step);
    pen.lineTo(w, i * step);
    pen.stroke();
  }
  // 竖着的线
  for (let i = 0; i <= w_l; i++) {
    pen.beginPath();
    pen.moveTo(i * step, 0);
    pen.lineTo(i * step, h);
    pen.stroke();
  }
  pen.restore();
}

function showGrid() {
  let canvas: any = document.getElementById('canvas-grid');
  let pen = canvas.getContext('2d');
  isShowGrid.value = !isShowGrid.value;
  if (isShowGrid.value) {
    drawGrid('#FD7013', 600, 600, pen); // 网格
  } else {
    pen.clearRect(0, 0, 600, 600);
  }
}

function toArc(degree: number) {
  return (degree * Math.PI) / 180;
}

function rotateOriginOffset(
  width: number,
  center: { x: number; y: number },
  arc: any
) {
  const r1 = width - center.x;
  const xRes1 = Math.cos(arc) * r1;
  const yRes1 = Math.sin(arc) * r1;
  const x1 = center.x + xRes1;
  const y1 = center.y + yRes1;

  const x0 = width;
  const y0 = center.y;
  const c0 = Math.sqrt(Math.pow(x0, 2) + Math.pow(y0, 2));
  const arc0 = Math.atan2(y0, x0);
  const arc_0 = arc0 + arc;
  const y2 = Math.sin(arc_0) * c0;
  const x2 = y2 / Math.tan(arc_0);

  const xLength = x1 - x2;
  const yLength = y1 - y2;
  return {
    x: xLength,
    y: yLength,
  };
}

function getDate() {
  const myDate = new Date();
  return {
    hours: myDate.getHours(),
    minutes: myDate.getMinutes(),
    seconds: myDate.getSeconds(),
  };
}
</script>
<template>
  <div class="fit">
    <div>canvas</div>

    <div>
      <q-btn label="显示网格" color="primary" @click="showGrid" />
    </div>
    <div class="relative-position">
      <canvas
        id="canvas"
        width="600"
        height="600"
        style="border: 1px solid red; position: absolute; top: 0; left: 0"
      ></canvas>
      <canvas
        id="canvas-seconds"
        width="600"
        height="600"
        style="
          border: 1px solid transparent;
          position: absolute;
          top: 0;
          left: 0;
        "
      ></canvas>
      <canvas
        id="canvas-grid"
        width="600"
        height="600"
        style="
          border: 1px solid transparent;
          position: absolute;
          top: 0;
          left: 0;
        "
      ></canvas>
    </div>
  </div>
</template>

<style lang="scss" scoped></style>