목차
1 인사^~^
2 오늘의 개발일지 주제
3 카카오API 사용하는방법
4 지도 띄우기
5 사용자 위치 근처 지도 검색하는법 →→ https://isjiji.tistory.com/44
Toy Project초보개발자 Toy-project 개발일지 ▲NO.6 ▲ 현재위치 근처 맛집, 카카오 API 지도 검색 Javascri
먼저 카카오 API를 이용한 지도, 지도 검색 개발일지를 기록한 https://isjiji.tistory.com/43 게시글을 확인해주세요 ^~^ 초보개발자 Toy-project 개발일지 ▲NO.6 ▲ 카카오 지도 API, 현재위치 근처 맛집 지
isjiji.tistory.com
1. 왜 오랜만에 개발일지를 쓰나요?
개발일지를 한번 작성하면 세시간가량의 시간이 소요된다. 퇴근 후, 블로그 기록에만 세시간을 투자하기엔 시간이 아까워서 '개발이나 더 하자' 하는 마음을 가졌다. 그렇게 하루 하루 개발일지 기록을 미루다보니 어느새 기록하지 않은지 두달이나 흘렀다.
개발일지를 기록하지는 않았지만 지난 두달 동안 기획했던 대부분의 목표를 달성했다. 후훗 !
처음에는 한달 반이라는 개발기한을 정해두었지만,
개발이 진행 될수록 빈틈이 보이고 수정 보완 할 사항이 늘어나서 목표 기한을 설정해두지 않고 꾸준히 개발할 예정이다.
2. 오늘 개발일지는 어떤주제 ?
오늘은 개발기획 사항 중 하나였던 "근처 맛집 지도" 개발 과정을 기록하고자한다.
kakao open API 를 이용하였다. (오픈소스 편리하게 공유해주는 카카오개발자님들 절받으세요~🙇♀️ https://apis.map.kakao.com/web/guide/ 가이드까지 꼼꼼하게 기록해준 그대들 완벽)
아래의 사진은 카카오지도 API를 이용해 근처 맛집 지도를 웹화면에 띄운 결과물이다.
로그인후, 홈화면에 들어오면 가장 아래에 근처 맛집 추천 지도를 띄워두었다.
(그런데 캡쳐로 보니, 현재 '맛집추천' 화면을 보고 있는데
네비게이터 바에는 Reservation 이 주황색으로 뜨며 Reservation이 현재 화면인 것 처럼 되어있다. 수정사항!!!)

3 카카오 API 사용하기
카카오Developer입장~ https://developers.kakao.com/ → 로그인 → 내 애플리케이션 → 애플리케이션 추가하기

추가된 애플리케이션을 누르면, 아래 사진처럼 App Key 가 뜨는데, App Key가 있어야 카카오API를 사용할 수 있다.

이제 오픈소스를 보러가자 ! 문서 → 지도 → Javascript (본인이 사용할것 고르면됨 나는 자스)
Javascript를 클릭하면 새로운 세상이 열린다. 푸항항 조항

왼쪽 네비바의 sample 를 클릭하면 카카오에서 제공하는 지도관련 API를 종류별로 만날 수 있다. 그중 내가 원하는 것은
"키워드로 장소검색하고 목록으로 표출하기"
https://apis.map.kakao.com/web/sample/

지도 아래에 오픈소스가 있다. 원하는 탭의 소스를 드래그해서 본인의 프로젝트에 드랍해준다.
코드에 대한 설명까지 한줄한줄 다 적혀있다. 아이고 자상해라~
https://apis.map.kakao.com/web/sample/keywordList/

여기서 부터 정말 중요
1) 아래 코드는 HTML 태그 아래에 입력해주어야한다.
그렇지 않을경우 error 가 뜨면서 지도가 정상작동을 하지않는다.
왜냐하면, script 태그에서 html의 코드를 사용하고있는데, html이 로드가 되지 않은 상황에서는 html 코드를 찾으면, 찾을 수 없기 때문이다. 그러니 아래 코드는 꼭 html 태그 아래쪽에 입력해두자 !!
2) 아까 추가해둔 App Key를 아래 url의 appkey 값으로에 입력해주어야한다.
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY를 사용하세요&libraries=services"></script>
3) 사이트 도메인을 입력해주어야한다. 내 애플리케이션 → 앱 설정 → 플랫폼 → WEB 플랫폼 등록
상용화하지 않은 도메인을 사용할 경우 << http://localhost:port번호 >> 까지만 적어주면된다.
이부분을 적어주지 않으면 또한 ~ error 발생^^

중요한거 끝
마무리
이렇게 하면, 나의 귀염뽀짝한 토이프로젝트에 맛집추천 리스트와 지도를 띄울 수 있다.
하지만, 너무나 아쉽게도 "현재위치" 근처 맛집을 검색할 수 없다.
키워드를 입력하고 검색하면, 이태원 혹은 한국 전체가 검색된다. 어떻게 해결할 수 있을까?
해결방법은 나눠서 기록했다. 아래 링크를 타고가세요~
Toy Project초보개발자 Toy-project 개발일지 ▲NO.6 ▲ 현재위치 근처 맛집, 카카오 API 지도 검색 Javascri
먼저 카카오 API를 이용한 지도, 지도 검색 개발일지를 기록한 https://isjiji.tistory.com/43 게시글을 확인해주세요 ^~^ 초보개발자 Toy-project 개발일지 ▲NO.6 ▲ 카카오 지도 API, 현재위치 근처 맛집 지
isjiji.tistory.com
HTML
//지도를 입력할 html
<section>
<div>
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-lg-8 col-xl-6 text-center">
<h2 class="mt-0">맛집 추천</h2>
<hr class="divider" />
</div>
</div></br>
<div class="map_wrap">
<div id="map" style="width:90%;height:100%;left:5%;bottom:3%;position:relative;overflow:hidden;"></div>
<div id="menu_wrap" class="bg_white">
<div class="option">
<div>
<form onsubmit="searchPlaces(this.keyword.value); return false;">
키워드 : <input type="text" id="keyword" size="15">
<button type="submit">검색하기</button>
</form>
</div>
</div>
<hr>
<ul id="placesList"></ul>
<div id="pagination"></div>
</div>
</div>
</div>
</section>
Javascript (현재위치에서 검색하는 것은 이 코드에 기록되어 있지만, 설명은 다음 개발일지에 있습니다.)
<script>
<!--지도-->
var userLng,userLat, mapContainer, map, infowindow,
ps = new kakao.maps.services.Places(); // 장소 검색 객체를 생성;
<!--var keyword = document.getElementById('keyword').value;-->
var markers = [];
navigator.geolocation.getCurrentPosition(getLocWeather, showErrorMsg);
function getLocWeather(position){ //현재 위치
userLat = position.coords.latitude; //위도
userLng = position.coords.longitude;//경도
mapContainer = document.getElementById('map'), // 지도를 표시할 div
mapOption = {
center: new kakao.maps.LatLng(userLat, userLng), // 지도의 중심좌표
level: 3 // 지도의 확대 레벨
};
map = new kakao.maps.Map(mapContainer, mapOption); //지도생성
infowindow = new kakao.maps.InfoWindow({zIndex:1}); // 검색 결과 목록이나 마커를 클릭했을 때 장소명을 표출할 인포윈도우를 생성
searchPlaces("맛집");
}
function showErrorMsg(error){ //위치찾기 오류발생
switch(error.code){
case error.PERMISSION_DENIED: alert("사용자가 사용 요청을 거부했습니다."); break;
case error.POSITION_UNAVAILABLE: alert("가져온 위치 정보를 사용할 수 없습니다."); break;
case error.TIMEOUT: alert("요청 허용 시간을 초과했습니다."); break;
case error.UNKNOWN_ERROR: alert("알 수 없는 오류가 발생했습니다."); break;
}
}
function searchPlaces(keyword) {// 키워드 검색 요청
if (!keyword.replace(/^\s+|\s+$/g, '')) {
alert('키워드를 입력해주세요');
return false;
}
ps.keywordSearch(keyword, placesSearchCB,{x:userLng , y:userLat}); // 장소검색 객체를 통해 키워드로 장소검색을 요청
}
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) {
var listEl = document.getElementById('placesList'),
menuEl = document.getElementById('menu_wrap'),
fragment = document.createDocumentFragment(),
bounds = new kakao.maps.LatLngBounds(),
listStr = '';
removeAllChildNods(listEl); // 검색 결과 목록에 추가된 항목들을 제거
removeMarker(); // 지도에 표시되고 있는 마커를 제거
for ( var i=0; i<places.length; i++ ) {
var placePosition = new kakao.maps.LatLng(places[i].y, places[i].x), // 마커를 생성하고 지도에 표시
marker = addMarker(placePosition, i),
itemEl = getListItem(i, places[i]); // 검색 결과 항목 Element를 생성
bounds.extend(placePosition); // 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해 LatLngBounds 객체에 좌표를 추가
// 마커와 검색결과 항목에 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();
};
})(marker, places[i].place_name);
fragment.appendChild(itemEl);
}
listEl.appendChild(fragment); // 검색결과 항목들을 검색결과 목록 Element에 추가
menuEl.scrollTop = 0;
map.setBounds(bounds); // 검색된 장소 위치를 기준으로 지도 범위를 재설정
}
function getListItem(index, places) {// 검색결과 항목을 Element로 반환하는 함수
var el = document.createElement('li'),
itemStr = '<span class="markerbg marker_' + (index+1) + '"></span>' +
'<div class="info">' +
' <h5>' + places.place_name + '</h5>';
if (places.road_address_name) {
itemStr += ' <span>' + places.road_address_name + '</span>' +
' <span class="jibun gray">' + places.address_name + '</span>';
} else {
itemStr += ' <span>' + places.address_name + '</span>';
}
itemStr += ' <span class="tel">' + places.phone + '</span>' +
'</div>';
el.innerHTML = itemStr;
el.className = 'item';
return el;
}
function addMarker(position, idx, title) { // 마커를 생성하고 지도 위에 마커를 표시하는 함수
var imageSrc = 'https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/marker_number_blue.png', // 마커 이미지 url, 스프라이트 이미지 사용
imageSize = new kakao.maps.Size(36, 37), // 마커 이미지의 크기
imgOptions = {
spriteSize : new kakao.maps.Size(36, 691), // 스프라이트 이미지의 크기
spriteOrigin : new kakao.maps.Point(0, (idx*46)+10), // 스프라이트 이미지 중 사용할 영역의 좌상단 좌표
offset: new kakao.maps.Point(13, 37) // 마커 좌표에 일치시킬 이미지 내에서의 좌표
},
markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imgOptions),
marker = new kakao.maps.Marker({
position: position, // 마커의 위치
image: markerImage
});
marker.setMap(map); // 지도 위에 마커를 표출
markers.push(marker); // 배열에 생성된 마커를 추가
return marker;
}
function removeMarker() {// 지도 위에 표시되고 있는 마커를 모두 제거
for ( var i = 0; i < markers.length; i++ ) {
markers[i].setMap(null);
}
markers = [];
}
function displayPagination(pagination) {// 검색결과 목록 하단에 페이지번호를 표시는 함수
var paginationEl = document.getElementById('pagination'),
fragment = document.createDocumentFragment(),
i;
while (paginationEl.hasChildNodes()) { // 기존에 추가된 페이지번호를 삭제
paginationEl.removeChild (paginationEl.lastChild);
}
for (i=1; i<=pagination.last; i++) {
var 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) {// 검색결과 목록 또는 마커를 클릭했을 때 호출되는 함수
var 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);
}
}
</script>