logo

𝝅번째 알파카의 개발 낙서장

OpenLayers를 여행하는 개발자를 위한 안내서 - 10. Open Street Map(OSM) 맵 만들기

프로젝트
⏰ 2022-03-14 19:53:00

D O W N

https://user-images.githubusercontent.com/50317129/156607880-c5abad92-1991-4c01-b85f-7153bf89cb64.png
OpenLayers를 여행하는 개발자를 위한 안내서
이 게시글은 OpenLayers를 여행하는 개발자를 위한 안내서 시리즈의 26개 중 10번 째 게시글입니다.
https://user-images.githubusercontent.com/50317129/260317030-e4b8575b-f09e-47f4-ab70-168a817268c6.png

Table of Contents

https://user-images.githubusercontent.com/50317129/260317030-e4b8575b-f09e-47f4-ab70-168a817268c6.png

Open Street Map

OSM이란, 전세계 지도 종사자들이 자율적으로 관리하는 세계지도다. 즉, 지도 분야의 오픈 소스라고 생각하면 이해하기 쉽다. 각 국의 기여자들이 지도를 관리하고 있으며, 각 국가의 영역은 해당하는 국가의 언어로 표시된다. 전세계를 대상으로 하는 서비스에도 무리없이 적용 가능하다는 장점이 있다. 단, 한국 기준으로 지도의 퀄리티가 그리 뛰어나진 않다.

OpenLayers는 라이브러리 단계에서 OSM을 기본 제공한다. 즉, 별다른 API 호출이나 설정 없이 간단한 코드 몇 줄 만으로도 웹 상에 세계지도를 띄울 수 있다.

이 장에서는 OpenLayers6를 활용하여 웹 상에 OSM을 띄우는 매우 기초적인 방법에 대해 다룬다.




웹 사이트에 OSM 띄우기

1. OpenLayers 구조 상기하기

일전에 언급했었지만, 혹시 모르니 다시 한 번 OpenLayers의 구조에 대해 짚고 넘어가자.

  • Feature: 점, 선, 면과 같은 요소 (벡터 레이어 한정)
  • Source: 레이이의 데이터 원천. Feature의 모음과 같다. (SHP, GeoJSON 등)
  • Layer: 데이터 원천을 토대로 정의한 데이터셋 (벡터, 이미지)
  • View: 사용자가 현재 맵을 바라보는 방식의 정보
  • Interaction: 맵의 상호작용 요소 (Zoom in, out 버튼 등)
  • Overlay: 맵에 표시할 요소

이 장에서는 OSM 하나만 있으면 되므로, 필요한 요소는 아래와 같다.

  • Source: OSM의 소스
  • Layer: OSM의 소스로 정의된 OSM 레이어
  • View: 뷰 정보

나머지 요소는 사용하지 않거나, 기본값을 사용한다.



2. OSM Source 만들기

OSM 데이터를 관리하는 OSM Source 객체를 생성하자.

TYPESCRIPT

1
2
3
4
5
6
7
import OSM from 'ol/source/OSM';

// 기본
const source = new OSM();

// 옵션 적용
const source = new OSM({ attributions: '<p>Developed by <a href="https://itcode.dev" target="_blank">RWB</a></p>', cacheSize: 0 });
NameTypeDefaultDescription
attributions🔗 ol/source/Source-AttributionLike | undefined기여 문구 (지도 우측 하단)
cacheSizenumber | undefined타일 캐시 크기
crossOriginstring | nullanonymousCORS 속성
imageSmoothingbooleantrueDeprecated 속성. 보간 사용 여부
interpolatebooleantrue보간 사용 여부
maxZoomnumber19최대 줌 레벨. 지정된 줌레벨을 초과할 경우 데이터 미출력
opaquebooleantrue불투명 여부
reprojectionErrorThresholdnumber0.5최대 재투영 오류 픽셀 (0 ~ 1)
tileLoadFunction🔗 ol/Tile-LoadFunction | undefinedURL 로드 함수
transitionnumber250렌더링 출력 애니메이션 시간
urlstringhttps://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.pngURL 양식. 중괄호 값은 OL에서 자동으로 할당
wrapXbooleantrue수직 감싸기 여부
zDirection🔗 ol/array-NearestDirectionFunction | number0줌 레벨이 실수(ex. 12.552)일 경우 더 높은 타일을 사용할지, 낮은 타일을 사용할지 여부

OSM Source는 OSM을 통해 생성할 수 있다. 파라미터로 객체 형태의 옵션을 받는다.

그 외 사용할 수 있는 옵션과 메서드의 종류는 🔗 ol/source/OSM에서 확인하자.



3. Layer 만들기

OSM Source를 담을 Layer 객체를 생성한다. 이 Layer는 할당된 OSM Source를 통해 OSM 지도를 표출해줄 것이다.

TYPESCRIPT

1
2
3
4
5
6
7
8
9
10
11
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

const source = new OSM({ attributions: '<p>Developed by <a href="https://itcode.dev" target="_blank">RWB</a></p>', cacheSize: 0 });

const layer = new TileLayer({
	source: source,
	properties: { name: 'base-osm' },
	zIndex: 1,
	preload: Infinity
});
NameTypeDefaultDescription
classNamestringol-layer클래스명
opacitynumber1투명도 (0 ~ 1)
visiblebooleantrue표시 여부
extent🔗 ol/extent-Extent | undefined레이어의 렌더링 범위. 해당 범위를 넘어가면 데이터를 표시하지 않음
zIndexnumber | undefined우선 순위 (높을수록 위에 표시)
minResolutionnumber | undefined최소 표시 해상도
maxResolutionnumber | undefined최대 표시 해상도
minZoomnumber | undefined최소 표시 줌 레벨
maxZoomnumber | undefined최대 표시 줌 레벨
preloadnumber0지정한 레벨까지 저해상도 타일을 미리 로드 (0은 미사용)
source🔗 ol/source/Tile-TileSource | undefined레이어의 소스
map🔗 ol/PluggableMap-PluggableMap | undefined지정한 Map 객체에서 해당 레이어를 오버레이로 사용
useInterimTilesOnErrorbooleantrue오류 시 중간타일 사용 여부
propertiesobject | undefined임의 속성. get(), set()으로 조작 가능

TileLayer 객체를 통해 타일 레이어를 생성할 수 있다.

옵션의 source는 필수 옵션으로, 이 옵션을 비우면 레이어에 아무 것도 뜨지 않아 레이어의 의미가 없다.

properties는 레이어의 임의의 속성을 지정할 수 있다. 위 처럼 레이어의 고유 식별자를 할당해주면, 레이어를 관리하는 데 도움이 된다. Map 객체에서 레이어를 뽑아낼 때, 고유 식별자가 없으면 곤란하기 때문.

그 외 사용할 수 있는 옵션과 메서드의 종류는 🔗 ol/layer/Tile에서 확인하자.



4. View 만들기

지도의 뷰잉 정보를 선언할 View 객체를 생성한다.

TYPESCRIPT

1
2
3
4
5
6
7
import View from 'ol/View';

const view = new View({
	projection: 'EPSG:3857',
	center: [ 14135490.777017945, 4518386.883679577 ],
	zoom: 17
});

[ 14135490.777017945, 4518386.883679577 ]EPSG:3857으로 표기한 서울시청 좌표다.

NameTypeDefaultDescription
center🔗 ol/coordinate-Coordinate | undefined지도의 중심
constrainRotationboolean | numbertrue회전 구속 여부. 숫자일 경우 회전 가능 갯수를 의미 (0일 경우, 90, 180, 270, 360)
enableRotationbooleantrue회전 가능 여부
extent🔗 ol/extent-Extent | undefined지도의 뷰잉 범위. 지정된 범위 밖을 벗어날 수 없음
constrainOnlyCenterbooleanfalsetrue일 경우 extent 제한이 View 중심에만 적용되며, 전체 extent에 적용되지 않음
smoothExtentConstraintbooleantrueView가 extent 범위를 약간 벗어날 수 있는지 여부
maxResolutionnumber | undefined최대 뷰잉 해상도. 지정 해상도 이상 확대 불가능.
minResolutionnumber | undefined최소 뷰잉 해상도. 지정 해상도 이상 축소 불가능.
maxZoomnumber28최대 뷰잉 줌 레벨. 지정 줌 레벨 이상 확대 불가능.
minZoomnumber0최소 뷰잉 줌 레벨. 지정 줌 레벨 이상 축소 불가능.
multiWorldbooleanfalse다중 월드 사용 여부
constrainResolutionbooleanfalse줌 레벨 정수만 허용 여부
smoothResolutionConstraintbooleantrue느슨한 확대/축소 규칙 사용 여부
showFullExtentbooleanfalse전체 구성된 extent 표시 여부
projection🔗 ol/proj-ProjectionLikeEPSG:3857좌표계
resolutionnumber | undefined초기 해상도
resolutionsArray<number> | undefined사용 가능한 해상도 목록 (내림차순) max/minResolution, max/minZoom, zoomFactor 옵션이 무시됨
rotationnumber0기본 회전값
zoomnumber | undefined기본 줌 레벨
zoomFactornumber2줌 배율
paddingArray<number>[ 0, 0, 0, 0 ]패딩

View 객체를 통해, 지도의 뷰잉 정보를 선언할 수 있다.

smoothResolutionConstraint 옵션은, 예를 들어 지도의 크기가 width: 120px, height: 80px이라고 가정하자. 기본값 false라면, 지도는 최대 80px까지 확대가 가능하다.

그러나 true라면, 지도는 최대 120px까지 확대가 가능해진다. 즉, 지도의 확대 기준을 가장 짧은 길이로 할지, 긴 길이로 할지 지정하는 것.



5. Map 만들기

모든 정보를 종합하여 지도를 만드는 Map 객체를 생성한다.

TYPESCRIPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

const source = new OSM({ attributions: '<p>Developed by <a href="https://itcode.dev" target="_blank">RWB</a></p>', cacheSize: 0 });

const layer = new TileLayer({
	source: source,
	properties: { name: 'base-osm' },
	zIndex: 1,
	preload: Infinity
});

const view = new View({
	projection: 'EPSG:3857',
	center: [ 14135490.777017945, 4518386.883679577 ],
	zoom: 17
});

const map = new Map({
	layers: [ layer ],
	target: 'map',
	view: view
});
NameTypeDefaultDescription
controls🔗 ol/Collection-Collection<🔗 ol/control/Control-Control> | Array<🔗 ol/control/Control-Control> | undefined🔗 ol/control/defaults지도 컨트롤 객체
pixelRationumberwindow.devicePixelRatio기기 픽셀 비율
interactions🔗 ol/Collection-Collection<🔗 ol/interaction/Interaction-Interaction> | Array<🔗 ol/interaction/Interaction-Interaction> | undefined
keyboardEventTargetHTMLElement | Document | string | undefined키보드 이벤트 대상 요소
layersArray<🔗 ol/layer/Base-BaseLayer> | 🔗 ol/Collection-Collection<🔗 ol/layer/Base-BaseLayer> | 🔗 ol/layer/Group-LayerGroup | undefined레이어 목록. 배열 뒤에 있을 수록 우선순위가 높아짐
maxTilesLoadingnumber16동시 로드 가능한 최대 타일 수
moveTolerancenumber1지도 이동 이벤트로 인식하기 위해 마우스가 움직여야할 최소 픽셀
overlays🔗 ol/Collection-Collection<🔗 ol/Overlay-Overlay> | Array<🔗 ol/Overlay-Overlay> | undefined지도 오버레이 객체
targetHTMLElement | string | undefined지도를 표시할 DOM 혹은 DOM 아이디
view🔗 ol/View-View | Promise<🔗 ol/View-View> | undefined지도 뷰 객체

Map 객체에 지금까지 선언한 객체들을 할당한다. target에 지정된 DOM에 선언된 지도가 표시된다.

target: map은 아이디가 map인 DOM에 지도를 표시한다는 뜻이다. 꼭 아이디가 아니더라도 HTMLElement를 할당할 수도 있다.




예제 확인하기

🔗 OpenLayers6 Sandbox - OSM에서 이를 구현한 예제를 확인할 수 있다.

단순 OSM 지도를 띄워놓은 페이지므로, 지도 뷰잉 외엔 딱히 상호작용할 요소는 없다.

OSM의 생김새와 국내에 서비스되는 지도의 차이를 비교하는 것도 좋을 것이다.

국내 한정으로 건물 정보가 누락된 곳이 많으며, 대중교통의 표시 또한 굉장히 부실하다. 국내 한정 서비스로는 메리트가 없는 이유.

🏷️ Related Tag

# GIS
# OpenLayers

😍 읽어주셔서 감사합니다!
도움이 되셨다면, 💝공감이나 🗨️댓글을 달아주시는 건 어떤가요?
블로그 운영에 큰 힘이 됩니다!
https://blog.itcode.dev/projects/2022/03/19/gis-guide-for-programmer-10