과거의 내가 미래의 나에게
지도 공부하기(3) - marker&cluster 생성 본문
작년 10월쯤 지도 공부를 조금 해놨는데, 그 조금이 뭐라고 요새 개발하는데 너무 도움이 된다. 근데 저번 글들이 다소 구성이 조악해서 아마 나중에 다시 건드려야 할 것 같다.
지도 컴포넌트를 만들다보니 전체적으로 크게 구조를 잡고 들어가는 식으로 하려다가 너무 모르는 것이 많아서 일단 기능을 구현하면서 익히고 다시 컴포넌트화를 시켜야 할 듯 하여 먼저 다짜고짜 기능을 구현해보려한다.
오늘은 지도 위에 마커를 띄운 것과 클러스터를 생성한 것에 대해 기록하고 추가적으로 정리할 것이 있다면 해보려한다.
Marker 띄우기
지도 위에 다양한 마커를 띄우고 개별 마커를 클릭하면 해당 마커의 스타일이 변경되는 작업을 기록해둔다.
마커는 지도 위에 위경도 좌표를 기반으로 하여 점 객체가 띄워진 형태다. 해당 점 객체에 스타일을 추가하거나 이미지를 넣으면 흔히 볼 수 있는 마커가 탄생되는 것이다.
오픈레이어즈(ol)로 이러한 점 객체를 띄우기 위해서 아래와 같은 과정을 거친다.
//import들은 생략함
const map = new OlMap({
target: // 지도 컨테이너 ID,
layers: // 맵 타일 레이어만 넣어놓음,
view: new OlView({
center: // 지도 중앙값,
zoom: // 기본 zomm 값,
projection: // 좌표계 설정,
}),
controls: [],
});
// 벡터 Source 생성
const vectorSource = new OlVectorSource();
// 위경도값 준비. 구분할 수 있게 key도 넣었다.
const markerList = [
{ key: 1, coord: [126.9706, 37.5546] },
{ key: 2, coord: [126.9711, 37.5542] },
{ key: 3, coord: [126.9716, 37.5538] },
{ key: 4, coord: [126.9721, 37.5534] },
{ key: 5, coord: [126.9726, 37.5530] }
];
//markerList를 feature로 만들어서 vectorSource에 넣는 작업
markerList.forEach((item) => {
// feature 생성
const marker = new OlFeature({
geometry: new OlPoint(item.coord),
key: item.key,
});
// feature에 스타일 추가
marker.setStyle(
new OlStyle({
image: new OlIcon({
anchor: [0.5, 1],
src: '/assets/icon/marker.png',
scale: 1.0,
}),
}),
);
vectorSource.addFeature(marker);
});
// 벡터 데이터들을 구성한 소스를 넣을 수 있는 레이어 생성
const vectorLayer = new OlVectorLayer({
source: vectorSource,
});
// 지도에 마커를 추가한 레이어 추가
map.addLayer(vectorLayer);
Cluster 생성
여러 마커가 띄워져있고 줌에 따라 마커들이 클러스터링이 생성되고 해제되는 작업을 기록해둔다.
클러스터는 여러 개의 데이터들을 그룹화하여 하나의 데이터로 재표출하는 것이다. 지도 위에 수많은 데이터들이 나열되어있으면 그 데이터들이 겹쳐보일 수도 있기에 확대/축소에 따라 데이터들을 하나로 합쳐서 보여주거나 혹은 나눠서 보여주는 것이다.
오픈레이어즈는 줌과 데이터들의 거리에 따라서 이들을 합쳐주거나 분리해주는 기능을 제공한다. 따라서 사용자는 데이터끼리의 거리를 설정하여 언제 클러스터가 될 지를 정해주면 오픈레이어즈가 알아서 합쳐주고 분리해줄 것이다.
const map = new OlMap({
target: // 지도 컨테이너 ID,
layers: // 맵 타일 레이어만 넣어놓음,
view: new OlView({
center: // 지도 중앙값,
zoom: // 기본 zomm 값,
projection: // 좌표계 설정,
}),
controls: [],
});
//개별 마커 소스 생성. 위와 동일
const vectorSource = new OlVectorSource();
const markerList = [
{ key: 1, coord: [126.9706, 37.5546] },
{ key: 2, coord: [126.9711, 37.5542] },
{ key: 3, coord: [126.9716, 37.5538] },
{ key: 4, coord: [126.9721, 37.5534] },
{ key: 5, coord: [126.9726, 37.5530] }
];
markerList.forEach((item) => {
const marker = new OlFeature({
geometry: new OlPoint(item.coord),
key: item.key,
});
marker.setStyle(
new OlStyle({
image: new OlIcon({
anchor: [0.5, 1],
src: '/assets/icon/marker.png',
scale: 1.0,
}),
}),
);
vectorSource.addFeature(marker);
});
// 클러스터 소스 생성
const clusterSource = new OlClusterSource({
distance: 40, // 클러스터링 거리 (픽셀 단위)
source: vectorSource, // 클러스터할 데이터 소스
});
// 클러스터 스타일 설정
const clusterStyle = (feature: any) => {
const size = feature.get('features').length; // 클러스터에 포함된 마커 개수
let iconSize = size > 1 ? 1.5 : 1.0; // 클러스터 크기에 따라 아이콘 크기 조정
return new OlStyle({
image: new OlIcon({
anchor: [0.5, 1],
src: size > 1 ? icon2 : icon, // 클러스터 아이콘:마커 아이콘
scale: iconSize,
}),
text: new OlText({
text: size > 1 ? size.toString() : '', // 클러스터된 데이터 숫자 표시
font: '14px Arial',
fill: new OlFill({ color: '#fff' }),
stroke: new OlStroke({ color: '#333', width: 3 }),
}),
});
};
// 클러스터 데이터들을 구성한 소스를 넣을 수 있는 클러스터 레이어 생성
const clusterLayer = new OlVectorLayer({
source: clusterSource,
style: (feature) => clusterStyle(feature),
});
// 클러스터 레이어 추가
map.addLayer(clusterLayer);