Lazy load maps

This commit is contained in:
Daniel Pupius
2025-04-30 10:50:46 -07:00
parent 64b026646d
commit 95800b33c7
6 changed files with 97 additions and 26 deletions

View File

@@ -11,7 +11,12 @@
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;300;400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Roboto+Mono:wght@400;500&family=Share+Tech+Mono&family=Space+Mono:wght@400;700&family=VT323&display=swap"
rel="stylesheet">
<!-- Google Maps API with environment variable API key -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=%VITE_GOOGLE_MAPS_API_KEY%"></script>
<script>
function gmapsCallback() {
window.dispatchEvent(new Event('google-maps-loaded'));
}
</script>
<script async src="https://maps.googleapis.com/maps/api/js?key=%VITE_GOOGLE_MAPS_API_KEY%&loading=async&callback=gmapsCallback"></script>
</head>
<body>

View File

@@ -31,8 +31,17 @@ export const GoogleMap: React.FC<GoogleMapProps> = ({
// If zoom is not provided, calculate based on accuracy
const effectiveZoom = zoom || calculateZoomFromAccuracy(accuracyMeters);
useEffect(() => {
if (mapRef.current && window.google && window.google.maps) {
// Track whether the map has been initialized
const isInitializedRef = useRef(false);
const initializeMap = () => {
if (
mapRef.current &&
window.google &&
window.google.maps &&
!isInitializedRef.current
) {
isInitializedRef.current = true;
// Create map instance
const mapOptions: google.maps.MapOptions = {
center: { lat, lng },
@@ -119,6 +128,34 @@ export const GoogleMap: React.FC<GoogleMapProps> = ({
radius: accuracyMeters,
});
}
};
useEffect(() => {
// Check if Google Maps API is already loaded
if (window.google && window.google.maps) {
initializeMap();
} else {
// Set up a listener for when the API loads
const handleGoogleMapsLoaded = () => {
initializeMap();
};
// Add event listener for Google Maps API loading
window.addEventListener('google-maps-loaded', handleGoogleMapsLoaded);
// Also try initializing after a short delay (backup)
const timeoutId = setTimeout(() => {
if (window.google && window.google.maps) {
initializeMap();
}
}, 1000);
// Cleanup
return () => {
window.removeEventListener('google-maps-loaded', handleGoogleMapsLoaded);
clearTimeout(timeoutId);
};
}
}, [lat, lng, effectiveZoom, accuracyMeters, precisionBits]);
return (

View File

@@ -1,5 +1,5 @@
import React from "react";
import { Radio, Signal, Battery, MapPin, Thermometer } from "lucide-react";
import { Radio, Battery, MapPin, Thermometer, Network } from "lucide-react";
import { Counter } from "../Counter";
import { NodeData } from "../../store/slices/aggregatorSlice";
import { getActivityLevel, getNodeColors, ActivityLevel } from "../../lib/activity";
@@ -35,7 +35,7 @@ export const MeshCard: React.FC<MeshCardProps> = ({
// Get icon based on type
const getIcon = () => {
return type === "gateway" ? (
<Signal className="w-4 h-4" />
<Network className="w-4 h-4" />
) : (
<Radio className="w-4 h-4" />
);

View File

@@ -124,24 +124,52 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
setNodesWithPosition(nodeArray);
}, [nodes, gateways]);
// Check for Google Maps API and initialize
const tryInitializeMap = useCallback(() => {
if (mapRef.current && window.google && window.google.maps) {
// Initialize map if not already done
if (!mapInstanceRef.current) {
initializeMap(mapRef.current);
}
// Create info window if not already done
if (!infoWindowRef.current) {
infoWindowRef.current = new google.maps.InfoWindow();
}
// Update markers and fit the map
updateNodeMarkers(nodesWithPosition, navigate);
return true;
}
return false;
}, [nodesWithPosition, navigate, updateNodeMarkers, initializeMap]);
// Handle map initialization and marker creation
useEffect(() => {
if (!mapRef.current || !window.google || !window.google.maps) return;
// Initialize map if not already done
if (!mapInstanceRef.current) {
initializeMap(mapRef.current);
// Try to initialize immediately if Google Maps is already loaded
if (tryInitializeMap()) {
return;
}
// Create info window if not already done
if (!infoWindowRef.current) {
infoWindowRef.current = new google.maps.InfoWindow();
}
// Update markers and fit the map
updateNodeMarkers(nodesWithPosition, navigate);
}, [nodesWithPosition, navigate, setupZoomListener]);
// Set up a listener for when the API loads
const handleGoogleMapsLoaded = () => {
tryInitializeMap();
};
// Add event listener for Google Maps API loading
window.addEventListener('google-maps-loaded', handleGoogleMapsLoaded);
// Also try initializing after a short delay (backup)
const timeoutId = setTimeout(() => {
tryInitializeMap();
}, 1000);
// Cleanup
return () => {
window.removeEventListener('google-maps-loaded', handleGoogleMapsLoaded);
clearTimeout(timeoutId);
};
}, [nodesWithPosition, navigate, tryInitializeMap]);
// Setup zoom listener when map is initialized
useEffect(() => {

View File

@@ -13,7 +13,7 @@ import {
Map,
Zap,
ChevronRight,
Signal,
Network,
Wifi,
Users,
Earth,
@@ -26,7 +26,7 @@ import { Separator } from "../Separator";
import { KeyValuePair } from "../ui/KeyValuePair";
import { Section } from "../ui/Section";
import { BatteryLevel } from "./BatteryLevel";
import { SignalStrength } from "./SignalStrength";
import { NetworkStrength } from "./NetworkStrength";
import { GoogleMap } from "./GoogleMap";
import { NodePositionData } from "./NodePositionData";
import { EnvironmentMetrics } from "./EnvironmentMetrics";
@@ -39,6 +39,7 @@ import {
getRegionName,
getModemPresetName,
} from "../../utils/formatters";
import { SignalStrength } from "./SignalStrength";
interface NodeDetailProps {
nodeId: number;
@@ -179,7 +180,7 @@ export const NodeDetail: React.FC<NodeDetailProps> = ({ nodeId }) => {
)}
>
{node.isGateway ? (
<Signal className="w-4 h-4" />
<Network className="w-4 h-4" />
) : (
<Radio className="w-4 h-4" />
)}
@@ -267,7 +268,7 @@ export const NodeDetail: React.FC<NodeDetailProps> = ({ nodeId }) => {
<div className="mt-4 pt-3 border-t border-neutral-700 space-y-3">
<div className="flex justify-between items-center mb-2 p-2 rounded effect-inset bg-neutral-700/50 ">
<span className="flex items-center">
<Signal className="w-4 h-4 mr-1.5" />
<Network className="w-4 h-4 mr-1.5" />
Gateway Node
</span>
{node.observedNodeCount !== undefined && (
@@ -391,7 +392,7 @@ export const NodeDetail: React.FC<NodeDetailProps> = ({ nodeId }) => {
<div className="flex justify-between items-center bg-neutral-700/50 p-2 rounded effect-inset">
<span className="text-neutral-400 flex items-center text-sm">
<Signal className="w-3 h-3 mr-2 text-neutral-300" />
<Network className="w-3 h-3 mr-2 text-neutral-300" />
Gateways
</span>
<div className="flex flex-col items-end">

View File

@@ -6,7 +6,7 @@ import {
RegionCode,
ModemPreset,
} from "../../lib/types";
import { Map as MapIcon, Signal, MapPin } from "lucide-react";
import { Map as MapIcon, MapPin, Network } from "lucide-react";
import { PacketCard } from "./PacketCard";
import { KeyValueGrid, KeyValuePair } from "../ui/KeyValuePair";
import { Map } from "../Map";
@@ -202,7 +202,7 @@ export const MapReportPacket: React.FC<MapReportPacketProps> = ({ packet }) => {
mapReport.modemPreset) && (
<div className="p-3 bg-neutral-800/50 rounded border border-neutral-700">
<h3 className="text-sm font-medium text-neutral-300 mb-3 flex items-center">
<Signal className="w-4 h-4 mr-2 text-cyan-400" />
<Network className="w-4 h-4 mr-2 text-cyan-400" />
Report Source
</h3>