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

はじめに

この記事は Elixirアドベントカレンダーのシリーズ4の23日目の記事です

今回は保存したGPSログを地図上に描画していきます

Hooksの改修

Hooksを以下のように修正しています

mounted直下

  • init イベントに変更

initイベント

  • 引数のlogを addSourceでgeojson形式でログデータを入れる
  • addLayerでログデータをどのように描画するかを指定
  • startボタンを押すまで自分の位置を取得しなかったので、自分の位置だけを更新する watchを追加

render_logイベント

  • 引数のlogでsourceを更新し、再描画する

start_loggingイベント

  • 自己位置だけを更新するwatchをクリアして、センターとGPSをLiveView側に送信する watchを追加

stop_loggingイベント

  • センターとGPSをLiveView側に送信するwatchをクリアして、 自己位置だけを更新するwatchを追加

genGeoJson関数

  • ログデータをGeoJson形式に変換
phoenix/assets/js/hooks.js
Hooks.MapLibere = {
  mounted() {
-   navigator.geolocation.getCurrentPosition((pos) => {
-     const init = [pos.coords.longitude, pos.coords.latitude];
+   this.handleEvent("init", ({ log }) => {
+     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());
+         map.addSource("map_log", {
+            type: "geojson",
+            data: {
+              type: "FeatureCollection",
+              features: genGeoJSON(log),
+            },
+          });
+          map.addLayer({
+            id: "points",
+            type: "circle",
+            source: "map_log",
+            layout: {},
+            paint: {
+              "circle-color": "#0000FF",
+              "circle-radius": 4,
+            },
+         });        
        });

        const user = new maplibregl.Marker().setLngLat(init).addTo(map);
+       const watchID = navigator.geolocation.watchPosition((position) => {
+          const coords = position.coords;
+          window.user.setLngLat([coords.longitude, coords.latitude]);
+       });
+       window.watchID = watchID;        
        window.user = user;
        window.map = map;
      });
    });

+  this.handleEvent("render_log", ({ log }) => {
+     window.map.getSource("map_log").setData({
+       type: "FeatureCollection",
+       features: genGeoJSON(log),
+     });
+   });

    this.handleEvent("start_logging", () => {
+     navigator.geolocation.clearWatch(window.watchID);
      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", {
          lat: coords.latitude,
          lng: coords.longitude,
        });
      });
      window.watchID = watchID;
    });

    this.handleEvent("stop_logging", () => {
      navigator.geolocation.clearWatch(window.watchID);
+     const watchID = navigator.geolocation.watchPosition((position) => {
+       const coords = position.coords;
+       window.user.setLngLat([coords.longitude, coords.latitude]);
+     });
+     window.watchID = watchID;     
    });
  },
};

+ const genGeoJSON = (log) => {
+  return log.map((latlng) => {
+    return {
+      type: "Feature",
+      properties: {},
+      geometry: {
+        type: "Point",
+        coordinates: latlng,
+      },
+    };
+  });
+ };


export default Hooks

ログデータを取得する list_position/1 を改修

route_idに紐づくpositionを取得していましたが、ログの表示に使うlat,lngだけが欲しいので selectで返すデータを加工します

lib/spotter/loggers.ex
  ...
  def list_positions(route_id) do
    from(
      pos in Position,
-     where: pos.route_id == ^route_id
+     where: pos.route_id == ^route_id,
+     select: [pos.lng, pos.lat]
    )
    |> Repo.all()
  end

end

LiveView側の改修

mount時の既存ログを描画する処理と、新規ログ登録時の処理を追加します

lib/spotter_web/live/route_live/show.ex
defmodule SpotterWeb.RouteLive.Show do
  ...
  @impl true
  def handle_params(%{"id" => id}, _, socket) do
+   log = Loggers.list_positions(id)

    socket
    |> assign(:page_title, page_title(socket.assigns.live_action))
    |> assign(:route, Loggers.get_route!(id))
+   |> assign(:log, log)
    |> assign(:pos, [0, 0])
    |> assign(:record, false)
+   |> push_event("init", %{log: log})
    |> then(&{:noreply, &1})
  end

  ...

  def handle_event("update", %{"lat" => lat, "lng" => lng}, socket) do
    if Geocalc.distance_between(socket.assigns.pos, [lat, lng]) > 100 do
      Loggers.create_position(%{lat: lat, lng: lng, route_id: socket.assigns.route.id})
+     new_log = [[lng, lat] | socket.assigns.log]

      socket
      |> assign(:pos, [lat, lng])
+     |> assign(:log, new_log)
+     |> push_event("render_log", %{log: new_log})
      |> then(&{:noreply, &1})
    else
      {:noreply, socket}
    end
  end
end

動作確認

追従モードの切り替えと、ログがMap上に描画されるのを確認できました

692eacface4bc0abc5461e065ec5dc3c.gif

最後に

本記事ではGPSログデータのMap上への描画と、追従ロジックの改修を行いました
 GPSロガーについてはこれで一旦完了になります

次はおまけでネイティブ機能の呼び出しについて解説します

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

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