Why does my OSMDROID MapView slowly move and interrupt keypresses? - javascript

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}.

Related

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;

#react-google-maps/api "google is not defined " error when accessed inside UseEffect hook

what im trying to do
place a marker on the map and calculate the distance between the marker and a static location on the map.
if the distance is greater than 1000 metres then i display address not available modal
problem description
Unable to access google inside UseEffect .
I loaded the script properly and followed the documentation
window.google is available in the onMapClick function but not anywhere in my index component or inside the useEffect hook
How do i access it ? Everything else works fine
Unhandled Runtime Error
ReferenceError: google is not defined
import React, { useRef, useState, useEffect, useCallback } from 'react';
import {
GoogleMap,
useLoadScript,
Marker,
InfoWindow,
MarkerClusterer,
} from '#react-google-maps/api';
import '#reach/combobox/styles.css';
import usePlacesAutoComplete, {
getGeocode,
getLatLng,
} from 'use-places-autocomplete';
import getDistanceFromLatLonInKm from '../../utils/getDistanceFromLatLonInKm.js';
import Modal from 'react-bootstrap/Modal';
import Button from 'react-bootstrap/Button';
import { Circle } from '#react-google-maps/api';
const libraries = ['places', 'geometry'];
const mapContainerStyle = {
width: '100%',
height: '40vh',
};
const center = {
lat: 25.33800452203996,
lng: 55.393221974372864,
};
const options = {
zoomControl: true,
};
const circleOptions = {
strokeColor: '#00a3a6',
strokeOpacity: 0.4,
strokeWeight: 2,
fillColor: '#00a3a6',
fillOpacity: 0.1,
clickable: false,
draggable: false,
editable: false,
visible: true,
radius: 1050,
zIndex: 1,
};
const initialMarker = { lat: null, long: null };
export default function index() {
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY,
libraries,
});
const [marker, setMarker] = useState(initialMarker);
const [showModal, setShowModal] = useState(false);
const handleModalClose = () => {
setShowModal(false);
setMarker(initialMarker);
};
const onMapClick = (event) => {
setMarker({
lat: event.latLng.lat(),
lng: event.latLng.lng(),
});
console.log(window.google); //accessible here
};
const renderMap = () => {
return (
<GoogleMap
mapContainerStyle={mapContainerStyle}
zoom={14}
options={options}
center={center}
onClick={onMapClick}>
<Circle center={center} options={circleOptions} />
{marker && <Marker position={{ lat: marker.lat, lng: marker.lng }} />}
</GoogleMap>
);
};
useEffect(() => {
if (
//cant access google here
google.maps.geometry.spherical.computeDistanceBetween(
new google.maps.LatLng(center.lat, center.lng),
new google.maps.LatLng(marker.lat, marker.lng)
) > 1000
) {
setShowModal(true);
}
}, [marker.lat]);
if (loadError) return 'Error Loading Maps';
if (!isLoaded) return 'Loading Maps';
return (
<>
<div>{renderMap()}</div>
<Modal
show={showModal}
onHide={handleModalClose}
backdrop="static"
keyboard={false}
centered>
<Modal.Header closeButton>
<Modal.Title>Address is out of bounds</Modal.Title>
</Modal.Header>
<Modal.Body>Sorry ! We Dont Deliver Food In Your Area .</Modal.Body>
<Modal.Footer>
<Button onClick={handleModalClose}>Choose New Address</Button>
</Modal.Footer>
</Modal>
</>
);
}
Turn on the internet connection in your computer...it will definitely work

Null reference error while using Polyline with react-native maps

When I use Polyline it gives me this error:
attempt to invoke interface method 'java.util.iterator java.util.list.iterator()' on a null object
At first, I thought I made something wrong or I mis-used google-map API so I tried with some hard-coded coords (as shown in my code below) but without any progress.
The code will run fine if I remove the Polyline part.
I googled hoping to find any solution but without any success also.
some info my about dev platform:
expo version 2.19.1
yarn version 1.16.0
Node version 10.15.2
Testing on a physical device with android PI installed.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Permissions, MapView } from 'expo'
// import Polyline from '#mapbox/polyline'
import { Polyline } from 'react-native-maps'
const locations = require('./locations.json')
export default class App extends React.Component {
state = {
latitude: null,
longitude: null,
locations: locations
}
componentDidMount() {
this.GetLocations()
}
GetLocations = async () => {
const { status } = await Permissions.getAsync(Permissions.LOCATION)
if (status !== 'granted') {
const response = await Permissions.askAsync(Permissions.LOCATION)
}
navigator.geolocation.getCurrentPosition(
({ coords: { latitude, longitude }}) => this.setState({ latitude, longitude}, this.mergeCoords),
(err) => console.log(`Error: ${err}`)
)
const { locations: [sampleLocation] } = this.state
this.setState({
desLatitude: sampleLocation.coords.latitude,
desLongitude: sampleLocation.coords.longitude,
}, this.mergeCoords)
}
mergeCoords = () => {
const { latitude, longitude, desLatitude, desLongitude } = this.state
const hasStartAndEnd = ( latitude !== null && desLatitude !== null )
// if the line have start and end
if (hasStartAndEnd) {
const concatStart = `${latitude},${longitude}`
const concatEnd = `${desLatitude},${desLongitude}`
this.getDirections(concatStart, concatEnd)
}
}
async getDirections(startLoc, desLoc) {
try {
// const res = await fetch(`https://maps.googleapis.com/maps/api/directions/json?key=MY_API_KEY&origin=${startLoc}&destination=${desLoc}`)
// const resJson = await res.json()
// const points = Polyline.decode(resJson.routes[0].overview_polyline.points)
// const coords = points.map( point => {
// return {
// latitude: point[0],
// longitude: point[1]
// }
// })
const coords = {
latitude: 31.262353,
longitude: 29.989506,
}
console.log("point, coords: ", coord)
this.setState({coords})
} catch(err) {
console.log('Error: ', err)
}
}
render() {
const { latitude, longitude, coords } = this.state
if (latitude) {
return (
<MapView
style={{ flex: 1 }}
showsUserLocation
initialRegion={{
latitude,
longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<MapView.Polyline
strokeWidth={2}
strokeColor="red"
coordinates={coords}
/>
</MapView>
)
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>We need your permissions !!</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
//use condional rendering
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Permissions, MapView } from 'expo'
// import Polyline from '#mapbox/polyline'
import { Polyline } from 'react-native-maps'
const locations = require('./locations.json')
export default class App extends React.Component {
state = {
latitude: null,
longitude: null,
locations: locations,
direct : false
}
componentDidMount() {
this.GetLocations()
}
GetLocations = async () => {
const { status } = await Permissions.getAsync(Permissions.LOCATION)
if (status !== 'granted') {
const response = await Permissions.askAsync(Permissions.LOCATION)
}
navigator.geolocation.getCurrentPosition(
({ coords: { latitude, longitude }}) => this.setState({ latitude, longitude},
this.mergeCoords),
(err) => console.log(`Error: ${err}`)
)
const { locations: [sampleLocation] } = this.state
this.setState({
desLatitude: sampleLocation.coords.latitude,
desLongitude: sampleLocation.coords.longitude,
}, this.mergeCoords)
}
mergeCoords = () => {
const { latitude, longitude, desLatitude, desLongitude } = this.state
const hasStartAndEnd = ( latitude !== null && desLatitude !== null )
// if the line have start and end
if (hasStartAndEnd) {
const concatStart = `${latitude},${longitude}`
const concatEnd = `${desLatitude},${desLongitude}`
this.getDirections(concatStart, concatEnd)
}
}
async getDirections(startLoc, desLoc) {
try {
// const res = await fetch(`https://maps.googleapis.com/maps/api/directions/json?
key=MY_API_KEY&origin=${startLoc}&destination=${desLoc}`)
// const resJson = await res.json()
// const points = Polyline.decode(resJson.routes[0].overview_polyline.points)
// const coords = points.map( point => {
// return {
// latitude: point[0],
// longitude: point[1]
// }
// })
const coords = {
latitude: 31.262353,
longitude: 29.989506,
}
console.log("point, coords: ", coord)
this.setState({coords, direct:true})
} catch(err) {
console.log('Error: ', err)
}
}
render() {
const { latitude, longitude, coords } = this.state
if (latitude) {
return (
<MapView
style={{ flex: 1 }}
showsUserLocation
initialRegion={{
latitude,
longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
{this.state.direct &&
<MapView.Polyline
strokeWidth={2}
strokeColor="red"
coordinates={coords}
/>}
</MapView>
)
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>We need your permissions !!</Text>
</View>
)
}
}

React Native Navigation v1 crashing in statTabBasedApp

When I navigate my app in startTabBasedApp (My 3 tabs) 1st screen to Render is the EventMap.js this is where my App crash. I just do not know why it crashing I tried to put console.log in all part of my codes but no error appeared.
So the main problem here is in the EventMap.js, because when I tried to remove the EventMap.js in my startTabBasedApp (Main Tabs) then uninstall the app, run react-native run-android, open the App navigate the Tabs (2) it works fine.
What I'm trying to do in my App is when user open the it and navigate it to the EventMap.js I want to get user's location instantly, just like in the Grab App.
How can I achieve this without crashing the App?
Here are my codes for EventMap.js
class EventMap extends Component {
constructor(props) {
super(props);
this.state = {
focusedLocation: {
latitude: 0,
longitude: 0,
latitudeDelta: 0.01,
longitudeDelta: Dimensions.get('window').width / Dimensions.get('window').height * 0.01
},
locationChosen: false,
markerPosition: {
latitude: 0,
longitude: 0
}
}
}
componentDidMount() {
this.didMountGetUserLocation();
};
//This is getting the location and exactly/automatically when they open
didMountGetUserLocation = () => {
navigator.geolocation.getCurrentPosition(pos => {
var lat = parseFloat(pos.coords.latitude)
var long = parseFloat(pos.coords.longitude)
var initialRegion = {
latitude: lat,
longitude: long,
latitudeDelta: 0.01,
longitudeDelta: Dimensions.get('window').width / Dimensions.get('window').height *0.01
};
this.setState({focusedLocation: initialRegion})
this.setState({locationChosen: true})
this.setState({markerPosition: initialRegion})
},
err => {
console.log(err);
});
};
pickLocationHandler = (event) => {
const coords = event.nativeEvent.coordinate;
//For animation of map
this.map.animateToRegion({
...this.state.focusedLocation,
latitude: coords.latitude,
longitude: coords.longitude
});
this.setState(prevState => {
return {
focusedLocation: {
...prevState.focusedLocation,
latitude: coords.latitude,
longitude: coords.longitude
},
locationChosen: true
};
});
};
getLocationHandler = () => {
navigator.geolocation.getCurrentPosition(pos => {
const coordsEvent = {
nativeEvent: {
coordinate: {
latitude: pos.coords.latitude,
longitude: pos.coords.longitude
}
}
};
this.pickLocationHandler(coordsEvent);
},
err => {
console.log(err);
alert("Fetching failed");
})
};
render() {
let marker = null;
if(this.state.locationChosen) {
marker = <MapView.Marker coordinate={this.state.markerPosition}/>
}
return(
<View style={{zIndex: -1}}>
<TouchableOpacity onPress={this.getLocationHandler} style={styles.iconContainer}>
<Icon name="md-locate" size={30} color="blue"/>
</TouchableOpacity>
<MapView
style={styles.map}
initialRegion={this.state.focusedLocation}
onPress={this.pickLocationHandler}
showsUserLocation={true}
ref={ref => this.map = ref} //For animating map movement
>
{marker}
</MapView>
</View>
);
}
}

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