feat(rover): home accepts grid/callsign/address; station markers labeled; imperial scale
This commit is contained in:
parent
4108a98e5d
commit
9ebb134a03
3 changed files with 88 additions and 7 deletions
|
|
@ -322,4 +322,20 @@ select.select {
|
|||
.leaflet-popup { pointer-events: none; }
|
||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip, .leaflet-popup-close-button { pointer-events: auto; }
|
||||
|
||||
/* Rover-page station + home label tooltips */
|
||||
.rover-station-label,
|
||||
.rover-home-label {
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border: none;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
|
||||
color: #0f172a;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
padding: 1px 4px;
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rover-station-label::before,
|
||||
.rover-home-label::before { display: none; }
|
||||
|
||||
/* This file is for your main application CSS */
|
||||
|
|
|
|||
|
|
@ -66,7 +66,12 @@ function buildStationMarker(station: Station): L.CircleMarker {
|
|||
fillColor: station.selected ? "#0ea5e9" : "#64748b",
|
||||
fillOpacity: 0.95,
|
||||
interactive: true
|
||||
}).bindTooltip(station.callsign, { direction: "top", offset: [0, -6] })
|
||||
}).bindTooltip(station.callsign, {
|
||||
permanent: true,
|
||||
direction: "right",
|
||||
offset: [6, 0],
|
||||
className: "rover-station-label"
|
||||
})
|
||||
}
|
||||
|
||||
export const RoverMap: Partial<RoverMapHook> = {
|
||||
|
|
@ -144,7 +149,7 @@ export const RoverMap: Partial<RoverMapHook> = {
|
|||
fill: false
|
||||
}).addTo(map)
|
||||
|
||||
L.control.scale({ metric: true, imperial: false, position: "bottomleft" }).addTo(map)
|
||||
L.control.scale({ metric: false, imperial: true, position: "bottomleft" }).addTo(map)
|
||||
|
||||
// Render initial stations from data attribute
|
||||
try {
|
||||
|
|
@ -178,6 +183,14 @@ export const RoverMap: Partial<RoverMapHook> = {
|
|||
this.setDriveRadius(km)
|
||||
})
|
||||
|
||||
this.handleEvent("update_home", ({ lat, lon }: { lat: number; lon: number }) => {
|
||||
this.homeLat = lat
|
||||
this.homeLon = lon
|
||||
if (this.homeMarker) this.homeMarker.setLatLng([lat, lon])
|
||||
if (this.driveCircle) this.driveCircle.setLatLng([lat, lon])
|
||||
this.map.flyTo([lat, lon], Math.max(this.map.getZoom(), 8), { duration: 0.6 })
|
||||
})
|
||||
|
||||
this.handleEvent("rover_results", (
|
||||
{ cells, drive_radius_km }: { cells: Cell[]; drive_radius_km: number }
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
use MicrowavepropWeb, :live_view
|
||||
|
||||
alias Microwaveprop.Accounts.User
|
||||
alias Microwaveprop.Geocoder
|
||||
alias Microwaveprop.Propagation
|
||||
alias Microwaveprop.Radio.CallsignClient
|
||||
alias Microwaveprop.Radio.Maidenhead
|
||||
alias Microwaveprop.Repo
|
||||
alias Microwaveprop.Rover
|
||||
|
|
@ -212,12 +214,20 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
end
|
||||
|
||||
def handle_event("set_home_qth", params, socket) do
|
||||
grid = params |> Map.get("home_grid", "") |> String.trim()
|
||||
attrs = %{"home_grid" => grid}
|
||||
input = params |> Map.get("home_grid", "") |> String.trim()
|
||||
|
||||
case update_home(socket, attrs) do
|
||||
{:ok, home} ->
|
||||
{:noreply, assign(socket, home: home, home_form_error: nil)}
|
||||
case resolve_home_input(input) do
|
||||
{:ok, %{lat: lat, lon: lon, grid: grid}} ->
|
||||
case update_home(socket, %{"home_grid" => grid, "home_lat" => lat, "home_lon" => lon}) do
|
||||
{:ok, home} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(home: home, home_form_error: nil)
|
||||
|> push_event("update_home", %{lat: home.lat, lon: home.lon})}
|
||||
|
||||
{:error, msg} ->
|
||||
{:noreply, assign(socket, home_form_error: msg)}
|
||||
end
|
||||
|
||||
{:error, msg} ->
|
||||
{:noreply, assign(socket, home_form_error: msg)}
|
||||
|
|
@ -404,6 +414,11 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
end
|
||||
end
|
||||
|
||||
defp update_home(_socket, %{"home_lat" => lat, "home_lon" => lon} = attrs) when is_number(lat) and is_number(lon) do
|
||||
grid = Map.get(attrs, "home_grid") || home_label(lat * 1.0, lon * 1.0)
|
||||
{:ok, %{label: grid, grid: grid, lat: lat * 1.0, lon: lon * 1.0, elev_m: nil}}
|
||||
end
|
||||
|
||||
defp update_home(_socket, %{"home_grid" => grid}) when is_binary(grid) and grid != "" do
|
||||
case Maidenhead.to_latlon(grid) do
|
||||
{:ok, {lat, lon}} ->
|
||||
|
|
@ -416,6 +431,43 @@ defmodule MicrowavepropWeb.RoverLive do
|
|||
|
||||
defp update_home(_socket, _attrs), do: {:error, "grid required"}
|
||||
|
||||
# Accepts grid (EM13qc), callsign (W5ABC), or address ("100 Main St, Dallas TX").
|
||||
# Returns {:ok, %{lat, lon, grid}} or {:error, "..."}.
|
||||
defp resolve_home_input(""), do: {:error, "enter a grid, callsign, or address"}
|
||||
|
||||
defp resolve_home_input(input) do
|
||||
cond do
|
||||
Maidenhead.valid?(input) -> resolve_home_grid(input)
|
||||
callsign?(input) -> resolve_home_callsign(input)
|
||||
true -> resolve_home_address(input)
|
||||
end
|
||||
end
|
||||
|
||||
defp resolve_home_grid(grid) do
|
||||
case Maidenhead.to_latlon(grid) do
|
||||
{:ok, {lat, lon}} -> {:ok, %{lat: lat, lon: lon, grid: grid}}
|
||||
:error -> {:error, "invalid grid"}
|
||||
end
|
||||
end
|
||||
|
||||
defp resolve_home_callsign(call) do
|
||||
case CallsignClient.locate(call) do
|
||||
{:ok, %{lat: lat, lon: lon}} -> {:ok, %{lat: lat, lon: lon, grid: home_label(lat, lon)}}
|
||||
{:error, msg} -> {:error, "callsign: #{msg}"}
|
||||
end
|
||||
end
|
||||
|
||||
defp resolve_home_address(addr) do
|
||||
case Geocoder.geocode(addr) do
|
||||
{:ok, %{lat: lat, lon: lon}} -> {:ok, %{lat: lat, lon: lon, grid: home_label(lat, lon)}}
|
||||
{:error, msg} -> {:error, "geocode: #{msg}"}
|
||||
end
|
||||
end
|
||||
|
||||
defp callsign?(input) when is_binary(input) do
|
||||
String.match?(input, ~r/^[A-Za-z0-9\/]{3,12}$/) and not Maidenhead.valid?(input)
|
||||
end
|
||||
|
||||
defp changeset_first_error(%Ecto.Changeset{errors: [{field, {msg, _}} | _]}) do
|
||||
"#{field}: #{msg}"
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue