feat: replace Google tile URL hack with leaflet-google-mutant for traffic layer
Add leaflet-google-mutant@0.16.0 (exact/locked version) as a proper bridge between the Google Maps JavaScript API and Leaflet. The old mt{s}.google.com tile URL approach was unofficial and produced empty tiles. Traffic layer now renders via createLayerComponent + googleMutant, loaded only after the Maps JS API script is injected and ready (keyed off NEXT_PUBLIC_GOOGLE_MAPS_API_KEY). Added leaflet-google-mutant to transpilePackages in next.config.mjs.
This commit is contained in:
@@ -10,7 +10,9 @@ import {
|
||||
TileLayer,
|
||||
useMap,
|
||||
} from "react-leaflet";
|
||||
import { createLayerComponent } from "@react-leaflet/core";
|
||||
import L from "leaflet";
|
||||
import "leaflet-google-mutant";
|
||||
import type { CallRecord, IncidentRecord, NodeRecord } from "@/lib/types";
|
||||
|
||||
// ── Leaflet icon fix ──────────────────────────────────────────────────────────
|
||||
@@ -145,6 +147,19 @@ function computeGroups<T extends { id: string; lat: number; lng: number }>(
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Google Maps traffic layer via leaflet-google-mutant ───────────────────────
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const GoogleTrafficOverlay = createLayerComponent<any, object>(
|
||||
(_props, ctx) => {
|
||||
// leaflet-google-mutant augments L.gridLayer after the side-effect import
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const instance = (L as any).gridLayer.googleMutant({ type: "roadmap" });
|
||||
instance.addGoogleLayer("TrafficLayer");
|
||||
return { instance, context: ctx };
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
|
||||
// ── MapRefCapture — exposes L.Map instance to parent ─────────────────────────
|
||||
function MapRefCapture({ onReady }: { onReady: (m: L.Map) => void }) {
|
||||
const map = useMap();
|
||||
@@ -342,6 +357,21 @@ export default function MapView({ nodes, activeCalls, incidents = [], lastUpdate
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
// Load Google Maps JS API for leaflet-google-mutant traffic layer
|
||||
const [googleReady, setGoogleReady] = useState(false);
|
||||
useEffect(() => {
|
||||
const key = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY;
|
||||
if (!key) return;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if ((window as any).google?.maps) { setGoogleReady(true); return; }
|
||||
if (document.querySelector('script[src*="maps.googleapis.com/maps/api/js"]')) return;
|
||||
const script = document.createElement("script");
|
||||
script.src = `https://maps.googleapis.com/maps/api/js?key=${key}`;
|
||||
script.async = true;
|
||||
script.onload = () => setGoogleReady(true);
|
||||
document.head.appendChild(script);
|
||||
}, []);
|
||||
|
||||
// Live clock for TOC situational awareness
|
||||
useEffect(() => {
|
||||
const id = setInterval(() =>
|
||||
@@ -438,14 +468,9 @@ export default function MapView({ nodes, activeCalls, incidents = [], lastUpdate
|
||||
</FeatureGroup>
|
||||
</LayersControl.Overlay>
|
||||
|
||||
{/* Overlay: Traffic — Google Maps traffic layer */}
|
||||
{/* Overlay: Traffic — Google Maps via leaflet-google-mutant */}
|
||||
<LayersControl.Overlay name="Traffic">
|
||||
<TileLayer
|
||||
url="https://mt{s}.google.com/vt?lyrs=traffic&x={x}&y={y}&z={z}"
|
||||
subdomains={["0", "1", "2", "3"]}
|
||||
attribution='Traffic © <a href="https://maps.google.com/">Google</a>'
|
||||
opacity={0.8}
|
||||
/>
|
||||
{googleReady ? <GoogleTrafficOverlay /> : <FeatureGroup />}
|
||||
</LayersControl.Overlay>
|
||||
|
||||
{/* Overlay: Weather Radar — NEXRAD via Iowa Env Mesonet; key forces remount on refresh */}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
output: "standalone",
|
||||
transpilePackages: ["leaflet", "react-leaflet"],
|
||||
transpilePackages: ["leaflet", "react-leaflet", "leaflet-google-mutant"],
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"react-dom": "^18.3.0",
|
||||
"firebase": "^10.12.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-google-mutant": "0.16.0",
|
||||
"react-leaflet": "^4.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Reference in New Issue
Block a user