Format contact detail page via Styler
This commit is contained in:
parent
18a291555c
commit
bf90249a06
1 changed files with 98 additions and 67 deletions
|
|
@ -225,10 +225,13 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
<% end %>
|
<% end %>
|
||||||
</:subtitle>
|
</:subtitle>
|
||||||
<:actions>
|
<:actions>
|
||||||
<button phx-click="toggle_flag" class={[
|
<button
|
||||||
"btn btn-sm",
|
phx-click="toggle_flag"
|
||||||
if(@contact.flagged_invalid, do: "btn-warning", else: "btn-ghost")
|
class={[
|
||||||
]}>
|
"btn btn-sm",
|
||||||
|
if(@contact.flagged_invalid, do: "btn-warning", else: "btn-ghost")
|
||||||
|
]}
|
||||||
|
>
|
||||||
<.icon name="hero-flag" class="w-4 h-4" />
|
<.icon name="hero-flag" class="w-4 h-4" />
|
||||||
{if @contact.flagged_invalid, do: "Unflag", else: "Flag as Invalid"}
|
{if @contact.flagged_invalid, do: "Unflag", else: "Flag as Invalid"}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -257,9 +260,9 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
<%= if @elevation_profile do %>
|
<%= if @elevation_profile do %>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="text-sm font-mono mb-2 text-center">
|
<div class="text-sm font-mono mb-2 text-center">
|
||||||
{format_band_ghz(@contact.band)} · {@contact.mode}
|
{format_band_ghz(@contact.band)} · {@contact.mode} · {format_dist(
|
||||||
· {format_dist(@elevation_profile.dist_km)}
|
@elevation_profile.dist_km
|
||||||
· {@contact.grid1 || "—"} → {@contact.grid2 || "—"}
|
)} · {@contact.grid1 || "—"} → {@contact.grid2 || "—"}
|
||||||
</div>
|
</div>
|
||||||
<table class="text-sm font-mono mb-2 mx-auto">
|
<table class="text-sm font-mono mb-2 mx-auto">
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -728,14 +731,10 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
defp extract_ducts(hrrr_path, soundings, surface_elev) do
|
defp extract_ducts(hrrr_path, soundings, surface_elev) do
|
||||||
hrrr_ducts = extract_hrrr_ducts(hrrr_path, surface_elev)
|
hrrr_ducts = extract_hrrr_ducts(hrrr_path, surface_elev)
|
||||||
|
|
||||||
if hrrr_ducts != [] do
|
if hrrr_ducts == [] do
|
||||||
hrrr_ducts
|
|
||||||
else
|
|
||||||
sounding_ducts = extract_sounding_ducts(soundings, surface_elev)
|
sounding_ducts = extract_sounding_ducts(soundings, surface_elev)
|
||||||
|
|
||||||
if sounding_ducts != [] do
|
if sounding_ducts == [] do
|
||||||
sounding_ducts
|
|
||||||
else
|
|
||||||
# Use the profile with the strongest (most negative) gradient
|
# Use the profile with the strongest (most negative) gradient
|
||||||
best =
|
best =
|
||||||
hrrr_path
|
hrrr_path
|
||||||
|
|
@ -743,7 +742,11 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
|> Enum.min_by(& &1.min_refractivity_gradient, fn -> nil end)
|
|> Enum.min_by(& &1.min_refractivity_gradient, fn -> nil end)
|
||||||
|
|
||||||
infer_duct_from_gradient(best, surface_elev)
|
infer_duct_from_gradient(best, surface_elev)
|
||||||
|
else
|
||||||
|
sounding_ducts
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
hrrr_ducts
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1015,9 +1018,15 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
verdict = (elevation_profile && elevation_profile.verdict) || (terrain && terrain.verdict)
|
verdict = (elevation_profile && elevation_profile.verdict) || (terrain && terrain.verdict)
|
||||||
|
|
||||||
case verdict do
|
case verdict do
|
||||||
"CLEAR" -> "Line of sight is clear between stations."
|
"CLEAR" ->
|
||||||
"FRESNEL_MINOR" -> "Line of sight is clear but with minor Fresnel zone encroachment."
|
"Line of sight is clear between stations."
|
||||||
"FRESNEL_PARTIAL" -> "Line of sight has partial Fresnel zone obstruction."
|
|
||||||
|
"FRESNEL_MINOR" ->
|
||||||
|
"Line of sight is clear but with minor Fresnel zone encroachment."
|
||||||
|
|
||||||
|
"FRESNEL_PARTIAL" ->
|
||||||
|
"Line of sight has partial Fresnel zone obstruction."
|
||||||
|
|
||||||
"BLOCKED" ->
|
"BLOCKED" ->
|
||||||
obs_dist = elevation_profile && elevation_profile.first_obstruction_km
|
obs_dist = elevation_profile && elevation_profile.first_obstruction_km
|
||||||
|
|
||||||
|
|
@ -1027,17 +1036,21 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
"Path is terrain-obstructed."
|
"Path is terrain-obstructed."
|
||||||
end
|
end
|
||||||
|
|
||||||
_ -> nil
|
_ ->
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp propagation_mechanism(terrain, elevation_profile, hrrr, soundings, dist_km) do
|
defp propagation_mechanism(terrain, elevation_profile, hrrr, soundings, dist_km) do
|
||||||
blocked? = terrain && terrain.verdict == "BLOCKED"
|
blocked? = terrain && terrain.verdict == "BLOCKED"
|
||||||
ducting? = has_ducting?(hrrr, soundings)
|
ducting? = has_ducting?(hrrr, soundings)
|
||||||
enhanced_refraction? = hrrr != nil && is_number(hrrr.min_refractivity_gradient) && hrrr.min_refractivity_gradient < -100
|
|
||||||
|
enhanced_refraction? =
|
||||||
|
hrrr != nil && is_number(hrrr.min_refractivity_gradient) && hrrr.min_refractivity_gradient < -100
|
||||||
|
|
||||||
long_path? = dist_km && dist_km > 100
|
long_path? = dist_km && dist_km > 100
|
||||||
|
|
||||||
ducts = elevation_profile && elevation_profile.ducts || []
|
ducts = (elevation_profile && elevation_profile.ducts) || []
|
||||||
likely_duct = Enum.find(ducts, & &1[:likely])
|
likely_duct = Enum.find(ducts, & &1[:likely])
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
|
|
@ -1049,10 +1062,12 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
|
|
||||||
blocked? && enhanced_refraction? ->
|
blocked? && enhanced_refraction? ->
|
||||||
grad = round(hrrr.min_refractivity_gradient)
|
grad = round(hrrr.min_refractivity_gradient)
|
||||||
|
|
||||||
"Enhanced refraction (dN/dh = #{grad} N-units/km) likely bent the signal over the obstruction. Conditions are super-refractive but below full ducting threshold."
|
"Enhanced refraction (dN/dh = #{grad} N-units/km) likely bent the signal over the obstruction. Conditions are super-refractive but below full ducting threshold."
|
||||||
|
|
||||||
blocked? ->
|
blocked? ->
|
||||||
diff_db = terrain && terrain.diffraction_db
|
diff_db = terrain && terrain.diffraction_db
|
||||||
|
|
||||||
if diff_db && diff_db > 0 do
|
if diff_db && diff_db > 0 do
|
||||||
"Path is obstructed with #{:erlang.float_to_binary(diff_db, decimals: 1)} dB diffraction loss. Contact may have been enabled by knife-edge diffraction or tropospheric scatter."
|
"Path is obstructed with #{:erlang.float_to_binary(diff_db, decimals: 1)} dB diffraction loss. Contact may have been enabled by knife-edge diffraction or tropospheric scatter."
|
||||||
else
|
else
|
||||||
|
|
@ -1076,11 +1091,14 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
defp duct_description(%{source: source, base_m_msl: base, top_m_msl: top, strength: strength}) do
|
defp duct_description(%{source: source, base_m_msl: base, top_m_msl: top, strength: strength}) do
|
||||||
base_ft = round(base * 3.28084)
|
base_ft = round(base * 3.28084)
|
||||||
top_ft = round(top * 3.28084)
|
top_ft = round(top * 3.28084)
|
||||||
src = case source do
|
|
||||||
"sounding" -> "sounding-detected"
|
src =
|
||||||
"inferred" -> "estimated"
|
case source do
|
||||||
_ -> "detected"
|
"sounding" -> "sounding-detected"
|
||||||
end
|
"inferred" -> "estimated"
|
||||||
|
_ -> "detected"
|
||||||
|
end
|
||||||
|
|
||||||
"#{src} layer at #{base_ft}-#{top_ft} ft, #{strength} M-units"
|
"#{src} layer at #{base_ft}-#{top_ft} ft, #{strength} M-units"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1095,16 +1113,12 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
defp band_summary(band_mhz, hrrr) when band_mhz <= 12_000 do
|
defp band_summary(band_mhz, hrrr) when band_mhz <= 12_000 do
|
||||||
if hrrr && is_number(hrrr.pwat_mm) && hrrr.pwat_mm > 20 do
|
if hrrr && is_number(hrrr.pwat_mm) && hrrr.pwat_mm > 20 do
|
||||||
"At 10 GHz, the elevated moisture (PWAT #{:erlang.float_to_binary(hrrr.pwat_mm, decimals: 1)} mm) enhances refractivity and ducting potential."
|
"At 10 GHz, the elevated moisture (PWAT #{:erlang.float_to_binary(hrrr.pwat_mm, decimals: 1)} mm) enhances refractivity and ducting potential."
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp band_summary(band_mhz, hrrr) when band_mhz >= 24_000 do
|
defp band_summary(band_mhz, hrrr) when band_mhz >= 24_000 do
|
||||||
if hrrr && is_number(hrrr.pwat_mm) && hrrr.pwat_mm > 25 do
|
if hrrr && is_number(hrrr.pwat_mm) && hrrr.pwat_mm > 25 do
|
||||||
"At #{round(band_mhz / 1000)} GHz, high moisture (PWAT #{:erlang.float_to_binary(hrrr.pwat_mm, decimals: 1)} mm) causes significant water vapor absorption."
|
"At #{round(band_mhz / 1000)} GHz, high moisture (PWAT #{:erlang.float_to_binary(hrrr.pwat_mm, decimals: 1)} mm) causes significant water vapor absorption."
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1116,12 +1130,15 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
details =
|
details =
|
||||||
if hrrr && is_number(hrrr.min_refractivity_gradient) do
|
if hrrr && is_number(hrrr.min_refractivity_gradient) do
|
||||||
grad = round(hrrr.min_refractivity_gradient)
|
grad = round(hrrr.min_refractivity_gradient)
|
||||||
label = cond do
|
|
||||||
grad < -157 -> "ducting"
|
label =
|
||||||
grad < -100 -> "super-refractive"
|
cond do
|
||||||
grad < -79 -> "enhanced"
|
grad < -157 -> "ducting"
|
||||||
true -> "normal"
|
grad < -100 -> "super-refractive"
|
||||||
end
|
grad < -79 -> "enhanced"
|
||||||
|
true -> "normal"
|
||||||
|
end
|
||||||
|
|
||||||
details ++ ["Refractivity gradient: #{grad} N-units/km (#{label})."]
|
details ++ ["Refractivity gradient: #{grad} N-units/km (#{label})."]
|
||||||
else
|
else
|
||||||
details
|
details
|
||||||
|
|
@ -1139,11 +1156,11 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
ducting_soundings = if is_list(soundings), do: Enum.filter(soundings, & &1.ducting_detected), else: []
|
ducting_soundings = if is_list(soundings), do: Enum.filter(soundings, & &1.ducting_detected), else: []
|
||||||
|
|
||||||
details =
|
details =
|
||||||
if ducting_soundings != [] do
|
if ducting_soundings == [] do
|
||||||
|
details
|
||||||
|
else
|
||||||
names = Enum.map_join(ducting_soundings, ", ", fn s -> s.station.name || s.station.station_code end)
|
names = Enum.map_join(ducting_soundings, ", ", fn s -> s.station.name || s.station.station_code end)
|
||||||
details ++ ["Ducting detected by soundings at: #{names}."]
|
details ++ ["Ducting detected by soundings at: #{names}."]
|
||||||
else
|
|
||||||
details
|
|
||||||
end
|
end
|
||||||
|
|
||||||
details =
|
details =
|
||||||
|
|
@ -1174,24 +1191,30 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
solar_hour = ts.hour + ts.minute / 60 + (lon || 0) / 15
|
solar_hour = ts.hour + ts.minute / 60 + (lon || 0) / 15
|
||||||
solar_hour = rem_float(solar_hour + 24, 24)
|
solar_hour = rem_float(solar_hour + 24, 24)
|
||||||
h = round(solar_hour)
|
h = round(solar_hour)
|
||||||
label = cond do
|
|
||||||
h >= 4 and h < 8 -> "dawn"
|
label =
|
||||||
h >= 8 and h < 12 -> "morning"
|
cond do
|
||||||
h >= 12 and h < 17 -> "afternoon"
|
h >= 4 and h < 8 -> "dawn"
|
||||||
h >= 17 and h < 21 -> "evening"
|
h >= 8 and h < 12 -> "morning"
|
||||||
true -> "night"
|
h >= 12 and h < 17 -> "afternoon"
|
||||||
end
|
h >= 17 and h < 21 -> "evening"
|
||||||
|
true -> "night"
|
||||||
|
end
|
||||||
|
|
||||||
"Solar hour ~#{h} (#{label})"
|
"Solar hour ~#{h} (#{label})"
|
||||||
end
|
end
|
||||||
|
|
||||||
defp td_note(temp_f, dewpoint_f) when is_number(temp_f) and is_number(dewpoint_f) do
|
defp td_note(temp_f, dewpoint_f) when is_number(temp_f) and is_number(dewpoint_f) do
|
||||||
depression = Float.round(temp_f - dewpoint_f, 1)
|
depression = Float.round(temp_f - dewpoint_f, 1)
|
||||||
label = cond do
|
|
||||||
depression < 3 -> "near saturation"
|
label =
|
||||||
depression < 8 -> "moist"
|
cond do
|
||||||
depression < 15 -> "moderate"
|
depression < 3 -> "near saturation"
|
||||||
true -> "dry"
|
depression < 8 -> "moist"
|
||||||
end
|
depression < 15 -> "moderate"
|
||||||
|
true -> "dry"
|
||||||
|
end
|
||||||
|
|
||||||
"T-Td = #{depression}°F (#{label})"
|
"T-Td = #{depression}°F (#{label})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1201,12 +1224,15 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
|
|
||||||
defp refractivity_note(grad) do
|
defp refractivity_note(grad) do
|
||||||
g = round(grad)
|
g = round(grad)
|
||||||
label = cond do
|
|
||||||
g < -157 -> "ducting"
|
label =
|
||||||
g < -100 -> "super-refractive"
|
cond do
|
||||||
g < -79 -> "enhanced"
|
g < -157 -> "ducting"
|
||||||
true -> "normal"
|
g < -100 -> "super-refractive"
|
||||||
end
|
g < -79 -> "enhanced"
|
||||||
|
true -> "normal"
|
||||||
|
end
|
||||||
|
|
||||||
"dN/dh = #{g} (#{label})"
|
"dN/dh = #{g} (#{label})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1224,12 +1250,15 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
|
|
||||||
defp wind_note(kts) do
|
defp wind_note(kts) do
|
||||||
k = Float.round(kts, 1)
|
k = Float.round(kts, 1)
|
||||||
label = cond do
|
|
||||||
k < 5 -> "calm"
|
label =
|
||||||
k < 15 -> "light"
|
cond do
|
||||||
k < 25 -> "moderate"
|
k < 5 -> "calm"
|
||||||
true -> "strong"
|
k < 15 -> "light"
|
||||||
end
|
k < 25 -> "moderate"
|
||||||
|
true -> "strong"
|
||||||
|
end
|
||||||
|
|
||||||
"#{k} kts (#{label})"
|
"#{k} kts (#{label})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1246,11 +1275,13 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
defp pressure_note(nil), do: "—"
|
defp pressure_note(nil), do: "—"
|
||||||
|
|
||||||
defp pressure_note(mb) do
|
defp pressure_note(mb) do
|
||||||
label = cond do
|
label =
|
||||||
mb < 1005 -> "low"
|
cond do
|
||||||
mb < 1015 -> "moderate"
|
mb < 1005 -> "low"
|
||||||
true -> "high"
|
mb < 1015 -> "moderate"
|
||||||
end
|
true -> "high"
|
||||||
|
end
|
||||||
|
|
||||||
"#{Float.round(mb, 1)} mb (#{label})"
|
"#{Float.round(mb, 1)} mb (#{label})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue