캔버스와 네이버 지도 API를 연동하기 위한 과정
🎯 이 문서를 읽고 난 후의 상태
- 프로젝트와 문제에 대한 컨텍스트를 이해했다.
- 지도와 캔버스를 연동하기 위해 어떤 설계 과정을 거쳤는지 이해했다.
- 네이버 지도와 캔버스를 연동하는 과정 속에서 겪은 어려움과 해결을 위한 시도를 알았다.
- 최종적으로 어떻게 네이버 지도와 캔버스를 연동했는지를 이해했다.
🤔 배경
현재 네이버 부스트캠프 9기에 참여해서 배우고 있다.
어느덧 마지막인 그룹 프로젝트를 하게 되었는데, "위치 기반 서비스"를 주제로 선정해서 진행하게 되었다.
"위치 기반 서비스"라는 큰 카테고리 내에서, 세부 주제를 정해서 진행해야만 했었다.
사업성이나, 아이디어의 독창성보다는 진짜 "우리가 쓸 법한, 우리 주변에 있는 문제를 해결해보자." 라는 취지에서 시작한 주제이다.
주제는 "중장년층을 위한 접근성을 바탕으로 한 위치 기반 서비스"로, 핵심은 지도 위에 캔버스를 띄우고, 거기에 자녀가 경로를 표시해서 부모님에게 전달하는 것이다.
이해를 돕기 위해서 먼저, 우리 프로젝트에 대한 깃허브 링크를 남긴다.
🤔 어떻게 시작할 것인가?
내가 팀에서 맡게 된 일은 지도와 캔버스 사이의 연동이었다.
네이버 지도와 캔버스 모두 처음이었기에, 어떻게 연동을 시킬 지에 대한 고민이 많았다.
그래서 제일 먼저 한 일은 자료조사였다.
일단, 이 기술들이 무엇인지 알고, 어떻게 돌아가는 지에 대해서 알아야 설계를 할 수 있었기 때문이다.

찾은 자료의 일부분인데, 한번 정리하고 남은 자료들이다.
구글링 하면 나오는 온갖 사용 자료와, 네이버 지도 팀의 QnA, 타입 관련해서는 타입 깃허브 등 많은 자료를 찾았던 것 같다.
관련해서 혹시라도 도움이 될까 싶어 몇 가지 참고자료를 남긴다.
- 줌레벨과 관련해서는 네이버 지도는 1~21단게를 사용중이며, 1~6단계는 모두 같은 단계로 취급한다. 추상적으로는 16단계가 맞으나, 엄격히 말하면 21단계이다.
🧑💻 함께 찾은 방향성
해당 자료 조사를 바탕으로 동료들과 함께 회의를 진행했다.
어떤 관점에서 접근해야할 지, 어떤 기능이 필요한 지 등을 함께 논의하였다.
특히, 지도와 캔버스를 각기 다른 레이어로 두고 다루기로 했어서, 레이어 사이에 어떤 인터페이스를 바탕으로 다룰 것인지를 함께 논의하였다.
처음에는 다음과 같은 형태를 생각했었다.
interface 주고받을데이터 {
위도: number,
경도: number,
x: number,
y: number,
}
이를 바탕으로 생각하고 있었는데, 동료가 기가막힌 해결책을 주었다.
interface 주고받을데이터 {
위도: number,
경도: number,
}
위도와 경도만을 갖고 데이터를 만들자.
그리고 이를 바탕으로 캔버스에서는 좌표로 바꿔서 출력을 하자는 의미였다.
배경이 되는 지도가 캔버스 위에 그려질 그림들의 기준이 되고 있고, 둘 사이를 연동하려면 어떤 기준점이 필요한데, 그걸 위도와 경도로 하면 어떻겠냐는 의견에서 였다.
처음에는 이해가 잘 되지 않았기에 논의 과정에서 정말 많은 의문과 질문을 던졌다.
단순 말로 표현하자니, 서로 잘못 이해하는 부분도 많았고, 오해하는 부분도 있었다.
이에, 그림을 그려가면서 구조를 논하였고, 이에 생각이 동기화되어 명확하게 이해할 수 있었다.
- 회의 내용 1
- 회의 내용 2


이렇게 시각적으로 함께 맞추어가다보니, 단순 인터페이스를 넘어서 어떻게 구현을 해야겠다가 보이기 시작했다.
그렇게 뽑아낸 내용은 다음과 같다.
- 지도와 캔버스는 각기 다른 레이어로 두고, 레이어 사이에는 위도와 경도를 주고 받는 인터페이스를 만들자.
- 캔버스에서는 지도의 위도와 경도를 받아서, 캔버스의 좌표로 바꾸어서 출력하자.
- 데이터는 (위도, 경도) 만을 다루자.
- 드래그 이벤트 시에는 각자 동일한 변화값 만큼 움직이면 될 것이다.
- 확대 축소시에는 동일한 비율로 확대 축소가 되면 될 것이다.
이렇게 함께 논의하고, 방향성을 잡았다.
🖼️ 작업 프로세스 추출
방향성이 잡히고, 본격적으로 작업에 착수하게 되었다.
그리고, 제일 먼저 한 일은, 내가 이걸 구현하기 위해서 어떤 과정을 거쳐야하는 지를 파악하는 것이었다.

아직 어떤 기능이 필요한지, 특정한 문제를 해결하기 위해서는 얼마만큼의 시간이 필요한지 견적이 잡히지 않는 상황이었다.
그래서, 기존 개발 경험을 바탕으로 빠르게 예상되는 작업을 나열하고, 순서를 정리하였다. 그리고 그 과정 속에서 필요하다고 생각되는 것들을 적어두었다.
🚀 내가 등록해둔 이슈 살펴보기
📌 요청 기능 설명
캔버스와 지도를 연동시켜서 같이 동작시킨다.
📝 기능 세부 사항
- 지도와 캔버스 연동 과정 설계
- 지도 위에 캔버스 레이어 출력
- 캔버스 컴포넌트 구현
- 지도 위에 함께 배치하는 레이아웃 구현 (하나의 Container 위에 여러 레이아웃 겹쳐서 구현)
- 지도의 끝 점과 캔버스 끝 점을 연계해서, 캔버스 좌표와 매핑
- 지도의 꼭짓점 좌표를 알아내는 함수가 필요
- 캔버스의 끝점의 크기를 알아내는 함수가 필요 (캔버스는 CSS와, 캔버스 내부 좌표가 일치해야함.)
- 위도/경도 좌표 -> X, Y로 바꾸는 함수 구현
- 드래그 이벤트 핸들러 구현
- 드래그 시 캔버스가 이동되게 구현
- 드래그 시 지도가 이동되게 구현
- 드래그 시 캔버스의 좌표와 지도가 정확히 매핑되게 구현
- 줌인 줌아웃 이벤트 핸들러 구현
- 줌인/줌아웃 시 캔버스가 확대/축소 되게 구현
- 줌인/줌아웃 시 지도가 확대/축소 되게 구현
- 줌인/줌아웃 시 좌표와 지도가 정확히 매핑되게 구현
🤔 기능 추가 배경 및 목적
MVP기능으로, 캔버스 위에 그리는 그림이 지도에 그대로 매핑될 수 있도록 기능을 제공해야 한다.
🚩 완료 조건 (Acceptance Criteria)
- 설계에 대한 기술적인 근거가 명확해야 한다.
- 지도 위에 캔버스 레이어가 겹쳐서 보여진다.
- 화면을 드래그 하였을 때 지도와 캔버스가 같이 움직인다.
- 캔버스 위의 마커나 선이 지도의 위도, 경도 상에 정확하게 배치된다.
- 화면을 줌인/줌아웃 하였을 때 지도와 캔버스가 같이 확대 축소가 된다.
- 캔버스 위의 마커와 선의 확대 축소 비율이 지도와 동일하게 유지된다.
- 각 과정에 대한 테스트코드가 작성되어 있다.
💡 참고 자료 (선택)
📝 설계에 대한 계획 수립

"길을 먼저 보고 개발에 착수하자." 라는 개발 철학이자 습관이 있다.
완벽하기 보다는 진짜 순수하게 길을 보는 용도로써의 설계. 그렇기에 설계는 최대한 간단하게, 그리고 빠르게 진행할 필요가 있었다.
이 역시도 대략적인 그림을 그리지 않고 설계에 들어갈 경우 시간이 많이 걸릴 위험이 있었다.
그래서 빠르게 무엇에 대해서 고려를 할 지 나열하고, 이에 대해서 순서를 정하였다.
🚀 내가 등록해둔 이슈 살펴보기
📌 작업 제목
지도와 캔버스 연동 과정 설계
🎯 목표
지도와 캔버스 연동 과정을 설계하고, 문서로 상세하게 작성한다.
📝 작업 세부 사항
- 지도와 캔버스 간의 좌표 변환 과정 설계
- 어떻게 (위도, 경도) <-&rt; (x, y)로 변환할 건지 함수 설계
- 컴포넌트 구조 설계
- z-index 기반으로 해서 어떻게 겹쳐서 보여줄 지 설계
- 레이어에 대해서 그림으로 그려서 표현하기
- 컴포넌트 계층도에 대해서 도식도로 그려서 표현하기
- 로딩부터 동작까지 흐름 설계
- 초기 로딩 시에, 어떤 조건이 필요한지, 순서는 어떻게 되어야 하는 지 설계
- 예) 네이버 지도 로딩과, 서버에서 초기값 로딩이 필요하다. 네이버의 중심점 좌표를 잡기 위해서는 서버에서 받아와야 하기에 서버와의 통신이 먼저 이루어지고, 네이버 지도 로딩이 이루어져야 한다. 즉, 로딩은 먼저 하되 화면 출력은 이후에 한다. 와 같이 구체적으로 시나리오가 나와야 함.
- 이전 화면에서 데이터를 받는 지 여부, 받는다면 서버와의 통신에서도 어떻게 공통으로 뽑아낼 수 있을지에 대한 설계
- 이벤트 발생 시 지도와 캔버스 위치를 어떻게 동기화시킬 지에 대해 설계
- 각 과정에 따라 대충 그림이 그려지면, 프로토타입 구현을 통해 실현 가능 여부 판단
🚩 완료 조건 (Acceptance Criteria)
- 지도와 캔버스 간의 좌표 변환 과정이 식으로 뚜렷하게 표현이 된다.
- 컴포넌트 구조가 도식도로 한 눈에 보이게 설계가 되었다. 그리고, 도식도만 보고도 어떻게 구현이 될 지 이해가 된다.
- 로딩부터 동작까지의 일련의 과정이 한 눈에 들어온다.
- 이벤트 발생 시 위치의 동기화를 어떻게 이룰 것인지 이해할 수 있다.
- 프로토타입을 통해서 각 과정이 실현 가능함을 보장할 수 있다.
📅 예상 소요 시간 및 일정
2일 소요 예정입니다. (2MD -> 16시간 예정)
📝 본격적인 설계의 시작 :: 내용 분석하기
설계에 들어가면서, 제일 먼저 한 일은 프로젝트 자체에서의 지도와 캔버스의 좀 더 자세한 구조를 파악하는 것이었다.
이를 파악하기 위해서, 동료들과 많은 이야기를 나누었다. 내가 생각하는 게 맞는지, 동료가 생각하는 바는 무엇인지 등 잦은 상호 동기화 시간을 가졌다.
그렇게 프로젝트에 대해서 서로가 생각하는 것을 일치 시키고, 이 내용을 바탕으로 다음과 같은 그림을 그렸다.

이렇게 작성하면서 관련된 요소의 파악도 진행하였다.
- 지도 테스트 이미지
- 캔버스 테스트 이미지


위와 같은 과정을 거쳐서 지도와 캔버스의 구조를 파악하였다.
캔버스의 경우는 노마드 코더님의 캔버스 강의를 필요한 부분만 빠르게 들으면서 파악하고자 했고, 네이버 지도는 예제를 참고하였다.
이를 통해서 각각이 동작하기 위해서는 어떤 데이터가 필요하고, 무엇이 요구되는지를 빠르게 파악할 수 있었다.
이 뿐만 아니라 직접 네이버 API를 뜯어보면서 어떻게 동작하는지 파악도 했는데 이렇게 파악한 내용은 아래와 같다.
⚙️ 캔버스 관련 요소 분석
- 캔버스는 왼쪽 위가 (0, 0) 이며, 오른쪽으로 가면 x가 증가하고, 아래로 가면 y가 증가한다.
- 경도(Longitude)는 캔버스상의 X좌표에 대응된다.
- 위도(Latitude)는 캔버스상의 Y좌표에 대응된다.
- 캔버스의 크기는 고정이 되어 있으며, 그 내부에 그려지는 요소만 변화한다.
- 캔버스와 관련된 이벤트는 캔버스 내부에서만 발생한다.
- 캔버스는 기본 HTML 관련 이벤트가 매핑되어 있으나, 그래픽에 대한 동작은 JS로 구현되어야 한다.
⚙️ 지도 관련 요소 분석
- 지도는 네이버 지도 API를 사용한다.
- 지도는 위도와 경도를 기반으로 한다.
- 각 요소는 타일 형태로 구현이 되어 있다. (타일은 지도의 한 부분을 의미한다.)
- 지도는 캔버스와는 다르게, 지도 자체적으로 이벤트를 가지고 있으며, 이벤트가 발생하면 지도 자체적으로 이벤트 핸들러가 동작한다.
- 지도는
Wrapper
가 되는HTML 태그
요소보다 약간 큰 사이즈가 랜더링된다. (지도의 크기는 지도의 크기를 의미하며, Wrapper는 지도를 감싸는 HTML 태그를 의미한다.) - 드래그나 줌인 줌아웃 이벤트로 사전에 랜더링 된 범위를 넘어서면 다시 랜더링이 된다.
- 지도 타일 이미지2
- 지도 타일 이미지2


위와 같이, 지도는 타일 형태로 구성되어 있으며 각 타일은 img
태그로 작성이 되어 있었다.
이벤트나 여타 동작을 처리함에 있어서 기존에 지도가 갖고 있는 이벤트를 덮어 씌우는 방식도 생각해보았으나, 각 이미지 태그를 하나하나 조작하거나, 관련해 서 처리하는 로직까지 고려하는 것은 너무 과한 행위라는 생각이 들었다. 또한, 프로젝트의 목표와도 맞지 않는 문제가 있었다.
이에 따라서, 지도와 캔버스를 각기 다른 레이어로 두고, 레이어 사이에는 위도와 경도를 주고 받는 인터페이스를 만들자는 초기 기획 방향으로, 설계를 굳히고, 진행하였다.
📝 지도와 캔버스의 연동 구조 설계
팀의 궁극적인 목표는 모듈화였다.
확장까지 고려했을 때 우리팀이 궁극적으로 지향하는 바는 지도에 연동되는 캔버스를 다른 곳에서도 사용할 수 있도록 하는 것이었다.
지도와는 별개로 지도와 연동되는 로직과, 캔버스를 오픈소스로 만들어서 배포하는 게 목표였다고 볼 수 있다.
이를 위해서는 지도와 나머지 구조간의 의존성을 최대한 끊을 필요가 있었다.

고민 끝에 설계한 구조는 위와 같다.
캔버스와 지도가 연동된 요소를 하나의 컴포넌트로 수립한다.
사용자(다른 개발자)는 캔버스와 지도가 어떻게 연동되었는지 알 필요가 없다.
캔버스에 그림을 그리고, 움직이거나 줌인 줌아웃이 지도와 연동된, 이 기능만 사 용할 수 있으면 된다.
그래서, 캔버스와 지도를 하나로 묶어서 <CanvasWithMap>
이라는 컴포넌트로 퍼사드 패턴
으로 묶었고, 필요한 동작은 외부에서 props
나 이벤트 등으로 제공한다.
또한, 지도의 경우도 어디까지나 배경의 역할만을 수행한다. 어떤 지도로 갈아끼워지든 간에, <CanvasWithMap>
은 몰라도 되며, 지도에 대해서 동일한 인터페이스로 기능하면 된다.
이에 따라서, 지도와 그 나머지 세부 요소를 전략 패턴
으로 갈아끼울 수 있게 설계 하였다.
이를 통해, 지도와 캔버스의 연동 과정에서 각각의 책임을 더욱 명확하게 할 수 있었다.
📝 캔버스와 지도의 좌표 변환 과정 설계
지도와 캔버스에 대해서 이미 본격적인 설계의 시작 :: 내용 분석하기에서 1차적으로 분석한 바가 있다.
좌표 변환은 추가적인 분석을 요구했다.
우선 당장의 완성을 위해서 네이버 지도를 기준으로 삼았기에, 네이버 지도의 좌표 변환을 먼저 생각해보았다.
이와 관련해서 네이버지도 API를 정말 깊게 찾아보았고, 그 내용은 다음과 같다.
🚀 네이버 지도 API를 통한 좌표 변환 과정 탐구
- 네이버 지도 API에서는 다음과 같은 기능을 제공한다.
- MapSystemProjection은 현재 설정된 지도 유형의 Projection을 가공해 지도 내부에서 사용하는 투영 객체이다. 이 객체를 이용하면 지도 좌표와 세계 좌표, 화면 픽셀 좌표를 서로 변환할 수 있다.
- 단, 이는 추후 확장 방안에서 카카오 지도, 구글 지도 등과 연동하기로 했으므로 고려하지 않는다.
LatLngBounds
클래스는 남서쪽과 북동쪽의 위/경도 좌표가 설정돼 있는 직사각형의 지리적 영역(이하 좌표 경계)을 정의한다.- 이는 왼쪽 아래 꼭짓점과 오른쪽 위 꼭짓점의 위/경도 좌표를 주는 메서드이다.
- 이런 기능은 대부분의 지도 API가 제공하고 있으며, 앞서 보여준 매핑도에도 부합한다.
- 지도 좌표 경계 확인하기
- 관련 예제는 위와 같다.
다음과 같은 이유로 2번으로 진행하기로 했다.
- 추후 확장 방안으로 여러 지도 API에 대한 대응을 고려하고 있다.
- 지도 API의 기본 기능을 최소한으로 사용하고자 한다.
- 2번의 방법으로 보다 더 많은 기술적인 성장을 이루고자 한다.
그러면 이제 다음과 같은 고민이 생겼다.
- 지도와 캔버스 각각의 꼭지점에 대해서 어떤 인터페이스로 매핑할 것인가?
- 꼭짓점을 기준으로 마커의 위치를 계산할 텐데, 그러면 위도 경도의 소숫점은 어떤 의미를 갖고 있는가?
- 네이버 지도에서 확대 축소시에 위도 경도의 소숫점 자리수는 어느 정도까지 의미있게 다루는가?
사전에 회의한 내용에 의거, 지도와 캔버스는 [위도, 경도]의 데이터만 다룬다.
이유는 다음과 같다.
- 사용자의 인터렉션이 잦은 지도 조작의 특성 상 캔버스상의 (x, y)를 (경도, 위도)에 매핑하고 (경도, 위도, x, y) 이렇게 데이터를 갖고 있으면 매번 (x, y) 값을 갱신해서 저장해야하는 문제가 생긴다.
- 반응형 UI/UX도 고려해야 한다. 이런 이유로 (x, y)에 대한 변경이 너무 잦고 경우의 수가 많은 것을 고려할 수 밖에 없다.
- 지도에서 연산을 하든, 캔버스 위에서 연산을 하든 캔버스에 출력할 (x, y) 값에 대한 연산은 필요하다.
- 지도 API에서 꼭짓점의 (위도, 경도)를 제공해준다면 캔버스 위의 특정 마커나 점에 대한 (위도, 경도)를 갖고 있으면 꼭짓점의 (위도, 경도)로 부터 우리가 가진 마커의 (위도, 경도) 정보를 계산해서 화면에 보여줄 수 있다. 이벤트 발생 시마다 계산을 해야한다는 문제가 있지만, 앞선 이유로 어떻게 하든 연산은 필요하다. 그리고, 이에 대한 부분은 드래그 이벤트의 최적화 기법 중 하나인 RequestAnimationFrame 등을 이용해서 특정 주기때에만 계산하게 하는 방법 등으로 최적화할 수 있다.
🤔 꼭짓점을 기준으로 마커의 위치를 계산할 텐데, 그러면 위도 경도의 소숫점은 어떤 의미를 갖고 있는가?
네이버 지도에서 사용하는 위도와 경도는 일반적으로 소수점 6~7자리까지 다룬다.
이에 대한 세부적인 내용은 다음과 같다.
위도/경도의 소수점 자릿수와 정밀도
- 소수점 5자리: 약 1미터의 정밀도를 제공한다.
- 소수점 6자리: 약 10센티미터의 정밀도를 제공한다.
- 소수점 7자리: 약 1센티미터의 정밀도를 제공한다.
위의 가이드 뿐 아니라 다양한 가이드에서 소수점 7째 자리까지 다루고 있다. 이에 따라서, 최소 6자리, 최대 7자리 수준의 정밀도를 다룬다고 생각하면 좋을 것 같다.
조금 더 찾아보니, 네이버지도 뿐 아니라, 구글 지도와 카카오 지도에서 사용하는 위도와 경도는 기본적으로 동일한 체계를 따른다고 한다.
위도와 경도는 전 세계적으로 공통된 지리적 좌표계를 기반으로 하며, 주로 **WGS84(World Geodetic System 1984)**라는 표준 좌표계를 사용한다. 이 좌표계는 GPS와 대부분의 온라인 지도 서비스에서 사용되기 때문에, 지도 서비스 간 위도와 경도의 의미는 동일하다고 한다.
즉, 위의 지표를 기준 삼아서 소수점 7번째 자리까지만 고려해서 다루면 된다는 것을 확인할 수 있었다.
🤔 네이버 지도에서 확대 축소시에 위도 경도의 소숫점 자리수는 어느 정도까지 의미있게 다루는가?
네이버 지도의 줌 단계는 다양한 확대/축소 레벨을 지원하며, 각 레벨은 특정 위도와 경도 범위에 대응된다. 일반적으로 줌 레벨이 낮을수록 지도가 더 축소되며, 줌 레벨이 높을수록 지도가 확대된다.