카카오톡 지도 API를 사용하기

이보아·2024년 7월 10일
0

📌 카카오톡 지도 API 사용하기 전에

오늘은 카카오톡 지도 API를 사용하여 웹 애플리케이션에 지도를 불러오는 방법에 대해 배웠다. React와 Next.js를 사용하여 카카오맵을 동적으로 로드하고, 특정 주소를 지도에 표시하는 방법을 구현하였다.

📖 학습 내용

1. 카카오맵 API 키 발급

카카오 디벨로퍼스에서 애플리케이션을 등록하고, JavaScript 키를 발급받았다.

2. 카카오맵 스크립트 동적 로드

loadKakaoMapScript 함수를 작성하여 카카오맵 스크립트를 동적으로 로드한다.

const loadKakaoMapScript = (kakaoMapKey: string): Promise<void> => {
    return new Promise((resolve, reject) => {
      
        const scriptUrl = `https://dapi.kakao.com/v2/maps/sdk.js?appkey=${kakaoMapKey}&autoload=false&libraries=services`;
        const script = document.createElement('script');
        script.src = scriptUrl;
        script.async = true;
        script.defer = true;

        script.onload = () => {
            if (window.kakao && window.kakao.maps) {
                window.kakao.maps.load(() => {
                    resolve();
                });
            } else {
                reject(new Error('카카오 맵 객체를 찾을 수 없습니다.'));
            }
        };

        script.onerror = () => {
            reject(new Error('카카오 맵 스크립트를 로드하는 데 실패했습니다.'));
        };

        document.head.appendChild(script);
    });
};

3. 주소를 좌표로 변환하고 지도에 마커 표시

주소를 좌표로 변환하는 searchAddressToCoords 함수를 작성하고, 변환된 좌표를 지도에 마커로 표시하였다.

const searchAddressToCoords = (address: string) => {
    if (!window.kakao || !window.kakao.maps) return;

    const geocoder = new window.kakao.maps.services.Geocoder();
    geocoder.addressSearch(address, (result, status) => {
        if (status === window.kakao.maps.services.Status.OK) {
            const { y, x } = result[0];
            setCoords({ lat: parseFloat(y), lng: parseFloat(x) });
        } else {
            setError('주소를 찾을 수 없습니다.');
        }
    });
};

4. 스켈레톤 로딩 화면 구현

지도가 로드되는 시간이 조금 걸려서 스켈레톤 로딩 화면을 표시하여 사용자 경험을 개선하였다.

const SkeletonLoader = () => (
    <div className="w-full h-full bg-gray-100 animate-pulse">
        <div className="w-full h-full bg-gray-300"></div>
    </div>
);

5. 카카오맵 컴포넌트 구현

KakaoMap 컴포넌트를 구현하여 지도 중심 좌표와 마커를 표시하였다.

const KakaoMap = ({ name, address }) => {
    const [isLoaded, setIsLoaded] = useState(false);
    const [coords, setCoords] = useState(null);

    useEffect(() => {
        loadKakaoMapScript(process.env.NEXT_PUBLIC_KAKAO_MAP_KEY)
            .then(() => {
                setIsLoaded(true);
                searchAddressToCoords(address);
            })
            .catch(() => {
                setError('지도를 로드하는 데 실패했습니다.');
            });
    }, [address]);

    if (!isLoaded || !coords) {
        return (
            <div className="w-full h-96">
                <SkeletonLoader />
            </div>
        );
    }

    return (
        <div className="w-full h-96">
            <Map center={coords} style={{ width: '100%', height: '100%' }} level={4}>
                <CustomOverlayMap position={coords} yAnchor={1} xAnchor={0.5}>
                    <div className="p-0 border-none text-center">
                        <Image src="/image/icons/marker.png" alt={name} width={140} height={140} />
                        <p className="m-0 text-18px font-bold bg-base p-1 font-secondary">{name}</p>
                    </div>
                </CustomOverlayMap>
            </Map>
        </div>
    );
};

❗트러블 슈팅

API x,y 값이 당연히 위도, 경도값인지 알았는데 알고보니 ..UTM-K (중부 원점계) 값으로 되어있었다. 그래서 위도, 경도로 전환이 필요하였고 방법을 찾아보니 아래 방법이 나와서 실행해봤다.

먼저 proj4를 설치해서 테스트 해봤다.

npm install proj4
import proj4 from 'proj4';

// UTM-K (중부 원점계) 좌표계 정의
const utmK = '+proj=tmerc +lat_0=38 +lon_0=127.5 +k=1 +x_0=200000 +y_0=500000 +ellps=GRS80 +units=m +no_defs';
// WGS84 (위도/경도) 좌표계 정의
const wgs84 = proj4.WGS84;

// 중부 원점계 좌표 (예시 좌표)
const utmKCoords = [200000, 500000]; // [x, y]

// 좌표 변환
const latLonCoords = proj4(utmK, wgs84, utmKCoords);

console.log('위도:', latLonCoords[1], '경도:', latLonCoords[0]);

🔧 수정한 코드

type KakaoMapProps = {
    name: string;
    address: string; 
};

주소를 받아오고, 타입을 지정한다.

const searchAddressToCoords = (address: string) => {
    const windowWithKakao = window as WindowWithKakao;
    if (!windowWithKakao.kakao || !windowWithKakao.kakao.maps) return;

    const geocoder = new windowWithKakao.kakao.maps.services.Geocoder();
    geocoder.addressSearch(address, (result: GeocoderResult[], status: string) => {
        if (status === windowWithKakao.kakao.maps.services.Status.OK) {
            const { y, x } = result[0];
            setCoords({ lat: parseFloat(y), lng: parseFloat(x) });
        } else {
            setError("주소를 찾을 수 없습니다.");
        }
    });
};

주소를 좌표로 변환하는 함수 추가한다.

useEffect(() => {
    if (!kakaoMapKey) {
        setError("카카오 맵 API 키가 유효하지 않습니다.");
        return;
    }
    loadKakaoMapScript(kakaoMapKey)
        .then(() => {
            setIsLoaded(true);
            searchAddressToCoords(address); // 주소를 좌표로 변환
        })
        .catch(() => {
            setError("지도를 로드하는 데 실패했습니다.");
        });
}, [kakaoMapKey, address]);

주소를 좌표로 변환하여 사용한다.

<Map
    center={coords} // 지도 중심 좌표 설정
    style={{ width: "100%", height: "100%" }}
    level={4} // 지도 확대 레벨
>

변환된 좌표를 사용
내 코드에 적용해서 확인해보니 변환된 좌표도 가게 주소와 일치하지 않았다. 그래서 가게 주소를 불러와서 위도 경도로 변경해주는 함수(카카오톡 지원)를 사용 하여 수정하였다. 앞으로 주소를 불러올 때는 API의 위도, 경도가 해당 주소와 맞는지 미리 확인해야 할 것 같다. 😂 그래도 UTM-K (중부 원점계)를 WGS84로 전환하는 방법을 알게 되어 공부가 되었다.

💡카카오톡 지도 API를 사용하기를 마치며

  • 카카오맵 API를 사용하여 동적으로 지도를 로드하고, 주소를 좌표로 변환하여 지도에 표시하는 방법을 익혔다.
  • 스켈레톤 로딩 화면을 구현하여 사용자 경험을 개선할 수 있었다.
  • 환경 변수로 API 키를 관리하여 보안성을 높이는 방법을 알게 되었다.
profile
매일매일 틀깨기

0개의 댓글