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