구글맵 지도 기능 구현 순서
1. Google Geocoding API 키 설정:
- console.cloud.google.com에 접속하여 API 및 서비스로 이동합니다.
- API 및 서비스 사용 설정을 선택한 후 geocode를 검색하여 활성화하고 API 키를 생성합니다.
- 생성한 API 키를 .env 파일에 추가합니다. 예: NEXT_PUBLIC_GOOGLE_GEOCODING_API_KEY=YOUR_API_KEY
2.새 컴포넌트 생성:
- components 폴더에 PropertyMap.jsx 파일을 생성합니다.
- PropertyMap 함수 컴포넌트를 만들고 property를 매개변수로 받습니다.
- 기본적으로 div 태그에 "map" 텍스트를 넣습니다.
- use client 지시자를 추가합니다.
3.필요한 패키지 설치:
- 터미널에서 다음 명령어를 실행하여 패키지를 설치합니다
npm install react-geocode mapbox-gl react-map-gl
4. 상태 설정:
- useState를 사용하여 lat, lng, viewport, loading, geocodeError 상태를 정의합니다.
- 초기 상태 값을 설정합니다.
5. Google Geocoding API 설정:
setDefaults 함수를 사용하여 API 키와 기본 설정을 추가합니다.
API 키는 환경 변수에서 가져옵니다: process.env.NEXT_PUBLIC_GOOGLE_GEOCODING_API_KEY
6.위도 및 경도 가져오기:
useEffect를 사용하여 컴포넌트가 마운트될 때 fromAddress 함수를 호출하여 주소로부터 위도와 경도를 가져옵니다.
비동기 함수 fetchCoords를 만들어 try-catch-finally 블록을 사용하여 API 요청을 처리합니다.
property 객체에서 주소 정보를 가져와 fromAddress 함수에 전달합니다.
응답에서 위도와 경도를 추출하여 상태를 업데이트합니다.
7.로딩 및 에러 처리:
loading 상태가 true일 경우 "loading..." 텍스트를 출력합니다.
geocodeError 상태가 true일 경우 "No location data found" 텍스트를 출력합니다.
8.PropertyMap 컴포넌트 활용:
상세 페이지 컴포넌트에서 PropertyMap 컴포넌트를 가져와 div 태그 대신 사용하고 property를 전달합니다.
"use client"; import { PropertyProps } from "@/app/properties/[id]/page"; import React from "react"; import { useEffect, useState } from "react"; import Geocode, { OutputFormat, setDefaults } from "react-geocode"; import Map, { Marker } from "react-map-gl"; import Image from "next/image"; import pin from "@/assets/images/pin.svg"; import Spinner from "@/components/Spinner"; import 'mapbox-gl/dist/mapbox-gl.css' import { PropertyCardProps } from "./PropertyCard"; type MarkerProps = { latitude: number; longitude: number; offsetLeft?: number; offsetTop?: number; draggable?: boolean; // Add other properties here }; const PropertyGoogleMap: React.FC<PropertyCardProps> = ({ property }) => { const [lat, setLat] = useState<number | null>(null); const [lng, setLng] = useState<number | null>(null); const [viewport, setViewport] = useState({ latitude: 0, longitude: 0, zoom: 12, width: "100%", height: "500px", }); const [loading, setLoading] = useState(true); const [geocodeError, setGeocodeError] = useState(false); setDefaults({ key: process.env.NEXT_PUBLIC_GOOGLE_GEOCODING_API_KEY, language: "ko", region: "KR", outputFormat: OutputFormat.JSON, }); useEffect(() => { // Geocode.setKey(process.env.NEXT_PUBLIC_GOOGLE_GEOCODING_API_KEY as string); // Geocode.setLanguage("ko"); // Geocode.setRegion("KR"); // Geocode.setLocationType("ROOFTOP"); const fetchCoords = async () => { setLoading(true); try { let addressText=`${property.location.address1} ${property.location.address2} ${property.location.address3} ${property.location.zipcode}`; addressText= '경기도 수원시 덕영대로 535번길' const res = await Geocode.fromAddress(addressText); if (res.results.length === 0) { setGeocodeError(true); return; } const { lat, lng } = res.results[0].geometry.location; setLat(lat); setLng(lng); setViewport(prevViewport => ({ ...prevViewport, latitude: lat, longitude: lng, })); } catch (error) { console.log("에러 =============>",error); setGeocodeError(true); } finally { setLoading(false); } }; fetchCoords(); }, [property]); if (loading) return <Spinner loading={loading} />; if (geocodeError) { return <div className="text-xl">No location data found</div>; } return ( !loading && ( <Map mapboxAccessToken={process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN} // mapLib={mapboxgl} initialViewState={{ longitude:lng!, latitude:lat!, zoom:15 }} style={{ width: 600, height:400 }} mapStyle="mapbox://styles/mapbox/streets-v11" > {lat && lng && ( <Marker latitude={lat} longitude={lng} offset={[-10,-20]} > <Image src={pin} alt="Location Pin" width={40} height={40}/> </Marker> )} </Map> ) ); }; export default PropertyGoogleMap;
setDefaults({ key: process.env.NEXT_PUBLIC_GOOGLE_GEOCODING_API_KEY, language: "ko", region: "KR", outputFormat: OutputFormat.JSON, });
setDefaults 함수는 react-geocode 라이브러리에 존재하지 않습니다.
대신 react-geocode는 setApiKey, setLanguage, setRegion, setLocationType과 같은 개별적인 설정 함수를 제공합니다.
따라서 setDefaults 대신 개별 설정 함수들을 사용해야 합니다.
2. Mapbox 지도 표시
Mapbox 설정
1)Mapbox API 키 설정:
Mapbox에 가입하고 대시보드에서 토큰을 생성합니다.
.env 파일에 NEXT_PUBLIC_MAPBOX_TOKEN으로 저장합니다.
NEXT_PUBLIC_MAPBOX_TOKEN=pk.abcdef1234567890
2)필요한 패키지 설치:
react-map-gl과 mapbox-gl 패키지를 이미 설치했습니다.
3)지도 컴포넌트 작성:
PropertyMap 컴포넌트를 수정하여 Mapbox 지도를 표시합니다.
useEffect에서 좌표를 가져와 상태를 업데이트합니다.
지도 렌더링 코드
1)필요한 모듈 가져오기:
"use client"; import { PropertyProps } from "@/app/properties/[id]/page"; import React, { useEffect, useState } from "react"; import Geocode from "react-geocode"; import Map, { Marker } from "react-map-gl"; import Image from "next/image"; import pin from "@/assets/images/pin.svg"; import Spinner from "@/components/Spinner";
2)PropertyMap 컴포넌트:
const PropertyMap: React.FC<PropertyProps> = ({ property }) => { const [lat, setLat] = useState<number | null>(null); const [lng, setLng] = useState<number | null>(null); const [viewport, setViewport] = useState({ latitude: 0, longitude: 0, zoom: 12, width: "100%", height: "500px", }); const [loading, setLoading] = useState(true); const [geocodeError, setGeocodeError] = useState(false); useEffect(() => { Geocode.setApiKey(process.env.NEXT_PUBLIC_GOOGLE_GEOCODING_API_KEY as string); Geocode.setLanguage("ko"); Geocode.setRegion("KR"); Geocode.setLocationType("ROOFTOP"); const fetchCoords = async () => { try { const res = await Geocode.fromAddress(`${property.location.address1} ${property.location.address2} ${property.location.address3} ${property.location.zipcode}`); if (res.results.length === 0) { setGeocodeError(true); return; } const { lat, lng } = res.results[0].geometry.location; setLat(lat); setLng(lng); setViewport(prevViewport => ({ ...prevViewport, latitude: lat, longitude: lng, })); } catch (error) { console.log(error); setGeocodeError(true); } finally { setLoading(false); } }; fetchCoords(); }, [property]); if (loading) return <Spinner />; if (geocodeError) { return <div className="text-xl">No location data found</div>; } return ( <Map initialViewState={viewport} style={{ width: viewport.width, height: viewport.height }} mapStyle="mapbox://styles/mapbox/streets-v11" mapboxAccessToken={process.env.NEXT_PUBLIC_MAPBOX_TOKEN} > {lat && lng && ( <Marker latitude={lat} longitude={lng} anchor="bottom"> <Image src={pin} alt="location" width={40} height={40} /> </Marker> )} </Map> ); }; export default PropertyMap;
3) CSS 파일 추가:
- mapbox-gl의 CSS 파일을 임포트하여 스타일 문제를 해결합니다.
import 'mapbox-gl/dist/mapbox-gl.css';
요약
- API 키 설정: .env 파일에 Google Geocoding과 Mapbox 키 추가.
- 패키지 설치: react-geocode, react-map-gl 등 필요한 패키지 설치.
- 지도 컴포넌트: PropertyMap 컴포넌트 작성, 좌표를 가져와 Mapbox 지도에 마커 표시.
- CSS 추가: mapbox-gl CSS 파일 임포트.
댓글 ( 0)
댓글 남기기