import "../../style/basket_court.css" import {CourtBall} from "./CourtBall"; import {ReactElement, RefObject, useCallback, useState,} from "react" import CourtPlayer from "./CourtPlayer" import {Player} from "../../tactic/Player" import {Action, MovementActionKind} from "../../tactic/Action" import RemoveAction from "../actions/RemoveAction" import ArrowAction from "../actions/ArrowAction" import BendableArrow, {Segment} from "../arrows/BendableArrow" import {middlePos, NULL_POS, Pos} from "../arrows/Pos" import BallAction from "../actions/BallAction"; import {CourtObject} from "../../tactic/CourtObjects"; export interface BasketCourtProps { players: Player[] actions: Action[] objects: CourtObject[] renderAction: (a: Action, key: number) => ReactElement setActions: (f: (a: Action[]) => Action[]) => void onPlayerRemove: (p: Player) => void onPlayerChange: (p: Player) => void onBallRemove: () => void onBallMoved: (ball: DOMRect) => void courtImage: string courtRef: RefObject } export function BasketCourt({ objects, onBallMoved, onBallRemove, players, actions, renderAction, setActions, onPlayerRemove, onPlayerChange, courtImage, courtRef, }: BasketCourtProps) { function bindArrowToPlayer(originRef: HTMLElement, arrowHead: DOMRect) { for (const player of players) { if (player.id == originRef.id) { continue } const playerBounds = document .getElementById(player.id)! .getBoundingClientRect() if ( !( playerBounds.top > arrowHead.bottom || playerBounds.right < arrowHead.left || playerBounds.bottom < arrowHead.top || playerBounds.left > arrowHead.right ) ) { const targetPos = document.getElementById(player.id)!.getBoundingClientRect() const action: Action = { fromPlayerId: originRef.id, toPlayerId: player.id, type: MovementActionKind.SCREEN, moveFrom: middlePos(originRef.getBoundingClientRect()), segments: [{next: middlePos(targetPos)}], } setActions((actions) => [...actions, action]) } } } const [previewArrowOriginPos, setPreviewArrowOriginPos] = useState(NULL_POS) const [isPreviewArrowEnabled, setPreviewArrowEnabled] = useState(false) const [previewArrowEdges, setPreviewArrowEdges] = useState([]) const updateActionsRelatedTo = useCallback((player: Player) => { const newPos = middlePos(document.getElementById(player.id)!.getBoundingClientRect()) setActions(actions => actions.map(a => { if (a.fromPlayerId == player.id) { return {...a, moveFrom: newPos} } if (a.toPlayerId == player.id) { const segments = a.segments.toSpliced(a.segments.length - 1, 1, { ...a.segments[a.segments.length - 1], next: newPos }) return {...a, segments} } return a })) }, []) return (
{"court"} {actions.map((action, idx) => renderAction(action, idx))} {players.map((player) => ( updateActionsRelatedTo(player)} onChange={onPlayerChange} onRemove={() => onPlayerRemove(player)} parentRef={courtRef} availableActions={(pieceRef) => [ onPlayerRemove(player)} />, setPreviewArrowEdges([ {next: middlePos(headPos)}, ]) } onHeadPicked={(headPos) => { setPreviewArrowOriginPos( middlePos(pieceRef.getBoundingClientRect()), ) setPreviewArrowEdges([ {next: middlePos(headPos)}, ]) setPreviewArrowEnabled(true) }} onHeadDropped={(headRect) => { bindArrowToPlayer(pieceRef, headRect) setPreviewArrowEnabled(false) }} />, player.hasBall && onBallMoved(ref.getBoundingClientRect())}/> ]} /> ))} {objects.map((object) => { if (object.type == "ball") { return ( ) } throw new Error("unknown court object", object.type) })} {isPreviewArrowEnabled && ( {}} endRadius={17} startRadius={26} /> )}
) }