[Vue.js] Kakao 지도 구현 01 - 설정 및 Level, Center 변경

Vue.js 프로젝트에서 Kakao 지도를 설정하고 중심 좌표와 Zoom Level을 변경하는 코드를 구현합니다.

[Vue.js] Kakao 지도 구현 01 - 설정 및 Level, Center 변경

아래와 같은 Vue.js 의 기능들을 주로 사용합니다.

  • KakaoMap.vue 파일 생성 - 지도를 렌더링하는 독립적인 컴포넌트를 작성합니다.
  • @click - zoomIn, zoomOut 기능, 항구 클릭으로 지도 중심 좌표 이동
  • props - 지도 옵션을 KakaoMap.vue 파일에 전달함

Source Code

총 4개의 파일

  • App.vue - 애플리케이션 루트 컴포넌트
  • KakaoMap.vue - 카카오 지도 컴포넌트
  • api.js - 백엔드 서버에서 데이터를 가져오는 모듈. 실제 서버가 없으므로 몇개의 샘플 데이터를 모듈 안에 지정한 후 사용합니다.
  • index.html - kakao 지도 관련 라이브러리 로드, google font icon 스타일시트를 로드함

프로젝트 구조

프로젝트구조
[ROOT] +- public | +- index.html (+) +- src +- components/map | +- KakaoMap.vue (+) | +- service | +- api.js (+) | +- App.vue (+) +- main.js

src/App.vue

  • 애플리케이션 루트 컴포넌트
  • 지도 컨트롤 기능 + KakaoMap.vue 를 사용
src/App.vue
<template> <div> <h3>kakao map demo(center, level)</h3> <div class="controll"> <button @click="zoom(-1)"> <span class="material-icons"> zoom_in </span> </button> <button @click="zoom(1)"> <span class="material-icons"> zoom_out </span> </button> </div> <div class="map-area"> <div class="harbors"> <div class="harbor" v-for="hbr in harbors" :key="hbr.seq" @click="showOnMap(hbr)" > <h4>{{ hbr.place }}</h4> </div> </div> <KakaoMap class="kmap" :options="mapOption" /> </div> <!-- <div class="kmap" ref="map"></div> --> </div> </template> <script> import KakaoMap from "./components/map/KakaoMap.vue"; import api from "./service/api"; export default { components: { KakaoMap, }, data() { return { mapOption: { center: { lat: 33.450701, lng: 126.570667, }, level: 8, }, harbors: [], // empty }; }, mounted() { api.harbor.all((res) => { console.log("[항구목록]", res.harbors); this.harbors = res.harbors; }); }, methods: { zoom(delta) { // delta : 1 or -1 // console.log("[delta]", delta); const level = Math.max(3, this.mapOption.level + delta); // min level 3 this.mapOption.level = level; // console.log(this.mapOption.level); }, showOnMap(harbor) { // console.log("[center]", harbor); this.mapOption.center = { lat: harbor.lat, lng: harbor.lng, }; }, }, }; </script> <style lang="scss"> button { border: 1px solid transparent; padding: 6px; background-color: #efefefdd; border-radius: 6px; &:hover { background-color: #ddd; border-color: #ddd; cursor: pointer; } &:active { background-color: #aaa; border-color: #aaa; } } .map-area { display: flex; .harbors { .harbor { padding: 10px; border: 1px solid transparent; &:hover { background-color: aliceblue; border-color: #6a9dff; cursor: pointer; } &:active { background-color: rgb(166, 197, 224); border-color: #4471c5; } h4 { margin: 0; } } } .kmap { flex: 1 1 auto; } } </style>

src/components/map/KakaoMap.vue

  • kakao 지도 렌더링용 컴포넌트
  • 재사용을 위해 별도의 컴포넌트로 분리함
src/components/map/KakaoMap.vue
<template> <div ref="map"></div> </template> <script> let kakao = window.kakao; export default { props: ["options"], data() { return { mapInstance: null, }; }, mounted() { kakao = kakao || window.kakao; console.log(this.$refs.map); // should be not null var container = this.$refs.map; const { center, level } = this.options; this.mapInstance = new kakao.maps.Map(container, { center: new kakao.maps.LatLng(center.lat, center.lng), level, }); // console.log(this.mapInstance); }, watch: { "options.level"(cur, prev) { console.log(`[LEVEL CHANGED] ${prev} => ${cur}`); // for testing this.mapInstance.setLevel(cur); }, "options.center"(cur) { // console.log("[NEW CENTER]", cur.lat, cur.lng); // for test this.mapInstance.setCenter(new kakao.maps.LatLng(cur.lat, cur.lng)); }, }, }; </script> <style> .kmap { height: 600px; } </style>

src/service/api.js

  • 백엔드 서버와의 통신을 담당함
  • 서버가 없으므로 몇개의 항구 데이터를 샘플로 사용합니다.
src/service/api.js
const api = { harbor: { all(callback) { // 서버가 없으므로 가짜 데이터를 사용함 const harbors = [ { seq: 398, place: "제주항 국제 여객 터미널", lat: 33.52456237850086, lng: 126.54371888191963, }, { seq: 399, place: "통영항", lat: 34.83952733985843, lng: 128.42015935198992, }, { seq: 400, place: "부산 국제 크루즈 터미널", lat: 35.07980714092641, lng: 129.0798233676466, }, { seq: 401, place: "여수 연안 여객 터미널", lat: 34.73912218990838, lng: 127.7326117746759, }, { seq: 402, place: "목포 연안 여객 터미널", lat: 34.78242103832617, lng: 126.38379614665682, }, { seq: 403, place: "군산항 연안 여객 터미널", lat: 35.97769454696543, lng: 126.63282769595156, }, { seq: 404, place: "인천항 연안 여객 터미널", lat: 37.45340487975725, lng: 126.59951650605112, }, ]; callback({ success: true, harbors }); }, }, }; export default api;

public/index.html

  • kakao 지도 라이브러리를 include 함
  • google font icon 스타일을 include 함
public/index.html
<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <title><%= htmlWebpackPlugin.options.title %></title> <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=e157567be3a5d1b3d0d3f47e1f7a5e6a" ></script> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> </head> <body> <noscript> <strong >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>

상세 구현에 대한 설명은 아래 문서에서 다룹니다.

0. 목록

  1. 지도 설정 및 테스트 - 지도 사용을 위한 설정, 올바로 작동하는지 테스트 코드 작성
  2. KakaoMap.vue 컴포넌트 생성 - 별도의 지도 렌더링용 컴포넌트를 준비
  3. Zoom 변경 버튼 준비 - zoom 변경 버튼 디자인
  4. Zoom Level 변경 기능 - 지도 확대/축소 기능 구현
  5. 지도 중심 변경 - 클릭한 항구로 지도 중심 이동

1. 지도 설정 및 테스트

2. KakaoMap.vue 컴포넌트 생성

3. Zoom 변경 버튼 준비

4. Zoom Level 변경 기능 - 지도 확대 축소

5. 지도 중심 변경 - 클릭한 항구로 지도 중심 이동