mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
120 lines
3.4 KiB
TypeScript
120 lines
3.4 KiB
TypeScript
import { LatLngBounds } from 'leaflet';
|
|
import { useCallback, useEffect, useRef } from 'react';
|
|
import { useMap, useMapEvents } from 'react-leaflet';
|
|
import { useMapActions } from '@/contexts/MapContexts.tsx';
|
|
|
|
/**
|
|
* Component to track map bounds and update context
|
|
* This enables viewport-based lazy loading of organizations
|
|
* Optimized with better debouncing and bounds comparison
|
|
*/
|
|
const MapBoundsTracker = () => {
|
|
const { setMapBounds } = useMapActions();
|
|
const boundsRef = useRef<LatLngBounds | null>(null);
|
|
const updateTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
const isUpdatingRef = useRef(false);
|
|
|
|
/**
|
|
* Check if bounds have changed significantly
|
|
* Uses a more efficient comparison that considers both area and position
|
|
*/
|
|
const hasBoundsChanged = useCallback(
|
|
(newBounds: LatLngBounds, oldBounds: LatLngBounds | null): boolean => {
|
|
if (!oldBounds) return true;
|
|
|
|
// Compare center position
|
|
const newCenter = newBounds.getCenter();
|
|
const oldCenter = oldBounds.getCenter();
|
|
const centerDiff =
|
|
Math.abs(newCenter.lat - oldCenter.lat) + Math.abs(newCenter.lng - oldCenter.lng);
|
|
|
|
// Compare bounds size (north-south and east-west spans)
|
|
const newSize = {
|
|
lat: newBounds.getNorth() - newBounds.getSouth(),
|
|
lng: newBounds.getEast() - newBounds.getWest(),
|
|
};
|
|
const oldSize = {
|
|
lat: oldBounds.getNorth() - oldBounds.getSouth(),
|
|
lng: oldBounds.getEast() - oldBounds.getWest(),
|
|
};
|
|
const sizeDiff = Math.abs(newSize.lat - oldSize.lat) + Math.abs(newSize.lng - oldSize.lng);
|
|
|
|
// Update if center moved significantly (>0.01 degrees) or size changed (>5%)
|
|
return centerDiff > 0.01 || sizeDiff > Math.max(newSize.lat, newSize.lng) * 0.05;
|
|
},
|
|
[]
|
|
);
|
|
|
|
const map = useMap();
|
|
|
|
/**
|
|
* Update bounds with debouncing
|
|
*/
|
|
const updateBounds = useCallback(
|
|
(immediate: boolean = false) => {
|
|
if (updateTimeoutRef.current) {
|
|
clearTimeout(updateTimeoutRef.current);
|
|
}
|
|
|
|
const update = () => {
|
|
if (isUpdatingRef.current) return;
|
|
|
|
const bounds = map.getBounds();
|
|
if (hasBoundsChanged(bounds, boundsRef.current)) {
|
|
boundsRef.current = bounds;
|
|
isUpdatingRef.current = true;
|
|
|
|
// Use requestAnimationFrame for smooth updates
|
|
requestAnimationFrame(() => {
|
|
setMapBounds(bounds);
|
|
// Reset flag after a short delay
|
|
setTimeout(() => {
|
|
isUpdatingRef.current = false;
|
|
}, 100);
|
|
});
|
|
}
|
|
};
|
|
|
|
if (immediate) {
|
|
update();
|
|
} else {
|
|
updateTimeoutRef.current = setTimeout(update, 300);
|
|
}
|
|
},
|
|
[map, setMapBounds, hasBoundsChanged]
|
|
);
|
|
|
|
useMapEvents({
|
|
moveend: () => {
|
|
updateBounds(false);
|
|
},
|
|
zoomend: () => {
|
|
// Faster update on zoom as it's a discrete action
|
|
updateBounds(false);
|
|
},
|
|
move: () => {
|
|
// Throttle during active movement to reduce updates
|
|
updateBounds(false);
|
|
},
|
|
});
|
|
|
|
// Initialize bounds on mount
|
|
useEffect(() => {
|
|
// Wait for map to be fully initialized
|
|
const timer = setTimeout(() => {
|
|
updateBounds(true);
|
|
}, 100);
|
|
|
|
return () => {
|
|
clearTimeout(timer);
|
|
if (updateTimeoutRef.current) {
|
|
clearTimeout(updateTimeoutRef.current);
|
|
}
|
|
};
|
|
}, [updateBounds]);
|
|
|
|
return null;
|
|
};
|
|
|
|
export default MapBoundsTracker;
|