Skip to content
html
<!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>
    html,
    body {
      width: 100vw;
      height: 100vh;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background-color: #ddd;
    }
  </style>
</head>

<body>
  <canvas id="canvas"></canvas>

  <script>
    const canvas = document.querySelector('#canvas')
    const context = canvas.getContext('2d')

    canvas.width = 650
    canvas.height = 450
    canvas.style.background = 'white'

    context.textAlign = 'center'
    context.textBaseline = 'middle'

    const drawGrid = (stepX, stepY, lineWidth, color) => {
      const { width, height } = canvas

      context.lineWidth = lineWidth
      context.strokeStyle = color

      // horizontal line
      for (let i = stepY + lineWidth; i < height; i += stepY) {
        context.beginPath()
        context.moveTo(0, i)
        context.lineTo(width, i)
        context.stroke()
      }

      // vertical line
      for (let i = stepX + lineWidth; i < width; i += stepX) {
        context.beginPath()
        context.moveTo(i, 0)
        context.lineTo(i, height)
        context.stroke()
      }
    }
    
    const center = { x: 325, y: 225 }
    const { PI, cos, sin } = Math

    const drawCircles = () => {
      const { x, y } = center
      const r1 = 200
      const r2 = 180
      const startAngle = 0
      const endAngle = PI * 2

      // 内外两个圆
      context.beginPath()
      context.arc(x, y, r1, startAngle, endAngle)
      context.strokeStyle = 'blue'
      context.stroke()
      context.arc(x, y, r2, startAngle, endAngle, true)
      context.fillStyle = 'rgba(0, 0, 0, .1)'
      context.fill()
    }

    const drawTicks = () => {
      const { x, y } = center
      const tickWidth = 2
      const tickHeight = 10

      for (let i = 0; i < 360; i += 10) {
        const angle = i / 180 * Math.PI
        const _x = x + cos(angle) * 180
        const _y = y + sin(angle) * 180
        const _tickHeight = i % 30 === 0 ? tickHeight : tickHeight / 2

        context.beginPath()
        context.moveTo(_x, _y)
        context.lineTo(_x - _tickHeight * cos(angle), _y - _tickHeight * sin(angle))
        context.lineWidth = i % 30 === 0 ? tickWidth : tickWidth / 2
        context.stroke()
      }
    }

    const drawdrawAnnotations = () => {
      const { x, y } = center
      const tickWidth = 2
      const tickHeight = 30
      
      context.font = '16px Arial'
      context.fillStyle = 'blue'

      for (let i = 0; i < 360; i += 10) {
        if (i % 30 === 0) {
          const angle = i / 180 * Math.PI
          const _x = x + cos(angle) * 180
          const _y = y + sin(angle) * 180

          context.fillText(i, _x - tickHeight * cos(angle), _y - tickHeight * sin(angle))
        }
      }
    }

    const drawCursor = () => {
      const { x, y } = center
      const r = 10
      const startAngle = 0
      const endAngle = PI * 2

      context.beginPath()
      context.arc(x, y, r, startAngle, endAngle)
      context.fillStyle = 'green'
      context.fill()
      context.beginPath()
      context.moveTo(x, y)

      context.lineTo(x - 200 * sin(30), y - 200 * cos(30))
      context.stroke()
    }

    drawGrid(10, 10, 0.5, '#ddd')
    drawCircles()
    drawTicks()
    drawdrawAnnotations()
    drawCursor()
  </script>
</body>

</html>