待ち合わせ専用！距離で色が変わるアプリをNetlifyとFirebaseで作ってみた！

こんにちは、推しと一緒に住んでいる元幼稚園教諭のりゆです。
**推し**とは**夫**のことなのですが、最近特に夫との待ち合わせが至福のひと時なのです。
ただ現実で待ち合わせている時、あることに気づいてしまったのです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/0eb7d3ac-69a8-0b58-4f1c-c64d6c4d3834.png" width=70%>

## 推しが近づいてくるところが見られないぞ！？

かといって世に出ているGPSアプリは、それぞれの個人情報を大切にしたいのでやりたくないのですね。
私自身、現在地を把握したいという欲求はありませんでした。
ただ推しが近づいてくるドキドキ感を味わいたいのです！！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/7878fc38-2e84-4c7b-65ab-66d8642ca80b.png" width=70%>


現状世の中を調べてみましたが、私が求めているサービスはありませんでした・・・😅
なので！ないなら作るしかないですね！！
大まかな距離で居場所がわかり、数字ではなく直感的に近づいてきていることが認識できて待ち合わせ時間が今までより楽しい体験になるものを作ろうと考えました！
## 距離に応じて色が光るWEBアプリ爆誕！！

色の変化をわかりやすくするため、動画にしました！ご覧ください↓
※動画編集上人揺れが起きていますが、アプリ内では起こりません！

https://x.com/riyu___11/status/1826442136440766845


距離５００mごとに応じて色が変わっていきます。（最大3500mまで）
色は赤〜青色の中でグラデーションになっています。


## どうやって使うの？ ##

### 推しとの待ち合わせに使います！

・実際に会うまでに、アプリを開きます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/061f4de7-8f03-7f15-b3f4-a0deae88500a.png" width=70%>

推しの真ん中にあるハートの部分の色が距離に応じて色が変化していきます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/9915a3a3-a560-68e6-3ab1-9cceca390fcc.png" width=70%>

・２人の距離が、近いと赤色、遠いと青色になっています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/17d35d49-a127-d906-589f-89fd39faf39c.png" width=70%>

　・実際に推しが来るまで、どんどん近づいていくことが色でわかり、ときめく体験ができます！！


### 実際に作ったシステム構成図

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/93e73ed9-8a0c-f016-80d9-9bcd3855ce82.png" width=70%>

### 制作環境

→ウェブアプリ開発プラットフォームです！！

・**Netlify**

https://www.netlify.com/

→静的サイトをホスティングできる

・**Firebase**

https://firebase.google.com/?hl=ja

→動的コンテンツの提供
→リアルタイムにデータを同期・保存できるものも提供されている。

## Netlify でGPS座標を取得するアプリを作る

・Netlifyでログインし、アプリを作成する

<details><summary>アプリのコード</summary>

```html

<html>
  <head>
    <meta charset="utf-8">
    <title>GPS</title>
    <meta name="viewport" content="width=device-width" />
    <meta name="description" content="Displays the straight line distance to Station." />
    <script src="https://geographiclib.sourceforge.io/scripts/geographiclib-geodesic.min.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      body {
        display: flex;
        align-items: center;
        justify-content: center;
        color: #FAFAFA;
        font-size: 24px;
        font-weight: 900;
        background: #FFC0CB; /* 背景色はピンク色 */
      }

      .display {
        display: flex;
        flex-direction: column;
        align-items: center;
      }

      #distanceText {
        font-size: 24px;
        margin-bottom: 10px;
      }

      #m {
        font-size: 40px;
      }

      #timestamp {
        position: fixed;
        bottom: 8px; right: 8px;
        color: #0D47A1;
        font-size: 12px;
      }
    </style>
  </head>
  <body>
    <div>
      <div class="display">
        <p id="distanceText">2人の距離</p> <!-- 距離表示の上にテキストを追加 -->
        <p id="m"></p>
      </div>
      <p id="timestamp"></p>
    </div>
    <script>
      const goalLatLong = [,]; // 目標地点の緯度,経度

      navigator.geolocation.watchPosition(handleWatchPosition, null, {
        enableHighAccuracy: true,
        timeout: 60000,
        maximumAge: 0
      });

      function handleWatchPosition(evt) {
        const latitude = evt.coords.latitude;
        const longitude = evt.coords.longitude;
        const accuracy = evt.coords.accuracy;
        const altitude = evt.coords.altitude;
        const altitudeAccuracy = evt.coords.altitudeAccuracy;
        const heading = evt.coords.heading || 0;
        const speed = evt.coords.speed;
        const timestamp = evt.timestamp;

        document.getElementById('timestamp').textContent = timestamp;

        if (latitude && longitude) {
          const geod = window.geodesic.Geodesic.WGS84;
          const r = geod.Inverse(
            latitude, longitude,
            ...goalLatLong
          );

          document.getElementById('m').textContent = `${ r.s12.toFixed(2) }m`;
        }
      }
    </script>
  </body>
</html>
```
</details>

↓実際の画面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/a2dc0154-b3e9-b18a-15ed-636d591f103e.png" width=70%>

・距離に応じて色の変化を緩やかなグラデーションにした画面
（コードはChatGPTに生成してもらった）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/4bdfcf2d-3cb4-2e7a-e72e-dd4f9a91ec41.png" width=70%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/7b50a4ae-eb54-951d-df76-bfff1e3ce110.png" width=70%>

・人の形をimageとしてコードに挿入
→人の画像はprocreateで描きました！
　ハートの形は色が変わるところが見たいため、部分的に透過して画像を作っています。
 <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/7899177c-4b92-2326-882b-e859b06e6aa9.png" width=70%>

## FirebaseでGPSの座標を保存する（index.html）

<details><summary>最終コード</summary>

```html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>GPS-based Color Gradient</title>
    <meta name="viewport" content="width=device-width" />
    <meta name="description" content="Displays the straight line distance to the current location." />
    <script src="https://cdn.jsdelivr.net/npm/geographiclib@1.52.2/geographiclib.min.js"></script>
    <script defer src="path/to/firebase-app-compat.js"></script>
    <script defer src="path/to/firebase-firestore-compat.js"></script>
    <script defer src="path/to/init.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      body {
        display: flex;
        align-items: center;
        justify-content: center;
        color: #000000;
        font-size: 24px;
        font-weight: 900;
        background: hsl(0, 70%, 90%);
        transition: background 0.5s ease;
        height: 100vh;
        text-align: center;
      }

      .display {
        display: none;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }

      #distanceText {
        font-size: 24px;
        margin-bottom: 10px;
      }

      #m {
        font-size: 40px;
      }

      #timestamp {
        position: fixed;
        bottom: 8px;
        right: 8px;
        color: #000000;
        font-size: 12px;
        z-index: 1;
      }

      img {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        height: 100vh;
        width: 100vw;
        object-fit: cover;
        z-index: 0;
      }
    </style>
  </head>
  <body>
    <img src="path/to/image.png" alt="Character Image">
    <div class="display">
      <p id="distanceText">２人の距離</p>
      <p id="m"></p>
    </div>
    <p id="timestamp"></p>
    <script type="module">
      const app = firebase.app();
      const db = firebase.firestore();

      (async () => {
        const updateRef = db.doc('path/to/document');
        const now = new Date();
        await updateRef.set({
          value: `${now.toLocaleString()}`
        });
        const { value } = (await updateRef.get()).data();

        console.log(value);
      })();

      const goalLatLong = [,]; // Replace with target location's latitude, longitude
      navigator.geolocation.watchPosition(handleWatchPosition, null, {
        enableHighAccuracy: true,
        timeout: 60000,
        maximumAge: 0
      });

      function handleWatchPosition(evt) {
        const latitude = evt.coords.latitude;
        const longitude = evt.coords.longitude;
        const timestamp = evt.timestamp;
        document.getElementById('timestamp').textContent = new Date(timestamp).toLocaleString();
        if (latitude && longitude) {
          const geod = window.GeographicLib.Geodesic.WGS84;
          const r = geod.Inverse(latitude, longitude, ...goalLatLong);
          const distance = r.s12;
          document.getElementById('m').textContent = `${distance.toFixed(2)}m`;

          const maxDistance = 4000;
          const hueIntervals = [0, 30, 60, 90, 120, 180, 210, 270];
          let hue;
          if (distance <= 500) {
            hue = interpolateHue(distance, 0, 500, hueIntervals[0], hueIntervals[1]);
          } else if (distance <= 1000) {
            hue = interpolateHue(distance, 500, 1000, hueIntervals[1], hueIntervals[2]);
          } else if (distance <= 1500) {
            hue = interpolateHue(distance, 1000, 1500, hueIntervals[2], hueIntervals[3]);
          } else if (distance <= 2000) {
            hue = interpolateHue(distance, 1500, 2000, hueIntervals[3], hueIntervals[4]);
          } else if (distance <= 2500) {
            hue = interpolateHue(distance, 2000, 2500, hueIntervals[4], hueIntervals[5]);
          } else if (distance <= 3000) {
            hue = interpolateHue(distance, 2500, 3000, hueIntervals[5], hueIntervals[6]);
          } else if (distance <= 3500) {
            hue = interpolateHue(distance, 3000, 3500, hueIntervals[6], hueIntervals[7]);
          } else if (distance <= 4000) {
            hue = interpolateHue(distance, 3500, 4000, hueIntervals[7], hueIntervals[7]);
          } else {
            hue = hueIntervals[7];
          }
          const saturation = 70;
          const lightness = 90;
          document.body.style.backgroundColor = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
        }
      }

      function interpolateHue(distance, minDist, maxDist, startHue, endHue) {
        const ratio = (distance - minDist) / (maxDist - minDist);
        return startHue + ratio * (endHue - startHue);
      }
    </script>
  </body>
</html>

```
</details>

ターミナルで「firebase.deploy」をして値を取る
Cloud Firestoreの中にGPSの値を取ることができる

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/ccaec1d5-8440-ab13-2e37-eb57f54f2328.png" width=70%>

## 完成したので使ってもらった
・家族２名に使ってもらって感想を聞いてみました！
　とてもよいFBをもらえたと思います。

:::note info
**WEBアプリの価値について**
・日常にない体験ができるね！
・アイデアが今まで見たことがなくて、面白そう。
・好きな人が近づいてくることがわかると、ワクワクするね！
・具体的な居場所が分からないので、個人情報も守られて良い。
:::

 :::note info
**WEBアプリの機能・UIについて**
・顔が似てるって特別感があって良いね
・５００mという距離の感覚と、色合いもちょうどいいよ
:::

:::note warn
**WEBアプリの機能・UIについて**
・常にアプリを開いている状態だったら、めちゃめちゃ困る。
　タブを後ろに持っていくなど、画面の切り替えができたらいいな。
・GPSをとることでバッテリーがたくさん使われる、その点が気になる
:::

## FBをうけて、私はどう思った？
**・日常にない体験で新しいアイデアだという言葉がとても嬉しかった！**

→距離で色が変わっていく体験はどのように受け入れられるのか不安に思っていました・・・
なので実際に今の日常がよりよく変わるだろうと感じている人がいるがわかり安心しました。
これからも自信を持って検証していきたいと感じました。

**・GPSアプリを常に開いている状態になってしまうのは私も気になっていて、これから他に手段はないか模索していきたいと考えている。**

**その他まだまだ検証していくことがたくさんありそうだ！！**