From a088bff7be907d62d9ced601abfb855fde4894a0 Mon Sep 17 00:00:00 2001 From: aronmal Date: Fri, 26 May 2023 18:25:14 +0200 Subject: [PATCH] Drawing function --- .../components/Gamefield/Gamefield.tsx | 47 ++++++++++++-- leaky-ships/hooks/useDraw.ts | 64 +++++++++++++++++++ leaky-ships/interfaces/frontend.ts | 11 ++++ 3 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 leaky-ships/hooks/useDraw.ts diff --git a/leaky-ships/components/Gamefield/Gamefield.tsx b/leaky-ships/components/Gamefield/Gamefield.tsx index c979382..acd750b 100644 --- a/leaky-ships/components/Gamefield/Gamefield.tsx +++ b/leaky-ships/components/Gamefield/Gamefield.tsx @@ -1,12 +1,13 @@ -// import Bluetooth from './Bluetooth' -// import FogImages from './FogImages' -import { Hit, MouseCursor, Target } from "../../interfaces/frontend" +import { Draw, Hit, MouseCursor, Target } from "../../interfaces/frontend" +// import Bluetooth from "./Bluetooth" +// import FogImages from "./FogImages" import Labeling from "./Labeling" import Ships from "./Ships" import BorderTiles from "@components/Gamefield/BorderTiles" import EventBar from "@components/Gamefield/EventBar" import HitElems from "@components/Gamefield/HitElems" import Targets from "@components/Gamefield/Targets" +import { useDraw } from "@hooks/useDraw" import { hitReducer, initlialTarget, @@ -52,17 +53,15 @@ function Gamefield() { } else if (!overlapsWithAnyBorder(targetPreview, mode)) setTarget({ show: true, x, y }) }, - [hits, mode, targetPreview] + [hits, mode, target, targetPreview] ) useEffect(() => { - console.log(1) const { x, y, show } = target const { shouldShow, ...position } = mouseCursor if (!shouldShow || overlapsWithAnyBorder(position, mode)) setTargetPreview((e) => ({ ...e, show: false })) else { - console.log(2, position) setTargetPreview({ ...position, show: !show || x !== position.x || y !== position.y, @@ -70,6 +69,29 @@ function Gamefield() { } }, [mode, mouseCursor, target]) + const [color, setColor] = useState("#f00") + const [disable, setDisable] = useState(false) + const { canvasRef, onMouseDown, clear } = useDraw(drawLine) + + function drawLine({ prevPoint, currentPoint, ctx }: 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() + } + return (
{/* */} @@ -95,7 +117,20 @@ function Gamefield() { {/* Debug */} +
+ + ) diff --git a/leaky-ships/hooks/useDraw.ts b/leaky-ships/hooks/useDraw.ts new file mode 100644 index 0000000..f07b813 --- /dev/null +++ b/leaky-ships/hooks/useDraw.ts @@ -0,0 +1,64 @@ +import { Draw, Point } from "../interfaces/frontend" +import { useEffect, useRef, useState } from "react" + +export const useDraw = ( + onDraw: ({ ctx, currentPoint, prevPoint }: Draw) => void +) => { + const [mouseDown, setMouseDown] = useState(false) + + const canvasRef = useRef(null) + const prevPoint = useRef(null) + + 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 handler = (e: MouseEvent) => { + if (!mouseDown) return + const currentPoint = computePointInCanvas(e) + + const ctx = canvasRef.current?.getContext("2d") + if (!ctx || !currentPoint) return + + onDraw({ ctx, currentPoint, prevPoint: prevPoint.current }) + prevPoint.current = currentPoint + } + + const computePointInCanvas = (e: MouseEvent) => { + const canvas = canvasRef.current + if (!canvas) return + + 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 + canvasRef.current?.addEventListener("mousemove", handler) + window.addEventListener("mouseup", mouseUpHandler) + + // Remove event listeners + return () => { + canvasRef.current?.removeEventListener("mousemove", handler) + window.removeEventListener("mouseup", mouseUpHandler) + } + }, [onDraw]) + + return { canvasRef, onMouseDown, clear } +} diff --git a/leaky-ships/interfaces/frontend.ts b/leaky-ships/interfaces/frontend.ts index 6e0f330..7f74958 100644 --- a/leaky-ships/interfaces/frontend.ts +++ b/leaky-ships/interfaces/frontend.ts @@ -47,3 +47,14 @@ interface removeMissile { } export type HitDispatch = fireMissile | removeMissile + +export interface Point { + x: number + y: number +} + +export interface Draw { + ctx: CanvasRenderingContext2D + currentPoint: Point + prevPoint: Point | null +}