本記事ではPhoenixのLiveViewでGoogleMapAPIを使用してGPS Loggerを作成していきます
今回は認証周りをすべて省いてLiveViewによるGoogleMapの更新のみに焦点を当てています
LiveViewとGoogleMapAPIで作る GPS Logger 1
LiveViewとGoogleMapAPIで作る GPS Logger 2
LiveViewとGoogleMapAPIで作る GPS Logger 3
LiveViewとGoogleMapAPIで作る GPS Logger short ver
LiveViewとGoogleMapAPIで作る GPS Logger Client watchOS APP + SwiftUI
プロジェクト作成、DB,GoogleMapセットアップ
mix phx.new google_map --live
cd google_map
cd assets
npm install @googlemaps/js-api-loader
cd ..
mix phx.gen.schema Loggers.Point points lat:decimal lng:decimal
mix ecto.create
mix ecto.migrate
assets/js/app.js
import "phoenix_html"
import {Socket} from "phoenix"
import topbar from "topbar"
import {LiveSocket} from "phoenix_live_view"
import Hooks from './hooks.js' // add this
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
// modify below
let liveSocket = new LiveSocket("/live", Socket, {
hooks: Hooks,
params: {_csrf_token: csrfToken}
})
...
assets/js/hooks.js
import { Loader } from "@googlemaps/js-api-loader";
let Hooks = {};
Hooks.Map = {
mounted() {
this.handleEvent("init_map", ({ points }) => {
const loader = new Loader({
apiKey: "your API key",
version: "weekly",
});
loader.load().then(() => {
const center = points.length == 0 ?
{ lat: 33.30639, lng: 130.41806 }
:
{ lat: parseFloat(points[0].lat), lng: parseFloat(points[0].lng) }
const map = new google.maps.Map(document.getElementById("map"), {
center: center,
zoom: 9,
});
window.map = map;
points.forEach((point) => {
this.addMarker(point)
});
});
});
this.handleEvent("created_point", ({ point }) => {
this.addMarker(point)
});
},
addMarker(point) {
const marker = new google.maps.Marker({
position: { lat: parseFloat(point.lat), lng: parseFloat(point.lng)},
animation: google.maps.Animation.DROP,
icon: {
path: google.maps.SymbolPath.CIRCLE,
fillColor: '#00F',
fillOpacity: 0.6,
strokeColor: '#00A',
strokeOpacity: 0.9,
strokeWeight: 1,
scale: 2
}
})
marker.setMap(window.map)
}
};
export default Hooks;
List, Create, Subscribe, Broadcast
lib/google_map/loggers.ex
defmodule GoogleMap.Loggers do
import Ecto.Query, warn: false
alias GoogleMap.Repo
alias GoogleMap.Loggers.Point
def list_points do
Repo.all(Point)
end
def create_point(attrs \\ %{}) do
%Point{}
|> Point.changeset(attrs)
|> Repo.insert()
|> broadcast(:created_point)
end
def subscribe(:map) do
Phoenix.PubSub.subscribe(GoogleMap.PubSub, "map")
end
def broadcast({:ok, point}, :created_point = event) do
Phoenix.PubSub.broadcast(GoogleMap.PubSub, "map", {event, point})
{:ok, point}
end
end
mount時、座標登録時の処理
lib/google_map_web/live/page_live.ex
defmodule GoogleMapWeb.PageLive do
use GoogleMapWeb, :live_view
alias GoogleMap.Loggers
@impl true
def mount(_params, _session, socket) do
Loggers.subscribe(:map)
points = Loggers.list_points |> Enum.map(fn p -> %{lat: p.lat, lng: p.lng} end)
{
:ok,
socket
|> push_event("init_map", %{points: points})
}
end
@impl true
def handle_info({:created_point, point}, socket) do
{
:noreply,
socket
|> push_event("created_point", %{ point: %{ lat: point.lat, lng: point.lng} })
}
end
end
[lib/google_map_web/live/page_live.html.leex].html
<h1>Show Map</h1>
<section id="googleMap" phx-update="ignore" phx-hook="Map">
<div id="map" style="height: 400px; border-radius:2em;"></div>
</section>
座標登録API
lib/google_map_web/controllers/point_controller.ex
defmodule GoogleMapWeb.PointController do
use GoogleMapWeb, :controller
alias GoogleMap.Loggers
alias GoogleMap.Loggers.Point
def create(conn, point_params) do
with {:ok, %Point{}} <- Loggers.create_point(point_params) do
send_resp(conn, 200, "ok")
end
end
end
lib/google_map_web/router.ex
defmodule GoogleMapWeb.Router do
...
scope "/api", GoogleMapWeb do
pipe_through :api
resources "/points", PointController, only: [:create]
end
...
end
最後に
いかがでしたでしょうか?
認証周りを除外すると少ないコードでGoogleMapのリアルタイム更新が実現できているのがわかります
GoogleMapAPIにはマーカーの描画だけではなく、scrollやハイライトなどいろいろあるので是非試してみてください
本記事は以上になります
次はGPSの送信側の記事をapple watch app, ReactNative辺りで書けたらと思います
コード