ElixirDesktop MapLibreで現在位置の表示と追従

# はじめに
この記事は Elixirアドベントカレンダーのシリーズ４の22日目の記事です

今回はGPSログから地図で現在位置の表示とログの保存について解説します



# 現在位置の表示

mount時の処理に以下を追加します
- 現在位置を取得
- 地図のセンターを現在位置に設定
- 現在位置にマーカーを追加
- 地図にコントロールUIを追加

ロギング開始時の処理に以下を追加します
- 地図のセンターを更新
- マーカーの位置を更新

```diff_javascript:assets/js/hooks.js
Hooks.MapLibre = {
  mounted() {
-   const map = new maplibregl.Map({
-   container: "map",
-     style: "https://tile2.openstreetmap.jp/styles/osm-bright/style.json",
-     center: { lat: 33.30639, lng: 130.41806 },
-     zoom: 8,
-   });
-   window.map = map;

+   navigator.geolocation.getCurrentPosition((pos) => {
+     const init = [pos.coords.longitude, pos.coords.latitude]
+     const map = new maplibregl.Map({
+       container: "map",
+       style: "https://tile2.openstreetmap.jp/styles/osm-bright/style.json",
+       center: init,
+       zoom: 12,
+     });
+
+     map.on("load", () => {
+       map.addControl(new maplibregl.NavigationControl());
+     });
+
+     const user = new maplibregl.Marker().setLngLat(init).addTo(map);
+     window.user = user;
+     window.map = map;
+   });

    this.handleEvent("start_logging", () => {
      const watchID = navigator.geolocation.watchPosition((position) => {
        const coords = position.coords;
+       window.user.setLngLat([coords.longitude, coords.latitude]);
+       window.map.setCenter([coords.longitude, coords.latitude]);
        this.pushEvent("update", {
-         heading: coords.heading,
          lat: coords.latitude,
          lng: coords.longitude,
-         speed: coords.speed,
-         timestamp: position.timestamp,
        });
      });
      window.watchID = watchID;
    });

    this.handleEvent("stop_logging", () => {
      navigator.geolocation.clearWatch(window.watchID);
    });
  },
};

export default Hooks;
```

# ライブラリの追加

移動距離が最後のログから100m離れていたら記録したいので、
100m移動したかの計算をGeoclacというライブラリを使ってlat,lngから２点間の距離を計算します

https://hexdocs.pm/geocalc/readme.html

```diff_elixir:mix.exs
  defp deps do
    [
      ...
-     {:req, "~> 0.3"}
+     {:req, "~> 0.3"},
+     {:geocalc, "~> 0.8"}
    ]
  end

```

追加したら以下のコマンドを実行します
```
mix deps.get
```

# ログの保存
最後のログから100m移動していたら保存するようにします

```diff_elixir:lib/spotter_web/live/route_live/show.ex
defmodule SpotterWeb.RouteLive.Show do
  use SpotterWeb, :live_view
  ...
  @impl true
  def handle_params(%{"id" => id}, _, socket) do
    {:noreply,
     socket
     |> assign(:page_title, page_title(socket.assigns.live_action))
     |> assign(:route, Loggers.get_route!(id))
+    |> assign(:pos, [0, 0])
     |> assign(:record, false)}
  end

- def handle_event("update", params, socket) do
+ def handle_event("update", %{"lat" => lat, "lng" => lng}, socket) do
-   IO.inspect(params) 
+   if Geocalc.distance_between(socket.assigns.pos, [lat, lng]) > 100 do
+     Loggers.create_position(%{lat: lat, lng: lng, route_id: socket.assigns.route.id})
+     {:noreply, assign(socket, :pos, [lat, lng])}
+   else
+     {:noreply, socket}
+   end
  end
end
```

# 動作確認

![d0f1af2e6ee1855f0a2b9c390c1552b4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/72c3ab09-6ea6-0fc6-574a-d0b917a084a2.gif)

位置を追従しながら、GPSログを保存しているのを確認できました

# 最後に
本記事では現在位置の表示・追従とログの保存について解説しました
次はログを地図上に描画していきます

本記事は以上になりますありがとうございました