概要
に対して機能追加
で構築したデータベースに対して、GraphQLを使用してWebカメラの情報を取得し、vue3-google-mapを使用してGoogle Map上にマーカーを設定した。
個人的には、検索結果を変数に設定するのみで、Google Map上のマーカーが更新されるのが便利だと思った。
マーカー登録部分
json配列webCamsに格納されているWebカメラの情報をGoogle Mapに登録している。
<template>
<GoogleMap id="gmap" ref="mapRef" api-key="<googlemap api key>" style="width: 100%; height: 500px" :center="center" :zoom="15">
<Marker :options="markerOptions" />
<MarkerCluster>
<Marker v-for="(webCam, i) in webCams" :options="{ position: {lat:webCam.location.latitude,lng:webCam.location.longitude} }" :key="i">
<InfoWindow>
<div><a v-bind:href="webCam.player.day.link" target="_blank">{{ webCam.title }}</a></div>
<div><img :src="webCam.image.current.thumbnail" /></div>
</InfoWindow>
</Marker>
</MarkerCluster>
</GoogleMap>
</template>
複数のアイコンを登録するには、vue3-google-mapライブラリのMarkerClusterコンポーネントを使用する。
また、InfoWindowタグを設定することにより、各マーカーに対して情報Windowを設定することができる。Json配列webCamsの中身が変更されると、マーカーも入れ替わる。個々のJsonには、「タイトル」「WebカメラのPlayerのリンク」「サムネイルへのリンク」を持たせた、
type webCamObj = {
id:string;
status: string;
title: string;
location : {
latitude: number;
longitude: number;
}
player : {
day:{
available:string;
link:string;
}
}
image : {
current : {
thumbnail:string;
}
};
};
検索結果を配列に設定する部分
Google Mapの緯度、経度の範囲を指定して、GraphQLを使用してMongoDB AtlasからWebカメラ情報をMax200件を検索した。取得したデータを以下の箇所で配列webCamsに設定する。webCamsに設定された内容で、Google Map上のマーカーが更新される。Javascriptで自作する場合、マーカーの削除、登録で手間がかかる。
webCams.value = Array.from(data.data.webcams);
getWebCamList関数は、Google Mapのイベントリスナーに登録し、Mapの範囲の変更とともにマーカーが入れ替わるようにした。
(以下のコードでは範囲指定が適当すぎて取れない箇所がある。)
const webCams = ref<Array<webCamObj>>([]);
const authToken = ref('');
const getWebCamList = function(map:any){
const latlngBound = map.getBounds();
const latlngNE = latlngBound.getNorthEast();
const latlngSW = latlngBound.getSouthWest();
const latitude_gte = latlngSW.lat(), latitude_lt = latlngNE.lat(), longitude_gte = latlngSW.lng(), longitude_lt = latlngNE.lng();
const token = 'Bearer ' + authToken.value ;
const queryMsg = `query {
webcams(query:{status:"active",location:{
longitude_lt:${longitude_lt},
longitude_gte:${longitude_gte},
latitude_lt:${latitude_lt},
latitude_gte:${latitude_gte}}}
,limit:200
,sortBy:ID_ASC) {
id
title
location{
latitude
longitude
}
player{
day{
available
link
}
}
image{
current{
thumbnail
}
}
}
}`;
const gmap = document.getElementById("gmap");
if (gmap != null && gmap != undefined){
gmap.style.pointerEvents ="none";
}
fetch('https://realm.mongodb.com/api/client/v2.0/app/<アプリID>/graphql', {
method: 'POST',
headers: {
'Authorization': token ,
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: queryMsg
})
})
.then(response => response.json())
.then(data =>{
webCams.value = Array.from(data.data.webcams);
const gmap = document.getElementById("gmap");
if (gmap != null && gmap != undefined){
gmap.style.pointerEvents = "auto";
}
})
.catch(error => console.error(error));
};
所感
変数の更新とともに、Map上のマーカーの情報も更新されるところが便利に感じた。
index.vue全文
<template>
<GoogleMap id="gmap" ref="mapRef" api-key="<googlemap api key>" style="width: 100%; height: 500px" :center="center" :zoom="15">
<Marker :options="markerOptions" />
<MarkerCluster>
<Marker v-for="(webCam, i) in webCams" :options="{ position: {lat:webCam.location.latitude,lng:webCam.location.longitude} }" :key="i">
<InfoWindow>
<div><a v-bind:href="webCam.player.day.link" target="_blank">{{ webCam.title }}</a></div>
<div><img :src="webCam.image.current.thumbnail" /></div>
</InfoWindow>
</Marker>
</MarkerCluster>
</GoogleMap>
</template>
<style>
#gmap {
pointer-events: auto;
}
</style>
<script setup lang="ts">
import { GoogleMap, InfoWindow, Marker ,MarkerCluster} from "vue3-google-map";
import { ref } from "vue";
import { webCamObj } from "./def/webCam"
const mapRef = ref(null);
const center = ref({ lat: 0, lng: 0 }); // first position
const markerOptions = ref({ position: center})
onMounted(() => {
getAuthenticate();
});
const webCams = ref<Array<webCamObj>>([]);
const authToken = ref('');
const getAuthenticate = function () {
fetch('https://realm.mongodb.com/api/client/v2.0/app/<アプリID>/auth/providers/api-key/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"key": "<MongoDB Atlas APIキー>"
})
})
.then(response => response.json())
.then(data =>{
authToken.value = data.access_token;
}).catch(error => console.error(error));
};
const getWebCamList = function(map:any){
const latlngBound = map.getBounds();
const latlngNE = latlngBound.getNorthEast();
const latlngSW = latlngBound.getSouthWest();
const latitude_gte = latlngSW.lat(), latitude_lt = latlngNE.lat(), longitude_gte = latlngSW.lng(), longitude_lt = latlngNE.lng();
const token = 'Bearer ' + authToken.value ;
const queryMsg = `query {
webcams(query:{status:"active",location:{
longitude_lt:${longitude_lt},
longitude_gte:${longitude_gte},
latitude_lt:${latitude_lt},
latitude_gte:${latitude_gte}}}
,limit:200
,sortBy:ID_ASC) {
id
title
location{
latitude
longitude
}
player{
day{
available
link
}
}
image{
current{
thumbnail
}
}
}
}`;
const gmap = document.getElementById("gmap");
if (gmap != null && gmap != undefined){
gmap.style.pointerEvents ="none";
}
fetch('https://realm.mongodb.com/api/client/v2.0/app/<アプリID>/graphql', {
method: 'POST',
headers: {
'Authorization': token ,
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: queryMsg
})
})
.then(response => response.json())
.then(data =>{
webCams.value = Array.from(data.data.webcams);
const gmap = document.getElementById("gmap");
if (gmap != null && gmap != undefined){
gmap.style.pointerEvents = "auto";
}
})
.catch(error => console.error(error));
};
//
// getLocation is called when the map is ready
//
const getLocation = function(map:any,center:any,markerOptions:any){
const markerIcon = {
url:'./images/man.png',
scaledSize: new mapRef.value.api.Size(30, 30)
}
navigator.geolocation.getCurrentPosition(
// success callback
function(position) {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
map.panTo({ lat, lng });
center.value = { lat: lat, lng: lng };
markerOptions.value = { position: center, icon: markerIcon };
},
// error callback
function(error) {
console.error(`Error getting location: ${error.message}`);
}
);
}
watch(() => mapRef.value?.ready, (ready) => {
if (!ready) return;
const map = mapRef.value.map;
getLocation(map,center,markerOptions);
map.addListener("idle", (e:any) => {
getWebCamList(map);
});
})
</script>