"""
Component 8 — Interactive Folium Map.
Draws:
• Full route polyline (color-coded by country)
• Source / destination markers with custom icons
• Toll plaza markers (green/orange/red by cost) with rich popups
showing plaza name, highway, vehicle rate, electronic vs cash split,
and data source.
"""
from typing import Dict, Any, List
import folium
from folium.plugins import Fullscreen
# Country theme colors
_THEMES = {
"India": {"route": "#FF9933", "accent": "#138808", "bg": "#FFFFFF"},
"United States": {"route": "#B22234", "accent": "#3C3B6E", "bg": "#FFFFFF"},
}
# Plaza cost thresholds for color coding (in currency units)
_LOW_THRESHOLD = {
"India": 50,
"United States": 3,
}
_MID_THRESHOLD = {
"India": 150,
"United States": 10,
}
def build_map(result: Dict[str, Any]) -> folium.Map:
"""
Build and return a Folium map from a calculator result dict.
"""
country = result["country"]
route = result["route"]
plazas: List[Dict] = result["plazas"]
theme = _THEMES.get(country, _THEMES["United States"])
currency_symbol = "₹" if country == "India" else "$"
electronic_label = "FASTag" if country == "India" else "E-ZPass"
coords = route["coords"]
mid_idx = len(coords) // 2
center = coords[mid_idx]
m = folium.Map(
location=list(center),
zoom_start=7,
tiles="CartoDB positron",
prefer_canvas=True,
)
Fullscreen(position="topright").add_to(m)
# ── Route polyline ────────────────────────────────────────────────────────
folium.PolyLine(
locations=[[lat, lon] for lat, lon in coords],
color=theme["route"],
weight=5,
opacity=0.85,
tooltip=f"{route['source']} → {route['destination']}",
).add_to(m)
# ── Source marker ────────────────────────────────────────────────────────
src = route["source_coords"]
folium.Marker(
location=[src[0], src[1]],
popup=folium.Popup(
f"Start: {route['source']}
"
f"Distance: {route['distance_display']}
"
f"Travel time: {route['duration_display']}",
max_width=220,
),
icon=folium.Icon(
color="green",
icon="play",
prefix="fa",
),
tooltip=f"Start: {route['source']}",
).add_to(m)
# ── Destination marker ────────────────────────────────────────────────────
dst = route["destination_coords"]
folium.Marker(
location=[dst[0], dst[1]],
popup=folium.Popup(
f"End: {route['destination']}
"
f"Total toll: {currency_symbol}{result['total_toll']:.2f}",
max_width=220,
),
icon=folium.Icon(
color="red",
icon="flag-checkered",
prefix="fa",
),
tooltip=f"End: {route['destination']}",
).add_to(m)
# ── Toll plaza markers ────────────────────────────────────────────────────
low_t = _LOW_THRESHOLD.get(country, 5)
mid_t = _MID_THRESHOLD.get(country, 10)
for plaza in plazas:
lat, lon = plaza["latitude"], plaza["longitude"]
if lat == 0 and lon == 0:
continue
rate = plaza["rate"]
e_rate = plaza["electronic_rate"]
c_rate = plaza["cash_rate"]
unavailable = plaza.get("rate_unavailable", False)
if unavailable:
marker_color = "gray"
elif rate <= low_t:
marker_color = "green"
elif rate <= mid_t:
marker_color = "orange"
else:
marker_color = "red"
icon_char = "₹" if country == "India" else "$"
if unavailable:
rate_html = "Rate unavailable"
elif e_rate != c_rate:
rate_html = (
f"{electronic_label}: {icon_char}{e_rate:.2f}
"
f"Cash: {icon_char}{c_rate:.2f}"
)
else:
rate_html = f"Toll: {icon_char}{rate:.2f}"
highway_html = f"Highway: {plaza['highway_number']}
" if plaza["highway_number"] else ""
source_html = f"
Source: {plaza['source']}"
popup_html = f"""