본문 바로가기

JAVASCRIPT

Leaflet과 OSM Building으로 3D 구현

Leaflet + OSM Building


Leaflet은,

오픈소스 자바스크립트 라이브러리이고 모바일 프렌들리한 맵입니다.

맵이구요. 오픈레이어스나 여타 GIS 보다 속도가 빠르다라는 얘기들이 종종있습니다. 

모든 사이트 테스트탑이나 모바일 플렛폼에 적합하고 확장된 많은 플러그인을 제공합니다. 실제로 쓸만한 플러그인이 몇개 있더라구요.

모든 브라우저에 적용가능하면서 우리 나라에서 가장 많이 쓰는 IE에는 7-11까지 지원 가능하네요.


그럼 OSM Building은 폴리곤 정보를 가지고 맵 위에 Canvas 2D를 이용해서 3D 객체를 올릴 수 있습니다. 

OSM Building 사이트에 가면 leaflet-OSMBuilding.js라는 것 같이 이미 같이 엮어진 라이브러리까지 제공합니다.

leaflet

OSM Building


leaflet 위에 3d 객체들이 쑤욱 올라와있어요.

구현!


//리플릿 라이브러리

<script src="../js/leaflet/leaflet-src.js"></script>

//vWorld 플러그인

<script src="../js/leaflet/proj4-compressed.js"></script>

<script src="../js/leaflet/proj4leaflet.js"></script>

<script src="../js/leaflet/leaflet-providers.js"></script>

<script src="../js/leaflet/Leaflet.KoreanTmsProviders.js"></script>

//OSM 빌딩 with leaflet

<script src="../js/leaflet/osm/OSMBuildings-Leaflet.debug.js"></script>

//내가 사용할 geoJson

<script type="text/javascript" src="korea-geojson_4.js"></script>

geoJson 데이터를 만드는거는 이전 블로그에서 참고하면 됨.


스타일

<style>

/* 폴리곤 영역 스타일 지정 */

#map {

width:500px;

height:500px;

}

/* 마우스 오버 시 표출 말 풍선 스타일  */

.info {

padding: 6px 8px;

font: 16px/18px Arial, Helvetica, sans-serif;

background: rgba(255,255,255,0.8);

box-shadow: 0 0 15px rgba(0,0,0,0.2);

border-radius: 5px;

}

/* 범례 화면 정렬 스타일 */

.info h4 {

margin: 0 0 5px;

color: #777;

}

/* 범례 정렬 지정 */

.legend {

text-align: left;

line-height: 18px;

color: black;

}

/* 범례 스타일 지정 */

.legend i {

width: 18px;

height: 18px;

float: left;

margin-right: 8px;

opacity: 0.7;

}

</style>


자바스크립트

//Leaflet 맵을 써도 되나 Vworld 플러그인으로 vWorld위에 올려보기로 했음.

//그리고 맵 선언부입니다.

map = L.map('map', {

continuousWorld: true,

worldCopyJump: false,

zoomControl: true

});


참고로 

이렇게 사용해도 무방하지만 leaflet 맵을 기본으로 사용하는 방법입니다.

setView의 []안에는 lat, lon이 그리고 뒤에는 scale을 인자로 받아요.

map = new L.Map('map').setView([37.16,126.90], 11);


걍 지도를 쓸려면 위에껄 

leaflet을 사용하려면 아래껄 사용하시면 되고


vWorld를 사용하려면 아래와 같이 맵 tileLayer를 올려야 함으로 일반지도와 위성지도를 설정합니다.

baseLayers = {

'VWORLD 위성지도' : L.tileLayer.provider('VWorld.Satellite'),

'VWORLD 일반지도': L.tileLayer.provider('VWorld.Street').addTo(map),

};

그리고 각종 도로정보나 지명 정보를 레이어로 올립니다.

overlayLayers = {

'VWorld Hybrid Map' : L.tileLayer.provider('VWorld.Hybrid').addTo(map)

};


레이어 설정 정보를 addTo map을 통해 레이어에 추가 합니다.

L.control.layers(baseLayers, overlayLayers, {

collapsed: false

}).addTo(map);


여기까지 맵은 깔릴거에요.

그럼 이제 OSM Buildings를 사용해서 3D를 올려볼게요.

//아까 위에서 선언한 map 객체를 인자로 주고 OSMBuildings를 인스턴스화합니다.

//그리고 다음 줄은 건물이 올라오면 시간대별로 날자와 시간대별로 건물의 그림자까지 표현할 수 있는데 렌더링할때 조금 느려지는 것 같아서 그림자가 안나오게 설정했어요. 다른 옵션을 줘서 없애벌리 수 있는지는 모르겠네요.

//그리고 geoJson 데이터를 넘겨줍니다.

building = new OSMBuildings(map);

building.date(new Date(2015, 03, 30, 16, 0));

building.set(geojson);

//building.set은 내부에서 자동으로 reset시켜줍니다. 데이터를 다시 넣어줘야 한다면 그냥 set을 통해 넘겨주면 알아서 reset하고 다시 그려줘요.


여기까지만하면 그냥 지도위에 geojson으로 그려진 폴리곤이 3D처럼 툭 위어 올라올겁니다. geojson을 잠깐 보면

{"type":"FeatureCollection","features":[

{ "type": "Feature", "properties": { 

"code": "3124062", "name": "동탄3동", "name_eng": "Dongtan3-dong",    "centerX":"37.20876838263550", "centerY":"127.05642814049498", "color": "rgb(59,79,161,0.9)", "height":88,"density":"880"},

이렇게 되있구요. 파라미터 속성 중에

color이나 height를 통해서 이 객체의 높이와 3D 객체의 색갈을 지정할 수 있씁니다.

density는 튤팁에 표기할 데이터 그리고 centerX와 centerY는 풍선말을 올리기 위해서 박아놓은 풍선말 좌표입니다.

OSM Buildings에서 제공하는 clickable 예제도 제공하지만 실제로 해보니 잘 안되는 것 같아서 그냥 다른 방법으로 현황 정보를 올리기로 했어요.

그래서 leaflet 맵에 폴리곤을 또 그리기로 했습니다. 

geojson 정보는 같은 걸 사용해서 

geojson = L.geoJson(geojson, {

style: style,

onEachFeature: onEachFeature

}).addTo(map);


와 같이 구현합니다.onEachFeature는 각각의 폴리곤에 대한 이벤트를 말하는거구요.

onEachFeature의 구현내용을 보면

function onEachFeature(feature, layer) {

layer.on({

mouseover: highlightFeature,

mouseout: resetHighlight,

click: zoomToFeature

});

onMarker(feature);

}

mouseover 등 각각의 이벤트에 대한 메서드를 붙일 수 있어요.

style는 위에서 density 값을 통해서 폴리곤에 그려질 색상 정보를 셋팅할 수 있어요.

function style(feature) {

var color = getColor(feature.properties.density);

return {

weight: 0,

opacity: 0,

color: color,

fillOpacity: 0.1,

fillColor: color

};

}

function getColor(d) {

return d > 1100 ? '#0023BF' :

      d > 1000  ? '#089BC5' :

      d > 900  ? '#11CB85' :

      d > 800  ? '#1BD21F' :

      d > 700   ? '#8CD825' :

      d > 600   ? '#DFC130' :

      d > 500   ? '#E5623B' :

            d > 400   ? '#EB4783' :

          d > 300   ? '#F253EC' :

    d > 200   ? '#A360F8' :

  d > 100   ? '#6E85FF' :

                    '#0023BF';

}


onEachFeature에 구현된 메서드는

mouseover과 mouseout 그리고 click시 발생할 이벤트를 구현해두시면 되고 아래에 onMarker(feature); 를 통해서 각각의 폴리곤마다 풍선말을 셋팅하게 됩니다.


좌표 정보를 가져와서 셋팅해주고 레이어를 addTo map 해줍니다.

배열에 넣는 이유는 레이어를 한꺼번에 지우기 위함도 있고 저렇게 사용하는 방법 말고도 group을 맺어줘서 없애벌리 수도 있어요.

function onMarker(feature) {

var lating = L.latLng(feature.properties.centerX, feature.properties.centerY);

var popLayer = L.popup({

maxHeight:35,

closeButton:false

}).setLatLng(lating).setContent('<p>'+feature.properties.name+'<br />'+feature.properties.density+'건</p>').addTo(map);

popArr.push(popLayer);

}


그리고 마지막으로 

<div id="map"></div>

에 구현된 화면이 그려지게 됩니다. 


풍선말은 저게 기본은 아니고 leaflet.css를 좀 손봤습니다.