권주희

display the kakao map in main page

- display the kakao map in main page
- add search location box
- create the marker to each map
......@@ -1274,6 +1274,24 @@
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
},
"@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"requires": {
"@emotion/memoize": "0.7.4"
}
},
"@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
},
"@emotion/unitless": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
},
"@hapi/address": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
......@@ -2848,6 +2866,22 @@
"resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.6.tgz",
"integrity": "sha512-1aGDUfL1qOOIoqk9QKGIo2lANk+C7ko/fqH0uIyC71x3PEGz0uVP8ISgfEsFuG+FKmjHTvFK/nNM8dowpmUxLA=="
},
"babel-plugin-styled-components": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz",
"integrity": "sha512-MBMHGcIA22996n9hZRf/UJLVVgkEOITuR2SvjHLb5dSTUyR4ZRGn+ngITapes36FI3WLxZHfRhkA1ffHxihOrg==",
"requires": {
"@babel/helper-annotate-as-pure": "^7.0.0",
"@babel/helper-module-imports": "^7.0.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"lodash": "^4.17.11"
}
},
"babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
......@@ -3160,6 +3194,11 @@
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"bootstrap": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz",
"integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
......@@ -3447,6 +3486,11 @@
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"camelize": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
"integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
},
"caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
......@@ -4087,6 +4131,11 @@
"postcss": "^7.0.5"
}
},
"css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
"integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU="
},
"css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
......@@ -4170,6 +4219,23 @@
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
},
"css-to-react-native": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.3.2.tgz",
"integrity": "sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw==",
"requires": {
"camelize": "^1.0.0",
"css-color-keywords": "^1.0.0",
"postcss-value-parser": "^3.3.0"
},
"dependencies": {
"postcss-value-parser": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
}
}
},
"css-tree": {
"version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
......@@ -4361,6 +4427,11 @@
}
}
},
"daum-map-api": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/daum-map-api/-/daum-map-api-1.0.2.tgz",
"integrity": "sha1-3hbrEB11Ea5dZC/CZsl/lHmJiqQ="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
......@@ -7391,6 +7462,11 @@
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"is-what": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-3.8.0.tgz",
"integrity": "sha512-UKeBoQfV8bjlM4pmx1FLDHdxslW/1mTksEs8ReVsilPmUv5cORd4+2/wFcviI3cUjrLybxCjzc8DnodAzJ/Wrg=="
},
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
......@@ -8453,6 +8529,11 @@
"p-is-promise": "^2.0.0"
}
},
"memoize-one": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
"integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
},
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
......@@ -8491,6 +8572,14 @@
}
}
},
"merge-anything": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-2.4.4.tgz",
"integrity": "sha512-l5XlriUDJKQT12bH+rVhAHjwIuXWdAIecGwsYjv2LJo+dA1AeRTmeQS+3QBpO6lEthBMDi2IUMpLC1yyRvGlwQ==",
"requires": {
"is-what": "^3.3.1"
}
},
"merge-deep": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz",
......@@ -11132,6 +11221,19 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-kakao-maps": {
"version": "0.0.13",
"resolved": "https://registry.npmjs.org/react-kakao-maps/-/react-kakao-maps-0.0.13.tgz",
"integrity": "sha512-1ZHGbdvucFpq3rPSee1UB8cY/61QloQeH2Kh1SMSvIoL2kIUIo1lbF8FnwkHo3zrbpqcS4kIFPvvDB5xs27MdA==",
"requires": {
"@babel/runtime-corejs3": "^7.6.2",
"babel-runtime": "^6.26.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"scriptjs": "^2.5.9",
"styled-components": "^4.3.2"
}
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
......@@ -11867,6 +11969,11 @@
"ajv-keywords": "^3.4.1"
}
},
"scriptjs": {
"version": "2.5.9",
"resolved": "https://registry.npmjs.org/scriptjs/-/scriptjs-2.5.9.tgz",
"integrity": "sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg=="
},
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
......@@ -12817,6 +12924,36 @@
}
}
},
"styled-components": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-4.4.1.tgz",
"integrity": "sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g==",
"requires": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/traverse": "^7.0.0",
"@emotion/is-prop-valid": "^0.8.1",
"@emotion/unitless": "^0.7.0",
"babel-plugin-styled-components": ">= 1",
"css-to-react-native": "^2.2.2",
"memoize-one": "^5.0.0",
"merge-anything": "^2.2.4",
"prop-types": "^15.5.4",
"react-is": "^16.6.0",
"stylis": "^3.5.0",
"stylis-rule-sheet": "^0.0.10",
"supports-color": "^5.5.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"stylehacks": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
......@@ -12839,6 +12976,16 @@
}
}
},
"stylis": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz",
"integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q=="
},
"stylis-rule-sheet": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz",
"integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw=="
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
......
......@@ -6,9 +6,12 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"bootstrap": "^3.4.1",
"daum-map-api": "^1.0.2",
"react": "^16.13.1",
"react-bootstrap": "^1.0.1",
"react-dom": "^16.13.1",
"react-kakao-maps": "0.0.13",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1"
},
......
......@@ -10,6 +10,16 @@
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<script
type="text/javascript"
src="//dapi.kakao.com/v2/maps/sdk.js?appkey=61abec34d0855ba1d434ea222263d4a5&libraries=services,clusterer,drawing"
></script>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous"
/>
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
......@@ -24,7 +34,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>HowsTheWeather</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
......
......@@ -3,6 +3,10 @@ import logo from "./logo.svg";
import "./App.css";
import Button from "react-bootstrap/Button";
import "./home.css";
import { Map, Marker, MarkerClusterer, Polyline } from "react-kakao-maps";
import "bootstrap/dist/css/bootstrap.min.css";
/* global kakao */
export default class Home extends Component {
constructor(props) {
......@@ -10,10 +14,210 @@ export default class Home extends Component {
this.state = {
map: null,
markers: [],
markers: [],
curMarker: new kakao.maps.Marker({
position: new kakao.maps.LatLng(37.503716, 127.044844),
}),
placeSearch: new kakao.maps.services.Places(),
infoWindow: new kakao.maps.CustomOverlay({}),
region: "은평구청",
curAirCondition: null,
routeInformation: null,
// curAirCondition: null,
// routeInformation: null,
};
this.removeAllChildNods = this.removeAllChildNods.bind(this);
}
searchPlaces() {
var keyword = document.getElementById("keyword").value;
if (!keyword.replace(/^\s+|\s+$/g, "")) {
alert("키워드를 입력해주세요!");
return false;
}
// 장소검색 객체를 통해 키워드로 장소검색을 요청합니다
this.state.placeSearch.keywordSearch(
keyword,
this.placesSearchCB.bind(this)
);
}
// 장소검색이 완료됐을 때 호출되는 콜백함수 입니다
placesSearchCB(data, status, pagination) {
if (status === kakao.maps.services.Status.OK) {
// 정상적으로 검색이 완료됐으면
// 검색 목록과 마커를 표출합니다
this.displayPlaces(data);
// 페이지 번호를 표출합니다
this.displayPagination(pagination);
} else if (status === kakao.maps.services.Status.ZERO_RESULT) {
alert("검색 결과가 존재하지 않습니다.");
return;
} else if (status === kakao.maps.services.Status.ERROR) {
alert("검색 결과 중 오류가 발생했습니다.");
return;
}
}
displayPlaces(places) {
var listEl = document.getElementById("placesList"),
menuEl = document.getElementById("menu_wrap"),
fragment = document.createDocumentFragment(),
bounds = new kakao.maps.LatLngBounds(),
listStr = "";
// 검색 결과 목록에 추가된 항목들을 제거합니다
// 페이지별로 보여주기 때문에 추가한 것 같음.
this.removeAllChildNods(listEl);
// 지도에 표시되고 있는 마커를 제거합니다
this.removeMarker();
for (var i = 0; i < places.length; i++) {
// 마커를 생성하고 지도에 표시합니다
var placePosition = new kakao.maps.LatLng(places[i].y, places[i].x),
marker = this.addMarker(placePosition, i),
itemEl = this.getListItem(i, places[i]); // 검색 결과 항목 Element를 생성합니다
// 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해
// LatLngBounds 객체에 좌표를 추가합니다
bounds.extend(placePosition);
// 마커와 검색결과 항목에 mouseover 했을때
// 해당 장소에 인포윈도우에 장소명을 표시합니다
// mouseout 했을 때는 인포윈도우를 닫습니다
// 함수를 조건문처럼 사용하여 해당 함수가 true일때 marker,places[i].place_name함수가 불리워짐.
fragment.appendChild(itemEl);
}
// 검색결과 항목들을 검색결과 목록 Elemnet에 추가합니다
listEl.appendChild(fragment);
menuEl.scrollTop = 0;
// 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
this.state.map.setBounds(bounds);
}
// 커스텀 오버레이를 닫기 위해 호출되는 함수입니다
closeOverlay() {
this.state.infoWindow.setMap(null);
}
getListItem(index, places) {
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;
}
addMarker(position, idx, title) {
var imageSrc =
"http://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(this.state.map); // 지도 위에 마커를 표출합니다
this.setState({ curMarker: marker });
this.state.markers.push(marker); // 배열에 생성된 마커를 추가합니다
return marker;
}
// 지도 위에 표시되고 있는 마커를 모두 제거합니다
removeMarker() {
for (var i = 0; i < this.state.markers.length; i++) {
this.state.markers[i].setMap(null);
}
this.setState({
markers: [],
});
}
// 검색결과 목록 하단에 페이지번호를 표시는 함수입니다
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);
}
removeAllChildNods(el) {
while (el.hasChildNodes()) {
el.removeChild(el.lastChild);
}
}
componentDidMount() {
// 컴포넌트가 만들어지고, render 함수가 호출된 이후에 호출되는 메소
// AJAX나 타이머를 생성하는 코드를 작성하는 파트이다.
let el = document.getElementById("map");
this.setState({
map: new kakao.maps.Map(el, {
//map option 설정
center: new kakao.maps.LatLng(37.503716, 127.044844),
level: 3,
}),
});
this.searchPlaces();
// marker.setMap(map);
}
render() {
......@@ -28,7 +232,11 @@ export default class Home extends Component {
<div className="map_wrap">
<div
id="map"
style={{ width: "1000px", height: "600px", align: "middle" }}
style={{
width: "1000px",
height: "600px",
align: "middle",
}}
></div>
<div id="menu_wrap" className="bg_white">
<div className="option">
......