@@ -898,6 +898,95 @@ export function MapView({
898898 startUserLocation ( ) ;
899899 } , [ startUserLocation , stopUserLocation ] ) ;
900900
901+ const stopUserLocation = useCallback ( ( ) => {
902+ if ( userLocationWatchIdRef . current !== null && navigator . geolocation ) {
903+ navigator . geolocation . clearWatch ( userLocationWatchIdRef . current ) ;
904+ }
905+ userLocationWatchIdRef . current = null ;
906+ isUserLocationActiveRef . current = false ;
907+ isUserLocationFollowingRef . current = false ;
908+ setIsUserLocationActive ( false ) ;
909+ setUserLocationFix ( null ) ;
910+ } , [ ] ) ;
911+
912+ useEffect ( ( ) => ( ) => stopUserLocation ( ) , [ stopUserLocation ] ) ;
913+
914+ const publishLocationNotice = useCallback (
915+ ( message : string , tone : "info" | "warning" | "error" = "error" ) => {
916+ onPublishNotice ?.( {
917+ id : USER_LOCATION_NOTICE_ID ,
918+ message,
919+ tone,
920+ persistent : false ,
921+ } ) ;
922+ } ,
923+ [ onPublishNotice ] ,
924+ ) ;
925+
926+ const startUserLocation = useCallback ( ( ) => {
927+ if ( ! navigator . geolocation ) {
928+ publishLocationNotice ( "Your browser does not support location services." ) ;
929+ return ;
930+ }
931+ isUserLocationActiveRef . current = true ;
932+ isUserLocationFollowingRef . current = true ;
933+ setIsUserLocationActive ( true ) ;
934+ setUserLocationFix ( null ) ;
935+ try {
936+ userLocationWatchIdRef . current = navigator . geolocation . watchPosition (
937+ ( position ) => {
938+ const nextFix : UserLocationFix = {
939+ lat : position . coords . latitude ,
940+ lon : position . coords . longitude ,
941+ accuracyM : Number . isFinite ( position . coords . accuracy ) ? position . coords . accuracy : null ,
942+ } ;
943+ setUserLocationFix ( nextFix ) ;
944+ if ( isUserLocationFollowingRef . current ) {
945+ setInteractionViewState ( null ) ;
946+ const didAnimate = animateMapToCenter ( mapRef , {
947+ center : { lat : nextFix . lat , lon : nextFix . lon } ,
948+ zoom : USER_LOCATION_ZOOM ,
949+ padding : resolveMapCameraPadding ( fitChromePadding , fitBottomInset ) ,
950+ } ) ;
951+ if ( ! didAnimate ) {
952+ updateMapViewport ( {
953+ center : { lat : nextFix . lat , lon : nextFix . lon } ,
954+ zoom : USER_LOCATION_ZOOM ,
955+ } ) ;
956+ }
957+ }
958+ } ,
959+ ( error ) => {
960+ console . error ( "[user-location] geolocation watch failed" , error ) ;
961+ publishLocationNotice ( userLocationErrorMessage ( error ) ) ;
962+ stopUserLocation ( ) ;
963+ } ,
964+ USER_LOCATION_WATCH_OPTIONS ,
965+ ) ;
966+ } catch ( error ) {
967+ console . error ( "[user-location] geolocation watch failed" , error ) ;
968+ publishLocationNotice ( "Could not get your location." ) ;
969+ stopUserLocation ( ) ;
970+ }
971+ } , [
972+ fitBottomInset ,
973+ fitChromePadding . bottom ,
974+ fitChromePadding . left ,
975+ fitChromePadding . right ,
976+ fitChromePadding . top ,
977+ publishLocationNotice ,
978+ stopUserLocation ,
979+ updateMapViewport ,
980+ ] ) ;
981+
982+ const toggleUserLocation = useCallback ( ( ) => {
983+ if ( isUserLocationActiveRef . current ) {
984+ stopUserLocation ( ) ;
985+ return ;
986+ }
987+ startUserLocation ( ) ;
988+ } , [ startUserLocation , stopUserLocation ] ) ;
989+
901990 useEffect ( ( ) => {
902991 const handleViewportChange = ( ) => {
903992 mapRef . current ?. resize ( ) ;
0 commit comments