0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

vue3-google-mapを使って複数のアイコンをGoogle Map上に登録

Posted at

概要

に対して機能追加

で構築したデータベースに対して、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;
        }
    };
};

実際のイメージは以下のような感じ。
image.png

検索結果を配列に設定する部分

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>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?