diff --git a/lib/microwaveprop_web/live/map_live.ex b/lib/microwaveprop_web/live/map_live.ex index a3bbe388..40f645b7 100644 --- a/lib/microwaveprop_web/live/map_live.ex +++ b/lib/microwaveprop_web/live/map_live.ex @@ -15,6 +15,14 @@ defmodule MicrowavepropWeb.MapLive do @default_center %{lat: 32.897, lon: -97.038} @default_zoom 7 + # Continental-US bounding box (excludes Alaska, Hawaii, Puerto Rico). Used + # to decide whether to show the "data is CONUS-only" banner to visitors + # whose Cloudflare geolocation falls outside the dataset's coverage. + @conus_lat_min 24.5 + @conus_lat_max 49.5 + @conus_lon_min -125.0 + @conus_lon_max -66.5 + # How often to re-query oban_jobs for pipeline state while the map is # open. Short enough that the "Updating…" chip shows up within a page- # visit for an in-progress hourly run, long enough to be cheap. @@ -53,6 +61,7 @@ defmodule MicrowavepropWeb.MapLive do valid_times = Propagation.available_valid_times(selected_band) selected_time = recovered_time || closest_to_now(valid_times) center = initial_center(session) + visitor = visitor_location(session) bounds = bounds_around(center) initial_scores = Propagation.scores_at(selected_band, selected_time, bounds) @@ -73,6 +82,7 @@ defmodule MicrowavepropWeb.MapLive do bounds: bounds, initial_center: center, initial_zoom: @default_zoom, + outside_conus: outside_conus?(visitor), grid_visible: false, radar_visible: false, antenna_height_ft: 33 @@ -86,6 +96,25 @@ defmodule MicrowavepropWeb.MapLive do defp initial_center(_session), do: @default_center + # Return the visitor's Cloudflare geolocation as a %{lat:, lon:} map, or + # nil when the CF headers weren't set (local dev, direct connect, tests + # without a stubbed session). + defp visitor_location(%{"cf_lat" => lat, "cf_lon" => lon}) when is_float(lat) and is_float(lon) do + %{lat: lat, lon: lon} + end + + defp visitor_location(_session), do: nil + + # True when the visitor's location is known and falls outside the CONUS + # bounding box. Missing geolocation returns false so we don't flash a + # banner at anyone we can't actually place. + defp outside_conus?(nil), do: false + + defp outside_conus?(%{lat: lat, lon: lon}) do + lat < @conus_lat_min or lat > @conus_lat_max or + lon < @conus_lon_min or lon > @conus_lon_max + end + # Build a bounding box roughly matching the hardcoded default (~3.4° × 9°) # around a given center so the initial HRRR score query still returns a # useful tile set for the visible area. @@ -486,6 +515,22 @@ defmodule MicrowavepropWeb.MapLive do