【リバースジオコーディング】JavaScriptで緯度と経度から住所を取得

JavaScriptで緯度と経度のデータから住所のデータを取得するには、逆ジオコーディング(reverse geocoding)と呼ばれる技術を使用します。逆ジオコーディングは、緯度と経度の情報を基に、その位置に関連する住所や地名などの情報を取得するプロセスです。

JavaScriptで逆ジオコーディングを実行するには、次の手順を実行します。

  1. 逆ジオコーディングを提供するサービスを選択します。Google Maps APIやMapbox APIなど、多くのジオコーディングサービスが利用可能です。それぞれのサービスには、APIキーの取得や利用規約の確認が必要な場合があります。
  2. 選択したサービスのドキュメントを参照して、逆ジオコーディングのエンドポイントやAPIメソッドについて学びます。
  3. JavaScriptでHTTPリクエストを送信して、逆ジオコーディングの結果を受け取ります。具体的な実装方法は、使用しているサービスやAPIによって異なりますが、一般的な方法は以下の通りです。
    • XMLHttpRequestやFetch APIを使用してHTTPリクエストを送信する。
    • 緯度と経度のデータをリクエストパラメータとして渡す。
    • レスポンスを受け取り、必要な住所情報を取り出す。

以下に、Google Maps Geocoding APIを使用した逆ジオコーディングの例を示します。

下記の記事を参考にしてMAP APIを取得してください。

const lat = 35.6895; // 緯度
const lng = 139.6917; // 経度

const apiKey = 'YOUR_API_KEY'; // Google Maps APIキー

const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${apiKey}`;

fetch(url)
  .then((response) => response.json())
  .then((data) => {
    if (data.results.length > 0) {
      const address = data.results[0].formatted_address;
      console.log(address); // 逆ジオコーディングの結果として取得した住所
    } else {
      console.log('No results found');
    }
  })
  .catch((error) => {
    console.log('Error:', error);
  });


上記のコードでは、latlngに緯度と経度のデータを設定し、Google Maps Geocoding APIのエンドポイントにリクエストを送信しています。APIキーを適切な値に置き換える必要があります。レスポンスデータから取得した住所情報を利用することができます。

これで下記の結果を得ることができました。

2-chōme-8-1 Nishishinjuku, Shinjuku City, Tokyo 160-0023, Japan

コードの例

下記ではVueのフレームワークを使ってユーザーが入力した緯度と経度から市、県、国名を表示させるフォームを紹介します。

実際に緯度と経度から住所を返す関数はfetchAddress()の部分になります。

※VuetifyのUIコンポーネントを使用しています。

<template>
  <v-form v-model="isValid">
    <v-container>
      <v-row>
        <v-col
          cols="12"
          md="4"
        >
          <v-text-field
            v-model="formState.video_title"
            :counter="20"
            :rules="rules20Char"
            label="Tour Title"
            required
          ></v-text-field>
        </v-col>
        <v-col
          cols="12"
          md="4"
        >
          <v-text-field
            v-model="formState.video_id"
            :counter="20"
            :rules="rules20Char"
            label="YouTube Video ID"
            required
          ></v-text-field>
        </v-col>

        <v-col
          cols="12"
          md="4"
        >
          <v-text-field
            v-model="formStateLocation.video_lat"
            :counter="20"
            :rules="rules20Char"
            label="Latitude"
            required
            @click:append-inner="fetchAddress"
          ></v-text-field>
        </v-col>
        <v-col
          cols="12"
          md="4"
        >
          <v-text-field
            v-model="formStateLocation.video_lng"
            :counter="20"
            :rules="rules20Char"
            label="Longitude"
            required
          ></v-text-field>
          {{ formStateAddress }}
        </v-col>
      </v-row>
      <v-btn
        type="submit"
        block
        class="mt-2"
        @click.prevent="postFormState"
        >Create a new 360 Tour!</v-btn
      >
    </v-container>
  </v-form>
  <v-btn @click="createForm">createForm</v-btn>
</template>

<script setup>
import { ref, reactive, watch, toRefs } from 'vue';
import { useDataStore } from '@/store/pinia';
import { onAuthStateChanged } from 'firebase/auth';
import { db } from '@/main.js';
import {
  collection,
  doc,
  onSnapshot,
  addDoc,
  updateDoc,
  deleteDoc,
  query,
  orderBy,
} from 'firebase/firestore';

const dataStore = useDataStore();

const isValid = ref(false);

const formStateAddress = ref('');

const formStateLocation = reactive({
  video_lat: '',
  video_lng: '',
});

let currentDate = '';

(function getDate() {
  const date = new Date();

  let day = date.getDate();
  let month = date.getMonth() + 1;
  let year = date.getFullYear();
  currentDate = `${day}/${month}/${year}`;
})();

const formState = reactive({
  uid: '',
  video_title: '',
  video_id: '',
  display_name: '',
  uploaded_date: currentDate,
});

watch(dataStore, () => {
  formState.uid = dataStore.userData.uid;
  formState.display_name = dataStore.userData.displayName;
  // console.log(formState);
});

const rules20Char = [
  (value) => {
    if (value) return true;
    return 'This section is required.';
  },
  (value) => {
    if (value?.length <= 20) return true;
    return 'This section must be less than 20 characters.';
  },
];

const apiKey = import.meta.env.VITE_MAPAPI_KEY; // Google Maps APIキー

const url = ref('');

function fetchAddress() {
  fetch(url.value)
    .then((response) => response.json())
    .then((data) => {
      if (data.results.length > 0) {
        console.log(url.value);
        let addressComponents = data.results[0].address_components;
        let city, state, country;

        for (const component of addressComponents) {
          const types = component.types;

          if (types.includes('locality')) {
            city = component.long_name;
          } else if (types.includes('administrative_area_level_1')) {
            state = component.long_name;
          } else if (types.includes('country')) {
            country = component.long_name;
          }
        }

        // console.log('City:', city);
        // console.log('State:', state);
        // console.log('Country:', country);
        formStateAddress.value = `${city}, ${state}, ${country}`;
      } else {
        formStateAddress.value = '';
        console.log('No results found');
      }
    })
    .catch((error) => {
      console.log('Error:', error);
      formStateAddress.value = '';
    });
}

watch(formStateLocation, async (newLocation) => {
  url.value = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${formStateLocation.video_lat},${formStateLocation.video_lng}&key=${apiKey}`;
  fetchAddress();
});

const videoCollection = collection(db, 'videos');

const form = reactive({
  ...formState,
  ...formStateAddress,
  ...formStateLocation,
});

function createForm() {
  combinedObjRefs = toRefs(form)
  // form = {
  //   ...formState,
  //   ...formStateAddress,
  //   ...formStateLocation,
  // };
  // form = Object.assign(formState, formStateAddress, formStateLocation);
  console.log(form);
}

function postFormState() {

}
</script>