SpotlightSeoul 프로젝트에서 공연장소를 네이버지도 API를 이용해서 보여주면 좋겠다는 생각으로 이번에 처음으로 지도 API를 적용해보았다.
https://www.ncloud.com/product/applicationService/maps
위 링크는 네이버 클라우드 플랫폼 Maps 서비스 페이지이다.
우선 이용 신청을 해야하기 때문에 링크를 들어가서 로그인을 한 후 이용 신청하기를 눌러준다.
그 뒤 Application 등록을 해야하는데 이름을 설정해주고 Service 선택 및 서비스 환경을 등록하는 페이지로 이동한다.
Application 이름을 설정해주고
나는 Web Dynamic Map을 선택하였다.
Web Dynamic Map은 월 10,000,000건 까지는 무료이기 때문에 규모가 큰 프로젝트가 아니라면 대부분 무료일 것이다.
그리고 우선은 로컬 환경에서 개발할 것이기 때문에 http://localhost를 서비스 URL로 추가해준다.
신청을 했으면 클라이언트 ID를 발급받았을 것이다.
클라이언트 ID는 인증 정보를 클릭한 뒤
여기서 확인할 수 있다.
옆에 있는 복사 버튼을 누른 뒤 클라이언트 ID를 복사해준다.
그 뒤 index.html
파일에 가서 이 코드를 추가해준다.
YOUR_CLIENT_ID에 복사한 클라이언트 ID를 붙여준다.
<script type="text/javascript"
src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=YOUR_CLIENT_ID"></script>
이 코드를 추가해줘야하는데 head
태그와 body
태그에 추가하는 것에는 차이가 있다.
head
태그 내에 추가하기
페이지의 HTML 구조가 완전히 로딩되기 전에 스크립트가 로딩된다.
스크립트가 페이지의 렌더링을 차단할 수 있으므로, async
나 defer
속성을 사용하여 이를 해결할 수 있다.
body
태그 내에 추가하기
일반적으로 </body>
태그 바로 앞에 스크립트를 추가하면, HTML 구조가 완전히 로딩된 후에 스크립트가 실행된다.
이 방법은 페이지 렌더링을 차단하지 않는다.
네이버지도 API 같은 경우, 지도를 표시할 HTML 요소가 먼저 로딩되어야 하므로 <body>
태그 끝 부분에 스크립트를 추가하는 것이 일반적이다.
하지만 필요에 따라서는 <head>
에 추가하고 async
나 defer
을 사용할 수도 있다.
이제 세팅은 거의 다 끝났는데 타입스크립트 설정을 해줘야한다.
네이버지도는 타입스크립트 사용법에 대해 공식문서에 기술해두었다.
https://navermaps.github.io/maps.js.ncp/docs/tutorial-3-Using-TypeScript.html
우선 네이버지도 API 타입 정의 파일을 설치해야한다.
npm i -D @types/navermaps
or
yarn add @types/navermaps --dev
그 후 네이버지도 API 공식문서 예제를 보며 적용해볼 수 있다.
우선 나는 필요한 기능이 지도에 마커를 표시하고 확대와 축소가 되는 기능이었다.
https://navermaps.github.io/maps.js.ncp/docs/tutorial-1-marker-simple.example.html
우선 마커를 적용시켜보자.
위 링크에 있는 예제에 있는 대로 사용이 가능하다.
var map = new naver.maps.Map('map', {
center: new naver.maps.LatLng(37.3595704, 127.105399),
zoom: 15
});
var marker = new naver.maps.Marker({
position: new naver.maps.LatLng(37.3595704, 127.105399),
map: map
});
naver.maps.Map
를 이용해 map 인스턴스를 만들어준 뒤 center는 naver.maps.Map.LatLng
를 이용해 좌표값(위도, 경도)을 설정해준다.
그리고 zoom은 확대의 정도인데 사용자의 편의에 맞춰 설정하면 된다.
값이 크면 더 확대가 많이 된다.
그리고 marker 인스턴스를 naver.maps.Marker
를 이용해 만들어준다.
position은 마커를 찍을 위치이기 때문에 위의 map 인스턴스에 적었던 좌표값을 똑같이 받아오면 된다.
그 후 map에는 위에서 선언해주었던 map 인스턴스를 가져와준다.
이렇게 되면 화면에 지도에 마커가 찍힌 채로 표시가 될 것이다.
여기서 나는 추가하고 싶었던 기능이 있었는데 이동/확대/축소를 했을 때 마커를 클릭하면 처음 지도화면으로 다시 돌아가는 기능이다.
// Marker 클릭 시 지도 초기화
naver.maps.Event.addListener(marker, 'click', () => {
map?.setCenter(new naver.maps.LatLng(latitude, longitude));
map?.setZoom(15);
});
마커를 클릭하면 좌표값을 중앙에 두고 zoom의 정도도 초기화된다.
이제 확대랑 축소를 할 수 있는 컨트롤 옵션을 추가해야 한다.
https://navermaps.github.io/maps.js.ncp/docs/tutorial-2-control-options.example.html
위 링크에서 정확한 정보를 확인 가능하다.
var mapOptions = {
zoomControl: true,
zoomControlOptions: {
style: naver.maps.ZoomControlStyle.SMALL,
position: naver.maps.Position.TOP_RIGHT
}
};
var map = new naver.maps.Map(document.getElementById('map'), mapOptions);
mapOptions 객체를 선언해줘야 한다.
zoomControl을 true로 해주고 zoomControlOptions로 style과 position을 설정해준다.
style
에는 SMALL과 LARGE 옵션이 있다.
naver.maps.ZoomControlStyle.SMALL
naver.maps.ZoomControlStyle.LARGE
그리고 position
에서 지도 화면의 어디에 둘 건지 설정해준다.
naver.maps.Position.의 뒤에 위치를 적어준다.
이렇게 원하는 기능을 모두 넣었다.
import { useState, useEffect } from 'react';
let mapInstance: naver.maps.Map | null = null;
const loadScript = (src: string, callback: () => void) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
script.onload = () => callback();
document.head.appendChild(script);
};
function MapInformation({
latitude,
longitude,
}: {
latitude: number;
longitude: number;
}) {
// 지도 로딩 상태
const [isMapLoaded, setMapLoaded] = useState(false);
const initMap = () => {
// 추가 옵션 설정
const mapOptions = {
zoomControl: true,
zoomControlOptions: {
style: naver.maps.ZoomControlStyle.SMALL,
position: naver.maps.Position.TOP_RIGHT,
},
center: new naver.maps.LatLng(latitude, longitude),
zoom: 16,
};
// 지도 초기화 확인
if (document.getElementById('map')) {
mapInstance = new naver.maps.Map('map', mapOptions);
}
// Marker 생성
const marker = new naver.maps.Marker({
position: new naver.maps.LatLng(latitude, longitude),
map: mapInstance,
});
// Marker 클릭 시 지도 초기화
naver.maps.Event.addListener(marker, 'click', () => {
mapInstance?.setCenter(new naver.maps.LatLng(latitude, longitude));
mapInstance?.setZoom(16);
});
// 지도 로드 완료
setMapLoaded(true);
};
useEffect(() => {
// 스크립트 로딩 확인
if (typeof naver === 'undefined') {
loadScript(
'https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=YOUR_CLIENT_ID',
initMap,
);
} else {
initMap();
}
}, [latitude, longitude]);
return (
<>
{/* 위치 정보(지도) */}
<div className="mb-8 mt-40 flex w-screen flex-col items-center">
<span className="sm:text-md font-Pretendard text-sm font-bold text-[#06439F] md:text-lg lg:text-xl xl:text-2xl 2xl:text-3xl">
위치 안내
</span>
{isMapLoaded && (
<div id="map" className="mt-4 h-[500px] w-11/12 sm:mt-6 lg:mt-8" />
)}
</div>
</>
);
}
export default MapInformation;
처음 지도 API를 사용해봤지만 참고할 만한 자료와 공식문서가 굉장히 잘 되어있어서 수월했다.
이렇게 지도를 추가해주면 직관성도 좋아지고 디자인적으로도 이뻐지는 것 같다.
다음엔 더 다양한 기능과 카카오지도, Google 지도도 활용해보도록 하자.
client id 노출되었어요! 다른 사람이 사용할 수 있으니 가리는 게 좋을 거 같아요 : )