운동을 그만둔 지도 어연 1년이 다 지나가는데, 이번에 대회를 한다길래 그냥 구경하러 갔다.
그런데 옆에 형들이 우리팀 누가 슛을 몇피에 쏘는지 수기로 기록하고 있더라.
저렇게 제출된 정보를 취합해서 경기 기록지를 만든다.
그런데 뭔가 프로그램 비스무리하게 만들어보면 저거보다 편하게 슛을 기록하고, 데이터를 시각화하면 효용성도 더 좋아질 것 같다는 생각이 들었다! 귀찮아서 그렇지..
그렇게 갑자기 열렬하게 몰입하게 된 프로젝트.
니즈를 파악해보자.
1. 수기로 기록하는 게 귀찮다! 편하게 기록하고, 그에 대한 데이터를 처리할 수 있으면 좋겠다!
2. 그렇다면 드래그 앤 드롭 방식으로 만들면 자세한 값을 입력하는 것보다 훨씬 쉽지 않을까??
3. 실용성이 있으면 좋겠는데.. 아무래도 자바나 파이썬을 이용해서 복잡하게 만드는 것보다 웹 기반이 훨씬 쓰기도 편하고 좋을 것 같다.
4. 정보는 어떻게 저장할까.. DB를 구성하기에는 아직 한참 모자르니 저번에 찍먹해봤던 localstorage를 이용해봐야겠다!
그렇게 만들기 시작.
1- 첫 번째 페이지 : 선수 등록
첫 번째 페이지는 선수 명단을 등록하는 페이지로 구상했다. 선수의 이름과 등번호를 넣으면, localstorage에 등번호:이름 꼴로 데이터를 집어넣으려 했다. 실수로 입력했을 때나, 로스터 초기화를 위해 해당 기능도 구상했다.
버튼이나 표, 입력란은 Bootstrap을 이용했다. 편하더라.

그렇게 구현된 첫 페이지. 선수 등록은 submit 버튼으로 굳이 버튼이 아니라 엔터만 눌러도 작동되도록 했고,
선수 이름란에 autofocus를 줘서 페이지가 submit되고 새로고침 된 후에 포커스가 자동으로 이름으로 가 입력하기 편하게 구현해봤다. 테이블은 html 상에서는 빈 상태이지만, Javascript를 통해 submit을 할 때마다 반복문을 돌려서 등록된 선수의 수만큼 row를 추가해주는 방법으로 구현했다.
로스터 비우기 버튼을 누르면 localstorage를 초기화한다.

기록 시작 버튼을 누르면 알림이 뜨고 확인해야 다음 페이지로 넘어갈 수 있도록 구현했다.
2-두 번째 페이지 : 슛 기록

이렇게 슈팅 기록으로 넘어오면, Shooting record 바로 아래 란에 자동으로 등록된 선수의 수만큼의 유니폼을 생성했다. 이에 css를 잘 이용해서 텍스트는 이미지 위에 머물게 했고, 최종적으로 얘를 div로 감싸서 draggable하게 해줬다. 그러면 드래그 시 통째로 움직일 테니까!
그렇게 유니폼을 구현하고, 아이스링크도 구현했는데, 드래그 앤 드롭 이벤트를 위해서 dragstart, dragover, drop 이벤트를 이용했다. 앞의 두 개는 preventDefault 함수를 써서 혹시모를 방해공작을 펼치지 못하게 했고, 마지막 drop에서 좀 애를 먹었는데, 간단히 image의 rect 객체(?)를 구해서 아이스링크 이미지의 왼쪽 x와 위쪽 y를 이용했다.
드래그를 했을 때 좌표가 나오는데 (아이스링크 왼쪽 끝+800- 드래그 종료 x좌표)를 하면 드래그한 부분의 x값이 나올 것. 왜 800이냐면 이미지가 800*400이다.
마찬가지로 y값도 구해주고, 여기에 각각 800과 400으로 나눠서 0~1 사이의 소수로 나오도록 했다.
그런데 여기서, 나는 이 슈팅 정보를 저장하고 싶었는데 localstorage를 앞에서처럼 통째로 사용하면 방도가 없어서, 싹 갈았다 ㅋ
앞에서 저장했던 정보는 playerinfo라는 키에 오브젝트를 만들고 그를 JSON으로 parse해서 넣었고, 이번 슈팅값도 recorded라는 키를 가지는 오브젝트를 localstorage에 저장하는 방법으로 구현했다.
이 때 기록에 실수가 있을 수 있으므로 잘못된 기록에 대해서는 삭제 기능을 구현하고 싶었는데, 그러기 위해서는 표에 번호와 삭제 버튼을 구현해야 했다. 번호가 있어야 어떤 기록이 잘못된 지 아니까!
그래서 슛을 저장할 때, recorded[idx] = {x:x, y:y, name:이름, num:등번호, idx:인덱스} 꼴로 저장해 준 것.
이 때 인덱스는 localstorage에 idx라는 키를 가지는 정수 value를 지정해서, 슈팅을 기록할 때마다 해당 idx를 사용하고 idx를 하나씩 늘리는 방법을 채용했다.
그러면 저장은 됐고, 삭제 차례이다.
삭제에서도 애를 좀 먹었다. 표에서 삭제를 하면 새로고침하면서 인덱스도 자동으로 정렬되는 기능을 구현하고 싶었다. 그래서 각 버튼에 onclick으로 삭제 함수를 넣어줬는데, 버튼의 부모 노드로 이동, 첫 번째 자식으로 이동하여 해당 행의 인덱스 값을 알아내는 방법을 채택했다.
그래서 그 번호부터 표의 마지막까지 반복문을 통해 recorded 오브젝트의 i번째 요소를 모두 i+1번째 요소로 바꿔줌으로서 해당 기능을 구현해낼 수 있었다. 새로고침하면 자동으로 recorded에 따라서 표가 그려지니까!
말은 이렇게 하지만 정말 힘들었다 ㅋㅋ...
그러다 보니 피리어드 정보도 저장하고 싶어져서 몇 피리어드인지 체크할 수 있는, 피리어드 값을 1p, 2p, 3p, ot로 아이디를 가지는 체크박스를 만들었다. 근데 이건 또 새로고침하면 할 때마다 체크 안 된 상태를 지정하고, 그렇다고 디폴트 설정으로 1p를 해주자니 기록 삭제 시마다 마지막 체크한 피리어드가 아니라 1p로 돌아가니.. 좀만 멍때리면 데이터가 꼬일 텐데.
그래서
let period = localStorage.getItem("period");
if(period == null){
period = '1p';
}
식으로 처음을 정의해주고,
checkbox.addEventListener("click", (e)=>{
localStorage.setItem('period', e.target.innerHTML);
}
식으로 체크를 하면 해당 텍스트를 localstorage 값에 업데이트를 한 다음에,
웹사이트가 새로고침 될 때마다 작동하도록 정의한 (유니폼 만들기, 표 만들기) init 함수에
document.querySelector("#period").click();
식으로 초기화와 함께 자동으로 체크박스를 클릭하도록 구현했다.
이렇게 슛의 순서, 슛의 위치, 슛 쏜 선수의 이름과 등번호, 슛을 쏜 피리어드 값을 저장했다.
이를 표에 넣는 건 식은 죽 먹기. object의 내용물은 키 값 순으로 정렬이 되는 것 같은데, 인덱스로 저장해놓은 덕분에 새로고침이 되도 저장된 recorded의 순서는 바뀌지 않았다.
그래서 드래그하고 드롭할 때마다 표에 순차적으로 더해주고, 그 값을 recorded에 넣고,
삭제를 눌러 새로고침이 되도 localstorage에 있는 recorded를 가져와서 다시 순차적으로 표를 만들어줬다.
3- 세 번째 페이지 - 슈팅 기록지

세 번째 페이지에는 아예 기록지를 구현했다.
recorded에 이미 데이터는 다 저장되어 있으므로 그걸로 표를 만드는 건 너무 쉽고, 내가 원했던 건 선수별 슈팅 카운트였다.
이는 playerinfo 한 명당 recorded를 다 돌면서 recorded[i].name이나 num이 playerinfo의 그것과 같은지 카운트한 후, 그걸 업데이트해주면 되었다. 개인적으로 개꿀 기능이라고 생각 ㅎ ㅎ
4- 네 번째 페이지: 슈팅 위치 데이터 그래프
네 번째 페이지는 내가 굳이굳이 슛 값을 xy로 저장한 이유가 있다. 바로 산점도 그래프를 그리기 위해서이다.
60*30의 그래프를 만들고 적절한 위치에 슛 정보를 넣어주면 어디서 슛을 쐈는지도 모두 체크할 수 있지 않을까, 라는 생각에서 출발했다.

적절한 값을 입력해서 라인들이나 골대를 그렸고, 반복문을 통해 슛의 피리어드를 체크, 그에 따라 다른 색의 그래프로 나오게 만들었다.
조금 더 완성도를 높이기 위해서는 링크 이미지 변경이 필요해 보인다.
5- 다섯 번째 페이지 : 팀내 선수별 슈팅 비율
마지막 페이지이다. 여기에는 팀의 슈팅 비율을 한눈에 파악할 수 있는 그래프를 넣었다.

요렇게 파이 그래프로 이름별 슛을 카운트하여 (아까 기록지와 같은 메커니즘) 파이 그래프를 그렸다.
힘들었다. 갑자기 꽂혀서 이게 뭐하는 짓인지 ㅋㅋㅋㅋ
그래도 완전 보람차고 뿌듯하고, 자바스크립트라는 녀석과 좀 친해진 것 같아 기쁘다.
이제 이거 들고 경희대학교 아이스하키부에 가볼 예정 ㅎ ㅎ
Shooting Record Program
gorang2.github.io
'Programming > Projects' 카테고리의 다른 글
[Hockey shot record] 1. 구성과 간단하게 구현 (0) | 2022.06.23 |
---|---|
네이버 지도를 이용한 카페 데이터 추출 프로그램 (0) | 2022.06.20 |
[Python] 화면 녹화 프로그램 2.-opencv, tkinter (0) | 2021.09.30 |
[Python] 화면 녹화 프로그램 1.-opencv, tkinter (0) | 2021.09.30 |
[Python] 계산기 만들기 - tkinter (0) | 2021.09.30 |
댓글