| 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 |
|
|