2020년 1월 31일 금요일

Docker 기반 Cesium 활용

이 글은 도커 기반 맵서버와 세슘 사용방법을 간략히 설명한다. 이 글은 다음 링크를 참고하였다.
도커를 실행하고, 다음과 같이 cesium 도커 이미지를 찾아 실행한다.

도커이미지 실행 후 도커에 지정된 포트 주소를 아래와 같이 입력하면, 다음과 같은 결과를 확인할 수 있다.
Cesium

도커에는 이와 유사한 이미지가 등록되어 있다. 이를 이용하면, 간단한 지도 서버는 쉽게 개발 가능하다. 참고로, 아래는 mapserver 이미지를 검색해 실행한 결과이다.
mapserver 

레퍼런스

2020년 1월 26일 일요일

Daum map 기반 Vue 웹 서비스 개발 방법

이 글은 간단한 Daum map(현재 카카오맵) 기반 Vue 웹 서비스 개발 방법을 소개한다. 이 글은 다음 맵을 사용하기 위해 개발 키 값을 얻고, 간단한 Vue 기반 Daum map 서비스를 개발방법을 설명한다. 참고로, 이 예제는 미리 개발된 vue-daum-mapdemo예제를 사용한다.

Vue.js는 node.js를 사용하며, node.js는 서버 개발을 쉽게 지원하는 플랫폼이며, Vue.js 는 node.js 에서 실행될 수 있는 동적 웹 UI(user interface) App 개발을 지원하는 유명한 프레임웍이다.

이 글에서 node.js나 vue 내용은 자세히 설명하지 않는다. 관련 내용은 아래 링크를 참고한다.
이 글의 예제를 따라한 결과는 다음과 같다.
실행 모습(스마트폰 화면)
환경 설정
Node.js와 Vue를 설치하고, Daum Map API key값을 카카오 개발자 사이트(developers.kakao.com)에서 획득한 한다. 키 값은 해당 사이트를 가입하고, 다음과 같이 앱을 추가하여 얻을 수 있다. 
앱을 추가한 후, 다음과 같이 앱 키를 얻을 수 있다. 

해당 키를 사용하는 웹사이트 주소를 다음과 같이 지정하면, 카카오 맵을 사용할 수 있다. 

다음과 같이 Vue CLI를 설치한다.
npm install -g vue-cli

카카오 맵 객체 기반 지도 앱 개발
다음과 같이 패키지를 설치하고, 프로젝트를 생성해 보자. 향상된 인터페이스 적용을 위해 vuetify를 사용하고, daum map을 사용하기 위해 vue-daum-map을 설치하였다. 
vue init webpack-simple mapdaum
cd mapdaum
npm i vue-daum-map
vue add vuetify
npm install vuetify-dialog
npm install
npm run dev

결과, 간단한 vue app이 서버로 실행될 것이다. 종료하고, vue 컴포넌트를 개발해 본다.

프로젝트 폴더내 main.js를 다음과 같이 코딩한다.

import Vue from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify';
import VuetifyDialog from 'vuetify-dialog'

Vue.config.productionTip = false

Vue.use(VuetifyDialog, {
  context: {
    vuetify
  }
})

new Vue({
  vuetify,
  render: h => h(App)
}).$mount('#app')

다음과 같이 App.vue를 코딩한다. 
<template>
  <v-app>
    <v-content>
      <HelloWorld/>
    </v-content>
  </v-app>
</template>

<script>
import HelloWorld from './components/HelloWorld';

export default {
  name: 'App',

  components: {
    HelloWorld,
  },

  data: () => ({
    //
  }),
};
</script>

다음과 같이 HelloWorld.vue 를 코딩한다. 그 중에 input key value 부분에 키 값을 넣는다. mapTypeId는 Hybrid map 형식으로 설정하고, 맵 위에 이벤트 받을 @event 함수를 설정한다. 이 경우는 클릭 이벤트 메시지를 받아, 다이얼로그를 호출하는 함수를 설정하였다. vue-daum-map에 대한 상세한 옵션과 이벤트는 이 링크를 참고한다. 
<template>
  <v-container>
   <h1>Daum Map Demo</h1>
    <vue-daum-map
      :appKey="appKey"
      :center.sync="center"
      :level.sync="level"
      :mapTypeId="mapTypeId"
      :libraries="libraries"

      @load="onLoad"
      @center_changed="onMapEvent('center_changed', $event)"
      @zoom_start="onMapEvent('zoom_start', $event)"
      @zoom_changed="onMapEvent('zoom_changed', $event)"
      @bounds_changed="onMapEvent('bounds_changed', $event)"
      @click="onMapEvent('click', $event)"
      @dblclick="onMapEvent('dblclick', $event)"
      @rightclick="onMapEvent('rightclick', $event)"
      @mousemove="onMapEvent('mousemove', $event)"
      @dragstart="onMapEvent('dragstart', $event)"
      @drag="onMapEvent('drag', $event)"
      @dragend="onMapEvent('dragend', $event)"
      @idle="onMapEvent('idle', $event)"
      @tilesloaded="onMapEvent('tilesloaded', $event)"
      @maptypeid_changed="onMapEvent('maptypeid_changed', $event)"

      style="width:500px;height:400px;">
    </vue-daum-map>

    <h2>Options</h2>
    <table>
      <colgroup>
        <col width="60" />
        <col />
      </colgroup>
      <tr>
        <th>Level</th>
        <td><input type="range" min="1" max="14" v-model.number="level"> {{level}}</td>
      </tr>
      <tr>
        <th>Lat</th>
        <td><input type="number" v-model.number="center.lat" step="0.0001"></td>
      </tr>
      <tr>
        <th>Lng</th>
        <td><input type="number" v-model.number="center.lng" step="0.0001"></td>
      </tr>
    </table>  
  </v-container>
</template>

<script>
import VueDaumMap from 'vue-daum-map';

export default {
  name: 'HelloWorld',
components: {VueDaumMap},
data: () => ({
appKey: "input key value",
center: {lat:37.541, lng:126.986},
level: 3,
mapTypeId: VueDaumMap.MapTypeId.HYBRID,
libraries: [],
mapObject: null
}),
methods: {
onLoad (map) {
// var bounds = map.getBounds();
// var boundsStr = bounds.toString();
// alert(boundsStr);
this.mapObject = map;
},
onMapEvent (event, params) {
var msg = event + params;
if(event == 'click') {
this.$dialog.confirm({
         text: "<center>Wild<br/><img src='https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg' height=200/><input value='input'></input><br/></center>"+msg, title: 'Information'});
}
}
}
};
</script>

다음과 같이 실행하면 결과를 확인할 수 있다.
npm run dev




좀 더 상세한 내용은 다음 링크를 참고한다.

레퍼런스

2020년 1월 25일 토요일

Vue와 Leaflet 기반 인터렉티브 맵 개발

이 글은 Vue기반 Leaflet 패키지를 이용한 인터렉티브 맵 개발을 간단히 소개한다.

맵을 웹사이트에 표현하는 방법은 다양한다. Google Maps, Mapbox, Leaflet 등을 사용하면 클릭 몇번으로 공간정보 맵 기반 서비스를 쉽게 개발할 수 있다.

이 글은 Leaflet 을 이용해 간단한 오픈 스트리트 맵(OSM. Open street map) 기반 인터렉티브 지도 개발 방법과 객체 함수 사용 방법 등을 간략히 보여준다.

Leaflet 개요
Leaflet은 손쉽게 상호동작을 지원하는 지도 개발을 지원하는 도구로 널리 사용된다. Leaflet을 이용하면, google map, open street map, bing map 등을 손쉽게 사용할 수 있고, 맵에 다양한 형식의 layer를 추가하거나 그래픽 정보를 만들 수 있다.
Leaflet 소개 영상

이 글은 Node.js 기반 Vue를 사용하는 Vue2Leaflet 을 이용한다.
이 패키지는 npm으로 설치할 수 있다.
npm install vue2-leaflet leaflet --save

yarn을 사용하므로 다음과 같이 설치한다(참고).
npm install --global yarn

이후 다음과 같은 절차로 소스 다운로드 받고, 라이브러리 심벌을 링크한 후 설치한다.
# clone the repository
git clone https://github.com/KoRiGaN/Vue2Leaflet.git
cd Vue2Leaflet
# install dependencies and build vue2-leaflet
npm install
# create a symlink for vue2-leaflet
yarn link
cd examples
yarn install
# create a symbolic link for vue2-leaflet in node_modules/
yarn link vue2-leaflet
# serve with hot reload at localhost:8080
yarn run serve

실행 결과를 다음과 같이 확인할 수 있다(심벌 에러가 날 경우 부록 참고).
실행 결과

소스 분석
소스 분석을 위해 Examples/src/componets 폴더 안의 GeometryTest.vue 예제를 확인해 본다. 이 예제는 leaflet l-map 객체와 l-circle, l-rectangle 객체를 이용해 맵과 그래픽을 표시한다. 그래픽 데이터는 data() 함수에서 종류별로 정의한다. 또한, Change rectangle sytle 이란 버튼을 추가하고, 이벤트 발생 시 선 두께를 변경한다.
<template>
  <div>
    <div style="height: 10%; overflow: auto;">
      <h3>Geometry</h3>
      <button @click="clickBtn">
        Change rectange style
      </button>
    </div>
    <l-map
      :zoom="zoom"
      :center="center"
      style="height: 90%"
    >
      <l-tile-layer
        :url="url"
        :attribution="attribution"
      />
      <l-circle
        :lat-lng="circle.center"
        :radius="circle.radius"
      />
      <l-rectangle
        :bounds="rectangle.bounds"
        :l-style="rectangle.style"
      />
      <l-polygon
        :lat-lngs="polygon.latlngs"
        :color="polygon.color"
      />
      <l-polyline
        :lat-lngs="polyline.latlngs"
        :color="polyline.color"
      />
    </l-map>
  </div>
</template>

<script>
import { latLng } from "leaflet";
import {
  LMap,
  LTileLayer,
  LCircle,
  LRectangle,
  LPolygon,
  LPolyline
} from "vue2-leaflet";  // library

export default {
  name: "GeometryTest",
  components: {
    LMap,
    LTileLayer,
    LCircle,
    LRectangle,
    LPolygon,
    LPolyline
  },
  data() {
    return {
      zoom: 11,
      center: [47.31322, -1.319482],
      circle: {
        center: latLng(47.41322, -1.0482),
        radius: 4500
      }, // Draw circle
      rectangle: {
        bounds: [[47.341456, -1.397133], [47.303901, -1.243813]],
        style: { color: "red", weight: 5 }
      }, // Draw rectangle
      polygon: {
        latlngs: [
          [47.2263299, -1.6222],
          [47.21024000000001, -1.6270065],
          [47.1969447, -1.6136169],
          [47.18527929999999, -1.6143036],
          [47.1794457, -1.6098404],
          [47.1775788, -1.5985107],
          [47.1676598, -1.5753365],
          [47.1593731, -1.5521622],
          [47.1593731, -1.5319061],
          [47.1722111, -1.5143967],
          [47.1960115, -1.4841843],
          [47.2095404, -1.4848709],
          [47.2291277, -1.4683914],
          [47.2533687, -1.5116501],
          [47.2577961, -1.5531921],
          [47.26828069, -1.5621185],
          [47.2657179, -1.589241],
          [47.2589612, -1.6204834],
          [47.237287, -1.6266632],
          [47.2263299, -1.6222]
        ],
        color: "#ff00ff"
      }, // Draw polygon
      polyline: {
        latlngs: [
          [47.334852, -1.509485],
          [47.342596, -1.328731],
          [47.241487, -1.190568],
          [47.234787, -1.358337]
        ],
        color: "green"
      }, // Draw polyline
      url: "http://{s}.tile.osm.org/{z}/{x}/{y}.png",
      attribution:
        '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    };
  },
  methods: {
    clickBtn() {
      this.rectangle.style.weight++;
      this.rectangle.style.color =
        this.rectangle.style.weight % 2 === 0 ? "blue" : "green";
    }
  }
};
</script>

맵을 다루다 보면, 미리 지정된 태그와 data() 함수로만 처리하기 어려운 경우가 있다. 이럴 경우, 맵 객체 등을 직접 접근해 코딩해야 한다. 다음과 같이 GeometryTest.vue 코드에 맵 태그를 ref attribute 로 설정하고, zoom 값을 재설정하는 함수를 만들어보자. 

<template>
  <div>
   ...
    <l-map
      ref="map"    
      :zoom="zoom"
      :center="center"
      style="height: 90%"
    >
   ...
  </div>
</template>

<script>
  methods: {
    clickBtn() {
      var z = this.$refs.map.mapObject.getZoom();
      this.$refs.map.mapObject.setZoom(z * 0.8);
    },
  },
</script>

이렇게 코딩하고 버튼을 클릭하면 zoom out이 될 것이다. 이와 관련된 상세한 내용은 Issues 리스트를 참고하라. refs 속성에 관한 내용은 아래 링크를 참고하라.
앞서 확인한 바와 같이 leaflet 을 이용하면 손쉽게 인터렉티브 맵 웹 어플리케이션을 개발할 수 있다.

부록 - 심벌 링크 이슈
run할 때 라이브러리 심벌 링크 처리 에러로 제대로 import 경로가 맞지 않는 경우 에러가 발생할 수 있다.
yarn link 심벌 에러

본인의 경우, 해당 소스가 많지 않아 코드의 import 경로를 수동으로 수정해 주었다. 소스가 많은 경우 yarn link 관련 레퍼런스를 참고해 문제를 해결해야 한다.
소스코드 import path 에러 수정 후

레퍼런스

Vue.js 소개 및 참고자료

Vue는 node.js 기반으로 application server를 만들거나, user interface를 개발할 때 매우 우용한 도구이다. 이 글은 이에 대한 간략한 소개와 관련 참고 자료이다.


2020년 1월 24일 금요일

Vuetify 기반 Vuetify Dialog 사용하기

Vuetify 기반 Vuetify Dialog를 사용하는 방법을 간단히 다룬다.
Vuetify는 별다른 설정없이 개선된 User Interface를 사용할 수 있는 방법을 제공하는 패키지이다. 이를 이용한 Dialog 표시 방법을 보여준다.
참고로, 이 글에서 소개할 다이얼로그는 모달(modal)방식이다. Vuetify dialog는 다양한 스타일의 다이얼로그를 간단한 명령으로 생성할 수 있다.

개발 환경
다음과 같이 개발 환경을 설정한다.
npm install @vue/cli -g
vue --version

Vuetify는 3.0 버전 이상이어야 제대로 동작한다.

프로젝트 생성
다음과 같이 프로젝트를 생성한다.
vue create app
cd app
vue add vuetify
npm install vuetify-dialog

다이얼로그 사용
생성된 폴더 내 main.js 에 다음과 같이 코딩한다.
import Vue from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify';
import VuetifyDialog from 'vuetify-dialog'

Vue.config.productionTip = false

Vue.use(VuetifyDialog, {
  context: {
    vuetify
  }
})

new Vue({
  vuetify,
  render: h => h(App)
}).$mount('#app')

HelloWorld.vue 다음과 같이 button과 관련된 코딩을 추가한다.
<template>
  ...
  <button v-on:click="greet">Greet</button>
  ...
</template>

<script>
export default {
  name: 'HelloWorld',
  methods: {
    greet: function () {
      this.$dialog.confirm({
         text: "What's your name? <img src='https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Natgeologo.svg/1200px-Natgeologo.svg.png' height=100/><input value='input'></input>", title: 'Warning'});
    }
  },
  ...
</script>

이제 서버를 실행한다.
npm run serve

결과는 다음과 같다. 

Greet 버튼을 클릭하면, 다음과 같이 모달 다이얼로그가 실행된다.

레퍼런스

2020년 1월 20일 월요일

Python 으로 라이노 Addin 개발

Python 으로 라이노 Addin 개발 방법을 간략히 설명한다.

레퍼런스
참고 - 유사위상
길이 등 치수는 없는 상대적 방향성만 정의된 위상구조
T1 = {S*, L, R, L, R, L3, R3, L*, R*}

간단한 Web 기반 공간정보 서비스 개발을 위한 Google map과 Vue.js 연동 방법

이 글은 웹 기반 Google map과 Vue.js 연동 방법을 예제를 통해 간단히 구현해 본다.
참고로, Vue.js는 node.js를 사용하며, node.js는 서버 개발을 쉽게 지원하는 플랫폼이며, Vue.js 는 node.js 에서 실행될 수 있는 동적 웹 UI(user interface) App 개발을 지원하는 유명한 프레임웍이다.

이를 활용하면, 인터넷 접속되는 다양한 디바이스에서 동작 가능한 공간정보 기반 앱 서비스를 제공하는 서버를 간단히 개발할 수 있다. 예를 들어, 맵위에 마커를 생성하거나, 계산된 결과를 오버랩하여 표시할 수 있다. 마커 등은 이벤트를 받을 수 있으므로, 클릭 시 좀 더 상세한 정보나 뷰를 표시하도록 할 수 있다.

이 글에서 node.js나 vue 내용은 자세히 설명하지 않는다. 관련 내용은 아래 링크를 참고한다. 다음(카카오) 맵 연동 방법은 이 글을 참고한다.
Google map을 사용하는 방법은 크게 두 가지가 있다. 하나는 직접 google map 객체를 사용하는 방법이고, 다른 하나는 npm 에서 설치가능한 google maps 패키지를 사용하는 방법이다. 이 글은 두 가지 방법 모두 소개한다.

이 글의 예제를 따라한 결과는 다음과 같다.
npm 에서 설치한 vue2-google-maps 패키지 이용 결과
 스마트폰에서 실행된 구글맵 앱 서비스(iPhone 9. Chrome. Safari)
Google map 객체 직접 이용 결과

환경 설정
Node.jsVue를 설치하고, Google Map API key값을 console.cloud.google.com 에서 획득한 한다(API key값 생성 방법은 레퍼런스 참고).
Google Map API
다음과 같이 Vue CLI를 설치한다.
npm install -g vue-cli

구글맵 객체 기반 지도 앱 개발
다음과 같이 패키지를 설치하고, 프로젝트를 생성해 보자.
vue init webpack-simple mapapp
cd mapapp
npm install
npm run dev

결과, 간단한 vue app이 서버로 실행될 것이다. 종료하고, vue 컴포넌트를 개발해 본다.

프로젝트 폴더의 index.html 파일을 다음과 같이 코딩한다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>communicating-between-vue-components</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  </head>
  <body>
    <div id="app"></div>
    <script src="https://maps.googleapis.com/maps/api/js?key=API key value"></script>

    <script src="/dist/build.js"></script>
  </body>
</html>

script에 생성된 google api key값을 설정한다.

main.js 를 코딩한다. 이 main.js는 GoogleMap, ListView, Sidebar 컴포넌트를 사용한다.
import Vue from 'vue'
import App from './App.vue'
import GoogleMap from './GoogleMap'
import ListView from './ListView'
import Sidebar from './Sidebar'

window.EventBus = new Vue({
  data(){
    return {
      sanfrancisco: [37.78268, - 122.41136]
    }
  }
});

Vue.component('GoogleMap', GoogleMap);
Vue.component('ListView', ListView);
Vue.component('Sidebar', Sidebar);

new Vue({
  el: '#app',
  render: h => h(App)
});

App.vue 를 코딩한다. App은 각 컴포넌트가 속할 구역을 템플릿으로 정의한다.
<template>
  <div id="app" class="container">
    <div class="row">
      <div class="col-4">
        <sidebar></sidebar>
      </div>
      <div class="col-8">
        <google-map></google-map>
      </div>
    </div>
    <div class="row">
      <list-view></list-view>
    </div>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

GoogleMap.vue를 src 폴더에 다음과 같이 만든다. div의 map에 Google Map을 mount 하고, 맵 객체를 생성해 설정한다.
<template>
    <div>
        <h1>Map is here</h1>
        <div id="map" class="h-250"></div>
    </div>
</template>

<style scoped>
    #map {
        margin: 0 auto;
        background: gray;
    }
    .h-250 {
        height:250px;
    }
</style>
<script>
  import Vue from 'vue';
  export default {
    props: {
      'latitude': {
        type: Number,
        default() {
          return EventBus.sanfrancisco[0]
        }
      },
      'longitude': {
        type: Number,
        default() {
          return EventBus.sanfrancisco[1]
        }
      },
      'zoom': {
        type: Number,
        default() {
          return 14
        }
      },
    },
    mounted() {
      this.$markers = [];
      this.$map = new google.maps.Map(document.getElementById('map'), {
        center: new google.maps.LatLng(this.latitude, this.longitude),
        zoom: this.zoom
      });
      Vue.nextTick().then(()=>{
        this.clearMarkers();
      });
    },
    created(){
      EventBus.$on('clear-markers', ()=>{
        this.clearMarkers();
        this.$markers = [];
      });
      EventBus.$on('add-marker', (data)=>{
        let marker     = this.makeMarker(data.latitude, data.longitude);
        this.$markers.push(marker);
      });
    },
    data(){
        return {};
    },
    methods: {
      makeMarker(latitude, longitude) {
        return new google.maps.Marker({
          position: new google.maps.LatLng(latitude, longitude),
          icon: null,
          map: this.$map,
          title: null,
        });
      },
      clearMarkers(){
        for( let i = 0; i < this.$markers.length; i++ ){
          this.$markers[i].setMap(null);
        }
      }
    }
  }
</script>

ListView.vue를 src 폴더에 다음과 같이 만든다. 이 컴포넌트는 마커 리스트를 보여준다.
<template>
    <div>
        <h1>ListView</h1>
        <p>Marker count: {{ markers.length }}</p>
        <table class="table">
            <thead>
                <tr>
                    <th>Index</th>
                    <th>Latitude</th>
                    <th>Longitude</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="marker in markers">
                    <td>{{ marker.index }}</td>
                    <td>{{ marker.latitude }}</td>
                    <td>{{ marker.longitude }}</td>
                </tr>
            </tbody>
        </table>
    </div>
</template>
<script>
    export default {
      created(){
        EventBus.$on('add-marker', (marker)=>{
          marker['index'] = this.index;
          this.index++;
          this.markers.push(marker);
        });
        EventBus.$on('clear-markers', ()=>{
          this.markers = [];
          this.index = 0;
        });
      },
      data(){
        return {
          index: 0,
          markers: []
        };
      }
    }
</script>

Slidebar.vue를 src 폴더에 다음과 같이 만든다. 이 컴포넌트는 마커를 생성하거나 삭제하는 버튼을 생성하고, 클릭 시에 이벤트를 발생한다. 이벤트는 EventBus를 통해 해당 기능을 실행하는 함수를 호출하도록 되어 있다.   
<template>
    <div>
        <h1>Sidebar</h1>
        <input type="number" step="0.0001" class="form-control" v-model="latitude">
        <input type="number" step="0.0001" class="form-control" v-model="longitude">
        <button @click="addMarker" class="btn btn-danger">Add marker</button>
        <button @click="clearMarkers" class="btn btn-default">Clear markers</button>
    </div>
</template>
<script>
  export default {
    data(){
      return {
        latitude: EventBus.sanfrancisco[0],
        longitude: EventBus.sanfrancisco[1]
      };
    },
    methods: {
      addMarker(){
        EventBus.$emit('add-marker', {
          latitude: this.latitude,
          longitude: this.longitude
        });
      },
      clearMarkers(){
        EventBus.$emit('clear-markers');
      }
    }
  }
</script>

이제 다음과 같이 실행해 보자.
npm run dev

그럼 다음과 같은 결과를 볼 수 있다. 개발용으로 Google map api 키값을 발급받은 것이라 development purposes only 문구가 맵위에 오버랩된다. 그래도, embedded된 구글맵을 테스트해보는 것에는 문제가 없다.

구글 맵에 marker를 add해 볼 수 있고, 그 리스트를 확인할 수 있다. 시간이 되면 marker에 event를 추가해 보자. 큰 문제 없이 동작하는 것을 확인할 수 있다.

vue2-google-maps 기반 지도 앱 개발
vue2-google-maps는 손쉽게 Vue기반 구글 맵을 사용할 수 있도록 만든 패키지이다. 이 예제에서는 vuetify란 패키지를 통해 좀 더 스타일 좋은 사용자 인터페이스 기능을 사용하겠다. 이를 사용하기 위해 다음과 같이 명령을 실행한다.

vue create map
cd map
vue add vuetify
npm install vuetify-dialog
npm i vue2-google-maps

main.js를 다음과 같이 코딩한다. vuetify와 dialog를 사용하기 위해 import를 하고, vue.use를 통해 VueGoogleMaps 사용을 설정한다. 그리고, 소스에서 key 값은 Google Map API키 값을 입력한다.
import Vue from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify';
import VuetifyDialog from 'vuetify-dialog'
import * as VueGoogleMaps from 'vue2-google-maps'

Vue.use(VueGoogleMaps, {
  load: {
    key: 'Input Google Map API key value',
    libraries: 'places', // This is required if you use the Autocomplete plugin
    // OR: libraries: 'places,drawing'
    // OR: libraries: 'places,drawing,visualization'
    // (as you require)

    //// If you want to set the version, you can do so:
    // v: '3.26',
  }
})

Vue.config.productionTip = false

Vue.use(VuetifyDialog, {
  context: {
    vuetify
  }
})

new Vue({
  vuetify,
  render: h => h(App)

}).$mount('#app')

App.vue를 다음과 같이 코딩한다. HelloWorld컴포넌트를 렌더링하기 위해 template에 이를 정의하고, script에서 HelloWorld 컴포넌트를 import한다.
<template>
  <v-app>
    <v-content>
      <HelloWorld/>
    </v-content>
  </v-app>
</template>

<script>
import HelloWorld from './components/HelloWorld';

export default {
  name: 'App',

  components: {
    HelloWorld,
  },

  data: () => ({
    //
  }),
};
</script>

HelloWorld.vue 컴포넌트를 다음과 같이 코딩한다. 앞서 GoogleMap를 vue에서 use하였으므로, GmapMap 컴포넌트를 사용할 수 있다. 옵션은 center위치, zoom 비율 등 다양한 값을 정의할 수 있다.
이 예제에서는 Marker를 2개 만들고, 마커를 클릭하였을 때 이벤트를 발생시켜, Vuetify 스타일 다이얼로그를 생성한다. 다이얼로그는 html로 기술하고, 이미지 사진을 추가하였다.
<template>
  <v-container>
<GmapMap
:center="{lat:10, lng:10}"
:zoom="7"
map-type-id="terrain"
style="width: 500px; height: 300px"
>
<GmapMarker
:key="index"
v-for="(m, index) in markers"
:position="m.position"
:clickable="true"
:draggable="true"
@click="clickMarker"
/>
</GmapMap>
  </v-container>
</template>

<script>
export default {
  name: 'HelloWorld',

data() {
return {
markers: [{
position: {
lat: 10.0,
lng: 10.0
}
}, {
position: {
lat: 11.0,
lng: 11.0
}
}]
};
},
methods: {
clickMarker: function () {  
      this.$dialog.confirm({
         text: "What's your name? <img src='https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Natgeologo.svg/1200px-Natgeologo.svg.png' height=100/><input value='input'></input>", title: 'Warning'});
}
}
};

</script>

실행 결과는 다음과 같다.
npm run serve
실행 후 화면
마커 클릭 시 다이얼로그

Javascript 기반 Vue 특성 상 실행상태에서 코드를 수정하면 바로 뷰에 반영되는 것을 확인할 수 있다. 다음은 Veufity Dialog 코드를 실행 중인 상태에서 수정한 결과이다. 서버를 중지하지 않고도 바로 결과가 반영되는 것을 확인할 수 있다.

vue2-google-maps의 좀 더 다양한 예제는 다음 링크를 참고한다.
구글 맵과 vue연동에 관한 좀 더 상세한 내용은 다음 레퍼런스를 참고한다.

레퍼런스