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

screen

OpenLayers를 여행하는 개발자를 위한 안내서 - 16. WMS GetImage를 사용하여 지도에 이미지 표시하기

projects

GIS

시리즈 톺아보기

OpenLayers를 여행하는 개발자를 위한 안내서

OpenLayers를 여행하는 개발자를 위한 안내서
count

WMS 🔗

이 장에선 WFS를 통해 지도에 이미지를 표시하는 방법에 대해 다룬다.

이전 장의 WFS는 공간정보 데이터를 GeoJSON으로 받아 직접 객체로 표시하지만, WMS는 객체를 GeoServer에서 이미지로 렌더링한 이미지를 받아 표시한다.

즉, GeoServer로 부터 직접 Tile Map을 받아 표현한다고 생각하면 된다.




WMS를 활용하여 지도에 표시하기 🔗

WMS를 표시하기 위해, 총 4개 객체가 필요하다. WMS는 이미지를 받아 표시하므로, 이 이미지를 담을 ImageWMS, 이를 활용하여 지도에 렌더링하는 ImageLayer. 나머지 ViewMap 객체가 필요하다

이 4가지 요소를 구현하는 방법을 차례로 설명하여, 최종적으로 WMS를 활용한 지도를 만든다.



1. GetImage URL 구성하기 🔗

GeoServer를 통해 데이터를 구축했던 데이터를 통해 WMS 이미지를 호출한다.

WMS 중에서도, 속성정보를 제공하는 GetImage를 사용한다. GetImage의 요청방법은 아래와 같다.

TXT

0GET https://example.com/geoserver/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&layers=test:building&exceptions=application%2Fjson&WIDTH=256&HEIGHT=256&CRS=EPSG%3A3857&STYLES=&BBOX=14168061.814827133%2C4367306.048101831%2C14168367.562940273%2C4367611.796214972
Parameter Example Require Description
service WMS (고정) Y 서비스명
version 1.3.0 (고정), 1.1.1, 1.1.0, 1.0.0 Y 버전
request GetMap (고정) Y 요청명
layers repo_name:layer_name Y 레이어명 (다수는 쉼표로 구분)
styles style1 적용할 스타일명 (비울 경우 GeoServer에서 설정한 기본 스타일 적용, 다수는 쉼표로 구분)
srs(or crs) EPSG:4326 기준 좌표계 (비울 경우 레이어의 기본 좌표계로 인식)
bbox Y 이미지 영역 좌표
width 256 Y 이미지 넓이
height 256 Y 이미지 높이
format image/png Y 요청명
transparent false (기본) 배경 투명 여부
bgcolor FFFFFF (기본) RRGGBB 형태의 배경 색상
exceptions application/vnd.ogc.se_xml (기본) 예외 응답 형식
time 2022-03-14T22:30.27.520+09:00 시계열 데이터를 위한 시간 (yyyy-MM-ddThh:mm:ss.SSSZ)
sld https://example.com/sld.xml XML 파일 경로
sld_body SLD XML

하지만 WMS의 URL, WFS에 비해 요구하는 파라미터의 갯수가 많아 다소 복잡하다. WFS에선, VectorSource에 직접 URL을 입력했지만, WMS의 소스 객체인 ImageWMS의 경우 몇 가지 필요한 값을 입력하면 알아서 URL을 만들어 호출해준다.

그냥 WMS는 이런 방식으로 직접 호출한다고만 알고 넘어가자.



2. ImageWMS 생성하기 🔗

OpenLayers의 ImageWMS 객체는 주어진 값을 통해 WMS URL을 생성해 호출한다.

TYPESCRIPT

0import { ImageWMS } from 'ol/source';
1
2const source = new ImageWMS({
3 url: 'https://example.com/geoserver/wms',
4 params: {
5 layers: 'test:building',
6 exceptions: 'application/json'
7 },
8 serverType: 'geoserver'
9});

ImageWMS에 대한 전체 정보는 공식 문서에서 확인할 수 있다.

설정의 세부 내용은 아래와 같다.

Name Type Default Description
attributions ol/source/Source-AttributionLike | undefined 기여 문구 (지도 우측 하단)
crossOrigin null | string | undefined 이미지의 CORS 속성 (참조)
hidpi boolean true 원격 서버에 WMS를 요청할 때, Map 객체의 pixelRatio 값을 사용
serverType ol/source/WMSServerType | string | undefined WMS 서버의 타입 (mapserver, geoserver, qgis 등)
hidpitrue일 때만 필요
imageLoadFunction ol/Image-LoadFunction | undefined true WMS URL의 이미지를 로드 메서드
WMS 호출 메서드를 오버라이딩할 때 사용함
imageSmoothing boolean true Deprecated된 속성으로, interpolate를 사용하길 권고함
interpolate boolean true 리샘플링 시 보간 값 사용 여부
params object WMS 요청 파라미터. 반드시 하나 이상의 LAYERS를 입력해야 함
STYLES는 기본적으로 ''로 빈 값을 가짐
VERSION1.3.0을 기본값으로 가짐
WIDTH, HEIGHT, BOX, CRS(SRS)는 동적으로 설정됨
projection ol/proj-ProjectionLike | undefined 프로젝션 객체. MapView 객체에 선언된 projection을 기본값으로 함
ratio number 1.5 이미지 요청 시 사용할 뷰포트의 크기. 1은 맵 뷰포트와 동일하며, 2는 맵 뷰포트가 가진 폭, 높이의 두배를 의미함
반드시 1 이상의 값을 가져야함
resolutions Array<number> | undefined 해상도. 특정 해상도를 지정할 경우, 지정된 해상도에서만 호출이 발생함
url string WMS URL

url, params.layers는 반드시 입력해야 정상적인 WMS 호출을 수행할 수 있다. 위 두 값만 입력하면, WMS에 필요한 나머지 파라미터는 ImageWMS에서 알아서 계산해 넣어준다.



3. TileLayer 생성하기 🔗

OpenLayers의 TileLayer 객체는 ImageWMS로 호출한 이미지를 통해 지도를 렌더링한다. 이 지도는 배경지도와 같은 이미지로 이루어져있다.

TYPESCRIPT

0import ImageLayer from 'ol/layer/Image';
1
2const layer = new TileLayer({
3 source: source,
4 minZoom: 15,
5 properties: { name: 'wms' },
6 zIndex: 5
7});
Name Type Default Description
className string ol-layer 클래스명
opacity number 1 투명도 (0 ~ 1)
visible boolean true 표시 여부
extent ol/extent-Extent | undefined 레이어의 렌더링 범위. 해당 범위를 넘어가면 데이터를 표시하지 않음
zIndex number | undefined 우선 순위 (높을수록 위에 표시)
minResolution number | undefined 최소 표시 해상도
maxResolution number | undefined 최대 표시 해상도
minZoom number | undefined 최소 표시 줌 레벨
maxZoom number | undefined 최대 표시 줌 레벨
map ol/PluggableMap-PluggableMap | undefined 지정한 Map 객체에서 해당 레이어를 오버레이로 사용
source (ol/source/Image-ImageSource | ol/source/VectorTile-VectorTile) | undefined 레이어의 소스
properties object | undefined 임의 속성. get(), set()으로 조작 가능

ImageLayer에 대한 전체 정보는 ol/layer/Image-ImageLayer에서 확인할 수 있다.



4. View 만들기 🔗

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

TYPESCRIPT

0import View from 'ol/View';
1import proj4 from 'proj4';
2
3const view = new View({
4 projection: 'EPSG:3857',
5 center: proj4('EPSG:4326', 'EPSG:3857', [ 127.28923267492068, 36.48024986578043 ]),
6 zoom: 17
7});
Name Type Default Description
center ol/coordinate-Coordinate | undefined 지도의 중심
constrainRotation boolean | number true 회전 구속 여부. 숫자일 경우 회전 가능 갯수를 의미 (0일 경우, 90, 180, 270, 360)
enableRotation boolean true 회전 가능 여부
extent ol/extent-Extent | undefined 지도의 뷰잉 범위. 지정된 범위 밖을 벗어날 수 없음
constrainOnlyCenter boolean false true일 경우 extent 제한이 View 중심에만 적용되며, 전체 extent에 적용되지 않음
smoothExtentConstraint boolean true View가 extent 범위를 약간 벗어날 수 있는지 여부
maxResolution number | undefined 최대 뷰잉 해상도. 지정 해상도 이상 확대 불가능.
minResolution number | undefined 최소 뷰잉 해상도. 지정 해상도 이상 축소 불가능.
maxZoom number 28 최대 뷰잉 줌 레벨. 지정 줌 레벨 이상 확대 불가능.
minZoom number 0 최소 뷰잉 줌 레벨. 지정 줌 레벨 이상 축소 불가능.
multiWorld boolean false 다중 월드 사용 여부
constrainResolution boolean false 줌 레벨 정수만 허용 여부
smoothResolutionConstraint boolean true 느슨한 확대/축소 규칙 사용 여부
showFullExtent boolean false 전체 구성된 extent 표시 여부
projection ol/proj-ProjectionLike EPSG:3857 좌표계
resolution number | undefined 초기 해상도
resolutions Array<number> | undefined 사용 가능한 해상도 목록 (내림차순) max/minResolution, max/minZoom, zoomFactor 옵션이 무시됨
rotation number 0 기본 회전값
zoom number | undefined 기본 줌 레벨
zoomFactor number 2 줌 배율
padding Array<number> [ 0, 0, 0, 0 ] 패딩


5. Style 정의하기 🔗

WMS 역시 이미지에 그려지는 요소를 스타일링할 수 있다.

WFS는 스타일 객체를 코드 내부에서 기술할 수 있었지만, WMS는 기본적으로 GeoServer와 같은 백엔드 영역에서 이루어지므로, 해당 서버에서 직접 스타일을 기술해준다.

보통 XML 형태로 기술하며, 이를 SLD라 부른다.


GeoServer의 경우, [스타일] 메뉴에서 관리할 수 있다. 별다른 조작을 하지 않았다면, 즉시 사용 가능한 몇 가지 SLD가 기본으로 탑재된다.

레이어 추가 시 [발행] 단계에서 스타일 설정을 할 수 있는데, 이 때 설정하는 것이 WMS에 사용할 SLD다.

여러개를 등록할 수도 있으며, 이 경우 STYLES에 명시된 이름으로 원하는 스타일을 호출할 수 있다. STYLES의 기본값은 ''로 비어있으며, 이 경우 지정된 기본 스타일을 사용하여 이미지를 렌더링한다.

XML

0<?xml version="1.0" encoding="UTF-8"?>
1<StyledLayerDescriptor version="1.0.0"
2 xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
3 xmlns="http://www.opengis.net/sld"
4 xmlns:ogc="http://www.opengis.net/ogc"
5 xmlns:xlink="http://www.w3.org/1999/xlink"
6 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
7 <!-- a Named Layer is the basic building block of an SLD document -->
8 <NamedLayer>
9 <Name>default_polygon</Name>
10 <UserStyle>
11 <!-- Styles can have names, titles and abstracts -->
12 <Title>Default Polygon</Title>
13 <Abstract>A sample style that draws a polygon</Abstract>
14 <!-- FeatureTypeStyles describe how to render different features -->
15 <!-- A FeatureTypeStyle for rendering polygons -->
16 <FeatureTypeStyle>
17 <Rule>
18 <Name>rule1</Name>
19 <Title>Gray Polygon with Black Outline</Title>
20 <Abstract>A polygon with a gray fill and a 1 pixel black outline</Abstract>
21 <PolygonSymbolizer>
22 <Fill>
23 <CssParameter name="fill">#ED143D</CssParameter>
24 <CssParameter name="opacity">0.6</CssParameter>
25 </Fill>
26 <Stroke>
27 <CssParameter name="stroke">#ED143d</CssParameter>
28 <CssParameter name="stroke-width">2</CssParameter>
29 </Stroke>
30 </PolygonSymbolizer>
31 <TextSymbolizer>
32 <Geometry>
33 <ogc:Function name="centroid">
34 <ogc:PropertyName>SHAPE</ogc:PropertyName>
35 </ogc:Function>
36 </Geometry>
37 <Label>
38 <ogc:PropertyName>buld_nm</ogc:PropertyName>
39 </Label>
40 <Font>
41 <CssParameter name="font-family">sans-serif</CssParameter>
42 <CssParameter name="font-size">16</CssParameter>
43 </Font>
44 <LabelPlacement>
45 <PointPlacement>
46 <AnchorPoint>
47 <AnchorPointX>0.5</AnchorPointX>
48 <AnchorPointY>0.5</AnchorPointY>
49 </AnchorPoint>
50 <Displacement>
51 <DisplacementX>0</DisplacementX>
52 <DisplacementY>0</DisplacementY>
53 </Displacement>
54 </PointPlacement>
55 </LabelPlacement>
56 <Halo>
57 <Radius>
58 <ogc:Literal>2</ogc:Literal>
59 </Radius>
60 <Fill>
61 <CssParameter name="fill">#000000</CssParameter>
62 </Fill>
63 </Halo>
64 <Fill>
65 <CssParameter name="fill">#FFFFFF</CssParameter>
66 </Fill>
67 </TextSymbolizer>
68 </Rule>
69 </FeatureTypeStyle>
70 </UserStyle>
71 </NamedLayer>
72</StyledLayerDescriptor>

위 SLD는 실제로 프로젝트의 WMS 요청에서 사용하는 SLD다. WFS에서 스타일 기술에 대한 문단을 읽어봤다면 이해가 더욱 쉬울 것이다. XML의 특성 상 복잡해보이지만, 잘 뜯어보면 별거 없다.

마찬가지로 PointPolygon 등, 데이터 형식에 따라 기술되는 형태가 조금씩 다르다.


굳이 GeoServer에 SLD를 기술하지 않아도 원하는 디자인을 사용할 수 있는 방법이 있는데, WMS의 요청 파라미터 중 sld_body를 활용하면 가능하다.

sld_body에 SLD를 직접 입력하면, 해당 SLD를 우선으로 적용한다. 파라미터의 내용은 SLD 그대로를 입력한다.



6. Map 만들기 🔗

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

TYPESCRIPT

0import Map from 'ol/Map';
1import { ImageWMS } from 'ol/source';
2import ImageLayer from 'ol/layer/Image';
3import View from 'ol/View';
4import proj4 from 'proj4';
5
6// WMS 소스 객체
7const source = new ImageWMS({
8 url: 'https://example.com/geoserver/wms',
9 params: {
10 layers: 'test:building',
11 exceptions: 'application/json'
12 },
13 serverType: 'geoserver'
14});
15
16// WMS 레이어 객체
17const layer = new ImageLayer({
18 source: source,
19 minZoom: 15,
20 properties: { name: 'wms' },
21 zIndex: 5
22});
23
24// 뷰 객체
25const view = new View({
26 projection: 'EPSG:3857',
27 center: proj4('EPSG:4326', 'EPSG:3857', [ 127.28923267492068, 36.48024986578043 ]),
28 zoom: 17
29});
30
31// 맵 객체
32const map = new Map({
33 layers: [ vworldBaseLayer, vworldHybridLayer, wfsLayer ],
34 target: 'map',
35 view: view
36});
Name Type Default Description
controls ol/Collection-Collection<ol/control/Control-Control> | Array<ol/control/Control-Control> | undefined ol/control/defaults 지도 컨트롤 객체
pixelRatio number window.devicePixelRatio 기기 픽셀 비율
interactions ol/Collection-Collection<ol/interaction/Interaction-Interaction> | Array<ol/interaction/Interaction-Interaction> | undefined
keyboardEventTarget HTMLElement | Document | string | undefined 키보드 이벤트 대상 요소
layers Array<ol/layer/Base-BaseLayer> | ol/Collection-Collection<ol/layer/Base-BaseLayer> | ol/layer/Group-LayerGroup | undefined 레이어 목록. 배열 뒤에 있을 수록 우선순위가 높아짐
maxTilesLoading number 16 동시 로드 가능한 최대 타일 수
moveTolerance number 1 지도 이동 이벤트로 인식하기 위해 마우스가 움직여야할 최소 픽셀
overlays ol/Collection-Collection<ol/Overlay-Overlay> | Array<ol/Overlay-Overlay> | undefined 지도 오버레이 객체
target HTMLElement | string | undefined 지도를 표시할 DOM 혹은 DOM 아이디
view ol/View-View | Promise<ol/View-View> | undefined 지도 뷰 객체

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

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

WMS로 호출한 이미지가 지도에 표시되는 것을 확인할 수 있다.



6-1. WMS 호출 방식 🔗

OpenLayers에서 제공하는 WMS 호출 방식에는 두 가지가 존재한다. 현재 영역의 전체 이미지를 불러오는 Image 방식과, 여러 격자로 쪼개서 불러오는 Tile 방식이 있다.

이 장에서는 현재 영역의 전체 이미지를 호출하는 Image 방식을 기술했다.

만약, 타일 형태로 WMS를 호출하고 싶다면, TileWMSTileLayer를 사용하면 된다. 사용법은 동일하다. 이 장에서 설명한 코드를 기준으로 ImageWMSTileWMS로 바꾸기만 해도 이상이 없는 수준. TileLayer도 마찬가지.


image

두 방식의 차이를 도식화하면 위 그림과 같다. 배경지도 또한 TileWMS 방식을 사용한다.

  • Image 방식

    • WMS 호출이 한 번만 가므로, 요청 수를 줄일 수 있다.
    • 응답 하나의 용량이 상대적으로 크며, 속도가 느리다.
  • Tile 방식

    • Image 방식 대비 WMS 호출 요청이 훨씬 많아진다.
    • 작은 이미지를 여러개 호출하므로, 상대적으로 속도가 빠르다.

차이를 확인하고, 자신의 서비스에 더 적합한 방식을 채택하면 된다.

배경 지도 또한 일종의 TileWMS와 같다.




예제 확인하기 🔗

image

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


GeoServer를 통해 공간정보 데이터를 호출하여, OpenLayers가 지도에 렌더링하는 걸 확인할 수 있다.