File size: 2,827 Bytes
a8b3f00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import type { FC } from 'react'
import { useCallback, useEffect, useRef } from 'react'

type GridMaskProps = {
  children: React.ReactNode
  wrapperClassName?: string
  canvasClassName?: string
  gradientClassName?: string
}
const GridMask: FC<GridMaskProps> = ({
  children,
  wrapperClassName,
  canvasClassName,
  gradientClassName,
}) => {
  const canvasRef = useRef<HTMLCanvasElement | null>(null)
  const ctxRef = useRef<CanvasRenderingContext2D | null>(null)
  const initCanvas = () => {
    const dpr = window.devicePixelRatio || 1

    if (canvasRef.current) {
      const { width: cssWidth, height: cssHeight } = canvasRef.current?.getBoundingClientRect()

      canvasRef.current.width = dpr * cssWidth
      canvasRef.current.height = dpr * cssHeight

      const ctx = canvasRef.current.getContext('2d')
      if (ctx) {
        ctx.scale(dpr, dpr)
        ctx.strokeStyle = '#D1E0FF'
        ctxRef.current = ctx
      }
    }
  }

  const drawRecord = useCallback(() => {
    const canvas = canvasRef.current!
    const ctx = ctxRef.current!
    const rowNumber = parseInt(`${canvas.width / 24}`)
    const colNumber = parseInt(`${canvas.height / 24}`)

    ctx.clearRect(0, 0, canvas.width, canvas.height)
    ctx.beginPath()
    for (let i = 0; i < rowNumber; i++) {
      for (let j = 0; j < colNumber; j++) {
        const x = i * 24
        const y = j * 24
        if (j === 0) {
          ctx.moveTo(x, y + 2)
          ctx.arc(x + 2, y + 2, 2, Math.PI, Math.PI * 1.5)
          ctx.lineTo(x + 22, y)
          ctx.arc(x + 22, y + 2, 2, Math.PI * 1.5, Math.PI * 2)
          ctx.lineTo(x + 24, y + 22)
          ctx.arc(x + 22, y + 22, 2, 0, Math.PI * 0.5)
          ctx.lineTo(x + 2, y + 24)
          ctx.arc(x + 2, y + 22, 2, Math.PI * 0.5, Math.PI)
        }
        else {
          ctx.moveTo(x + 2, y)
          ctx.arc(x + 2, y + 2, 2, Math.PI * 1.5, Math.PI, true)
          ctx.lineTo(x, y + 22)
          ctx.arc(x + 2, y + 22, 2, Math.PI, Math.PI * 0.5, true)
          ctx.lineTo(x + 22, y + 24)
          ctx.arc(x + 22, y + 22, 2, Math.PI * 0.5, 0, true)
          ctx.lineTo(x + 24, y + 2)
          ctx.arc(x + 22, y + 2, 2, 0, Math.PI * 1.5, true)
        }
      }
    }
    ctx.stroke()
    ctx.closePath()
  }, [])

  const handleStartDraw = () => {
    if (canvasRef.current && ctxRef.current)
      drawRecord()
  }

  useEffect(() => {
    initCanvas()
    handleStartDraw()
  }, [])

  return (
    <div className={`relative bg-white ${wrapperClassName}`}>
      <canvas ref={canvasRef} className={`absolute inset-0 w-full h-full ${canvasClassName}`} />
      <div className={`absolute w-full h-full z-[1] bg-gradient-to-b from-white/80 to-white rounded-lg ${gradientClassName}`} />
      <div className='relative z-[2]'>{children}</div>
    </div>
  )
}

export default GridMask