카카오 지도 API로 지도 가운데 마커 표시하기

김선은·2024년 6월 5일
0

https://apis.map.kakao.com/web/sample/addr2coord/
https://apis.map.kakao.com/web/documentation/

getCenter 메서드와 같은 설명은 2번째 링크 documentation를 참고할 수 있습니다.
카카오 개발자 페이지에서 appkey를 발급받아서 사용해야합니다.

원하는 동작은 다음과 같습니다.

  • 지도가 처음 뜨는 위치를 서울시청으로 할 것
  • 가운데 마커가 고정으로 있을 것
  • 클릭이 아니라, 지도를 움직이는 방식으로 이용하기
  • 지도가 움직이면 바뀐 위치의 가운데 마커에 해당되는 주소 얻기

환경은 Next14의 App 라우터입니다.

카카오 지도의 스크립트를 사용할 컴포넌트는 윈도우를 사용해야해서 클라이언트 컴포넌트로 작성해야 합니다.

주요 기능별 설명

스크립트 비동기 로드

import Script from 'next/script'

next/script를 사용하여 카카오 지도 API 스크립트를 비동기적으로 로드합니다. 이는 페이지 로딩 속도를 향상시킵니다.

상태 변수 정의:

const [address, setAddress] = useState('')

address 상태 변수를 정의하여 지도 중심의 주소를 저장합니다.

카카오 지도 로드 함수:

const loadKaKaoMap = () => {
  // 카카오 지도 API가 로드된 후 실행될 콜백 함수
  window.kakao.maps.load(() => {
    // 지도를 표시할 HTML 요소를 가져옵니다.
    const mapContainer = document.getElementById('map');
    
    // 지도의 초기 설정 옵션을 지정합니다.
    const mapOption = {
      // 지도의 중심 좌표를 설정합니다. (서울시청 기준)
      center: new window.kakao.maps.LatLng(37.5667, 126.9782),
      // 지도의 확대 레벨을 설정합니다.
      level: 1,
    };

    // 지도를 생성합니다.
    const map = new window.kakao.maps.Map(mapContainer, mapOption);
    
    // 마커를 생성하고 지도의 중심에 위치시킵니다.
    const marker = new window.kakao.maps.Marker({
      position: map.getCenter(),
      map: map,
    });

    // 주소를 변환할 Geocoder 객체를 생성합니다.
    const geocoder = new window.kakao.maps.services.Geocoder();

    // 좌표를 주소로 변환하는 함수입니다.
    const updateAddress = (coords) => {
      geocoder.coord2Address(
        coords.getLng(),
        coords.getLat(),
        (result, status) => {
          if (status === window.kakao.maps.services.Status.OK) {
            // 변환된 주소를 가져옵니다.
            const detailAddr = result[0].road_address
              ? result[0].road_address.address_name
              : result[0].address.address_name;
            // 변환된 주소를 상태 변수에 저장합니다.
            setAddress(detailAddr);
          }
        }
      );
    };

    // 초기 지도 중심의 주소를 변환합니다.
    updateAddress(map.getCenter());

    // 지도의 중심이 변경될 때마다 실행될 이벤트 리스너를 추가합니다.
    window.kakao.maps.event.addListener(map, 'idle', function () {
      // 지도의 새로운 중심 좌표를 가져옵니다.
      const center = map.getCenter();
      // 마커를 새로운 중심 좌표로 이동시킵니다.
      marker.setPosition(center);
      // 새로운 중심 좌표의 주소를 변환하여 업데이트합니다.
      updateAddress(center);
    });
  });
};

지도 초기화: 지도와 마커를 초기화하고 지도 중심을 설정합니다.
주소 변환 함수: geocoder.coord2Address를 사용하여 좌표를 주소로 변환합니다.
중심 좌표 변경 이벤트 리스너: idle 이벤트를 사용하여 지도의 중심이 변경될 때마다 마커 위치를 지도 중심으로 업데이트하고, 주소를 변환하여 상태 변수 address에 저장합니다.

useEffect로 주소 로그 출력:

useEffect(() => {
  console.log(address)
}, [address])

address 상태가 변경될 때마다 콘솔에 현재 주소를 출력합니다.
동작을 확인할 수 있습니다.

컴포넌트 렌더링:

return (
  <>
    <Script
      strategy="afterInteractive"
      src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_CLIENT}&libraries=services,clusterer,drawing&autoload=false`}
      onReady={loadKaKaoMap}
    />
    <div id="map" style={{ width: '100%', height: '650px' }}></div>
    <div>현재 주소: {address}</div>
  </>
)

Next Script

Next Script 컴포넌트를 사용하여 카카오 지도 API 스크립트를 로드하고, 로드가 완료되면 loadKaKaoMap 함수를 실행합니다. 이때 스크립트 src 파라미터에 autoload=false를 꼭 추가해야 합니다. useEffect로 동작 순서를 관리하지 않아도됩니다.

스크립트 src 파라미터

appkey: 카카오 개발자 사이트에서 발급받은 앱 키를 지정합니다.
autoload=false: 스크립트 로드 후 자동으로 API를 초기화하지 않도록 설정합니다. 이렇게 하면 스크립트를 로드한 후 직접 초기화할 수 있습니다.
libraries=services,clusterer,drawing: 추가 라이브러리(서비스, 클러스터러, 드로잉)를 로드하여 지도 API의 기능을 확장합니다.
이 설명을 참고하여 코드를 이해하고, 필요에 맞게 사용할 수 있습니다.

최종 코드

'use client'

import Script from 'next/script'
import { useEffect, useState } from 'react'

declare global {
  interface Window {
    kakao: any
  }
}

const SearchMap = () => {
  const [address, setAddress] = useState('')

  const loadKaKaoMap = () => {
    window.kakao.maps.load(() => {
      const mapContainer = document.getElementById('map')
      const mapOption = {
        center: new window.kakao.maps.LatLng(37.5667, 126.9782),
        level: 1,
      }

      const map = new window.kakao.maps.Map(mapContainer, mapOption)
      const marker = new window.kakao.maps.Marker({
        position: map.getCenter(),
        map: map,
      })

      const geocoder = new window.kakao.maps.services.Geocoder()

      const updateAddress = (coords: any) => {
        geocoder.coord2Address(
          coords.getLng(),
          coords.getLat(),
          (result: any, status: any) => {
            if (status === window.kakao.maps.services.Status.OK) {
              const detailAddr = result[0].road_address
                ? result[0].road_address.address_name
                : result[0].address.address_name
              setAddress(detailAddr)
            }
          }
        )
      }

      updateAddress(map.getCenter())

      window.kakao.maps.event.addListener(map, 'idle', function () {
        const center = map.getCenter()
        marker.setPosition(center)
        updateAddress(center)
      })
    })
  }

  useEffect(() => {
    console.log(address)
  }, [address])

  return (
    <>
      <Script
        strategy="afterInteractive"
        src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_CLIENT}&libraries=services,clusterer,drawing&autoload=false`}
        onReady={loadKaKaoMap}
      />
      <div id="map" style={{ width: '100%', height: '650px' }}></div>
    </>
  )
}

export default SearchMap
profile
기록은 기억이 된다

0개의 댓글