전에는 각 원의 위치에 따라 포지션 명을 바꿔주도록 하였다
이번에는 선수 리스트를 받아서 원을 우클릭하면 선수의 리스트를 띄워주도록 해보자
이후 이름을 선택하면 이름이 원에 뜨고 리스트에서는 사라지게 구현하자
우선 같이 프론트 개발을 하고있는 팀원은 TS로 개발을 하고있는데 우클릭을 해서 선수 리스트를 뜨게하는것까지 구현을 해주었다
목데이터 (Mock Data)
type Players = {
id: number;
//등번호
name: string;
already?: boolean;
//들어가있는지 유무
//주장 유무랑 포지션 추가 예정
}
export const playersList: Players[] = [
{
id: 1,
name: "1번",
already: true
},
{
id: 2,
name: "2번",
already: true
},
{
id: 3,
name: "3번",
already: true
},
{
id: 4,
name: "4번",
already: true
},
{
id: 5,
name: "5번",
already: true
},
{
id: 6,
name: "6번",
already: true
},
{
id: 7,
name: "7번",
already: true
},
{
id: 8,
name: "8번",
already: true
},
{
id: 9,
name: "9번",
already: true
},
{
id: 10,
name: "10번",
already: true
},
{
id: 11,
name: "11번",
already: true
},
{
id: 12,
name: "12번",
already: false
},
{
id: 13,
name: "13번",
already: false
},
{
id: 14,
name: "14번",
already: false
},
];
-----------------------------------------------------
CSS
.move {
background-color:skyblue;
width:80px;
height:80px;
border-radius:75px;
text-align:center;
margin:0 auto;
font-size:30px;
vertical-align:middle;
line-height:50px;
cursor: grab;
position: absolute;
}
.move:hover {
background-color: pink;
}
.formation {
width: 600px;
height: 950px;
background-image: url(https://velog.velcdn.com/images%2Fqnrl3442%2Fpost%2F733d5e03-5531-4e99-98e6-6f9a05c26c15%2Fformation.png);
}
.GK {
background-color:skyblue;
width:80px;
height:80px;
border-radius:75px;
text-align:center;
margin:0 auto;
font-size:30px;
vertical-align:middle;
line-height:50px;
cursor: not-allowed;
position: absolute;
}
.button {
border-radius:50%;
text-align:center;
font-size:30px;
vertical-align:middle;
line-height:50px;
}
-------------------------------------------------------------------
import React, { useState } from 'react';
import "./Formation.css";
import Draggable, { DraggableData } from 'react-draggable';
import axios from 'axios';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import { Button } from '@mui/material';
import { playersList } from './data';
//s 조심
function Formation() {
type PlayerType = {
id: number;
name: string;
already: boolean;
};
const [playerList, setPlayerList] = useState(playersList);
//s 조심
const [Status, SetStatus] = useState(true)
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
event.preventDefault();
//event.preventDefault() 브라우저 우클릭을 막아준다.
};
const handleClose = () => {
setAnchorEl(null);
};
const onStatusHandler = () => {
SetStatus(!Status)
}
const readDB = () => {
if (Status) {
console.log("read")
axios.get('/api/readUser') // res = axios 이런식으로 해서 res를 가지고 있어야됨 방법 찾아보자
.then(res => {
console.log(res.data)
// const name = res.data.UserName
// const x = res.data.x
// const y = res.data.y
// console.log(name,x,y)
})
console.log("포메이션 원에 위에서 받은 선수 데이터 넣어주기")
} else {
console.log("send")
const body = {
Status: Status,
first_Position: Content1 //첫번째 요소 포지션
}
axios.post('/api/sendUser', body)
.then(res => {
console.log(res.data)
})
}
}
// 포지션 위치 값 보내는 방법
// const [Position1, SetPosition1] = useState({ x: 0, y: 0 });
// const trackPos = (data) => {
// SetPosition1({ x: data.x, y: data.y });
// };
// let body = {
// first: Position1
// }
// axios.post('/api/position', body)
// .then(res => {
// console.log(res.data)
// })
const [Content1, SetContent1] = useState("ST");
------------------------ Content2~9------------
const [Content10, SetContent10] = useState("RB");
const onContentHandler1 = (props: string) => {
SetContent1(props)
}
const onDragHandler1 = (data: DraggableData) => {
if (data.x > 80 && data.y < 120 && data.x < 450) {
onContentHandler1("ST")
} else if (data.x < 80 && data.y < 200) {
onContentHandler1("LW")
} else if (data.x > 450 && data.y < 200) {
onContentHandler1("RW")
} else if (data.x > 80 && data.y > 120 && data.y < 185 && data.x < 450) {
onContentHandler1("CF")
} else if (data.x > 80 && data.y > 185 && data.y < 275 && data.x < 450) {
onContentHandler1("CAM")
} else if (data.x < 80 && data.y > 200 && data.y < 440) {
onContentHandler1("LM")
} else if (data.x > 450 && data.y > 200 && data.y < 440) {
onContentHandler1("RM")
} else if (data.x > 80 && data.y > 275 && data.y < 460 && data.x < 450) {
onContentHandler1("CM")
} else if (data.x < 80 && data.y > 440) {
onContentHandler1("LB")
} else if (data.x > 450 && data.y > 440) {
onContentHandler1("RB")
} else if (data.x > 80 && data.y > 460 && data.y < 560 && data.x < 450) {
onContentHandler1("CDM")
} else if (data.x > 80 && data.y > 560 && data.x < 450) {
onContentHandler1("CB")
}
}
--------------------------- onDragHandler2~9--------------------------------
const onContentHandler10 = (props: string) => {
SetContent10(props)
}
const onDragHandler10 = (data: DraggableData) => {
if (data.x > 80 && data.y < 120 && data.x < 450) {
onContentHandler10("ST")
} else if (data.x < 80 && data.y < 200) {
onContentHandler10("LW")
} else if (data.x > 450 && data.y < 200) {
onContentHandler10("RW")
} else if (data.x > 80 && data.y > 120 && data.y < 185 && data.x < 450) {
onContentHandler10("CF")
} else if (data.x > 80 && data.y > 185 && data.y < 275 && data.x < 450) {
onContentHandler10("CAM")
} else if (data.x < 80 && data.y > 200 && data.y < 440) {
onContentHandler10("LM")
} else if (data.x > 450 && data.y > 200 && data.y < 440) {
onContentHandler10("RM")
} else if (data.x > 80 && data.y > 275 && data.y < 460 && data.x < 450) {
onContentHandler10("CM")
} else if (data.x < 80 && data.y > 440) {
onContentHandler10("LB")
} else if (data.x > 450 && data.y > 440) {
onContentHandler10("RB")
} else if (data.x > 80 && data.y > 460 && data.y < 560 && data.x < 450) {
onContentHandler10("CDM")
} else if (data.x > 80 && data.y > 560 && data.x < 450) {
onContentHandler10("CB")
}
}
return (
<div className="formation">
<button onClick={() => {
onStatusHandler()
readDB()
}}>
{Status ? "편집" : "편집 완료"}
</button>
<Draggable
disabled={Status}
defaultPosition={{ x: 145, y: 80 }}
onDrag={(e, data) => onDragHandler1(data)}
bounds={{ top: 0, left: 0, right: 520, bottom: 740 }}
// onStop={(e, data) => trackPos(data)}
// 포지션 위치 값 보내는 방법
>
<div className="move">
<Button className="button"
disabled={Status}
id="basic-button"
aria-controls={open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onContextMenu={handleClick}
><div>{Content1}</div>
</Button>
</div>
</Draggable >
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
PaperProps={{
style: {
maxHeight: "200px",
width: '20ch',
},
}}
//스크롤 만드는것
>
{playerList.map((player): JSX.Element => {
return (
// player.already === false &&
<MenuItem onClick={handleClose}>{player.name}</MenuItem>
);
})}
</Menu>
{/* <MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem> */}
<Draggable
disabled={Status}
defaultPosition={{ x: 380, y: 80 }}
onDrag={(e, data) => onDragHandler2(data)}
bounds={{ top: 0, left: 0, right: 520, bottom: 740 }}
>
<div className="move">
<div>{Content2}</div>
</div>
</Draggable>
--------- 3~10번 Draggable------------------
<Draggable
disabled={true}
defaultPosition={{ x: 260, y: 790 }}
>
<div className="GK">
<div>GK</div>
</div>
</Draggable>
</div >
)
}
export default Formation
겹치는 코드는 --------- 여기서는 이걸로 조금 짧게 표현했다
코드를 해석해보면 목데이터를 불러온다
그리고 playlist에 기본 값으로 넣어주고 anchorEl, open 을 만들었다
Menu라는 것을 만들어 draggable안의 button 에서 menu를 불러오도록 만든것 같다
내가 작성한 코드가 아니라서 제대로된 알지못한다 ㅠ
일단 리스트가 뜨는것까지만 구현했다고 하여서 이후는 내가 구현하기로했다
목데이터를 보면 already라는 불린값이 있는데 이 already가 false일때만 리스트에 나오게 코드를 만들어야 된다고 들었다
그래서 menu에서 menuitem을 만들 때 if로 한번 걸러주었다
{playerList.map((player, idx) => {
if(player.already === false){
return (
<MenuItem
onClick={() => {handleClose()}}
key={idx}
>
{player.name}
</MenuItem>
)
}
})}
그리고 idx값을 주어 각 리스트에 키값을 넣어주었다
이후 목데이터를 수정한후에 테스트해보았다
제대로 리스트가 떳다
이후 선택되면 already 값을 바꿔주려고 생각을 해보았다
지금 보면 Menuitem에 handleClose()가 걸려있다
그래서 저걸 사용해서 해보려고 handleClose에 player를 props로 넣어주었다
그러면 선택될 때 그 선택되는 선수가 담겨서 들어갈것이다
const handleClose = ({id, name, already}) => {
setAnchorEl();
setPlayerList(playerList.map((player) =>
player.id === id ? { ...player, already: !already} : player)
)
}
프롭스를 바로 구조분해를 하고 setPlayerList를 이용해서 지금 받아온 id와 비교를 해서
같은 id가 있으면 already를 바꿔주고 같지않으면 그냥 냅두게 삼항연산자로 작성을 하였다
이렇게 하니까 변경이 되고 선택된 값은 리스트에서 사라졌다
그런데 1번을 고른 후 2번을 고르면 다시 1번의 already를 false로 바꿔줘야하는데 그걸 어떻게 구현해야할지
아무리 머리를 싸매고 생각을 해도 방법이 나오지않았다
처음에는 똑같이 삼항연산자를써서 true를 모두 false로 바꾼 뒤에 선택된 값만 다시 true로 바꿔주면 되지않을까 싶었는데
되지않고 한번 사라지면 계속 뜨지않았다
그래서 일단 이건 나중에 구현하기로 하고 선택되는 선수의 이름을 원에 띄워주기를 먼저 하려고 했다
그래서 const [Name1, SetName1] = useState("")
를 먼저 만들어주고 Name핸들러를 만들어서
메뉴 onClick에 걸어주고 props로 똑같이 해당 선수를 받았다
그리고 Name을 Draggable에 넣어주니까 선택되는 선수로 이름이 변경 되었다
비교를 위해 두번째 원도 똑같이 해주고 Name핸들러 2를 만들어서 2를 걸어주었다
그런데 1번에서 고른 값이 2번 원에 나오는 것이다
혼자는 어려워서 팀원과 같이 디스코드를 하면서 진행하였지만 둘다 원인을 찾지 못하였고 다음에 하기로 하였다
다음 포스트에서 이어서 작성하겠다