본문 바로가기

공부/Next

Next 카카오 맵 행정구역 나누기

반응형

 

시도 별로 행정구역을 나누는 작업을 진행한 내용입니다.

 

행정구역 데이터 파일 📖

SHP 파일

시도, 시군구, 읍면동, 리 별로 데이터가 있어 원하는 파일을 다운 받으면 됩니다.

 

 

대한민국 최신 행정구역(SHP) 다운로드 – GIS Developer

 

www.gisdeveloper.co.kr

 

 

저는 시도 정보가 필요했기 때문에 가장 최신 SHP 파일을 다운로드 했습니다.

시도 SHP

 

파일을 다운로드하고 압축을 풀면 3개의 파일이 들어있습니다.

 

 

 

방위나 지도가 담긴 공간 데이터 파일을 JSON 파일로 사용하기 위해 `XrProjection` 으로 변환을 해야 합니다.

 

 

[GIS] XrProjection v3.1 – GIS Developer

다양한 좌표계 간의 변환 툴입니다. 특히 대한민국에서 사용하는 좌표계에 대해 손쉽게 변환할 수 있는 정보를 기본으로 제공합니다. 투영(Projection)에 사용하는 3, 7, 10 파라메터를 모두 지원합

www.gisdeveloper.co.kr

 

 

`XrProjection`을 실행시키면 아래 사진과 같은 화면이 나오게 됩니다.

단일 SHP 파일 변환

 

입력 SHP에 아까 다운로드한 `ctprvn.shp`

좌표계는 `UTM-K(GRS80 타원체)`

아래 좌표계는 `WGS84 타원체의 경위도`

출력 SHP는 기존 `ctprvn.shp`를 선택하고 뒤에 `_wgs84`를 붙여주고 변환 버튼 클릭

SHP 파일 변환 성공

 

 

파일 변환에 성공하게 되면 `_wgs84`가 붙은 파일 3개가 생성이 됩니다.

 

 

이렇게 방위를 변환한 파일을 JSON 파일로 변경하기 위해서는 아래 사이트에 접속해 줍니다.

 

 

mapshaper

Drop, paste or select files to import. Shapefile, GeoJSON, TopoJSON, KML and CSV formats are supported. Files can be zipped or gzipped.

mapshaper.org

 

 

아까 생성된 3개의 파일을 선택하고 `encoding=euckr`을 적어줍니다.

import

 

`encoding=euckr`을 적는 이유

SHP 내용 중 한글로 되어 있는 부분을 깨지지 않도록 하기 위해서입니다!

 

이후 Submit 버튼을 누르게 되면 아래 같이 시도 지도가 나오게 됩니다!!

 

근데 우리나라는 섬이 엄청 많기 이대로 변환하면 지도 용량이 커지게 됩니다. 그래서 작은 섬들은 나타나지 않게 간략화해주기 위해서 우측 상단에 `Simplify` 버튼을 클릭하고 prevent shape removal을 체크하고 `Apply`버튼을 눌러줍니다.

 

 

그리고 위에 Settings 바를 움직이면서 시군 경계면 지역을 보면서 조절을 하면 됩니다!

시도 지도

 

 

이제 `Export`버튼을 눌러 `GeoJSON`을 체크하고 precision=0.001 encoding=utf-8을 적어주고 `Export`버튼을 눌러줍니다.

 

Precision, Encoding

`Precision`은 위경도의 소수점 몇 자리까지를 표시할지를 결정하는데 시도를 보여 주는 것으로 그리 정밀하지 않기 때문에 3자리로 설정을 하고 `Encoding`은 한글이 깨지지 말라고 utf-8로 설정을 했습니다.

 

 

JSON 파일

다운로드한 파일을 이제 적용만 해주면 끝입니다!

행정구역 json

 

코드 작성 📖

JSON 데이터

`features > geometry > coordinates` 속성에 해당 지역 좌표들이 배열로 들어있는 걸 확인할 수 있습니다.

{
  "type": "FeatureCollection",
  "features": [
     {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [128.54880989370014, 38.301950820518755],
            [128.5600921732829, 38.25735515107489],
            ....
          ]
        ]
      },
      "properties": {
        "CTPRVN_CD": "42",
        "CTP_ENG_NM": "Gangwon-do",
        "CTP_KOR_NM": "강원도"
      }
    },
    ....
  ],
}

 

 

받아온 json 데이터에서 type이 `Polygon`이면 3차원 배열로 `MultiPolygon`이면 4차원 배열로 구성되어 있습니다.

const [geoList, setGeoList] = useState([]);
  useEffect(() => {
    const { features } = coordRegionCode;

    const data = [];

    for (let item of features) {
      const { geometry, properties } = item;
      const { CTP_KOR_NM } = properties;
      const { coordinates, type } = geometry;

      const pathList = [];

      if (type === "Polygon") {
        for (let areaList of coordinates) {
          const path = [];
          for (let area of areaList) {
            path.push({
              lng: area[0],
              lat: area[1],
            });
          }
          pathList.push(path);
        }
      } else if (type === "MultiPolygon") {
        for (let polygon of coordinates) {
          for (let areaList of polygon) {
            const path = [];
            for (let area of areaList) {
              if (Array.isArray(area)) {
                path.push({
                  lng: area[0],
                  lat: area[1],
                });
              }
            }
            pathList.push(path);
          }
        }
      }

      data.push({
        name: CTP_KOR_NM,
        path: pathList,
        isHover: false,
        key: Math.random(),
      });
    }
    setGeoList(data);
  }, []);

 

그래서 조건문을 통해 3,4차원에 배열을 `pathList`에 push 해줍니다.

 

 

geoList를 map 메서드를 이용해 `Polygon`을 만들어줍니다.

return (
    <Map
      id="map"
      center={{
        // lat: 36.450701,
        // lng: 127.570667,
        lat: 35.90701,
        lng: 127.570667,
      }}
      className="w-[100vw] h-[100vh] relative"
      level={12}
    >
      {geoList.map((item, index) => {
        const { key, path, isHover } = item;
        const color = globalColor[index];
        return (
          <Polygon
            key={key}
            path={path}
            strokeWeight={2} // 선의 두께입니다
            strokeColor={color} // 선의 색깔입니다
            strokeOpacity={0.8} // 선의 불투명도 입니다
            strokeStyle={"solid"} // 선의 스타일입니다
            fillColor={isHover ? color : "#ffffff"} // 채우기 색깔입니다
            fillOpacity={0.4} // 채우기 불투명도 입니다
            onMouseover={() => {
              // 마우스 오버시 색 변경
              setGeoList((pre) =>
                pre.map((area) => {
                  if (area.key === key) {
                    return {
                      ...area,
                      isHover: true,
                    };
                  }
                  return area;
                })
              );
            }}
            onMouseout={() => {
              // 색 다시 reset
              setGeoList((pre) =>
                pre.map((area) => {
                  if (area.key === key) {
                    return {
                      ...area,
                      isHover: false,
                    };
                  }
                  return area;
                })
              );
            }}
          />
        );
      })}
    </Map>
  );

 


출처 🏷️

https://velog.io/@airwalk741/%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A7%B5-%ED%96%89%EC%A0%95%EA%B5%AC%EC%97%AD-%EB%82%98%EB%88%84%EA%B8%B0

https://blog.naver.com/PostView.nhn?blogId=kcchang61&logNo=221350672356

반응형