You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.9 KiB
124 lines
3.9 KiB
import "../../style/basket_court.css"
|
|
import {ReactElement, RefObject} 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 {useXarrow} from "react-xarrows"
|
|
import BallAction from "../actions/BallAction";
|
|
import {CourtObject} from "../../tactic/CourtObjects";
|
|
import {CourtBall} from "./CourtBall";
|
|
|
|
export interface BasketCourtProps {
|
|
players: Player[]
|
|
actions: Action[]
|
|
objects: CourtObject[]
|
|
renderAction: (a: Action) => ReactElement
|
|
setActions: (f: (a: Action[]) => Action[]) => void
|
|
onPlayerRemove: (p: Player) => void
|
|
onBallDrop: (ref: HTMLElement) => void
|
|
onPlayerChange: (p: Player) => void
|
|
|
|
onBallRemove: () => void
|
|
|
|
onBallMoved: (ball: DOMRect) => void
|
|
|
|
courtImage: string
|
|
courtRef: RefObject<HTMLDivElement>
|
|
}
|
|
|
|
export function BasketCourt({
|
|
players,
|
|
objects,
|
|
actions,
|
|
renderAction,
|
|
setActions,
|
|
onBallDrop,
|
|
onPlayerRemove,
|
|
onBallRemove,
|
|
onBallMoved,
|
|
onPlayerChange,
|
|
courtImage,
|
|
courtRef,
|
|
}: BasketCourtProps) {
|
|
function bindArrowToPlayer(
|
|
originRef: RefObject<HTMLDivElement>,
|
|
arrowHead: DOMRect,
|
|
) {
|
|
for (const player of players) {
|
|
if (player.id == originRef.current!.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 action = {
|
|
type: MovementActionKind.SCREEN,
|
|
moveFrom: originRef.current!.id,
|
|
moveTo: player.id,
|
|
}
|
|
setActions((actions) => [...actions, action])
|
|
}
|
|
}
|
|
}
|
|
|
|
const updateArrows = useXarrow()
|
|
|
|
return (
|
|
<div id="court-container" ref={courtRef} style={{ position: "relative" }}>
|
|
<img src={courtImage} alt={"court"} id="court-svg" />
|
|
{players.map((player) => (
|
|
<CourtPlayer
|
|
key={player.id}
|
|
player={player}
|
|
onDrag={updateArrows}
|
|
onChange={onPlayerChange}
|
|
onRemove={() => onPlayerRemove(player)}
|
|
parentRef={courtRef}
|
|
availableActions={(pieceRef) => [
|
|
<RemoveAction
|
|
key={1}
|
|
onRemove={() => onPlayerRemove(player)}
|
|
/>,
|
|
<ArrowAction
|
|
key={2}
|
|
originRef={pieceRef}
|
|
onArrowDropped={(headRect) =>
|
|
bindArrowToPlayer(pieceRef, headRect)
|
|
}
|
|
/>,
|
|
player.hasBall && <BallAction key={3} onDrop={onBallDrop}/>
|
|
]}
|
|
/>
|
|
))}
|
|
|
|
{objects.map((object) => {
|
|
if (object.type == "ball") {
|
|
return (
|
|
<CourtBall
|
|
onMoved={onBallMoved}
|
|
ball={object}
|
|
onRemove={onBallRemove}
|
|
key="ball"
|
|
/>
|
|
)
|
|
}
|
|
throw new Error("unknown court object", object.type)
|
|
})}
|
|
|
|
{actions.map(renderAction)}
|
|
</div>
|
|
)
|
|
}
|