안녕하세요 React Component 들을 기반으로 카카오 맵 API를 불러와 카페 웹 지도를 구현 하고자 하는데요 아무리 구글링하여 예제들을 참고하여 지도가 잘 뜨도록 코딩을 해도 생각대로 잘 구현이 되지 않아 Dev Talk에다 질문 글 올립니다 ㅠㅠ
** index.html **
Coffee Maps** Resume.js **
import React, { Component } from “react”;
class Resume extends Component {
getRandomColor() {
let letters = “0123456789ABCDEF”;
let color = “#”;
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
render() {
if (!this.props.data) return null;
const skillmessage = this.props.data.skillmessage;
const education = this.props.data.education.map(function(education) {
return (
// 카카오맵 API
<div>
<div id="map"></div>
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=76ca9236bc363cb579d11ca8d617f00b&libraries=services"></script>
<script src="js/map.js"></script>
</div>
);
});
const skills = this.props.data.skills.map(skills => {
const backgroundColor = this.getRandomColor();
const className = "bar-expand " + skills.name.toLowerCase();
const width = skills.level;
return (
<li key={skills.name}>
<span style={{ width, backgroundColor }} className={className}></span>
<em>{skills.name}</em>
</li>
);
});
return (
<section id="resume">
<div className="row education">
<div className="three columns header-col">
<h1>
<span>Maps</span>
</h1>
</div>
<div className="nine columns main-col">
<div className="row item">
<div className="twelve columns">{education}</div>
</div>
</div>
</div>
<div className="row skill">
<div className="three columns header-col">
<h1>
<span>Skills</span>
</h1>
</div>
<div className="nine columns main-col">
<p>{skillmessage}</p>
<div className="bars">
<ul className="skills">{skills}</ul>
</div>
</div>
</div>
</section>
);
}
}
export default Resume;
** Map.js **
import React, { Component } from “react”;
import styled from “styled-components”;
class Maps extends Component {
handleMap = () => {
// 마커를 클릭했을 때 해당 장소의 상세정보를 보여 줄 커스텀 오버레이
var placeOverlay = new kakao.maps.CustomOverlay({zindex: 1}),
contentNode = document.createElement(‘div’),
markers = [],
currCategory = ‘’;
// 지도를 웹 브라우저 상에 표시할 DOM Element를 지정
const mapContainer = document.getElementById("map");
mapOption = {
center: new kakao.maps.LatLng(37.20993410884578, 127.05867025427891), // 지도의 중심좌표
level: 3 // 지도의 확대 레벨
};
// 지도를 생성하고 객체(Object)를 DOM에 반환하여 출력
const map = new kakao.maps.Map(mapContainer, mapOption);
// 장소 검색 객체를 생성
var ps = new kakao.maps.services.Places(map);
// 지도에 idle Event를 등록
kakao.maps.event.addListener(map, 'idle', searchPlaces);
// 커스텀 오버레이의 Contents Node에 css class를 추가
contentNode.className = 'placeinfo_wrap';
/* 커스텀 오버레이의 컨텐츠 노드에 mousedown, touchstart 이벤트가 발생했을때
지도 객체에 이벤트가 전달되지 않도록 이벤트 핸들러로 kakao.maps.event.preventMap 메소드를 등록 */
addEventHandle(contentNode, 'mousedown', kakao.maps.event.preventMap);
addEventHandle(contentNode, 'touchstart', kakao.maps.event.preventMap);
// 커스텀 오버레이 컨텐츠를 설정합니다
placeOverlay.setContent(contentNode);
addCategoryClickEvent();
// Element에 이벤트 핸들러를 추가시키는 함수
function addEventHandle(target, type, callback) {
if (target.addEventListener) {
target.addEventListener(type, callback);
} else {
target.attachEvent('on' + type, callback);
}
}
// 카테고리 검색을 요청하는 함수입니다
function searchPlaces() {
if (!currCategory) {
return;
}
placeOverlay.setMap(null);
removeMarker();
ps.categorySearch(currCategory, placesSearchCB, {useMapBounds:true});
}
// 장소검색이 완료됐을 때 호출되는 콜백함수 입니다
function placesSearchCB(data, status, pagination) {
if (status === kakao.maps.services.Status.OK) {
// 정상적으로 검색이 완료됐으면 지도에 마커를 표출합니다
displayPlaces(data);
} else if (status === kakao.maps.services.Status.ZERO_RESULT) {
// 검색결과가 없는경우
alert("해당 지역의 약국 정보 조회 결과가 존재하지 않습니다.");
} else if (status === kakao.maps.services.Status.ERROR) {
// 에러로 인해 검색결과가 나오지 않은 경우
alert("예기지 않은 오류 발생으로 인해 약국 정보 조회 결과를 정상적으로 출력 하는데 실패 하였습니다.");
}
}
// 지도에 마커를 표출하는 함수
function displayPlaces(places) {
var order = document.getElementById(currCategory).getAttribute('data-order');
for ( var i=0; i<places.length; i++ ) {
// 마커를 생성하고 지도에 표시
var marker = addMarker(new kakao.maps.LatLng(places[i].y, places[i].x), order);
/* 마커와 검색결과 항목을 클릭 했을 때
장소정보를 표출하도록 클릭 이벤트를 추가 */
(function(marker, place) {
kakao.maps.event.addListener(marker, 'click', function() {
displayPlaceInfo(place);
});
})(marker, places[i]);
}
}
// 마커를 생성하고 지도 위에 마커를 표시하는 함수
function addMarker(position, order) {
var imageSrc = 'https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/places_category.png', // 마커 이미지 url, 스프라이트 이미지를 씁니다
imageSize = new kakao.maps.Size(27, 27), // 마커 이미지의 크기
imgOptions = {
spriteSize : new kakao.maps.Size(72, 206), // 스프라이트 이미지의 크기
spriteOrigin : new kakao.maps.Point(46, (order*36)), // 스프라이트 이미지 중 사용할 영역의 좌상단 좌표
offset: new kakao.maps.Point(11, 28) // 마커 좌표에 일치시킬 이미지 내에서의 좌표
},
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 displayPlaceInfo (place) {
var content = '<div class="placeinfo">' +
' <a class="title" href="' + place.place_url + '" target="_blank" title="' + place.place_name + '">' + place.place_name + '</a>';
if (place.road_address_name) {
content += ' <span title="' + place.road_address_name + '">' + place.road_address_name + '</span>' +
' <span class="jibun" title="' + place.address_name + '">(지번 : ' + place.address_name + ')</span>';
} else {
content += ' <span title="' + place.address_name + '">' + place.address_name + '</span>';
}
content += ' <span class="tel">' + place.phone + '</span>' +
'</div>' +
'<div class="after"></div>';
contentNode.innerHTML = content;
placeOverlay.setPosition(new kakao.maps.LatLng(place.y, place.x));
placeOverlay.setMap(map);
}
// 각 카테고리에 클릭 이벤트를 등록
function addCategoryClickEvent() {
var category = document.getElementById('category'),
children = category.children;
for (var i=0; i<children.length; i++) {
children[i].onclick = onClickCategory;
}
}
// 카테고리를 클릭했을 때 호출되는 함수입
function onClickCategory() {
var id = this.id,
className = this.className;
placeOverlay.setMap(null);
if (className === 'on') {
currCategory = '';
changeCategoryClass();
removeMarker();
} else {
currCategory = id;
changeCategoryClass(this);
searchPlaces();
}
}
// 클릭된 카테고리만 클릭된 스타일을 적용하는 함수
function changeCategoryClass(el) {
var category = document.getElementById('category'),
children = category.children,
i;
for ( i=0; i<children.length; i++ ) {
children[i].className = '';
}
if (el) {
el.className = 'on';
}
}
/* 지도상 컨트롤 메뉴 삽입
일반 지도와 스카이 뷰 지도 타입으로 변경 할 수 있는 지도 타입 컨트롤 추가 */
const mapTypeControl = new kakao.maps.MapTypeControl();
// 컨트롤을 추가하고자 하는 지도를 지정
map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
// 지도 Zoom-In, Zoom-Out 기능을 지원하는 Zoom 컨트롤 추가
const zoomControl = new kakao.maps.ZoomControl();
map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);
// 좌표 정보를 주소로 변환
// 좌표 정보를 주소로 변환하는 객체를 생성
var geocoder = new kakao.maps.services.Geocoder();
var marker = new kakao.maps.Marker();
infowindow = new kakao.maps.InfoWindow({zindex: 2});
// 현재 지도 중심좌표로 주소를 검색해서 지도 좌측 상단에 표시
searchAddrFromCoords(map.getCenter(), displayCenterInfo);
/* 지도 클릭시 클릭한 지점의 위치 자표를 주소 정보롤 변환시켜
브라우저 상에 보여지도록 하는 이벤트를 추가 */
kakao.maps.event.addListener(map, 'click', function(mouseEvent) {
searchDetailAddrFromCoords(mouseEvent.latLng, function(result, status) {
if (status === kakao.maps.services.Status.OK) {
var detailAddr = !!result[0].road_address ? '<div>도로명주소 : ' + result[0].road_address.address_name + '</div>' : '';
detailAddr += '<div>지번 주소 : ' + result[0].address.address_name + '</div>';
var content = '<div class="bAddr">' +
'<span class="title">법정동 주소정보</span>' +
detailAddr +
'</div>';
// 마커를 클릭한 위치에 표시합니다
marker.setPosition(mouseEvent.latLng);
marker.setMap(map);
// 인포윈도우에 클릭한 위치에 대한 법정동 상세 주소정보를 표시합니다
infowindow.setContent(content);
infowindow.open(map, marker);
}
});
});
// 중심 좌표나 확대 수준이 변경됐을 때 지도 중심 좌표에 대한 주소 정보를 표시하도록 이벤트를 등록합니다
kakao.maps.event.addListener(map, 'idle', function() {
searchAddrFromCoords(map.getCenter(), displayCenterInfo);
});
function searchAddrFromCoords(coords, callback) {
// 좌표로 행정동 주소 정보를 요청합니다
geocoder.coord2RegionCode(coords.getLng(), coords.getLat(), callback);
}
function searchDetailAddrFromCoords(coords, callback) {
// 좌표로 법정동 상세 주소 정보를 요청합니다
geocoder.coord2Address(coords.getLng(), coords.getLat(), callback);
}
// 지도 좌측상단에 지도 중심좌표에 대한 주소정보를 표출하는 함수입니다
function displayCenterInfo(result, status) {
if (status === kakao.maps.services.Status.OK) {
var infoDiv = document.getElementById('centerAddr');
for(var i = 0; i < result.length; i++) {
// 행정동의 region_type 값은 'H' 이므로
if (result[i].region_type === 'H') {
infoDiv.innerHTML = result[i].address_name;
break;
}
}
}
}
}
render() {
<div className="Mapwrap">
<div id="Map"></div>
</div>
}
}
export default Maps;