// 마커를 담을 배열입니다
let markers = [];
const mapContainer = document.getElementById('map'), // 지도를 표시할 div
mapOption = {
center: new kakao.maps.LatLng(37.566826, 126.9786567), // 지도의 중심좌표
level: 12 // 지도의 확대 레벨
};
// 지도를 생성합니다
const map = new kakao.maps.Map(mapContainer, mapOption);
// 마커 클러스터러를 생성합니다
const clusterer = new kakao.maps.MarkerClusterer({
map: map, // 마커들을 클러스터로 관리하고 표시할 지도 객체
averageCenter: true, // 클러스터에 포함된 마커들의 평균 위치를 클러스터 마커 위치로 설정
minLevel: 6 // 클러스터 할 최소 지도 레벨
});
// 일반 지도와 스카이뷰로 지도 타입을 전환할 수 있는 지도타입 컨트롤을 생성합니다
const mapTypeControl = new kakao.maps.MapTypeControl();
// 지도에 컨트롤을 추가해야 지도위에 표시됩니다
// kakao.maps.ControlPosition은 컨트롤이 표시될 위치를 정의하는데 TOPRIGHT는 오른쪽 위를 의미합니다
map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
// 지도 확대 축소를 제어할 수 있는 줌 컨트롤을 생성합니다
const zoomControl = new kakao.maps.ZoomControl();
map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHTBOTTOM);
// 지도가 이동, 확대, 축소로 인해 중심좌표가 변경되면 마지막 파라미터로 넘어온 함수를 호출하도록 이벤트를 등록합니다
let getLat = null;
let getLng = null;
kakao.maps.event.addListener(map, 'center_changed', function() {
// 지도의 레벨을 얻어옵니다
const level = map.getLevel();
// 지도의 중심좌표를 얻어옵니다
const latlng = map.getCenter();
console.log('중심 위도: '+latlng.getLat() + ', 경도: ' + latlng.getLng());
getLat = latlng.getLat();
getLng = latlng.getLng();
});
// 장소 검색 객체를 생성합니다
const ps = new kakao.maps.services.Places();
// 검색 결과 목록이나 마커를 클릭했을 때 장소명을 표출할 인포윈도우를 생성합니다
const infowindow = new kakao.maps.InfoWindow({zIndex:1});
// 키워드로 장소를 검색합니다
searchPlaces();
// 키워드 검색을 요청하는 함수입니다
function searchPlaces() {
let keyword = document.getElementById('keyword').value;
let radius = $("input[name='radius']:checked").val();
$.ajax({
url : 'ajaxMap.php',
type : 'GET',
data : { 'msg': keyword, 'radius':radius, 'lat':getLat, 'lng':getLng },
dataType: 'json',
success : function(json) {
if(json.length == 0) {
alert('검색 데이터가 없습니다.');
return;
}
console.log('데이터 갯수 :: ' + json.length);
displayPlaces(json);
// 클러스터에 마커들을 추가합니다
clusterer.addMarkers(markers);
var pagination = [ '1', '2', '3' ];
displayPagination(pagination);
},
error : function(xhr, status, error){
alert("에러코드 : " + xhr.status); //요청에 실패하면 에러코드 출력
},
complete : function() {
}
});
}
// 장소검색이 완료됐을 때 호출되는 콜백함수 입니다
function placesSearchCB(data, status, pagination) {
if (status === kakao.maps.services.Status.OK) {
// 정상적으로 검색이 완료됐으면 검색 목록과 마커를 표출합니다
displayPlaces(data);
// 페이지 번호를 표출합니다
displayPagination(pagination);
} else if (status === kakao.maps.services.Status.ZERO_RESULT) {
alert('검색 결과가 존재하지 않습니다.');
return;
} else if (status === kakao.maps.services.Status.ERROR) {
alert('검색 결과 중 오류가 발생했습니다.');
return;
}
}
// 검색 결과 목록과 마커를 표출하는 함수입니다
function displayPlaces(places) {
let listEl = document.getElementById('placesList'),
menuEl = document.getElementById('menu_wrap'),
fragment = document.createDocumentFragment(),
bounds = new kakao.maps.LatLngBounds(),
listStr = '';
// 검색 결과 목록에 추가된 항목들을 제거합니다
removeAllChildNods(listEl);
// 지도에 표시되고 있는 마커를 제거합니다
removeMarker();
const cntEl = document.getElementById('datacount');
cntEl.innerText = '검색 개수 : ' + places.length;
for (let i=0; i<places.length; i++) {
let color_marker = "marker-icon-blue.png";
if (places[i].yn == 0) { // 없으면 => 빨간색
color_marker = "marker-icon-red.png";
if(places[i].isbiz > 0) {
color_marker = "marker-icon-green.png";
}
} else {
color_marker = "marker-icon-blue.png";
if(places[i].isbiz > 0) {
color_marker = "marker-icon-orange.png";
}
}
// 마커를 생성하고 지도에 표시합니다.
let idx = places[i].idx; // 절대 var 변수를 선언하면 안된다. 반드시 let 변수를 선언해야 제대로 동작되더라. 개삽질을 엄청했다.
let title = places[i].idx;
let placePosition = new kakao.maps.LatLng(places[i].latitude, places[i].longitude);
let marker = addMarkers(placePosition, color_marker, title);
let itemEl = getListItem(i, places[i], color_marker); // 검색 결과 항목 Element를 생성합니다
// 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해 LatLngBounds 객체에 좌표를 추가합니다
bounds.extend(placePosition);
// 마커와 검색결과
// 항목에 mouseover 했을때 해당 장소에 인포윈도우에 장소명을 표시합니다. mouseout 했을 때는 인포윈도우를 닫습니다
(function(marker, title) {
kakao.maps.event.addListener(marker, 'mouseover', function() {
displayInfowindow(marker, title);
});
kakao.maps.event.addListener(marker, 'mouseout', function() {
infowindow.close();
});
itemEl.onmouseover = function () {
displayInfowindow(marker, title);
};
itemEl.onmouseout = function () {
infowindow.close();
};
// 마커에 클릭 이벤트를 등록한다.
kakao.maps.event.addListener(marker, 'click', function() {
//map.panTo(placePosition); // 지도 중심을 부드럽게 이동시킨다.
console.log('idx:' + idx);
custom_infowindow(idx);
});
})(marker, places[i].bldNM);
fragment.appendChild(itemEl);
}
// 검색결과 항목들을 검색결과 목록 Elemnet에 추가합니다
listEl.appendChild(fragment);
menuEl.scrollTop = 0;
// 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
map.setBounds(bounds);
}
function custom_infowindow(idx){
$('#dialog').load('infowindow.php?do='+idx, function() {
$(this).dialog({
autoOpen : true,
height : 'auto',
width : 'auto',
position: { my: "center", at: "center", of: window },
title : 'XX정보',
buttons : {
"닫기" : function() {
$(this).dialog("close");
}
}
});
});
}
// 검색결과 항목을 Element로 반환하는 함수입니다. 위도, 경도, 번호, 건물명, 도로명주소, 지번주소
function getListItem(index, places, _color) {
let el = document.createElement('li'),
itemStr = '<span style="float:left;position:absolute;width:33px; height:31px;margin:10px 0 0 10px;"><img width="31" height="31" src="./marker/' + _color + '"></span>' +
'<div class="info">' +
' <h5>' + places.bldNM + '</h5>';
if (places.stAddress) {
itemStr += ' <span>' + places.stAddress + '</span>' +
' <span class="jibun gray">' + places.jiAddress + '</span>';
} else {
itemStr += ' <span>' + places.jiAddress + '</span>';
}
itemStr += ' <span class="tel">' + places.idx + '</span>' +
'</div>';
el.innerHTML = itemStr;
el.className = 'item';
return el;
}
function addMarkers(position, _color, title) {
const imageSrc = './marker/' + _color;
const imageSize = new kakao.maps.Size(33, 33);
const imageOptions = {
offset: new kakao.maps.Point(27, 69)
};
const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOptions)
// 마커를 생성합니다
const marker = new kakao.maps.Marker({
position: position,
//title: title,
image: markerImage
});
marker.setMap(map); // 마커가 지도 위에 표시되도록 설정합니다
markers.push(marker); // 생성된 마커를 배열에 추가합니다
return marker;
}
// 지도 위에 표시되고 있는 마커를 모두 제거합니다
function removeMarker() {
//clusterer.removeMarkers(markers);
clusterer.clear(); // 추가된 모든 마커 삭제
for ( let i = 0; i < markers.length; i++ ) {
markers[i].setMap(null);
}
markers = [];
}
// 검색결과 목록 하단에 페이지번호를 표시는 함수입니다
function displayPagination(pagination) {
let paginationEl = document.getElementById('pagination'),
fragment = document.createDocumentFragment(),
i;
// 기존에 추가된 페이지번호를 삭제합니다
while (paginationEl.hasChildNodes()) {
paginationEl.removeChild (paginationEl.lastChild);
}
for (i=1; i<=pagination.last; i++) {
let el = document.createElement('a');
el.href = "#";
el.innerHTML = i;
if (i===pagination.current) {
el.className = 'on';
} else {
el.onclick = (function(i) {
return function() {
pagination.gotoPage(i);
}
})(i);
}
fragment.appendChild(el);
}
paginationEl.appendChild(fragment);
}
// 검색결과 목록 또는 마커를 클릭했을 때 호출되는 함수. 인포윈도우에 장소명을 표시합니다
function displayInfowindow(marker, title) {
const content = '<div style="padding:5px;z-index:1;">' + title + '</div>';
infowindow.setContent(content);
infowindow.open(map, marker);
}
// 검색결과 목록의 자식 Element를 제거하는 함수입니다
function removeAllChildNods(el) {
while (el.hasChildNodes()) {
el.removeChild (el.lastChild);
}
}