Severian's picture
initial commit
a8b3f00
raw
history blame
2.83 kB
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