leaky-ships/leaky-ships/hooks/useDraw.ts

119 lines
3.1 KiB
TypeScript

import { Draw, Point } from "../interfaces/frontend"
import { useDrawProps } from "./useDrawProps"
import { socket } from "@lib/socket"
import { useEffect, useRef, useState } from "react"
function drawLine({ prevPoint, currentPoint, ctx, color }: Draw) {
const { x: currX, y: currY } = currentPoint
const lineColor = color
const lineWidth = 5
let startPoint = prevPoint ?? currentPoint
ctx.beginPath()
ctx.lineWidth = lineWidth
ctx.strokeStyle = lineColor
ctx.moveTo(startPoint.x, startPoint.y)
ctx.lineTo(currX, currY)
ctx.stroke()
ctx.fillStyle = lineColor
ctx.beginPath()
ctx.arc(startPoint.x, startPoint.y, 2, 0, 2 * Math.PI)
ctx.fill()
}
export const useDraw = () => {
const [mouseDown, setMouseDown] = useState(false)
const canvasRef = useRef<HTMLCanvasElement>(null)
const prevPoint = useRef<null | Point>(null)
const { color } = useDrawProps()
const onMouseDown = () => setMouseDown(true)
const clear = () => {
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext("2d")
if (!ctx) return
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const handler = (e: MouseEvent) => {
if (!mouseDown) return
const currentPoint = computePointInCanvas(e)
const ctx = canvasRef.current?.getContext("2d")
if (!ctx || !currentPoint) return
drawLine({ ctx, currentPoint, prevPoint: prevPoint.current, color })
prevPoint.current = currentPoint
}
const computePointInCanvas = (e: MouseEvent) => {
const rect = canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
return { x, y }
}
const mouseUpHandler = () => {
setMouseDown(false)
prevPoint.current = null
}
// Add event listeners
canvas.addEventListener("mousemove", handler)
window.addEventListener("mouseup", mouseUpHandler)
// Remove event listeners
return () => {
canvas.removeEventListener("mousemove", handler)
window.removeEventListener("mouseup", mouseUpHandler)
}
}, [color, mouseDown])
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext("2d")
if (!ctx) return
socket.on("playerEvent", (event) => {
if (!canvasRef.current?.toDataURL() || event.type !== "connect") return
console.log("sending canvas state")
socket.emit("canvas-state", canvasRef.current.toDataURL())
})
socket.on("canvas-state-from-server", (state: string, index) => {
console.log("I received the state")
const img = new Image()
img.src = state
img.onload = () => {
ctx?.drawImage(img, 0, 0)
}
})
socket.on("draw-line", ({ prevPoint, currentPoint, color }, index) => {
if (!ctx) return console.log("no ctx here")
drawLine({ prevPoint, currentPoint, ctx, color })
})
socket.on("canvas-clear", clear)
return () => {
socket.removeAllListeners()
}
})
return { canvasRef, onMouseDown, clear }
}