우선 CGV의 좌표를 가져오기 위해 영화관 시설 데이터가 담긴 CSV 파일을 다운로드
https://www.culture.go.kr/bigdata/user/data_market/detail.do?id=54331f17-d090-4b91-bc8c-95ccb134303f
카카오 맵 API를 이용해 화면에 지도를 출력 후, CSV파일에서 CGV의 데이터만 파싱 후 지점명, 주소, 도로명 주소, 위도 경도를 가져와 뿌려주었다. d3.csv 메서드를 이용할 때 두 번째 함수가 비동기로 실행되어서 여기서 애를 많이 먹었다...
처음엔 아래처럼 코드를 작성했다.
let test = [];
d3.csv("cgvList.csv", function (data) {
if (data.poi_nm == "CGV") {
let obj = {};
obj.content = '<div>' + data.branch_nm + '</div>';
// obj.latlng = new kakao.maps.LatLng(data.x, data.y);
test.push(obj); // 배열에 추가
}
});
console.log( test);
console.log("test[0] : " + test[0]);
console.log("test.length : " + test.length);
이런 식으로 d3.csv를 이용해 csv파일을 가져오고, 데이터를 전역변수 배열에 추가해주었는데 콘솔창에 출력해보니 test 즉 배열 전체는 출력이 되는데 인덱스나 길이를 출력하려니까 자꾸 undefined 0 으로 출력되었다......ㅜㅜ 당최... 배열은 잘 출력이 되는데 인덱스로 출력하니 안되는 이유를 알 수가 없었다!!!!
여기저기 질문글 남기고 찾아보니 test는 객체를 출력한건데, 직렬화해서 출력한 게 아니라 그 객체의 레퍼런스를 갖고 있는 거라서 그 객체의 내부에 저장된 값이 이후에 바뀐거라 이미 출력한 이후에라도 바뀔 수 있다고 한다.
console.log(test) 대신 console.log(JSON.stringify(test))처럼 직렬화해서 출력하면 생각했던대로 빈 배열([])만 출력될 것이라고...
레퍼런스나 비동기 병렬 처리 부분은 공부가 조금 더 필요할 것 같다!!ㅜㅜ 추가로 promise, async/await에 대한 부분도...
어쨌든 해결 방법을 찾았다. d3.csv 에 메서드체이닝으로 then을 연결 후 여기에서 뒷부분에 실행해야할 코드를 넣어주었다.
카카오 맵 API에 csv파일에서 파싱해온 cgv의 위도 경도를 이용해 마커를 표시하고, 마우스를 올리면 지점명과 주소, 도로명 주소를 오버레이로 표시되도록 했다.
----- HTML 코드
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=99fbd6629cf7202febfa5d915b1ff3c3"></script>
<script defer src="./map.js"></script>
<style>
.wrap {position: absolute;left: 0;bottom: 40px;width: 288px;height: 110px;margin-left: -144px;text-align: left;overflow: hidden;font-size: 12px;font-family: 'Malgun Gothic', dotum, '돋움', sans-serif;line-height: 1.5;}
.wrap * {padding: 0;margin: 0;}
.wrap .info {width: 286px;height: 100px;border-radius: 5px;border-bottom: 2px solid #ccc;border-right: 1px solid #ccc;overflow: hidden;background: #fff;}
.wrap .info:nth-child(1) {border: 0;box-shadow: 0px 1px 2px #888;}
.info .title {padding: 5px 0 0 10px;height: 30px;background: #eee;border-bottom: 1px solid #ddd;font-size: 18px;font-weight: bold;}
.info .body {position: relative;overflow: hidden;}
.info .desc {position: relative;margin: 13px 0 0 10px;height: 75px;}
.desc .ellipsis {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
.desc .jibun {font-size: 11px;color: #888;margin-top: -2px;}
.info:after {content: '';position: absolute;margin-left: -12px;left: 50%;bottom: 0;width: 22px;height: 12px;background: url('https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/vertex_white.png')}
</style>
</head>
<body>
<div id="map" style="width:1200px;height:600px;"></div>
</body>
</html>
----- JavaScript 코드
var mapContainer = document.getElementById('map'), // 지도를 표시할 div
mapOption = {
center: new kakao.maps.LatLng(35.15683361469301, 129.05663293413534), // 지도의 중심좌표 - 서면 롯데백화점으로 설정
level: 4 // 지도의 확대 레벨,
};
var map = new kakao.maps.Map(mapContainer, mapOption); // 지도를 생성합니다
// 마커를 표시할 위치와 내용을 가지고 있는 객체 배열입니다
// var positions = [{
// content: '<div>예시1</div>',
// latlng: new kakao.maps.LatLng(127.387989439949, 36.3475950596837),
// }];
// 국내 영화관 목록 데이터 csv 파일 불러오기
d3.csv("cgvList.csv", function (data) {
if (data.poi_nm == "CGV") { // CGV만 파싱
let obj = {}; // 지점명과 주소, 위도 경도 반환받을 배열
obj.content =
'<div class="wrap">' +
' <div class="info">' +
' <div class="title">CGV ' +
data.branch_nm + // 지점명
' </div>' +
' <div class="body">' +
' <div class="desc">' +
' <div class="ellipsis">'+
data.sido_nm + " " + data.sgg_nm + " " + data.bemd_nm + " " + data.ri_nm + " " + data.beonji + // 주소
' </div>' +
' <div class="jibun ellipsis">(도로명) ' +
data.rd_nm + " " + data.bld_num + // 도로명 주소
' </div>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
obj.latlng = new kakao.maps.LatLng(data.y, data.x); // 위도, 경도
return obj;
}
}).then((positions) => { // 여기에서 매개변수로 들어간 positions는 위에서 리턴한 obj를 담은 배열임
for (var i = 0; i < positions.length; i++) {
// 마커를 생성합니다
var marker = new kakao.maps.Marker({
map: map, // 마커를 표시할 지도
position: positions[i].latlng // 마커의 위치
});
// 마커 위에 커스텀오버레이를 표시합니다
// 마커를 중심으로 커스텀 오버레이를 표시하기위해 CSS를 이용해 위치를 설정했습니다
var overlay = new kakao.maps.CustomOverlay({
content: positions[i].content,
map: map,
position: marker.getPosition()
});
overlay.setMap(null); // 처음엔 오버레이 다 닫은 상태로 만듦
kakao.maps.event.addListener(marker, 'mouseover', makeOverListener(map, marker, overlay)); // 마우스 올리면 오버레이 표시
kakao.maps.event.addListener(marker, 'mouseout', makeOutListener(overlay)); // 마우스 제거하면 오버레이 닫음
}
});
// 오버레이를 표시하는 클로저를 만드는 함수
function makeOverListener(map, marker, overlay) {
return function() {
overlay.setMap(map);
};
}
// 오버레이를 닫는 클로저를 만드는 함수
function makeOutListener(overlay) {
return function() {
overlay.setMap(null);
};
}
그러면 이런식으로 지도에 CGV의 위치가 마커로 표시되어 나타난다.
여기서 마우스를 올리면 해당 CGV의 지점명과 주소가 오버레이로 나타난다!!!
이야 어렵다!!!!
'2. Front-end > 2-3. Java Script' 카테고리의 다른 글
JS - [ 모든 자식 엘리먼트 삭제 ] (0) | 2022.06.29 |
---|---|
JS - [ 카카오 맵 API ] (0) | 2022.05.31 |
JS - [ CSV 파일 불러오기 ] (0) | 2022.05.28 |
JS - [좌석 만들기] (0) | 2022.05.25 |
JS - [ 오늘부터 14일간 날짜 출력 ] (0) | 2022.05.24 |