ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 한강 프로젝트 2. Canvas API 를 사용한 시간표 만들기
    개발기/한강 프로젝트 2021. 6. 21. 17:53

    목차

    한강 프로젝트 0. 첫 끗발이 개 끗발이다 (설계)

    한강 프로젝트 1. 자동 로그인!! (Auth 페이지 - 로그인, 회원가입, 아이디, 비밀번호 찾기)

    한강 프로젝트 2. Canvas API 를 사용한 시간표 만들기 (시간표 페이지)

    한강 프로젝트 3. (강의평 페이지)

    한강 프로젝트 4. (강의자료 페이지)

    한강 프로젝트 5. (강의자료 상세 페이지)

    한강 프로젝트 6. (강의평 상세 페이지)

    한강 프로젝트 7. (메인 페이지)

    한강 프로젝트 8. (배포)

    한강 프로젝트 9. (회고)

    한강 프로젝트 10. (분석) - Google Analytics를 이용한 웹 로그 분석

     


    잘못된 정보를 기술한 부분이 있다면 댓글이나 jong951005@gmail.com 으로 지적해주시면 감사하겠습니다!!

     

    안녕하세요 :) 이번 주는 어제 merge한 따끈따끈한 작업 내역을 적어보려 합니다. 시간표 페이지를 구현하며 고민했던 부분들입니다.

     

    시간표 페이지 입니다. 사용자는 왼쪽에 있는 검색 추가 란에서 강의를 추가할 수 있으며 오른쪽의 시간표에서 확인할 수 있습니다.

     


    어떻게 만들어야 하나...

    프로젝트를 시작할 때부터 주변 개발자 분들에게 "시간표가 많이 어려울 것이다." 라는 경고를 들어왔기 때문에, 막연한 두려움을 가지고 있었습니다. 그리고 마침내 시간표를 작업할 때가 왔을 때, 제가 생각한 방법은 세 가지가 있었습니다.

     

    1. 오픈 소스의 도움을 받자 !!

    2. div를 사용해서 어떻게 잘 만들어보자 !!

    3. Canvas API를 사용해보자 !!

     

    "거인의 어깨 위에 올라타라" 라는 말이 있죠. 잘 만들어진 오픈 소스를 발견한다면 약간만 변형하여 현 프로젝트에 사용할 수 있을 것이라 생각했습니다. 그러나 마음에 드는 오픈 소스를 찾지 못했고, 이를 분석해서 개량하는 것 보다 새로 만드는 것이 더 빠르겠다는 판단을 했습니다. 이후 div 와 canvas 사이에서 고민하였는데, 제 선택은 canvas였습니다.
    첫 번째로, Semantic Web의 취지에 보다 더 잘 맞는다고 생각하였습니다. 두 번째로, div를 사용한다면 여러 요소들을 치밀히 계산하여 CSS 작업을 해야 할 텐데, 이 보다는 JS로 그래픽 요소를 표현하는게 맞다고 생각했습니다. 마지막은 호기심입니다. Canvas API를 찾아보며 인터렉티브 웹 개발이라는 용어를 알게 되었습니다. 그래픽 디자인을 WebGL, canvas를 활용하여 표현한 것을 보고 굉장한 호기심이 생겨났고, 이번 기회에 canvas 한 번 공부해보자 !! 라는 생각을 했습니다. 

     


    어떤 걸 구현해야 하나...

    도구는 정해졌습니다. 이제는 어떤 작업들을 해야 할지 파악할 때입니다.
    시간표 개발에서 제가 해야 할 작업들은 크게 네 가지로 정리할 수 있었습니다.

     

    1. Default 시간표를 그려야 한다.

    2. Default 시간표에 강의들을 추가할 수 있어야 한다.

    3. 검색 추가 란에서 강의들을 hover 하였을 때 검은색 테두리로 해당 강의가 위치할 부분을 알려주어야 한다.

    4. 시간표에 추가된 강의들을 클릭하였을 때 클릭한 강의에 대한 상호 작용이 가능해야 한다.

     

    시간표 페이지에는 이외에도 여러 상호작용 가능한 요소들이 있지만, Canvas 안에서 구현해야 할 요소는 위의 네 가지라고 판단했습니다. 서론이 길었습니다. 그럼 이제 구현 과정을 설명하겠습니다!!

     


    Default 시간표 그리기

    텅 빈 시간표를 그려야 합니다.

    Default 시간표를 그리기 위해 총 3가지 절차로 나눴습니다.

     

    1. 수평선을 그리자.

    2. 수직선을 그리자.

    3. 요일과 시간을 넣어주자.

     

    moveTo, lineTo, stroke 등을 사용해 선을 그리고, fillText를 사용해 요일과 시간을 넣어줍니다.

     


     

    Default 시간표에 강의 추가하기

    시간표에 강의를 추가할 수 있어야 합니다.

    검색 추가란에 있는 강의를 클릭하였을 때, 해당 강의에 대한 시간 정보를 분석해서 시간표에 추가해야 합니다.

     

    백엔드로부터 넘어오는 강의 데이터는 다음과 같습니다.

    강의 정보가 담긴 json 입니다.

    중점적으로 봐야 할 키는 class_time입니다. 

     

    백엔드 팀의 창연님이 만들어주신 class_time 입니다.

     

    class_time은 강의 시간에 대한 내용을 담고 있습니다. 앞서 언급한 json 에 담긴 데이터는 월요일 오후 2~4시에 수강해야 하는 강의입니다. 문제는 일주일에 여러 번 수강해야 할 강의가 있다는 점입니다. 예를 들어 화 11~1시, 목 2~4시에 수강해야 하는 강의라면 class_time은 [104, 105, 106, 107, 410, 411, 412, 413] 으로 넘어옵니다. 

    시간표를 원활하게 그리기 위해, 이를 [[104, 105, 106, 107], [410, 411, 412, 413]] 으로 분해해야 할 필요가 있습니다. 아래의 함수는 class_time을 분해하는 함수입니다.

     

    앞서 설명을 드리지 못했지만, 사용자는 시간표 상단에 있는 바를 이용해 시간표를 추가하고 변경할 수 있습니다. displayTimetable은 현재 화면에서 보여지고 있는 시간표입니다. 사용자가 다른 시간표를 클릭한다면, 해당 시간표로 displayTimetable이 변경됩니다. 그리고 변경될 때마다 아래 useEffect 내의 코드들이 실행됩니다.

     

    앞서 언급한 distributeClassTime을 사용하여 강의들을 분해하고, 분해한 강의들을 캔버스에 그립니다.

    이후, 강의에 대한 제목, 교수명 등을 추가하고, 해당 강의의 x, y 좌표를 저장합니다. 4번을 설명할 때 언급하겠지만, storePositionOfCanvas는 클릭 이벤트를 위해 사용되는 함수입니다.

     

     


     

    강의들을 hover 하였을 때, 검은색 테두리로 해당 강의 시간 알려주기

    강의를 hover 할 때마다 해당 강의가 위치하게 될 곳을 검은색 테두리로 보여줍니다.

    이 작업의 쟁점인 부분은 hover 할 때마다 이미 캔버스에 그려진 검은색 테두리를 지워야 한다는 점입니다.

    문제는 테두리를 지우기 위해 Canvas의 clearRect API를 사용하였을 때, 뒤에 있는 default 시간표나 이미 그려진 강의까지 지워진다는 것이었습니다.

    해당 부분만 배경선을 다시 긋거나, 지워진 강의를 그리면 되지만 깔끔하지 못하다 생각하였고, 다른 방법은 없을까 고민하게 되었습니다.

     

    그렇게 해서 떠올리게 된 방법은 시간표 위에 하나의 캔버스를 더 올리자!! 였습니다.

    CandidateLectureCanvas가 언급한 canvas 입니다.

    즉, 시간표는 같은 너비, 높이를 가진 canvas가 두 개가 있는 형태입니다.

    그러나 hover 할 때 보여주는 CandidateLectureCanvas는 background 컬러가 없으며 강의를 hover 할 때마다 기존에 그렸던 요소들을 clear 하고 다시 그리게 됩니다.

     

    앞서 했었던 것처럼, distributeClassTime을 사용해 class_time을 분해해주고, 분해한 class_time에 대해 strokeRect를 사용해 검은색 테두리를 그립니다.

     


     

    강의를 클릭하였을 때 이벤트 발생시키기

    강의를 클릭하면 해당 강의 정보가 담긴 모달을 띄웁니다.

    제일 많이 고민한 부분입니다.

    canvas는 하나의 태그이기 때문에, 클릭할 경우 전체 canvas 에 대한 이벤트가 발생합니다. 제가 원했던 것은 이게 아니라 캔버스 내부 강의를 클릭할 경우 해당 강의에 대한 이벤트를 발생시키는 것이었습니다.

     

    제가 생각했던 아이디어는 캔버스가 그려질 때, 좌상단 지점과 width, height를 강의 정보와 함께 저장해두자!! 였습니다.

     

    앞서 잠깐 설명하였는데, 캔버스가 그려질 때 storePositionOfCanvas를 사용해 redux store에 해당 강의의 좌표와 정보들을 저장합니다.

     

     

    이후, click 이벤트가 발생할 때 실행시킬 함수를 바인딩 해야합니다.

     

    해당 함수는 캔버스에 클릭이 발생하였을 때, 클릭이 발생한 position과 그 position에 해당하는 강의를 찾아 modal 에게 넘겨줍니다.

    getOffsetPositionOnCanvas, findLectureOnPosition은 아래에서 설명하겠습니다.

     

    getOffsetPositionOnCanvas는 canvas 내부에서 클릭이 발생한 상대 위치를 반환합니다.

    그리고 findLectureOnPosition은 클릭이 발생한 x, y 좌표에 강의가 있는지 확인합니다. 당연한 말이지만, 없을 경우엔 모달을 띄우지 않습니다.

     


    마무리

    지금까지 시간표 구현 작업 내역을 적어봤습니다.

    개발 전 막연한 두려움이 있었는데, Canvas API를 공부하고 사용해보면서 매우 큰 재미를 느꼈습니다. 특히 한 영상을 보고 이런 웹을 만들수도 있구나 라는 큰 자극을 받았습니다. 새삼스럽지만 웹의 세계는 참 방대한 것 같습니다 !!

    댓글

Designed by Tistory.