react leaflet move markers with animation - javascript

I am using the GeoJSON layer to show markers
In MapComponent.js
<MapContainer
whenCreated={(mapInstance) => {
mapRef.current = mapInstance;
}}
center={center}
zoom={zoom}
style={{ width: '100%', height: '100%' }}
maxZoom={maxZoom}
maxNativeZoom={maxNativeZoom}
zoomControl={false}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
maxZoom={maxZoom}
maxNativeZoom={maxNativeZoom}
/>
TrackingResults &&
<Markers
TrackingResults={TrackingResults}
openPopupId={openPopupId}
setOpenPopupId={setOpenPopupId}
/>
</MapContainer>
In the Marker.js Custom component.
const Markers = ({ TrackingResults, openPopupId, setOpenPopupId }) => {
const { t } = useTranslation();
const layerRef = useRef();
const updateLayer = () => {
const layer = layerRef.current;
if (layer != null && layer.getLayers().length > 0) {
layer.eachLayer((marker) => {
const { feature } = marker;
if (feature != null && feature.geometry != null) {
const lat = feature.geometry.coordinates[0];
const lng = feature.geometry.coordinates[1];
if (
lat !== marker.getLatLng().lat ||
lng !== marker.getLatLng().lng
) {
marker.setLatLng([lat, lng]);
// console.log(marker);
}
}
});
}
};
useEffect(() => {
updateLayer();
}, [markers]);
return TrackingResults.map((m) => (
<GeoJSON
ref={layerRef}
key={m.id}
data={m.data}
pointToLayer={pointToTrackingResultLayer}
onEachFeature={(
feature,
layer,
currentPopupId = openPopupId,
changePopupId = setOpenPopupId
) => onEachTrackable(feature, layer, currentPopupId, changePopupId, t)}
/>
));
}
And pointToTrackingResultLayer looks like
import L from 'leaflet';
export const pointToTrackingResultLayer = (feature, latlng) =>
L.marker([latlng.lat, latlng.lng], {
icon: myicon(feature.id),
});
I want to move the marker to the new position that is being controlled by the updateLayer function in markers.js

Related

Why does my OSMDROID MapView slowly move and interrupt keypresses?

I am creating a React Native application, with Native Base and I use a map. As I would Like to have it usable on both Android and IOS I decided to use the package react-native-maps-osmdroid. Currently I am trying to make it work on Android. I am successful in showing the map, moving the map and adding markers to the map, but I see that the map is slowly moving northwest without me understanding why. To save a marker with the button I have added on the bottom of the map, the map either has to be tapped so it stands still or one has to continually tap the save-button until one triggers the save function between map-movements. Below is the map code.
import React, {useEffect, useState} from 'react';
import {StyleSheet, View} from 'react-native';
import {Button, Box, Text} from 'native-base';
import MapView, {
PROVIDER_OSMDROID,
Marker,
Polyline,
} from 'react-native-maps-osmdroid';
import {MarkerType} from '../helpers';
import CustomPin from '../../custom/CustomPin'; //svg
import CustomPosition from '../../custom/CustomPosition'; //svg
import {requestLocation} from '../../helpers/LocationService';
const style = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
},
button: {
padding: 10,
bottom: 10,
marginLeft: 2,
marginRight: 2,
},
});
/**
* Route parameters it might expect
* markers: List of lat/long positions to set as markers on the map.
* showControls: Whether the add / delete markers controls should be visible
* selfPosition:
*/
export default TripMap = ({navigation, route}) => {
const [markers, addMarkers] = useState(
route.params.markers ? [...route.params.markers] : [],
); //Current marker on the map. Will be populated through props when opening the map from a trip screen. Either through logging or adding a location. Will also be filled by this screen's add marker button.
const [markerControl, setMarkerControl] = useState(
route.params.showControls ? true : false,
); //Should the add marker/delete markers be shown
const positionSelf = route.params.selfPosition
? route.params.selfPosition
: null;
const [coordinatesArray, setCoordinatesArray] = useState([]);
const [selectedMarker, setSelectedMarker] = useState(null);
/*
Initial region to show on the map.
latitude and longitude are the values for the center of the map on the screen. Delta is how much around that point is showing, aka controls zoom. Lower the values to get better zoom.
*/
const [myRegion, setRegion] = useState(
route.params.position
? {
latitude: route.params.position.latitude,
longitude: route.params.position.longitude,
latitudeDelta: 0.05,
longitudeDelta: 0.09,
}
: {
latitude: route.params.markers
? route.params.markers[0].latlng.latitude
: 59.91355589226327,
longitude: route.params.markers
? route.params.markers[0].latlng.longitude
: 10.751138495614148,
latitudeDelta: 0.05,
longitudeDelta: 0.09,
},
);
useEffect(() => {
if (route.params.position) return;
getLocation();
if (route.params.markers) {
let tempArray = [];
route.params.markers.forEach(marker => {
tempArray.push(marker.latlng);
});
setCoordinatesArray(tempArray);
}
}, []);
const regionChange = async function (region) {
if (region !== null || region !== undefined)
region.latitudeDelta = Math.min(
region.latitudeDelta,
85 - Math.abs(region.latitude),
);
if (region.latitude >= 85) {
region.latitude = -85 + (region.latitude - 85);
} else if (region.latitude <= -85) {
region.latitude = 85 + (region.latitude + 85);
}
region.longitudeDelta = Math.min(
region.longitudeDelta,
180 - Math.abs(region.longitude),
);
if (region.longitude >= 180) {
region.longitude = -180 + (region.longitude - 180);
} else if (region.longitude <= -180) {
region.longitude = 180 + (region.longitude + 180);
}
setRegion(region);
};
const addMarker = async (lat, lng) => {
if (route.params.singleMarker === true) {
if (markers.length > 0) {
replaceMarker(lat, lng);
return;
}
}
let newMarker = {
title: 'Anchorage marker',
description: 'New anchorage marker',
latlng: {
latitude: lat,
longitude: lng,
},
draggable: true,
type: MarkerType.POSITION,
};
addMarkers(oldArray => [...oldArray, newMarker]);
};
const replaceMarker = async (lat, lng) => {
let newMarker = {
title: 'Anchorage marker',
description: 'New anchorage marker',
latlng: {
latitude: lat,
longitude: lng,
},
draggable: true,
type: MarkerType.POSITION,
};
addMarkers([newMarker]);
};
const saveMarker = async function () {
const returnScreen = route.params.returnScreen
? route.params.returnScreen
: 'LandingPage';
navigation.navigate(returnScreen, {
...route.params,
location: markers[0].latlng,
targetLocation: route.params.targetLocation
? route.params.targetLocation
: null,
});
};
const MarkerControlView = function () {
return (
<Box justifyContent="flex-end" style={{flexDirection: 'row'}}>
{route.params.singleMarker === true && markers.length > 0 && (
<Button
mt="3"
style={style.button}
onPress={saveMarker}
disabled={markers.length === 0}>
Lagre pin
</Button>
)}
{markers.length === 0 && (
<Button mt="2" style={style.button} onPress={addMarker}>
Legg til pin
</Button>
)}
</Box>
);
};
const DisplayControls = function (props) {
if (props.showControls) {
return <MarkerControlView />;
}
return <Box></Box>;
};
const getLocation = function () {
requestLocation(setRegion);
};
return (
<Box style={style.map} justifyContent="center">
<MapView
provider={PROVIDER_OSMDROID}
style={style.map}
minZoomLevel={3}
initialRegion={myRegion}
region={myRegion}
onRegionChangeComplete={regionChange}
onPress={mapEvent => {
addMarker(
mapEvent.nativeEvent.coordinate.latitude,
mapEvent.nativeEvent.coordinate.longitude,
);
}}>
<Polyline
coordinates={coordinatesArray}
strokeColor="#000"
strokeWidth={4}></Polyline>
{markers.map((marker, index) => (
<Marker
key={Math.random()}
rea
coordinate={marker.latlng}
title={marker.title}
description={marker.description}
draggable={marker.draggable}
onDragEnd={e => (marker.latlng = e.nativeEvent.coordinate)}
onPress={() => setSelectedMarker(marker)}
pinColor={'red'}>
<View style={{width: 50, height: 50}}>
<CustomPin width="50px" height="50px" color={marker.type.color} />
</View>
</Marker>
))}
{positionSelf !== null && (
<Marker key={positionSelf.latitude} coordinate={positionSelf}>
<View style={{width: 50, height: 50}}>
<CustomPosition />
</View>
</Marker>
)}
</MapView>
<Box alignItems="center" justifyContent="flex-end" style={style.map}>
<DisplayControls showControls={markerControl} />
</Box>
{selectedMarker && (
<Box alignItems="center" justifyContent="flex-end" style={style.map}>
<Text>{selectedMarker.title}</Text>
</Box>
)}
</Box>
);
};
I can clearly see the map move even without having touched it once, but it moves slowly.
The route parameter is versions of this: route: {"key": "TripMap-Zl5rO2SgH8kyJjYhWQumK", "name": "TripMap", "params": {"returnScreen": "AnchorageTabView", "showControls": true, "singleMarker": true}, "path": undefined}.

Cant render react google maps data before refresh page

In may app I have to show a list of markers and markers that are already stored in sessionStorage, but I cant set markers, zoom and center of the map at first render of the page, I nees refresh the page to see data on it.
FIRST RENDER:
AFTER REFRESH:
Part of the code is justa above, I have a loadMap where I instaciate map with useLoadScript, I can post it here too if it's necessary!
import React, { useState, useEffect } from "react"
import { GoogleMap, Marker } from "#react-google-maps/api"
import { Trash } from "phosphor-react"
import { useNavigate } from "react-router-dom"
var tempMarker
function Map({
markers,
setMarkers,
wayPoints,
setWayPoints,
routeHead,
setRouteHead,
}) {
const [isMounted, setIsMounted] = useState(false)
const [reload, setReload] = useState(false)
const navigate = useNavigate()
let marker
function refreshPage() {
console.log("passei aqui refresh")
window.location.reload(false)
}
const onChangeMarkers = () => {
if (markers) {
if (markers.length > 0) {
setWayPoints(markers)
sessionStorage.removeItem("markers")
sessionStorage.setItem("markers", JSON.stringify(markers))
if (reload) {
refreshPage()
setReload(false)
}
}
}
}
useEffect(() => {
if (!isMounted) {
setIsMounted(true)
setReload(false)
onChangeMarkers()
}
}, [])
const handleOnLoad = (map) => {
onChangeMarkers()
const bounds = new window.google.maps.LatLngBounds()
if (markers) {
if (markers.length > 0) {
markers.forEach(({ latitude, longitude }) => {
let pos = new window.google.maps.LatLng(latitude, longitude)
bounds.extend(pos)
})
} else {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
}
map.setZoom(13)
map.setCenter(pos)
},
(e) => {
console.log(e)
},
{ maximumAge: 15000, timeout: 60000, enableHighAccuracy: true }
)
} else {
let pos = new window.google.maps.latLng()
pos = { lat: -16.6446324, lng: -49.416115 }
map.setZoom(10)
map.setCenter(pos)
}
}
}
map.fitBounds(bounds)
map.addListener("click", function (e) {
placeMarker(e.latLng, map)
})
}
const handleSubmit = async (event) => {
navigate("/WayPointsTable", { replace: false })
}
function placeMarker(location, map) {
if (marker == null) {
marker = new window.google.maps.Marker({
position: location,
map: map,
})
} else {
marker.setPosition(location)
}
const markerId = markers.length
const markerQtde = markerId + 1
tempMarker = {
idRota: routeHead.idRota,
idVeiculo: routeHead.idVeiculo,
idFrota: routeHead.idFrota,
idMotorista: routeHead.idMotorista,
idAjudante1: routeHead.idAjudante1,
idAjudante2: routeHead.idAjudante2,
idAjudante3: routeHead.idAjudante3,
idCarga: routeHead.idCarga,
idPonto: markerQtde,
latitude: parseFloat(marker.getPosition().lat().toFixed(6)),
longitude: parseFloat(marker.getPosition().lng().toFixed(6)),
cpfCNPJ: "CPF/CNPJ",
nome: "PONTO " + markerQtde,
endereco: "informe o endereco",
distanciaMinima: "100",
horarioParada: "00:00",
dataHoraInicio: routeHead.dtHrInicio,
dataHoraFim: routeHead.dtHrFim,
observacao: "",
valorAReceber: 0,
custoPernoite: 0,
idSequencia: markerQtde,
distanciaEmKm: 1,
tipoRegistro: "2.ENTREGA",
}
console.log(tempMarker)
markers.push(tempMarker)
map.setZoom(14)
let pos = new window.google.maps.LatLng(
parseFloat(marker.getPosition().lat().toFixed(6)),
parseFloat(marker.getPosition().lng().toFixed(6))
)
map.setCenter(pos)
setReload(true)
onChangeMarkers()
}
const handleMarkerClick = (evt) => {
console.log(evt)
}
const handleMarkerDrag = (mk, index) => {
const newLat = parseFloat(mk.latLng.lat().toFixed(6))
const newLng = parseFloat(mk.latLng.lng().toFixed(6))
markers = markers.map((marker, i) => {
if (i === index) {
marker = { ...marker, latitude: newLat, longitude: newLng }
}
return marker
})
setMarkers(markers)
setReload(false)
onChangeMarkers()
}
const handleDeleteMarker = (index) => {
if (index !== undefined) {
markers = markers
.filter((marker, i) => i !== index)
.map((marker, i) => {
marker = { ...marker, id: i }
return marker
})
setMarkers(markers)
setReload(true)
onChangeMarkers()
}
}
return (
<div className="flex flex-row">
<div className="bg-zinc-300 w-1/4">
<h2 className="text-center text-black font-bold p-2">
PONTOS DE ENTREGA
</h2>
<div className="flex flex-col">
<div className="overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="py-2 inline-block min-w-full sm:px-6 lg:px-8">
<div className="overflow-hidden">
<table className="min-w-full">
<tbody className="text-black font-semibold">
{isMounted &&
wayPoints &&
wayPoints.length > 0 &&
wayPoints.map(({ nome }, index) => {
return (
<tr key={index}>
<td>{index + 1} - </td>
<td>{nome.substr(0, 18)}</td>
<td>
<div
key={index}
className="inline-block align-middle w-4 bg-red-700 text-white rounded "
onClick={() => handleDeleteMarker(index)}
>
<Trash size={16} alt="Excluir" />
</div>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
</div>
</div>
<div className="flex flex-col items-center">
<button
onClick={() => handleSubmit()}
className=" bg-red-500 hover:bg-red-700 py-2 px-4 mt-3 rounded text-zinc-100 font-bold "
>
Enviar
</button>
</div>
</div>
<GoogleMap
onLoad={handleOnLoad}
afterLoad={refreshPage}
mapContainerStyle={{ width: "100vw", height: "100vh" }}
>
{isMounted &&
wayPoints &&
wayPoints.length > 0 &&
wayPoints.map(({ nome, idSequencia, latitude, longitude }, index) => (
<Marker
key={index}
position={{ lat: latitude, lng: longitude }}
title={nome}
addListener
draggable
onClick={handleMarkerClick}
onDragEnd={(marker) => handleMarkerDrag(marker, index)}
icon={
"http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=" +
idSequencia +
"|FF0000|000000"
}
></Marker>
))}
</GoogleMap>
</div>
)
}
export default Map

How to trigger function on button onClick in the InfoWindow content in react-google-maps/api?

I am trying to trigger the function reportPost() on the button onClick which is located in the infoWindow element. When I click on the marker icon and infoWindow starts to render, the function triggers itself and when the window is already loaded, the button does not work (can't trigger func). How can I prevent this and fix the button?
import { useState, useEffect, useCallback } from "react";
import {
GoogleMap,
useJsApiLoader,
Marker,
InfoWindow,
} from "#react-google-maps/api";
import Axios from "axios";
import markerIcon from "../images/markerIcon.png";
const containerStyle = {
width: "100%",
height: "100%",
};
const options = {
mapId: process.env.MAP_ID,
streetViewControl: false,
};
const center = {
lat: 52.22611704066942,
lng: 19.357910156250004,
};
function Map() {
const [markers, setMarkers] = useState([]);
useEffect(() => {
Axios.get("http://localhost:3001/api/markers").then((response) => {
setMarkers(response.data);
});
}, []);
function reportPost(markerid) {
console.log(markerid);
}
const { isLoaded } = useJsApiLoader({
id: "google-map-script",
googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
});
const onLoad = useCallback(function callback(map) {
setMap(map);
}, []);
const onUnmount = useCallback(function callback(map) {
setMap(null);
}, []);
const [map, setMap] = useState(null);
const [activeMarker, setActiveMarker] = useState(null);
const handleActiveMarker = (marker) => {
setActiveMarker(marker);
};
return isLoaded ? (
<div className="w-100 h-hero flex">
<GoogleMap
mapContainerStyle={containerStyle}
options={options}
center={center}
zoom={6}
onLoad={onLoad}
onUnmount={onUnmount}
>
{markers.map(
(
{ markerid, latitude, longitude, description },
i,
arr
) => {
const position = {
lat: latitude,
lng: longitude,
};
return (
<Marker
key={markerid}
icon={markerIcon}
position={position}
onClick={() => handleActiveMarker(markerid)}
>
{activeMarker === markerid ? (
<InfoWindow
onCloseClick={() => setActiveMarker(null)}
>
<div>
<div>
{description}
</div>
<div>
<button
onClick={reportPost(markerid)}
>
Report Post
</button>
</div>
</div>
</InfoWindow>
) : null}
</Marker>
);
}
)}
</GoogleMap>
</div>
) : null;
}
export default Map;
I think the onclick needs a callback, you can try doing it this way:
<button onClick={() => reportPost(markerid)}>
Report Post
</button>

How to change map zoom dynamically when clicking on a marker in react leaflet v.3.x?

i tried to find many things regards this but i can't make it work. what i want is when click on marker map got center on that location and got full zoom. for example i have total 23 markers on all around Unites states and initial map zoom is 4. what i want is if user click on marker in map then map center change to that marker lat, lng and got zoom in for suppose to 14 from 4. markeres are render already i don't want markers renders in function MyMapComponent. it come from API data. there is no clue how to do. i tried useMapEvents but it works on map click not marker click and if i use markers eventHandlers click i can't call map useMapEvents to set lat, lng and change zoom.
Here is my code:
function MyMapComponent() {
const map = useMapEvents({
click: () => {
let data = {lat: 46.8835319, lng: -114.0348327}
map.flyTo(data, 18)
}
})
return null}
above code is i need to change map center and zoom
<div className="project-view-section">
<MapContainer bounds={outerBounds} center={[37.2755, -104.6571]} zoom={mapOptions.zoom} scrollWheelZoom={false}>
<MyMapComponent />
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Mapbox Satellite">
<TileLayer
url={'https://api.mapbox.com/styles/v1/mapbox/satellite-v9/tiles/256/{z}/{x}/{y}#2x?access_token='+MAPBOX_TOKEN}
attribution="Map data © <a href="https://www.mapbox.com/">Mapbox</a>"
/>
</LayersControl.BaseLayer>
<LayersControl.BaseLayer name="Mapbox Streets">
<TileLayer
url={'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}#2x?access_token='+MAPBOX_TOKEN}
attribution="Map data © <a href="https://www.mapbox.com/">Mapbox</a>"
/>
</LayersControl.BaseLayer>
</LayersControl>
<MarkerClusterGroup>
{
state.markersData.map((element, index) =>
<Marker
key={index}
marker_index={index}
position={element}
icon={icon}
eventHandlers={{click: () => {test()},}}>
</Marker>
)
}
</MarkerClusterGroup>
</MapContainer>
</div>
is there any way to accomplish this?
You should use eventHandlers prop on Marker and listen to click event. Then use native leaflet's code: map.setView(coords, zoom)
function Markers({ data }) {
const map = useMap();
return (
data.length > 0 &&
data.map((marker, index) => {
return (
<Marker
eventHandlers={{
click: () => {
map.setView(
[
marker.geometry.coordinates[1],
marker.geometry.coordinates[0]
],
14
);
}
}}
key={index}
position={{
lat: marker.geometry.coordinates[1], // your api structure
lng: marker.geometry.coordinates[0] // your api structure
}}
icon={icon}
>
<Popup>
<span>{marker.properties.label}</span>
</Popup>
</Marker>
);
})
);
}
Use Markers comp as a MapContainer child then.
Demo with a free api
import React, { useState, useRef, useEffect } from 'react';
import {
MapContainer,
Marker,
Popup,
TileLayer,
useMap
} from 'react-leaflet';
import L from 'leaflet';
import { v4 as uuidv4 } from 'uuid';
import 'leaflet/dist/leaflet.css';
import { useTranslation } from 'react-i18next';
const iconMarker = new L.Icon({
iconUrl: require('../assets/images/loc.png'),
iconAnchor: [25, 50],
popupAnchor: [0, -30],
iconSize: new L.Point(50, 50),
});
function Markers({ data, isActive }) {
const map = useMap();
const [refReady, setRefReady] = useState(false);
let popupRef = useRef();
useEffect(() => {
if (refReady && isActive) {
popupRef.addTo(map);
}
}, [isActive, refReady, map]);
return (
data.length > 0 &&
data.map((marker, index) => {
return (
<Marker
key={index}
eventHandlers={{
click: () => {
map.setView([marker.latitude, marker.longitude], 16);
},
}}
position={{
lat: marker.latitude,
lng: marker.longitude,
}}
icon={iconMarker}
>
<Popup
ref={(r) => {
popupRef = r;
setRefReady(true);
}}
>
<span>{marker.name}</span>
</Popup>
</Marker>
);
})
);
}
const Map = ({ devices }) => {
const { t } = useTranslation();
const locationLati = [devices?.map((location) => location.latitude)];
const latitudeList = [...locationLati[0]];
const locationLongi = [devices?.map((location) => location.longitude)];
const longitudeList = [...locationLongi[0]];
let positionCurrent = [latitudeList[0], longitudeList[0]];
const newDevice = [...devices].reverse();
return (
<MapContainer
center={[0,0]}
zoom={12}
markerZoomAnimation={true}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Markers data={newDevice} isActive />
</MapContainer>
);
};
export default Map;

Google is not defined using react google maps?

I have read the other questions related to this and tried implementing what the answers were on there.
They recommended adding /*global google */ - did not work
Next was to add const google = window.google; - did not work
I will post the code below and the error.
The error is happening where new google.maps is being called
Map.js:
/* global google */
import { default as React, Component } from 'react';
import raf from 'raf';
import canUseDOM from 'can-use-dom';
const google = window.google;
import { withGoogleMap, GoogleMap, Circle, InfoWindow, Marker } from 'react-google-maps';
import withScriptjs from 'react-google-maps/lib/async/withScriptjs';
const googleMapURL =
'https://maps.googleapis.com/maps/api/js?v=3.27&libraries=places,geometry&key=AIzaSyA7XEFRxE4Lm28tAh44M_568fCLOP_On3k';
const geolocation =
canUseDOM && navigator.geolocation
? navigator.geolocation
: {
getCurrentPosition(success, failure) {
failure("Your browser doesn't support geolocation.");
},
};
const GeolocationExampleGoogleMap = withScriptjs(
withGoogleMap(props =>
<GoogleMap defaultZoom={8} center={props.center}>
{props.center &&
<InfoWindow position={props.center}>
<div>User's Location</div>
</InfoWindow>}
{props.center &&
<Circle
center={props.center}
radius={props.radius}
options={{
fillColor: 'red',
fillOpacity: 0.2,
strokeColor: 'red',
strokeOpacity: 1,
strokeWeight: 1,
}}
/>}
>
{props.markers.map((marker, index) => {
const onClick = () => props.onMarkerClick(marker);
const onCloseClick = () => props.onCloseClick(marker);
return (
<Marker
key={index}
position={marker.position}
title={(index + 1).toString()}
onClick={onClick}
>
{marker.showInfo &&
<InfoWindow onCloseClick={onCloseClick}>
<div>
<strong>
{marker.content}
</strong>
<br />
<em>The contents of this InfoWindow are actually ReactElements.</em>
</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>,
),
);
function generateInitialMarkers() {
const southWest = new google.maps.LatLng(-31.203405, 125.244141);
const northEast = new google.maps.LatLng(-25.363882, 131.044922);
const lngSpan = northEast.lng() - southWest.lng();
const latSpan = northEast.lat() - southWest.lat();
const markers = [];
for (let i = 0; i < 5; i++) {
const position = new google.maps.LatLng(
southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random(),
);
markers.push({
position,
content: 'This is the secret message'.split(' ')[i],
showInfo: false,
});
}
return markers;
}
export default class GeolocationExample extends Component {
constructor(props) {
super(props);
super(props);
this.state = {
center: null,
content: null,
radius: 6000,
markers: generateInitialMarkers(),
};
const isUnmounted = false;
handleMarkerClick = this.handleMarkerClick.bind(this);
handleCloseClick = this.handleCloseClick.bind(this);
}
handleMarkerClick(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: true,
};
}
return marker;
}),
});
}
handleCloseClick(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false,
};
}
return marker;
}),
});
}
componentDidMount() {
const tick = () => {
if (this.isUnmounted) {
return;
}
this.setState({ radius: Math.max(this.state.radius - 20, 0) });
if (this.state.radius > 200) {
raf(tick);
}
};
geolocation.getCurrentPosition(
(position) => {
if (this.isUnmounted) {
return;
}
this.setState({
center: {
lat: position.coords.latitude,
lng: position.coords.longitude,
},
content: 'Location found using HTML5.',
});
raf(tick);
},
(reason) => {
if (this.isUnmounted) {
return;
}
this.setState({
center: {
lat: 60,
lng: 105,
},
content: `Error: The Geolocation service failed (${reason}).`,
});
},
);
}
componentWillUnmount() {
this.isUnmounted = true;
}
render() {
return (
<GeolocationExampleGoogleMap
googleMapURL={googleMapURL}
loadingElement={<div style={{ height: '100%' }}>loading...</div>}
containerElement={<div style={{ height: '100%' }} />}
mapElement={<div style={{ height: '100%' }} />}
center={this.state.center}
content={this.state.content}
radius={this.state.radius}
onMarkerClick={this.handleMarkerClick}
onCloseClick={this.handleCloseClick}
markers={this.state.markers}
/>
);
}
}
You are loading async script. When you initialize google constant there is no google object. You can solve this by using 'ref' for map component. Ref callback fired when google object exists. For example:
<GoogleMap defaultZoom={8} center={props.center} ref={()=>{props.onMapLoad}}>...</GoogleMap>
...
constructor(props) {
...
this.onMapLoad = this.onMapLoad.bind(this)
}
...
onMapLoad() {
/*init markers and all objects with "google" here*/
}
...
<GeolocationExampleGoogleMap
onMapLoad={this.onMapLoad}
...
/>
and, of course, do not init google const, use just google object instead,

Categories