본문 바로가기

d3.js

Naver Maps + D3.js

지난 Google Map + D3.js에 이어 Naver Maps API를 이용하여 Naver Map과 D3.js를 연동해보자.


우선 Naver Map 객체를 생성한다.

Naver Map도 Google Map과 마찬가지로 MapOption 줌레벨, 지도유형 등을 세팅 가능하다.

자세한 사항은 여기를 참고하기 바란다.

var map = new nhn.api.map.Map('map' ,{
	point : new nhn.api.map.LatLng(37.556059, 126.91009),
	zoom : 8,
	enableWheelZoom : true,
	enableDragPan : true,
	enableDblClickZoom : false,
	mapMode : 0,
	activateTrafficMap : false,
	activateBicycleMap : false,
	minMaxLevel : [ 1, 14 ],
	size : new nhn.api.map.Size(1300, 600)
});

Map상에 표시할 정보로는 서울 열린 데이터 광장에서 서울시 도서관정보를 가져왔다.

해당 데이터는 도서관 위치정보(위도/경도), 면적, 주소, 전화번호의 컬럼으로 구성되어있다. 

var data = [{"OBJECTID":"21","GU_NM":"구로구","HNR_NAM":"구로3동","MTC_AT":"1","MASTERNO":"777","SLAVENO":"1","NEADRES_NM":"구로구 디지털로 27다길 65 2층","FCLTY_NM":"꿈마을 도서관","ORN_ORG":"구로구 시설관리공단","EBT_MAN":" ","FLY_GBN":"구립도서관","OPNNG_DE":"2007-04-05","AR":"476","HMPG_CN":"lib.guro.go.kr/dreamtown/","CTTPC_CN":"830-5807","CREAT_DE":" ","LNG":"126.8901147","LAT":"37.4872202"}, /*생략*/];

서울시 도서관정보에서 위도/경도(LNG/LAT)를 위용하여 Naver Map에 D3.js를 이용하여 circle를 표시하고자 한다. Naver Map API에서는 기본적으로 nhn.api.map.Circle를 제공한다. 여기서는 nhn.api.map.Circle를 사용하지 않고 D3.js로 직접 랜더링 해볼 것이다. circle의 사이즈는 도서관 면적(AR)을 중심점은 위도/경도를 이용할 것 이다.

var color = d3.scale.category10();
var radius = d3.scale.linear().domain([0, 3000]).range([10, 50]);

서울시 구별로 색상을 달리하기위한 color함수와 도서관 면적 사이즈를 적용하기 위한 radius함수를 정의하였다.

radius함수에서 domain은 도서관 면적의 min/max값이며 range는 10~50으로 설정하였다.

var layer = d3.select('.nmap_drawing_pane').append("div").attr("class", "library");

도서관 정보를 표시하고자 하는 div element을 nmap_drawing_pane에 append해준다.(nmap_overlay_pane도 가능)


Naver Map Rendering Element


var padding = 50,
	pluspadding = 1;
					
var marker = layer.selectAll("svg")
	.data(d3.entries(data))
	.each(transform)
	.enter().append("svg:svg")
	.each(transform)
	.attr("class", "marker");
					
marker.append("svg:circle")
	.attr("r", function(d){return radius(d.value.AR) >= 50 ? 50 : radius(d.value.AR);})
	.attr("cx", function(d){return padding;})
	.attr("cy", function(d){return padding;})
	.style("fill", function(d,i){return color(d.value.GU_NM);})
	.attr("fill-opacity", "0.7")
	.on("click",function(d){ alert(d.value.FCLTY_NM); map.setCenter(new nhn.api.map.LatLng(d.value.LAT, d.value.LNG)); });
					
marker.append("svg:text")
	.attr("x", function(d){return padding;})
	.attr("y", function(d){return padding;})
	.attr("dy", ".31em").style("text-anchor", "middle")
	.text(function(d) { return d.value.LNG > 0 ? d.value.HNR_NAM : ""; });

여기까지는 특별할게 없다. 서울시 도서관정보를 토대로 D3.js를 이용하여 circle를 랜더링하는 소스이다.

아래 transform 함수에서 서울시 도서관 위치정보를 토대로 Naver Map상에 표시해준다.

function transform(d) {
	var r = radius(d.value.AR) >= 50 ? 50 : radius(d.value.AR);
	LatLng = new nhn.api.map.LatLng(d.value.LAT, d.value.LNG);
						
	var oSize  = new nhn.api.map.Size(28, 37); 
	var oOffset = new nhn.api.map.Size(28, 37); 
	var oIcon  = new nhn.api.map.Icon('http://static.naver.com/maps2/icons/pin_spot2.png', oSize, oOffset); 
					    
	var oMarker = new nhn.api.map.Marker(oIcon, { title : d.value.FCLTY_NM }); 
	oMarker.setPoint(LatLng);
						
	map.addOverlay(oMarker);
	oMarker.setVisible(true);
						
	return d3.select(this)
		.style("left", (parseInt(d3.select(oMarker)[0][0]["_elEl"].style.left)-padding) + "px")
		.style("top", (parseInt(d3.select(oMarker)[0][0]["_elEl"].style.top)-padding) + "px")
		.style("width", (r+padding+pluspadding) + "px")
		.style("height", (r+padding+pluspadding) + "px");
}

이 함수의 역활은 서울시 도서관 위치 정보(위도/경도)를 Naver Map상에 픽셀로 변환된 LEFT, TOP값을 알아내기 위함이다. google map의 경우 projection.fromLatLngToDivPixel() 메서드로 해당 값들을 알아낼 수 있었는데 Naver Map의 경우 내가 잘 모르는건지 해당 값을 리턴해주는 메서드가 없더라... 그래서 위 소스를 보면 Marker의 style정보에서 LEFT, TOP값을 얻어오는 것을 볼 수 있다. 


Marker Rendering Element


위 정보를 얻어와서 circle marker의 Naver Map상의 position left, top설정을 해준다.


D3.js Circle Redering Element


이제 완성된 소스를 실행해보면 아래와 같은 결과를 볼수 있다.


Naver Maps + D3.js Circle

위 Map상에 Naver Map Marker를 없애려면  oMarker.setVisible(false); 로 수정하면 된다.


Naver Map도 Google Map과 마찬가지로 zoom, dragend와 같은 각종 이벤트를 제공한다.

해당 이벤트를 사용하는 방법도 간단하게 살펴보자.

var zoomEvent = function(zoom){
	var defaultBounds = map.getBound();
	var defaultCenter = map.getCenter();
	var defaultLevel = map.getLevel();
	var defaultMapMode = map.getMapMode();
}
					
var dragEvent = function(drag){
	console.log(drag);
}
map.attach("zoom",zoomEvent);
map.attach("dragend",dragEvent);
위 소스를 보면 Naver Map에서 zoom 이벤트가 발생할때 Map상에 줌레벨, 위도/경도 정보를 구할 수 있다. 해당 정보를 이용하여 현재 Map상에 표현할 마커나 차트정보를 서버 측에서 구해와 랜더링 할 수 있을 것이다.


참고자료


'd3.js' 카테고리의 다른 글

Google Maps + D3.js  (8) 2014.02.11
bar chart  (4) 2013.09.16
Using D3.js to draw a grid‎  (3) 2013.05.31