오늘은 카카오톡 지도 API를 사용하여 웹 애플리케이션에 지도를 불러오는 방법에 대해 배웠다. React와 Next.js를 사용하여 카카오맵을 동적으로 로드하고, 특정 주소를 지도에 표시하는 방법을 구현하였다.
카카오 디벨로퍼스에서 애플리케이션을 등록하고, JavaScript 키를 발급받았다.
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);
});
};
주소를 좌표로 변환하는
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('주소를 찾을 수 없습니다.');
}
});
};
지도가 로드되는 시간이 조금 걸려서 스켈레톤 로딩 화면을 표시하여 사용자 경험을 개선하였다.
const SkeletonLoader = () => (
<div className="w-full h-full bg-gray-100 animate-pulse">
<div className="w-full h-full bg-gray-300"></div>
</div>
);
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로 전환하는 방법을 알게 되어 공부가 되었다.