KakaoMap.js 6.12 KB
Newer Older
Kim, Subin's avatar
Kim, Subin committed
1
2
3
4
5
import { useState, useEffect, useRef } from "react";
import styles from "./kakao-map.module.scss";

const { kakao } = window;

6
const KakaoMap = ({ keyword, cinemaInfo, setCinemaInfo }) => {
Kim, Subin's avatar
Kim, Subin committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    const kakaoMapDiv = useRef(null)
    const menu = useRef(null)
    const searchList = useRef(null)
    const page = useRef(null)
    const [places, setPlaces] = useState([])
    let markers = []

    useEffect(() => {
        const container = kakaoMapDiv.current
        const options = {
            center: new kakao.maps.LatLng(33.450701, 126.570667),
            level: 3
        };
        const map = new kakao.maps.Map(container, options);
        const ps = new kakao.maps.services.Places();
        const infowindow = new kakao.maps.InfoWindow({ zIndex: 1 });

        searchPlaces(keyword)

        // 키워드 검색을 요청하는 함수입니다
        function searchPlaces(keyword) {
            if (!keyword.replace(/^\s+|\s+$/g, '')) {
                alert('키워드를 입력해주세요.');
                return false
            }
            // 장소검색 객체를 통해 키워드로 장소검색을 요청합니다
            ps.keywordSearch(keyword, placesSearchCB);
        }

        // 장소검색이 완료됐을 때 호출되는 콜백함수 입니다
        function placesSearchCB(data, status, pagination) {
            if (status === kakao.maps.services.Status.OK) {
                displayPlaces(data);
Kim, Subin's avatar
Kim, Subin committed
40
                displayPagination(pagination); // 페이지 번호를 표출합니다
Kim, Subin's avatar
Kim, Subin committed
41
42
43
44
45
46
47
48
49
50
51
52
53
54
            } 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 = searchList.current,
                menuEl = menu.current,
                fragment = document.createDocumentFragment(),
Kim, Subin's avatar
Kim, Subin committed
55
                bounds = new kakao.maps.LatLngBounds();
Kim, Subin's avatar
Kim, Subin committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

            for (let i = 0; i < places.length; i++) {
                // 마커를 생성하고 지도에 표시합니다
                let placePosition = new kakao.maps.LatLng(places[i].y, places[i].x),
                    itemEl = getListItem(i, places[i]); // 검색 결과 항목 Element를 생성합니다

                displayMarker(places[i], itemEl)
                // 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해 LatLngBounds 객체에 좌표를 추가합니다
                bounds.extend(placePosition);
                fragment.appendChild(itemEl);
            }
            // 검색결과 항목들을 검색결과 목록 Elemnet에 추가합니다
            listEl.appendChild(fragment);
            menuEl.scrollTop = 0;
            // 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
            map.setBounds(bounds);
        }

        function displayMarker(place, itemEl) {
            let marker = new kakao.maps.Marker({
                map: map,
                position: new kakao.maps.LatLng(place.y, place.x),
            })
            kakao.maps.event.addListener(marker, 'mouseover', function () {
                infowindow.setContent('<div style="padding:5px;font-size:12px;">' + place.place_name + '</div>')
                infowindow.open(map, marker)
            })
            kakao.maps.event.addListener(marker, 'mouseout', function () {
                infowindow.close();
            })
            itemEl.onmouseover = function () {
Kim, Subin's avatar
Kim, Subin committed
87
88
                itemEl.style.background = 'rgba(0, 0, 0, 0.075)';
                itemEl.style.cursor = 'pointer';
Kim, Subin's avatar
Kim, Subin committed
89
90
91
92
                infowindow.setContent('<div style="padding:5px;font-size:12px;">' + place.place_name + '</div>')
                infowindow.open(map, marker)
            };
            itemEl.onmouseout = function () {
Kim, Subin's avatar
Kim, Subin committed
93
                itemEl.style.background = '#fff';
Kim, Subin's avatar
Kim, Subin committed
94
95
                infowindow.close();
            };
96
97
98
            itemEl.onclick = function () {
                setCinemaInfo({ ...cinemaInfo, address: place.address_name })
            }
Kim, Subin's avatar
Kim, Subin committed
99
100
101
102
103
104
105
106
107
108
        }
    }, [keyword])

    // 검색결과 목록 하단에 페이지번호를 표시는 함수입니다
    function displayPagination(pagination) {
        let paginationEl = page.current,
            fragment = document.createDocumentFragment(),
            i;

        for (i = 1; i <= pagination.last; i++) {
Kim, Subin's avatar
수빈    
Kim, Subin committed
109
            // let el = <a>{i}</a>
Kim, Subin's avatar
Kim, Subin committed
110
            let el = document.createElement('a');
Kim, Subin's avatar
Kim, Subin committed
111
            // el.href = "#";
Kim, Subin's avatar
Kim, Subin committed
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
            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);
    }

    // 검색결과 항목을 Element로 반환하는 함수입니다
    function getListItem(index, places) {
Kim, Subin's avatar
Kim, Subin committed
129
130
        let el = document.createElement('div'),
            itemStr = '<div className="info">' +
Kim, Subin's avatar
Kim, Subin committed
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
                '   <h5>' + places.place_name + '</h5>';

        if (places.road_address_name) {
            itemStr += '    <span>' + places.road_address_name + '</span>' +
                '   <span className="jibun gray">' + places.address_name + '</span>';
        } else {
            itemStr += '    <span>' + places.address_name + '</span>';
        }

        itemStr += '  <span className="tel">' + places.phone + '</span>' +
            '</div>';

        el.innerHTML = itemStr;
        el.className = 'item';
        return el;
    }

    return (
        <>
            <div ref={kakaoMapDiv} style={{ width: "500px", height: "400px" }}></div>
Kim, Subin's avatar
Kim, Subin committed
151
            <div ref={menu} className={`${styles.menu} bg-white`}>
Kim, Subin's avatar
Kim, Subin committed
152
153
154
155
156
157
158
159
                <div ref={searchList}></div>
                <div ref={page}></div>
            </div>
        </>
    )
}

export default KakaoMap