본문 바로가기

카테고리 없음

Draggable 이용해서 축구 포메이션 만들어보기

1. Draggable 이란?

 

React-Draggable은 드래그로 아이템의 순서를 변경하기보다,

컴포넌트를 드래그해서 위치를 옮기는 기능에 강점이 있는 라이브러리입니다.

 

2. React-Beautiful-DnD, React DnD랑의 차이점은?

 

일단 사용량 자체만 보자면

 

 

 

내가 사용한 React-Draggable이 사용량이 훨씬 많다.

 

React-Draggable과 React-Beautiful-DnD, React-DnD의 차이점은

 

React-DnD, Beautiful-DnD :

아까 언급했듯이 Draggable은 요소보단 컴포넌트에 중점이라면, React-DnD와 Beautiful-DnD는 요소가 중점이라고 생각하면 된다.

드래그로 아이템의 순서를 변경할때 편하며, 둘의 차이점을 보자면 React-DnD는 UI/UX가 미리 정해져있지 않은 경우가 있지만

Beautiful-DnD는 좋은 UI/UX나 동작이 이미 정의가 되어있다.

 

그래서 사용량으로 총합해서 보자면 Draggable > Beautiful-DnD > React-DnD 순으로 많이 쓰인다.

 

나도 그래서 처음엔 당연히 사용량이 많은 Draggable이 좋겠지 하고 선택을 했다.

 

3. 설치 및 사용법

 

1. 라이브러리 설치

 

npm install react-draggable

 

 

2. 사용하고자 하는 컴포넌트에 선언

 

import Draggable from "react-draggable";

 

3. 드래그하고자 하는 컴포넌트를 감싸주기

 

<Draggable>
    <div>
    	Can Drag
    </div>
</Draggable>

 

 

4. 실제 사용해보기

 

일단 스포츠 경기장에 드래그 가능한 요소를 추가해야하기 때문에

 

요소들에 Draggable을 넣어준다.

 

{BasketplayersList.map((player) => (
    <div key={player.id} style={{position: "absolute"}}>
        <div style={{position: "relative"}}>
            <Draggable
                defaultPosition={{ x: player.x, y: player.y }}
                bounds={bounds}
            >
               <D.PlayerContainer style={{cursor: "pointer"}}>
                   <People/>
                   <D.PlayerText style={{ userSelect: 'none' }}>
                       {player.name}
                   </D.PlayerText>
               </D.PlayerContainer>
            </Draggable>
        </div>
    </div>
))}

 

하지만 이렇게 한다면, 요소안에서만 움직이지 않을 수 있다.

그렇기 때문에 미리 따온 이미지에 useRef를 사용해서 요소의 크기만큼 움직일 수 있게끔 해준다.

 

const formationFieldRef = useRef<HTMLDivElement>(null);

useEffect(() => {
    if (formationFieldRef.current) {
        const { left, top, right, bottom } = formationFieldRef.current.getBoundingClientRect();
        setBounds({ left, top, right: right - left - 70, bottom: bottom - top - 70 }); //right, bottom에 요소크기 빼기
    }
}, []);

<D.ImgBox ref={formationFieldRef} img = {BasketField} style={{position: "relative"}}>

 

크기가 측정된 이미지의 크기를 바탕으로 bounds를 설정해, 요소들의 움직임을 제한한다.

 

여기서 가끔 이미지의 크기만큼 움직이긴 하는데 이미지에 접근을 못하는 문제가 생겼는데,

이러한 문제는 relative, absolute를 주며 해결하였고,

 

또 다른 문제가 생겼는데 바로 defaultPosition을 요소별로 같게 줘도 서로의 좌표가 다르게 나온다는 것이다.

예를 들어 0 ,0으로 defaultPosition을 줬을때 요소들이 멀어지고, 각자의 0, 0좌표가 모두 다르게 나온다.

 

그런 문제도 처음에 겹치지 않아서 문제인 것이니 relative, absolute를 줘서 해결하였다.

 

<div key={player.id} style={{position: "absolute"}}>
    <div style={{position: "relative"}}>
        <Draggable
            defaultPosition={{ x: player.x, y: player.y }}
            bounds={bounds}
            nodeRef={formationFieldRef}
        >
            <D.PlayerContainer style={{cursor: "pointer"}}>
                <People/>
                <D.PlayerText style={{ userSelect: 'none' }}>
                    {player.name}
                </D.PlayerText>
            </D.PlayerContainer>
        </Draggable>
    </div>
</div>

 

5. 마무리

 

처음 사용해보는 라이브러리라 찾아보는 자료들도 많고, 생각했던 것보다 많이 걸렸던 것 같지만

만드는 것 자체가 재밌어서 질리지가 않았다.