[OpenLayers3] 히트맵(HeatMap)

ol3에서 포인트 데이터를 받아 포인트 데이터가 많이 모여 있는 곳을 효과적으로 시각화 해주는 히트맵에 대한 예를 살펴 보겠습니다. 먼저 히트맵에 대해 구현하고조 하는 결과를 아래의 웹 페이지에서 먼저 확인해 봅시다.

위의 실행 결과는 지진이 발생하 지점을 히트맵으로 표시하는 것인데요. 지진 발생이 밀집된 곳은 빨간색으로 표시됨으로써 지진 발생 빈도가 많은 지점을 시각적으로 빠르고 효과적으로 판단할 수 있습니다. 히트맵 결과를 얻기 위해서는 포인트 데이터뿐만 아니라 반경 크기(Radius Size)나 블러링 크기(Blur Size) 값이 필요합니다. 각각의 포인트 지점에서 주어진 반경 크기 안에 포함되는 다른 포인트를 찾아 히트맵의 결과에 반영함으로 반경 크기가 클수록 더 많은 포인트가 그 결과에 반영됨으로써 빨간색의 결과가 더 많이 표시됩니다. 그리고 블러링 크기가 클수록 색상으로 더 흐리게 표시하게 됩니다.

자, 이제 위의 웹페이지에 대한 코드를 살펴볼텐데요. 먼저 필요한 외부 CSS와 스크립트를 포함합니다.




OpenLayers3에 대한 CSS와 js 파일 및 jQuery에 대한 js 파일이 포함되었습니다. 다음은 UI에 대한 코드입니다.

지도가 표시될 div 요소가 있는데, id가 map으로 지정되어 있구요. 히트맵을 위한 입력값을 위한 input 요소가 2개가 있으며 각각에 대한 id를 radius와 blur로 지정되어 있습니다. 이 input 요소는 앞서 설명드렸듯이 각각 검색 반경 크기와 블러링 크기값으로 사용됩니다. 이제 UI에 영혼을 불어 넣을 스크립트를 살펴보겠습니다.

먼저 jQuery의 ready 이벤트를 아래처럼 준비해 둡니다.


위의 …. 부분에 코드를 추가할 것인데요. jQuery의 ready 이벤트는 웹페이지에 대한 모든 준비가 끝났을때 호출됩니다.

먼저 히트맵 표시를 위한 검색반경 및 블러링 크기값을 UI로 부터 얻기 위한 객체를 미리 정의합니다.

var blur = $('#blur');
var radius = $('#radius');

히트맵도 레이어의 종류 중 하나인데요. 다음처럼 히트맵을 위한 레이어 변수를 정의합니다.

var vector = new ol.layer.Heatmap({
    source: new ol.source.Vector({
        url: 'https://openlayers.org/en/v3.19.1/examples/data/kml/2012_Earthquakes_Mag5.kml',
        format: new ol.format.KML({
            extractStyles: false
        })
    }),
    blur: parseInt(blur.val(), 10),
    radius: parseInt(radius.val(), 10),                
    weight: function (feature) {
        var magnitude = parseFloat(feature.get('magnitude'));
        return magnitude - 5;
    }
});

히트맵을 위해 포인트 데이터를 입력 받아야 하는데요. 이를 위해 데이터 소스가 필요합니다. 2번 코드에 ol.source.Vector 클래스로 데이터 소스 객체를 생성하는데.. 실제 데이터 경로를 3번 코드에서 url 문자열로 지정하고 있고, 이 url에서 받는 리소스의 형식은 4번 코드를 통해 지정합니다. 그리고 히트맵의 블러링 크기와 검색 반경의 크기 지정을 위해 각각 8번과 9번에서 지정하고 있습니다. 또한 옵션으로 가중치값을 10번 코드에서 지정하고 있는데요. 함수 형태로 각 포인트에 대한 가중치 값을 계산할 수 있는 함수를 지정할 수 있는데, 가중치의 값이 범위가 0~1 이므로 이 함수 역시 0~1 사이의 값으로 떨어지도록 반환해야 합니다. 위의 코드는 포인트에 대한 속성값 중 maginitude 값을 얻어 이 값에 5를 뺀값으로 하고 있습니다. kml 데이터를 보면 모든 포인트의 magnitude 값은 5~6 사이의 소수값이므로 5를 빼면 0~1사이의 값이 됩니다.

다음은 히트맵 밑에 표시될 배경맵으로 Stamen 서비스 중 toner 레이어에 대한 객체 정의입니다.

var raster = new ol.layer.Tile({
    source: new ol.source.Stamen({
        layer: 'toner'
    })
});

이제 히트맵에 대한 레이어와 배경맵에 대한 레이어 객체가 준비되었으므로, 지도 객체를 생성하고 이 두개의 레이어를 추가해 히트맵과 배경맵을 원하는 div에 표시합니다. 아래의 코드를 통해서 말입니다.

var map = new ol.Map({
    layers: [raster, vector],
    target: 'map',
    view: new ol.View({
        center: [13527858.897415451, 1822818.8878542576],
        zoom: 3
    })
});

2번 코드가 앞서 정의해둔 2개의 레이어 객체에 대한 추가이고, 3번은 지도를 표시할 div의 id이며, 4번은 처음 지도가 표시될 좌표와 줌 레벨값입니다.

이제 마지막으로 검색 반경과 블러링 크기를 설정할 수 있는 input UI에 대해 change 이벤트를 지정해서 사용자가 설정값을 변경하면 바로 지도에 반영될 수 있도록 합니다.

radius.on('change', function () {
    vector.setRadius(parseInt(radius.val(), 10));
});

blur.on('change', function () {
    vector.setBlur(parseInt(blur.val(), 10));
});

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

[OpenLayers3] WFS 벡터 레이어에 라벨 표시하기

이 글은 “[OpenLayers3] WFS를 이용한 벡터 레이어”에서 속성 데이터를 이용해 라벨을 표시하는 방법을 설명합니다. 실행 결과는 아래의 웹 페이지와 같습니다.

“[OpenLayers3] WFS를 이용한 벡터 레이어”의 글을 충분히 이해하고 앞으로 설명할 코드로 수정하기 바랍니다.

WFS에 의한 벡터 데이터 소스 객체를 이용해 벡터 레이어를 생성하는 코드 중 minResolution과 maxResolution 속성값을 아래처럼 추가하고 style을 getStyle이라는 사용자 정의 함수로 변경합니다.

var vector = new ol.layer.Vector({
    source: vectorSource,
    style: getStyle,
    minResolution: 0,
    maxResolution: 12
});

위의 코드 중 3번의 style 속성에 getStyle 함수로 대체 되었습니다. 그리고 minResolution과 maxResolution 속성값을 0과 12로 지정했는데요. 지도의 해상도 값이 이 minResolution과 maxResolution 속성값의 범위에 있을 때만 WFS 레이어가 표시되라는 의미입니다. 중요한 것은 style 속성에 지정된 getStyle 함수입니다. 이 함수는 다음과 같습니다.

function getStyle(feature, resolution) {
    var style = new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: 'rgba(255, 255, 0, 1.0)',
            width: 4
        }),
        fill: new ol.style.Fill({
            color: 'rgba(255,0,0,0.4)'
        }),
        text: new ol.style.Text({
            font: '12px Verdana',
            scale: 2,
            text: getLabelText(feature),
            fill: new ol.style.Fill({ color: 'red' }),
            stroke: new ol.style.Stroke({ color: 'yellow', width: 3 })
        })
    });

    return style;
}

기존에 style 속성에는 바로 ol.style.Style 타입의 객체를 생성했었지만, 이 글에서는 getStyle이라는 사용자 정의 함수로 변경되었습니다. 이 함수는 2개의 인자를 받습니다. 첫번째 인자인 feature는 스타일을 적용할 도형에 대한 feature와 현재의 지도 축척값을 화면 단위로 변경한 값인 resolution입니다. 라벨을 표현하고자 할때는 10번의 text 속성값을 갖도록 ol.style.Style 객체를 생성해 함수에서 반환하면 되는데요. text 속성에는 라벨의 폰트과 글자 크기 및 텍스트의 채움색과 외곽선 스타일을 지정할 수 있습니다. 중요한 것은 라벨을 표시할 속성값의 지정인데요. 바로 13번 코드의 text 속성에 getLabelText라는 또 다른 사용자 정의 함수를 사용하고 있으며 다음과 같습니다.

function getLabelText(feature) {
    var text = feature.get('name');
    if (text) {
        return text;
    } else {
        return '';
    }
}

위의 함수는 feature 라는 라벨을 적용하고자 하는 피쳐 객체를 인자로 받습니다. 이 피쳐에서 name이라는 속성값을 얻어와 이 값이 undefined이나 null인 경우에 빈 문자열을 반환하고, 그렇지 않은 경우에는 name에 해당하는 속성값에 대한 문자열을 그대로 반환하므로써 표시할 라벨에 대한 문자열 값을 지정할 수 있습니다.

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

[OpenLayers3] WFS를 이용한 벡터 레이어

WFS는 Web Feature Service로 Feature는 도형과 속성을 가진 데이터 단위입니다. WFS를 지원하는 공간 서버를 통해 도형의 구성 좌표와 속성 데이터를 가져오고 이런 데이터를 클라이언트에서 받아 화면에 그릴 수 있는데요. 이에 대해 ol3에서 어떻게 처리하는지 살펴보도록 하겠습니다. 먼저 우리가 만들 최종 결과 지도 웹 페이지는 아래와 같습니다.

오픈 스트리트 맵을 배경지도 레이어로 사용 되고 있고, 벡터 레이어를 통해 WFS로 받은 도형이 노란색 외곽선과 반투명한 빨간색의 채움 스타일로 그려지고 있습니다. 위의 웹 페이지에 대한 구현 코드를 살펴보겠는데요. 먼저 필요한 외부 CSS와 자바스크립트 라이브러리를 페이지에 포함하는 코드입니다.

    
    
    

다음은 UI에 대한 태그입니다.

위의 div는 다음과 같은 크기에 대한 스타일이 지정되어 있습니다.


이제 필요한 라이브러리와 스타일, 그리고 UI는 준비가 되었는데요. 이 UI가 작동할 수 있도록 스크립트 코드를 작성하겠습니다. 먼저 jQuery의 ready 이벤트 함수를 아래처럼 미리 추가해 둡니다.


이제 위의 ….에 해당하는 부분에 스크립트 코드를 추가해 보도록 하겠습니다. 먼저 WFS를 이용해 데이터를 받을 벡터 레이어의 소스 객체를 아래처럼 생성합니다.

var vectorSource = new ol.source.Vector({
    format: new ol.format.GeoJSON(),
    url: function (extent) {
        var strUrl = 'https://ahocevar.com/geoserver/wfs?service=WFS&' +
            'version=1.1.0&request=GetFeature&typename=osm:water_areas&' +
            'outputFormat=application/json&srsname=EPSG:3857&' +
            'bbox=' + extent.join(',') + ',EPSG:3857';

        return strUrl;
    },
    strategy: ol.loadingstrategy.bbox
});

WFS 방식을 통해 공간서버에 Feature 데이터를 요청할 수 있는데요. WFS는 요청받은 데이터를 XML이나 JSON과 같은 형식으로 결과를 클라이언트에게 전달합니다. 또한 WFS는 URL 호출 방식으로 Feature 데이터를 요청합니다. 바로 3번의 url 속성이 WFS를 URL로 호출할때 사용하는 url 문자열입니다. https://ahocevar.com/geoserver/wfs 까지가 WFS 서비스를 제공하는 서버의 주소이고, 이후 ? 다음이 WFS 서비스 호출시 전달하는 인자값들입니다. 각 인자값은 다음과 같습니다.

  1. service=WFS
  2. version=1.1.0
  3. request=GetFeature
  4. typename=osm:water_areas
  5. outputFormat=application/json
  6. srsname=EPSG:3857
  7. bbox=100,100,200,200,EPSG:3857

1번은 해당 URL 요청이 WFS 서비스라는 의미이고, 2번은 WFS의 버전을 의미하며, 3번은 WFS 기능 중 Feature 정보를 얻기 위한 GetFeature 기능에 대한 호출의 의미이고, 4번은 WFS에 의해 서비스 되는 공간 데이터 이름이고, 5번은 결과의 형식을 JSON 포맷으로 전달해줄 것에 대한 내용이며, 6번은 결과에 대한 좌표 체계를 무엇으로 할 것인지를 지정하는 것입니다. 끝으로 7번은 Feature를 조회할 좌표 범위인데요. 100,100,200,200,EPSG:3857은 최소 X 좌표값, 최소 Y 좌표값, 최대 X 좌표값, 최대 Y 좌표값, 좌표값의 좌표체계을 의미하며 해당 좌표체계로 지정된 좌표계 범위(Bounding Box)에 포함되는 Feature를 조회하라는 의미입니다.

레이어를 위한 데이터 소스가 준비되었으므로 레이어 객체를 생성할 수 있는데요. 해당 코드는 아래와 같습니다.

var vector = new ol.layer.Vector({
    source: vectorSource,
    style: new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: 'rgba(255, 255, 0, 1.0)',
            width: 4
        }),
        fill: new ol.style.Fill({
            color: 'rgba(255,0,0,0.4)'
        })
    })
});

WFS 서비스를 위한 레이어는 ol.layer.Vector 타입에 대한 객체인데요. 이 객체의 생성을 위해 낲서 생성한 데이터 소스 객체인 vectorSource 변수를 생성자의 source 속성에 지정하고 style 속성에는 도형을 그릴때 사용할 수 있는 외곽선 스타일과 채움 스타일을 지정합니다.

다음은 WFS에 의한 벡터 레이어 밑에 배경맵으로 사용할 오픈 스트리트 맵에 대한 레이어 객체의 생성입니다.

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

이제 끝으로 앞서 생성한 2개의 레이어 객체, 즉 WFS에 의한 벡터 레이어와 오픈 스트리트 맵에 대한 레이어로 구성된 지도 객체를 생성합니다.

var map = new ol.Map({
    layers: [raster, vector],
    target: 'map',
    view: new ol.View({
        center: [-8910887.277395891, 5382318.072437216],
        maxZoom: 19,
        zoom: 15
    })
});

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

[OpenLayers3] 지도 상에 팝업 정보창 표시

ol3에서 지도 상의 특정한 좌표 지점에 팝업창을 표시하여 해당 지점과 관련된 정보를 표시하는 기능에 대한 API를 살펴 보겠습니다. 먼저 아래의 웹 페이지에 표시된 지도를 클릭하면 클릭된 지점에 대한 경위도 좌표계를 도분초로 표시하는데요. 한번 확인해 보시기 바랍니다.

위의 지도 상의 팝업에 대한 기능을 구현하는 코드를 하나 하나 살펴 보겠습니다. 먼저 필요한 외부 CSS와 스크립트를 아래처럼 추가합니다.




다음은 필요한 UI에 대한 태그인데요. ol3에서는 팝업창에 대한 구체적인 UI에 대해 ol3 엔진단에서 제공하는 것이 아니고 개발자가 직접 제공해야 합니다. 팝업창을 구성하는 닫기 버튼이라든지, 실제 내용이 표시되는 div 영역이라든지 말입니다. 아래는 UI에 대한 태그입니다.

id가 map인 div에 지도가 표시됩니다. 그리고 id가 popup인 div가 실제 팝업창인데요. 이 div 내부에는 다시 id가 popup-closer이라는 a 태그가 있고, id가 popup-content인 div가 있습니다. popup-closer인 a 태그는 팝업을 닫는 버튼으로 사용되고, popup-content인 div는 팝업의 내용을 채울 컨테이너로 사용됩니다. 이제 각 UI에 대한 지정된 스타일에 대한 코드를 살펴 봅시다.