[OpenLayers3] 코드로 도형 그리기

ol3에서 코드를 통해 도형을 지도에 생성하고자 할 때 사용하는 API를 정리해 봅니다. 먼저 아래의 지도 웹 화면은 총 4개의 Feature를 벡터 레이어에 추가해 표시하고 있습니다. 즉, 텍스트 스타일의 포인트 피쳐, 이미지 스타일의 포인트 피쳐, 폴리라인 피쳐, 폴리곤 피쳐입니다. 피쳐는 1700cc죠? 여기서 각 피쳐를 마우스로 클릭하면 피쳐에 대해 미리 저장해둔 속성값을 alert 창으로 표시해 줍니다. 참고로 Feature는 좌표 데이터와 속성 데이터를 함께 갖는 개념의 데이터랍니다.

자, 이제 위의 지도 페이지에 대한 코드를 살펴보겠습니다. 먼저 필요한 CSS와 js 라이브러리를 포함하는 코드입니다.




다음으로 UI에 대한 코드를 살펴 보겠습니다. 지도가 표시되는 div가 있고, 이 div에 대한 크기를 css로 지정하고 있습니다.




    

이제 다음은 스크립트 코드에 대해 살펴볼텐데요. 먼저 웹 페이지의 모든 css 및 외부 라이브러리 로딩과 UI가 준비되었을 때 호출되는 jQuery의 ready 이벤트를 아래처럼 만들어 둡니다.


위의 코드 중 … 부분에 앞으로 더 많은 코드를 추가할 것인데요. Feature를 추가할 수 있는 레이어를 위한 데이터 소스는 ol.source.Vector입니다. 또한 이 소스를 통해 생성할 수 있는 레이어는 ol.layer.Vector이구요. 아래의 코드처럼 필요한 벡터 소스와 레이어에 대한 객체를 생성합니다.

var vectorSource = new ol.source.Vector();
var vectorLayer = new ol.layer.Vector({ source: vectorSource });

위에서 생성한 레이어는 지도에 추가되어야 합니다. 아래 코드의 6번째 줄을 보면 앞서 생성해 둔 레이어 객체 변수가 보입니다.

var map = new ol.Map({
    layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM()
        }),
        vectorLayer
    ],
    
    target: 'map',
    
    controls: ol.control.defaults({
        attributionOptions: ({
            collapsible: false
        })
    }),

    view: new ol.View({
        center: [14827315, 4785815],
        zoom: 5
    })
});

위의 코드를 좀더 살펴보면, 지도 객체의 생성을 위해 ol.Map의 생성자를 호출하고 있는데요. 이 생성자에서 받는 옵션 객체를 보면 layers 키 값으로 Open Street Map 레이어와 앞서 만들어 둔 벡터 레이어를 지정해 레이어를 구성하고 있습니다. 그리고 9번의 target은 지도 표시될 div의 id이구요. 17번은 초기에 지도가 표시될 좌표와 줌 레벨값을 지정하고 있습니다.

다음으로 4개의 Feature를 추가하는 사용자 정의 함수를 어래처럼 호출합니다.

addImagePoint(vectorSource);
addTextPoint(vectorSource);
addPolyline(vectorSource);
addPolygon(vectorSource);

먼저 addImagePoint 함수를 살펴보면 다음과 같습니다.

function addImagePoint(/* ol.source.Vector */ src) {
    var feature = new ol.Feature(
        {
            geometry: new ol.geom.Point([14827315, 4785815])
        }
    );

    var style = new ol.style.Style({
        image: new ol.style.Icon({
            src: 'http://www.gisdeveloper.co.kr/images/kochu.png',
            scale: 0.7,
        })
    });

    feature.setStyle(style);
    feature.set('name', '이미지 포인트 Feature');

    src.addFeature(feature);
}

Feature의 정의는 3가지가 필요합니다. 하나는 도형, 즉 지오메트리(Geometry)의 좌표값이고 이 도형을 그리기 위한 스타일이며, 마지막으로 속성값의 지정입니다. 2-6번 코드가 포인트 지오메트리의 좌표값을 지정하는 코드이며, 8~13번은 해당 포인트를 화면에 표시할때 이미지 스타일 객체를 생성하는 코드입니다. 그리고 15번의 setStyle을 통해 스타일을 지정합니다. 그리고 16번은 속성을 key 값과 value 값을 통해 지정합니다. 이렇게 생성된 피쳐는 벡터 레이어의 소스에 addFeature 함수를 통해 18번 코드처럼 추가됩니다.

나머지 3개에 대한 함수에 대한 코드는 아래와 같습니다.

function addPolygon(/* ol.source.Vector */ src) {
    var feature = new ol.Feature({
        geometry: new ol.geom.Polygon(
            [
                [
                    [13768449, 4871327],
                    [14556056, 5287144],
                    [14445986, 4166883],
                    [13995925, 3861135],
                    [13768449, 4871327],
                ]
            ]
        )
    });

    var style = new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: 'blue',
            width: 3
        }),
        fill: new ol.style.Fill({
            color: 'rgba(0,0,255,0.6)'
        })
    });

    feature.setStyle(style);
    feature.set('name', '폴리곤 Feature');

    src.addFeature(feature);
}

function addPolyline(/* ol.source.Vector */ src) {
    var feature = new ol.Feature({
        geometry: new ol.geom.LineString([
            [16030985, 5565986],
            [15480638, 4318534],
            [14384837, 3780417],                            
        ])
    });

    var style = new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: 'red',
            width: 4
        })
    });

    feature.setStyle(style);
    feature.set('name', '폴리라인 Feature');

    src.addFeature(feature);
}

function addTextPoint(/* ol.source.Vector */ src) {
    var feature = new ol.Feature({
        geometry: new ol.geom.Point([13778283, 4331832])
    });

    var style = new ol.style.Style({
        text: new ol.style.Text({
            text: "ol3",
            scale: 2,
            offsetY: 0,
            stroke: new ol.style.Stroke({
                color: 'black',
                width: 1
            }),
            fill: new ol.style.Fill({
                color: 'yellow'
            })
        })
    });

    feature.setStyle(style);
    feature.set('name', '텍스트 포인트 Feature');

    src.addFeature(feature);
}

각 함수를 보면 도형의 형태에 따른 지오메트리의 타입과 해당 좌표값의 지정에 대한 형태만 다르고 스타일이나 속성값을 지정하는 형태는 유사합니다. 여기서는 지오메트리에 대해 Point과 Polyline에 대한 LineString 그리고 Polygon 만을 언급하였는데요. 이외에도 MultiLineString, MultiPolygon, MultiPoint 등도 있습니다.

이제 끝으로 피쳐를 마우스로 클릭하면 해당 피쳐에 대한 속성값을 표시하는 코드를 살펴 보겠습니다.

map.on('singleclick', function (evt) {
    var feature = map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
        return feature;
    });

    if (feature) {
        alert(feature.get('name'));
    }
});

지도에 대한 singleclick 이벤트를 등록했고, 이 이벤트를 통해 클릭한 피쳐와 피쳐의 소속 레이어를 얻을 수 있는 forEachFeatureAtPixel 함수를 이용하고 있습니다. 앞서 피쳐를 생성할때 name이라는 키값으로 속성값을 저장해 두었는데요. 위의 코드에서 사용하고 있는 것을 볼 수 있습니다.

아래는 위에서 설명한 전체 코드에 대한 다운로드입니다.

[OpenLayers3] 마우스로 도형 그리기

OL3에서 도형을 마우스로 그리기는 코드를 정리해 봅니다. OL3에서 마우스를 이용해 도형을 그리기 위한 목적으로 사용되는 레이어가 있는데요. 바로 ol.source.Vector를 소스(source)로 갖는 ol.layer.Vector 레이어입니다. 먼저 이 글에서 만들어 볼 웹 페이지는 아래와 같습니다.

그리고자 하는 도형을 선택하고 지도 위에서 마우스로 도형을 그릴 수 있습니다. 선이나 폴리곤의 경우 Shift 키를 누른 상태에서 마우스를 드래그하면 Free-Drawing 기능처럼 자유롭게 도형을 그려나갈 수 있습니다. 위의 지도 페이지에 대한 코드를 살펴 봅시다.

먼저 필요한 CSS와 라이브러리를 웹 페이지에 포함하기 위해 다음 코드를 입력합니다.






6번의 #map은 지도를 포함하는 div의 너비와 높이에 대한 스타일 설정입니다.

다음으로 UI에 대한 코드를 살펴 보겠습니다. 지도를 위한 div와 그리고자 하는 도형을 선택할 수 있는 select 컨트롤인데요. 다음과 같습니다.

select 컨트롤에 대한 중요한 부분은 select을 구성하는 항목(option)에 대한 value 속성값인데요. 이 속성값의 문자열 값을 그리고자 하는 도형으로 지정할때 그대로 사용됩니다.

다음으로 스크립트 코드를 살펴보겠습니다. jQuery의 ready 이벤트에 필요한 코드를 모두 작성할 것인데요. jQuery의 ready 이벤트를 아래처럼 입력해 놓습니다.


위의 …. 부분에 앞으로 설명한 코드가 입력되는데요. 먼저 Open Street Map을 레이어로 추가하기 위해 raster 변수를 정의합니다.

var raster = new ol.layer.Tile({
    source: new ol.source.OSM()
});

다음으로 지도 위에 마우스로 도형을 생성하기 위한 레이어를 위해 vector라는 변수를 아래처럼 정의합니다.

var source = new ol.source.Vector({ wrapX: false });

var vector = new ol.layer.Vector({
    source: source
});

위의 코드 중 1번은 vector 레이어에서 사용할 소스를 위한 변수 정의인데요. wrapX를 false로 줌으로써 화면 상의 동일한 좌표에 대해 중복으로 도형을 표시하지 않도록 합니다.

다음으로 지도를 위한 map 변수를 정의하는 코드인데요. 앞서 만들어 둔 raster와 vector 변수를 layers 속성 지정을 위해 사용하고 있고, 지도를 표시할 div의 id를 target 속성에 지정하고 있으며, view에 화면에 표시할 초기 지도 좌표와 줌 레벨 값을 지정하고 있습니다.

var map = new ol.Map({
    layers: [raster, vector],
    target: 'map',
    view: new ol.View({
        center: [-11000000, 4600000],
        zoom: 4
    })
});

화면에 지도가 표시되고 마우스를 이용해 도형을 그릴 수 있는 레이어까지 추가해 두었습니다. 다음으로 select 컨트롤에서 지도에 그릴 도형을 선택하면 마우스를 이용해 도형을 그릴 수 있는 코드를 살펴보겠습니다.

var typeSelect = document.getElementById('type');
var draw;

typeSelect.onchange = function () {
    map.removeInteraction(draw);
    addInteraction();
};

function addInteraction() {
    var value = typeSelect.value;
    if (value !== 'None') {
        draw = new ol.interaction.Draw({
            source: source,
            type: (typeSelect.value)
        });
        
        map.addInteraction(draw);
    }
}

addInteraction();

먼저 그릴 도형을 선택할 수 있는 select 컨트롤을 어디서든 접근할 수 있도록 1번 코드에서 typeSelect 변수에 select 컨트롤을 id로 얻어 받아 둡니다. 그리고 2번에 draw 변수가 있는데요. 이 draw 변수는 우리가 선택한 도형을 그리기(Draw) 위한 사용자와의 상호작용(Interaction)에 대한 객체를 생성해 두고 지도 객체에 addInteraction 함수를 통해 추가하면 그리기 상호작용이 작동되며 필요한 때에 다시 removeInteraction 함수를 통해 제거하면 상호작용을 제거 할 수 있습니다. 4번 코드는 select 컨트롤에 대한 선택 항목이 변경될때 호출되는 이벤트인데요. 5~6번의 실행 코드를 보면 먼저 기존의 상호작용 객체를 제거하고 다시 addInteraction이라는 사용자 정의 함수를 호출하여 상호작용 객체를 추가해 줍니다. 9번에 addInteraction 함수의 정의가 있는데요. 선택 항목의 value 속성이 None이 아닌 경우에 12번 코드를 통해 ol.interaction.Draw 클래스 객체를 생성합니다. ol.interaction.Draw 객체를 생성할때 인자는 어떤 레이어의 소스에 사용자가 그릴 도형이 저장될지(source)와 도형의 타입(type)을 지정합니다. 이렇게 생성된 그리기 상호작용 객체를 17번에서 지도에 추가하면 바로 지도 상에 도형을 그릴 수 있게 됩니다. 마지막으로 21번에서 addInteraction 함수를 직접 호출해서 웹 페이지가 처음 뜰때 바로 도형을 그릴 수 있게 합니다.

아래는 위에서 설명한 전체 코드에 대한 다운로드입니다.

[OpenLayers3] ArcGIS Tiled REST MapService 사용하기

OpenLayers는 ESRI의 ArcGIS 서버에서 제공하는 다양한 지도 서비스를 활용할 수 있는데요. 그 중 Tiled REST MapService를 하나의 레이어로 추가해 보는 예제를 살펴보겠습니다. 아래의 페이지는 오픈 스트리트맵을 첫번째 레이어로 하고, 그 위에 ArcGIS의 REST MapService에서 제공하는 레이어를 중첩하였습니다.

위의 페이지에 대한 코드를 살펴보겠습니다. 먼저 필요한 라이브러리와 스타일시트에 대한 링크입니다.




그리고 UI인데요. 앞서 실행 페이지를 보면 지도 하나만 똭! 있습니다. 즉, 아래처럼 div 태그 하나만 있습죠.


    

자, 이제 이 div에 걸 마술의 주문 코드를 살펴보겠습니다.


주요 코드만을 설명드리면, 먼저 ArcGIS MapService에서 제공하는 서비스 URL이 필요한데요. 우리가 ArcGIS를 설치하고 지도를 설정할 시간이… 못하는게 절대 아니고 시간이 없으므로 ArcGIS Online에서 제공하는 URL을 사용하겠는데, 바로 3번 코드의 url 변수에 할당된 문자열이 ArcGIS Online에서 제공하는 url입니다. 이 url 변수는 10번 코드에서 ol.layer.Tile 객체를 생성하는데 사용되는데요. 보다 정확히는 이 ol.layer.Tile 객체에 데이터를 제공하는 소스(source) 생성을 위한 ol.source.TileArcGISRest 객체 생성을 위한 url 인자의 값으로 사용됩니다. 참고로 ol.layer.Tile 객체의 생성시 11번 코드의 extent는 해당 레이어의 렌더링 범위로, 이 범위를 벗어나는 경우 렌더링을 하지 않습니다. 이 extent는 옵션으로 지정하지 않아도 되며, 지정하지 않으면 범위에 따른 렌더링 여부를 결정하지 않고 항상 렌더링하려고 합니다.

아래는 위에서 설명한 전체 코드에 대한 다운로드입니다.

[OpenLayers3] CartoDB 사용하기

OpenLayers는 CartoDB를 데이터소스로 사용해 지도로 가시화할 수 있습니다. CartoDB는 PostgreSQL이라는 DBMS를 공간 데이터 저장소로 사용하며 PostGIS를 이용해 공간 연산을 처리해 사용자에게 GeoJSON과 같은 형식으로 공간 데이터를 서비스합니다. 공간 데이터가 DBMS에 있으므로 사용자는 직접 SQL 문을 OpenAPI의 파라메터로 던져 주고, 그 결과를 받아 해석해 사용자가 원하는 스타일로 지도를 그릴 수 있습니다.

아래의 실행 결과는 이 글을 통해 작성한 코드로 CartoDB에서 유럽에 대한 공간 데이터를 가져오는데요. 면적에 대한 조건을 SQL의 WHERE 절에 지정함으로써 필터링을 하고 있습니다.

자, 이제 위의 결과에 대한 코드를 작성해 보도록 할깝 show~!

먼저 아래코드를 통해 OpenLayers에 대한 CSS와 라이브러리 js 파일, 그리고 jQuery 라이브러리를 문서에 추가합니다.




다음으로 UI를 구성할 건데요. 지도를 표시할 div과 면적에 대한 조건을 선택할 수 있는 form을 아래처럼 추가합니다.


    

UI 작성이 끝났으므로, 이제 작동을 위한 스크립트를 jQuery의 ready 이벤트에 작성합니다. jQuery의 ready 이벤트는 아래와 같죠.

$(function () {
    ....
});

위의 코드 중 …에 해당하는 부분에 아래부터 언급되는 코드를 순서대로 입력합니다. 순서대로 입력하는 코드를 하나 하나 설명드리겠습니다. OpenLayers는 레이어에 대한 데이터를 가져오는 곳을 소스(source)라고 하는데요, 먼저 cartoDB에 대한 데이터소스의 객체를 아래처럼 생성해야 합니다.

var mapConfig = {
    'layers': [{
        'type': 'cartodb',
        'options': {
            'cartocss_version': '2.1.1',
            'cartocss': '#layer { polygon-fill: #F00; ' +
                        'polygon-opacity: 0.75; ' +
                        'line-width: 1; ' + 
                        'line-color: #ff0;}',
            'sql': 'select * from european_countries_e where area > 0'
        }
    }]
};

var cartoDBSource = new ol.source.CartoDB({
    account: 'documentation',
    config: mapConfig
});

15번 코드가 CartoDB에 대한 소스 객체를 생성하고 있는데요. 소스 객체 생성을 위한 구성값을 1~13번 코드를 통해 작성합니다. CartoDB의 소스 객체를 위한 구성값은 레이어의 그룹인데, 위의 코드는 1개의 레이어를 사용했으며 이 레이어를 화면에 그릴때 사용하는 채움색과 투명도 그리고 외곽선색 및 굵기를 cartocss라는 key 값으로 지정하고 있고, sql이라는 key 값을 통해 CartoDB의 서버에게 가져올 공간 데이터에 대한 SQL 쿼리문을 지정하고 있습니다.

이제 다음은 OpenLayers의 Map 객체를 생성하는 코드입니다.

var map = new ol.Map({
    layers: [
        new ol.layer.Tile({ source: new ol.source.OSM() }),
        new ol.layer.Tile({ source: cartoDBSource })
    ],
    target: 'map',
    view: new ol.View({
    center: [0, 0],
    zoom: 2
    })
});

Open Street Map에 대한 Tile 레이어와 함께 4번에서 앞서 이미 만들어 둔 CartoDB의 소스 객체를 통해 또 하나의 Tile 레이어를 구성합니다.

끝으로 사용자가 조건을 변경할 수 있는 컴보박스의 선택값을 변경할때 해당 조건에 대해 CartoDB의 서버에 재요청을 해야 하는데요. 아래의 코드가 바로 이에 해당합니다.

function setArea(n) {
    mapConfig.layers[0].options.sql =
        select * from european_countries_e where area > ' + n;

    cartoDBSource.setConfig(mapConfig);
}

$('#country-area').on('change', function () {
    setArea(this.value);
});

이제 실행해 보면 해당 조건, 즉 면적에 대한 조건과 일치하는 유럽의 나라만 그려지는 것을 볼 수 있습니다.

아래는 위에서 설명한 전체 코드에 대한 다운로드입니다.