내 산행이력을 기록해주는 프로젝트를 진행하던 도중, 그냥 기록만 하기에는 허전하기에 산림청에 공공데이터를 활용해 등산로의 난이도, 길이, 소요시간 등을 표기해주었습니다.
해당 데이터는 링크에서 제공하고 있습니다.
데이터에는 등산로 경로를 제공하는 polyline
과 각 주요 지점의 정보를 제공하는 point
두가지 형태로 제공하고 있습니다.
공간 데이터 타입은 POINT
, LINESTRING
, POLYGON
등 여러 타입이 존제하며 이 블로그를 통해서 확인하실 수 있습니다.
데이터를 JSON
형태로 다운받아 열어보면 해당 지점에 대한 좌표값이 배열 형태로 첨부되어 있습니다.
이 좌표는 PCS_ITRF2000_TM
라는 좌표계 타입으로 카카오 지도에서 사용하고 있는 위경도 기준의 EPSG:4326
타입으로 변경해주어야 사용할 수 있었습니다.
import proj4 from "proj4";
function positionToLatLon(position) {
const first =
'PROJCS["PCS_ITRF2000_TM",GEOGCS["GCS_ITRF_2000",DATUM["D_ITRF_2000",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",200000.0],PARAMETER["False_Northing",600000.0],PARAMETER["Central_Meridian",127.0],PARAMETER["Scale_Factor",1.0],PARAMETER["Latitude_Of_Origin",38.0],UNIT["Meter",1.0]]';
const second = "EPSG:4326"; // WGS84
const [lng, lat] = proj4(first, second, position);
return [lat, lng];
}
좌표 타입의 변환은 Pro4j
라는 라이브러리를 사용해주었습니다.
첫번째 인자로 변환 전의 좌표계 타입을 넣어주여야 하는데, 이 데이터는 공공데이터의 JSON
파일에 spatialRefernce
를 통해서 확인하실 수 있습니다.
등산로 데이터에는 다양한 데이터를 제공하고 있으나 저는
이렇게 6가지 데이터만 따로 수집하여 활용하려 합니다.
const insertRoute = async (mountainId, features) => {
for (const {
attributes: {
PMNTN_DFFL: difficulty,
PMNTN_UPPL: upTime,
PMNTN_GODN: downTime,
PMNTN_LT: length,
PMNTN_NM: name
},
geometry: { paths }
} of features) {
const _path = paths.map(positions => positions.map(position => positionToLatLon(position)));
const route = {
name,
mountainId,
difficulty,
upTime,
downTime,
length: length * 1000,
paths: JSON.stringify(_path)
};
await supabase.from("routes").insert(route);
}
};
const processMountain = async ([name, { features }]) => {
const { data } = await supabase.from("mountains").select("*").eq("name", name).single();
if (!data) return;
const mountainId = data.id;
await insertRoute(mountainId, features);
};
export const processMountainList = async () => {
const mountainEntries = Object.entries(MOUNTAIN_LIST_DATA);
for (const entry of mountainEntries) {
await processMountain(entry);
}
};
위와 같은 함수를 활용해서 자동으로 데이터의 형태를 변환, DB에 저장해주고 있습니다.
이 과정에서 등산로 좌표의 경우 [[x, y], [x, y], [x, y]]
와 같이 2중 배열의 형태로 저장되어 있습니다.
supabase
에 배열을 저장하는 행위는 가능하나, 2중 배열의 경우 방법을 찾지 못해 배열을 분해해 따로 따로 rows
로 만들어야 하나 고민했으나, 데이터의 크기가 크지 않기에 해당 이중 배열을 JSON.stringify
를 통해 문자열로 만들어 하나의 column
에 저장한 후, 사용할 때 JSON.parse
를 통해 다시 객체 형태로 변환해 사용해주었습니다.
마지막으로 가져온 데이터를 지도에 그려주기만 하면 작업은 종료됩니다.
카카오 맵 SDK를 활용하고 있기에, kakao.maps.Polyline
을 사용해 선을 그려주었습니다.
난이도에 따라, 쉬움은 초록색, 중간은 주황색, 어려움은 빨간색으로 선을 구분해주었습니다.