import { CourtBall } from "./CourtBall" import { ReactElement, RefObject, useCallback, useLayoutEffect, useState, } from "react" import CourtPlayer from "./CourtPlayer" import { Player } from "../../model/tactic/Player" import { Action, ActionKind } from "../../model/tactic/Action" import ArrowAction from "../actions/ArrowAction" import { middlePos, ratioWithinBase } from "../arrows/Pos" import BallAction from "../actions/BallAction" import { CourtObject } from "../../model/tactic/Ball" import { contains } from "../arrows/Box" import { CourtAction } from "../../views/editor/CourtAction" 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: ReactElement courtRef: RefObject } export function BasketCourt({ players, actions, objects, renderAction, setActions, onPlayerRemove, onPlayerChange, onBallMoved, onBallRemove, courtImage, courtRef, }: BasketCourtProps) { function placeArrow(origin: Player, arrowHead: DOMRect) { const originRef = document.getElementById(origin.id)! const courtBounds = courtRef.current!.getBoundingClientRect() const start = ratioWithinBase( middlePos(originRef.getBoundingClientRect()), courtBounds, ) for (const player of players) { if (player.id == origin.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 end = ratioWithinBase(middlePos(targetPos), courtBounds) const action: Action = { fromPlayerId: originRef.id, toPlayerId: player.id, type: origin.hasBall ? ActionKind.SHOOT : ActionKind.SCREEN, moveFrom: start, segments: [{ next: end }], } setActions((actions) => [...actions, action]) return } } const action: Action = { fromPlayerId: originRef.id, type: origin.hasBall ? ActionKind.DRIBBLE : ActionKind.MOVE, moveFrom: ratioWithinBase( middlePos(originRef.getBoundingClientRect()), courtBounds, ), segments: [ { next: ratioWithinBase(middlePos(arrowHead), courtBounds) }, ], } setActions((actions) => [...actions, action]) } const [previewAction, setPreviewAction] = useState(null) const updateActionsRelatedTo = useCallback((player: Player) => { const newPos = ratioWithinBase( middlePos( document.getElementById(player.id)!.getBoundingClientRect(), ), courtRef.current!.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 }), ) }, []) const [internActions, setInternActions] = useState([]) useLayoutEffect(() => setInternActions(actions), [actions]) return (
{courtImage} {players.map((player) => ( updateActionsRelatedTo(player)} onChange={onPlayerChange} onRemove={() => onPlayerRemove(player)} courtRef={courtRef} availableActions={(pieceRef) => [ { const baseBounds = courtRef.current!.getBoundingClientRect() const arrowHeadPos = middlePos(headPos) const target = players.find( (p) => p != player && contains( document .getElementById(p.id)! .getBoundingClientRect(), arrowHeadPos, ), ) setPreviewAction((action) => ({ ...action!, segments: [ { next: ratioWithinBase( arrowHeadPos, baseBounds, ), }, ], type: player.hasBall ? target ? ActionKind.SHOOT : ActionKind.DRIBBLE : target ? ActionKind.SCREEN : ActionKind.MOVE, })) }} onHeadPicked={(headPos) => { ;(document.activeElement as HTMLElement).blur() const baseBounds = courtRef.current!.getBoundingClientRect() setPreviewAction({ type: player.hasBall ? ActionKind.DRIBBLE : ActionKind.MOVE, fromPlayerId: player.id, toPlayerId: undefined, moveFrom: ratioWithinBase( middlePos( pieceRef.getBoundingClientRect(), ), baseBounds, ), segments: [ { next: ratioWithinBase( middlePos(headPos), baseBounds, ), }, ], }) }} onHeadDropped={(headRect) => { placeArrow(player, headRect) setPreviewAction(null) }} />, player.hasBall && ( onBallMoved(ref.getBoundingClientRect()) } /> ), ]} /> ))} {internActions.map((action, idx) => renderAction(action, idx))} {objects.map((object) => { if (object.type == "ball") { return ( ) } throw new Error("unknown court object" + object.type) })} {previewAction && ( {}} onActionChanges={() => {}} /> )}
) }