React

 

1. 설치

npm install react-kakao-maps-sdk

 

 

 

2. <script> 태그 추가

이 라이브러리를 사용하기 위해서는 필수적으로 Kakao Maps API를 불러와야 한다.
API 키 발급받는 법

<script
  type="text/javascript"
  src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY&libraries=services,clusterer"
></script>

 

 

 

KakaoMap.jsx

import React, { useState, useEffect } from "react";
import { Map, MapMarker } from "react-kakao-maps-sdk";



const KakaoMap = ({ keyword, latitude, longitude }) => {
  const { kakao } = window;
  const [info, setInfo] = useState();
  const [markers, setMarkers] = useState([]);
  const [map, setMap] = useState();
  const [mapLength, setMapLength] = useState(1000);

  useEffect(() => {
    const overlayBox = document.querySelector(".overlaybox");
    if (overlayBox) {
      const grandParent = overlayBox.parentElement.parentElement;
      if (grandParent) {
        setBorder(grandParent.style.border); // border 값을 업데이트합니다.
        grandParent.style.border = "0"; // border 값을 0으로 설정합니다.
      }
    }


  }, []);

  useEffect( () => {
    if (!map) return;
  
    if(mapLength===1000){
      createMap(keyword);
    }
     
    if(mapLength===0){
      createMap(keyword);
      // 예 let address = "충청북도 청주시 상당구 미원면";
      //만약에 검색된 스터디카페 값이 없다면  충청북도 청주시 까지로 해서 검색
      let parts = keyword.split(" ");
      let result = parts[0] + " " + parts[1];
      console.log(result);  // 출력: "충청북도 청주시"
      createMap( result);
    }

  }, [map,mapLength]);

  async function createMap(keyword){   
    const ps = new kakao.maps.services.Places();
     ps.keywordSearch(`${keyword} 스터디카페`, async (data, status, _pagination) => {      
      setMapLength(data.length);
      
      if (status === kakao.maps.services.Status.OK) {
        // 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해
        // LatLngBounds 객체에 좌표를 추가합니다
        const bounds = new kakao.maps.LatLngBounds();
        let markers = [];
        
        for (var i = 0; i < data.length; i++) {
          // @ts-ignore
          markers.push({
            position: {
              lat: data[i].y,
              lng: data[i].x,
            },
            content: data[i].place_name,
          });
          // @ts-ignore
          bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
        }
        setMarkers(markers);

        // 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
        map.setBounds(bounds);

        //보더값 제거 배경색 투명
        const overlayBox = document.querySelector(".overlaybox");
        if (overlayBox) {
          const grandParent = overlayBox.parentElement.parentElement;
          if (grandParent) {
            setBorder(grandParent.style.border); // border 값을 업데이트합니다.
            setBackgroundColor(grandParent.style.background);
            grandParent.style.border = "0"; // border 값을 0으로 설정합니다.
            grandParent.style.background = "rgba(255,255,255,0)";
          }
        }
      }
    });

  }



  return (
    <div>
      <Map
        center={{ lat: latitude, lng: longitude }}
        style={{
          width: "100%",
          height: "700px",
          borderRadius: "20px",
        }}
        level={3}
        onCreate={setMap}
      >
        {/* //지도에 보여줄 위치 지정 (위도,경도)  */}

        {markers.map((marker) => (
          <MapMarker
            style={{ border: "tranparent" }}
            //position={{ lat: latitude, lng: longitude }}

            key={`marker-${marker.content}-${marker.position.lat},${marker.position.lng}`}
            position={marker.position}
            onClick={() => setInfo(marker)}
            image={{
                src: "https://cdn-icons-png.flaticon.com/512/5737/5737612.png",
                size: {
                  width: 50,
                  height: 50
              }
            }}        
           
          >
            {info && info.content === marker.content && (
              <>
                <div
                  style={{
                    color: "#000",
                    fontSize: "16px",
                    fontWeight: "600",
                    border: "2px solid #e30d7c",
                    borderRadius: "5px",
                    padding: "5px",
                    backgroundColor: "#ffffff",
                    boxShadow: "0 0 10px rgba(0, 0, 0, 0.1)",
                    width: "300px",
                    textAlign: "center",
                  }}
                >
                  ☕???? {marker.content}
                </div>
              </>
            )}
          </MapMarker>
        ))}
      </Map>
    </div>
    //핀에 적힐 이름 (위치 이름)
  );
};

export default KakaoMap;

 

 

 

 

 

StudyCafeFinder

import Header from "../../components/Header";
import { useLoaderData } from "react-router-dom";
import { API_BASE_URL } from "../../api-config";
import { getAuthToken, getUser } from "../../util/auth";
import KakaoMap from "../../components/KakaoMap";
import UserTable from "../../components/UserTable";

const { kakao } = window;

const StudyCafeFinder = () => {
  const { findCafeInfo } = useLoaderData();

  return (
    <>
      <div>
        <Header />

        <main className="container mt-5">
         
         
          {findCafeInfo && findCafeInfo.users && (
            <UserTable users={findCafeInfo.users} />
          )}

        

          <KakaoMap
            keyword={findCafeInfo.address}
            latitude={findCafeInfo.lat}
            longitude={findCafeInfo.lng}
          />
        </main>
      </div>
     
    </>
  );
};

export default StudyCafeFinder;

// 로더 함수
export async function loader({ request, params }) {
  const token = getAuthToken();
  const user = getUser();


  const response = await fetch(`${API_BASE_URL}/users/studyCafeFinder`, {
    method: "POST",
    body: JSON.stringify(user),
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer " + token,
    },
  });

  if (!response.ok) {
    return json({ message: "데이터를 가져올 수 없습니다." }, { status: 500 });
  } else {
    //좌표
    let findCafeInfo = "";
    const searchOptionArray = [];
    let users = "";
    let getAddress = "";

    const resData = await response.json();
    users = resData.result;

    const addresses = await users.map((user) => {
      return user.address;
    });

    //샘플 예
    // const addresses = [
    //   "서울 송파구 동남로 99",
    //   "서울 강남구 테헤란로 212",
    //   "대구 수성구 동대구로 441",
    // ];

    const newAddresses = addresses.map((address) => {
      const parts = address.split(" ");
      parts.pop(); // 마지막 요소(번지수)를 제거합니다.
      return parts.join(" "); // 주소를 다시 합칩니다.
    });

    try {
      //1.주소로 좌표 구하기
      await latAndLong(newAddresses, searchOptionArray);

      //2.중간좌표 구하기
      findCafeInfo = await centerPosition(searchOptionArray);

      //3.중간좌표로 주소 구하기
      getAddress = await getAddressFn(findCafeInfo)
        .then((res) => res)
        .catch((err) => console.error(err));
    } catch (error) {
      console.log("error :", error);
    }

    findCafeInfo.users = users;
    findCafeInfo.address = getAddress;

    
    return { findCafeInfo: findCafeInfo };
  }
}

//1.주소로 좌표 구하기
async function latAndLong(addresses, searchOptionArray) {
  const geocoder = new kakao.maps.services.Geocoder();

  const promises = addresses.map(
    (address) =>
      new Promise((resolve, reject) => {
        geocoder.addressSearch(address, function (result, status) {
          if (status === kakao.maps.services.Status.OK) {
            const coords = new kakao.maps.LatLng(result[0].y, result[0].x);

            const searchOption = {
              location: coords,
              radius: 2000,
              sort: kakao.maps.services.SortBy.DISTANCE,
            };

            resolve(coords);
          } else {
            reject(new Error("Failed to get coordinates"));
          }
        });
      })
  );

  await Promise.all(promises)
    .then((coordsArray) => {
      searchOptionArray.push(...coordsArray);
    })
    .catch((error) => console.error(error));
  return searchOptionArray;
}

//2. 중간좌표 구하기
async function centerPosition(locations) {
  //ex) const locations = [
  //   { La: 127.047486752713, Ma: 37.504059366187 },
  //   { La: 126.976425200039, Ma: 37.5626231544518 },
  //   { La: 126.978989954189, Ma: 37.5735042429813 }
  // ];

  let sumLat = 0;
  let sumLng = 0;

  locations.forEach((location) => {
    sumLat += location.Ma;
    sumLng += location.La;
  });

  const avgLat = sumLat / locations.length;
  const avgLng = sumLng / locations.length;

  return { lat: avgLat, lng: avgLng };
}

//3.좌표를 이용해서 주소값 가져오기
async function getAddressFn({ lat, lng }) {
  const geocoder = new window.kakao.maps.services.Geocoder();
  const res = await new Promise((resolve, reject) => {
    geocoder.coord2RegionCode(lng, lat, (result, status) => {
      if (status === window.kakao.maps.services.Status.OK) {
        for (let i = 0; i < result.length; i++) {
          if (result[i].region_type === "H") {
            resolve(result[i].address_name);
          }
        }
      } else {
        reject(new Error("주소를 찾을 수 없습니다."));
      }
    });
  });
  return res;
}

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

Better early than late. (쇠뿔도 단김에 빼랬다.)

댓글 ( 0)

댓글 남기기

작성