Related
I am essentially trying to replicate a ride sharing application. Once the user inputs their start location, I would like the marker to dynamically update on the map itself once they leave the start location input field.
I have attempted adding the coordinates as a dependant in the useEffect dependancy array, but that only results in the markers showing up if I change tabs or applications. I would like the marker to show up once I click the location that I would like to start from/ go to.
I am open to whatever solution you may have. I just want the map to update with the marker(s) dynamically once I select a given place.
Here is the code for the map:
import { useEffect, useState } from 'react'
import mapboxgl from 'mapbox-gl'
import { useStateValue } from '../pages/contextAPI/StateProvider'
import Search from '../pages/search'
import { UberLogo, Menu } from '../public/index.js'
export const mapToken = (mapboxgl.accessToken =
'pk.eyJ1IjoibW1tOTciLCJhIjoiY2wybHdpM204MHI0NjNkbnFnbjFneG05dCJ9.igV5GTfa9RLOXtK_SaeOXQ')
const addMarkerEvent = (lng, lat, map) => {
new mapboxgl.Marker({}).setLngLat([lng, lat]).addTo(map)
}
const addMarkerFunction = (map) => (event) => {
var coordinates = event.lngLat
//console.log(coordinates)
new mapboxgl.Marker({})
.setLngLat([coordinates.lng, coordinates.lat])
.addTo(map)
}
const Map = () => {
const [{ startLong, startLat, endLong, endLat }] = useStateValue()
const [state, setState] = useState({
pickupLat: startLat,
pickupLong: startLong,
dropoffLat: endLat,
dropoffLong: endLong,
confirmed: false
})
const confirmed = () => {
setState({ ...state, confirmed: true })
console.log('confirmed')
}
//load map onto screen
useEffect(() => {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition((pos) => {
//assign coords from navigator to variables
let locatedLat = pos.coords.latitude
let locatedLong = pos.coords.longitude
setState({ ...state, pickupLat: startLat, pickupLong: startLong })
//create new instance of map
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [locatedLong, locatedLat],
zoom: 13,
projection: 'mercator'
})
map.dragRotate.disable()
map.touchZoomRotate.disableRotation()
//add controls to map
const geolocateControl = new mapboxgl.GeolocateControl({
positionOptions: { enableHighAccuracy: true },
showUserHeading: true,
trackUserLocation: true
})
map.addControl(geolocateControl)
map.addControl(new mapboxgl.FullscreenControl())
map.addControl(new mapboxgl.NavigationControl())
//trigger geolocate control when map loads
map.on('load', () => geolocateControl.trigger())
if (confirmed) {
map.on('load', () => addMarkerEvent(startLong, startLat, map))
map.on('load', () => addMarkerEvent(endLong, endLat, map))
console.log('Gone through useEffect')
}
//map.on('click', addMarkerFunction(map))
})
} else {
alert('Geolocator is not available')
}
}, [state.confirmed])
return (
<div id='map' style={{ height: '100vh', width: '100vw' }}>
{/* <div
style={{
position: 'absolute',
zIndex: '10',
bottom: 0,
right: '50%',
backgroundColor: 'grey'
}}
>
Tester
</div> */}
<div className='search__container'>
{/* <div className='header'>
<UberLogo />
<div className='profile'>
<Menu />
</div>
</div> */}
<Search click={confirmed} />
</div>
</div>
)
}
export default Map
Here is the code for the Search component:
import { useState, useEffect } from 'react'
import { useStateValue } from './contextAPI/StateProvider.js'
import axios from 'axios'
import { mapToken } from '../components/Map'
import { Reset, Circle, Square, Line } from '../public'
const Search = ({ click }) => {
const [state, setState] = useState({
startpoint: '',
endpoint: '',
selectedStart: null,
selectedEnd: [],
startSearchResult: [],
endSearchResult: [],
startChecked: false,
endChecked: false
})
//define parameters for contextAPI
const [{ endPoint, startLat, startLong, errorMessage }, dispatch] =
useStateValue()
//Regular functions
const handleChange = (id) => {
if (id === 'start') {
setState({ ...state, startChecked: !state.startChecked })
}
if (id === 'end') {
setState({ ...state, endChecked: !state.endChecked })
}
}
const reset = () => {
setState({
startpoint: '',
endpoint: '',
startSearchResult: [],
endSearchResult: []
})
dispatch({
type: 'RESET'
})
}
const getStartCoordinate = (point) => {
if (state.startpoint !== '') {
axios
.get(
`https://api.mapbox.com/geocoding/v5/mapbox.places/${point}.json?` +
new URLSearchParams({
access_token: mapToken,
limit: 8,
proximity: 'ip'
})
)
.then((response) => {
let resultArray = response.data.features
setState({ ...state, startSearchResult: resultArray })
//console.log(resultArray)
})
.catch((err) => console.log(err))
}
}
const getEndCoordinate = (point) => {
if (state.endpoint !== '') {
axios
.get(
`https://api.mapbox.com/geocoding/v5/mapbox.places/${point}.json?` +
new URLSearchParams({
access_token: mapToken,
limit: 8,
proximity: 'ip'
})
)
.then((response) => {
let resultArray = response.data.features
setState({ ...state, endSearchResult: resultArray })
})
.catch((err) => console.log(err))
}
}
const selectedCoordinate = (id, point) => {
if (id === 'start') {
setState({
...state,
selectedStart: [point.center[0], point.center[1]],
startpoint: point.text,
startChecked: false
})
//dispatch to ContextAPI
dispatch({
type: 'START_LOCATION',
latitude: point.center[1],
longitude: point.center[0],
location: point.center
})
// console.log('State Start Coordinate:' + state.selectedStart)
// console.log('ContextEnd:' + startLong + ',' + startLat)
}
if (id === 'end') {
setState({
...state,
selectedStart: [point.center[0], point.center[1]],
endpoint: point.text,
endChecked: false
})
dispatch({
type: 'END_LOCATION',
latitude: point.center[1],
longitude: point.center[0],
location: point.center
})
console.log('State End Coordinate:' + state.selectedEnd)
console.log('ContextEnd:' + endPoint)
}
}
const updateInput = (id) => (e) => {
if (id === 'start') {
setState({
...state,
startpoint: e.target.value,
startChecked: true
})
}
if (id === 'end') {
setState({
...state,
endpoint: e.target.value,
endChecked: true
})
}
}
//destructured Component
const SearchResults = ({ id, searchResults }) => {
return (
<div className='searchResults__wrapper'>
{searchResults.map((result) => (
<button
className='result__wrapper'
key={result.id}
onClick={() => selectedCoordinate(id, result)}
>
<div className='result__title'>{result.text}</div>
<div className='result__description'>{result.place_name}</div>
</button>
))}
</div>
)
}
//execute coordinate functions when user types in values
useEffect(() => {
getStartCoordinate(state.startpoint)
getEndCoordinate(state.endpoint)
}, [state.startpoint, state.endpoint])
return (
<div className='search__wrapper'>
<div className='search__header'>
<button onClick={reset}>
<Reset sz='2em' />
<span>Start Again</span>
</button>
</div>
{/* Container holding the search element */}
<div className='search__inputContainer'>
<div className='search__left_col'>
<Circle h={12} w={12} />
<Line h={50} w={2.5} />
<Square dim={12} />
</div>
<div className='search__right_col'>
<input
placeholder='Enter pickup location'
value={state.startpoint}
onChange={updateInput('start')}
style={{
border: state.startpoint ? '2px solid #27ae60' : '2px solid black'
}}
/>
<div
className='search__results search__results--start'
style={{ display: state.startChecked ? 'block' : 'none' }}
>
<SearchResults id='start' searchResults={state.startSearchResult} />
</div>
<input
placeholder='Enter destination'
value={state.endpoint}
onChange={updateInput('end')}
style={{
border: state.endpoint ? '2px solid #27ae60' : '2px solid black'
}}
/>
<div
className='search__results search__results--end'
style={{ display: state.endChecked ? 'block' : 'none' }}
>
<SearchResults id='end' searchResults={state.endSearchResult} />
</div>
</div>
</div>
<div className='search__button'>
<button onClick={click}>Confirm Trip</button>
</div>
</div>
)
}
export default Search
I was expecting that the dynamic nature would be accomplished once I add the state/ context as a dependancy in the useEffect dependancy array, but that did not force a re-render of the map component as I expected. It would only re-render once I change to another tab or application.
I would preferably want it to re-render as smooth as possible, akin to what you would get in a ride sharing app
I'm trying to get my position on a map and it works fine on my computer in Google Chrome, but when simulating to android/iPhone nothing happens when using for example Custom Location on iPhone Simulator. Tried it on my actual iPhone as well without any luck.
All settings I can find for accepting location on simulator/real device is ON
GoogleMap.js
import React from 'react'
import GoogleMapReact from 'google-map-react'
import {usePosition} from "./usePosition";
const defaultProps = {
center: {
lat: 10.0000000,
lng: 12.0000000,
},
zoom: 18.7,
}
const MeOnMap = ({ text }) => <div className="me-on-map"><img src="static/walking.gif" width="30" /></div>
const GoogleMap = () => {
const { latitude, longitude} = usePosition();
return (
<div style={{ marginLeft: '-17px', height: '528px', width: '109%' }}>
<GoogleMapReact
bootstrapURLKeys={{ key: '*********' }}
defaultCenter={defaultProps.center}
defaultZoom={defaultProps.zoom}
yesIWantToUseGoogleMapApiInternals
options={{ scrollwheel: false, zoomControl: false, fullscreenControl: false, gestureHandling: 'none', styles: [{ stylers: [{ 'saturation': 100 }, { 'gamma': 0.5 }]}] }}
>
<MeOnMap
lat={latitude}
lng={longitude}
text={''}
/>
</GoogleMapReact>
</div>
)}
export default GoogleMap
geo.js
import React from 'react';
import {usePosition} from './usePosition';
export const UsePositions = () => {
const {latitude, longitude} = usePosition();
return (
<code>
My position,<br/>
latitude: {latitude}<br/>
longitude: {longitude}<br/>
</code>
);
};
usePosition.js
import {useState, useEffect} from 'react';
const defaultSettings = {
enableHighAccuracy: false,
timeout: Infinity,
maximumAge: 0,
};
export const usePosition = (watch = false, settings = defaultSettings) => {
const [position, setPosition] = useState({});
const [error, setError] = useState(null);
const onChange = ({coords, timestamp}) => {
setPosition({
latitude: coords.latitude,
longitude: coords.longitude,
accuracy: coords.accuracy,
speed: coords.speed,
timestamp,
});
};
const onError = (error) => {
setError(error.message);
};
useEffect(() => {
if (!navigator || !navigator.geolocation) {
setError('Geolocation is not supported');
return;
}
let watcher = null;
if (watch) {
watcher =
navigator.geolocation.watchPosition(onChange, onError, settings);
} else {
navigator.geolocation.getCurrentPosition(onChange, onError, settings);
}
return () => watcher && navigator.geolocation.clearWatch(watcher);
}, [
settings.enableHighAccuracy,
settings.timeout,
settings.maximumAge,
]);
return {...position, error};
};
Anyone's got any idea what could be wrong?
Thanks!!
Never mind, it had to do with location being blocked if not gathered from secure connection
Origin does not have permission to use Geolocation service -- even over HTTPS
solved it by running npm with --https
I used React Google Maps api in one of my Gatsby sites. I created the following component and imported it into one of my pages. Here is the code for the compenent.
import React, { useState } from "react"
import {
GoogleMap,
useLoadScript,
Marker,
InfoWindow,
} from "#react-google-maps/api"
import { useStaticQuery, graphql } from "gatsby"
import mapStyles from "./mapStyles"
const Indianapolis = {
lat: 39.768402,
lng: -86.158066,
}
const mapContainerStyle = {
height: "100%",
width: "100%",
}
const options = {
styles: mapStyles,
disableDefaultUI: true,
zoomControl: true,
}
const Map = () => {
const data = useStaticQuery(graphql`
{
allKmlPoint {
edges {
node {
properties {
name
Longitude
Latitude
FRP_Project_Numbers
description
styleUrl
styleHash
}
id
}
}
}
}
`)
const [selected, setSelected] = useState(null)
const frpLocation = data.allKmlPoint.edges
//console.log(process.env.GATSBY_GOOGLE_MAPS_API_KEY)
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: process.env.GATSBY_GOOGLE_MAPS_API_KEY,
})
const mapRef = React.useRef()
const onMapLoad = React.useCallback(map => {
mapRef.current = map
console.log(map)
}, [])
const onUnmount = React.useCallback(function callback(map) {
console.log(map)
}, [])
if (loadError) return "Error"
if (!isLoaded) {
return "Loading..."
}
//console.log("comes here")
return (
<div className="map-container">
<span className="top-text">Project</span>
<span className="horizontal-line"></span>
<span className="bottom-text">
Locati<span className="full-color">o</span>ns
</span>
<span className="map-blurb">
FRP has a project portfolio across a wide geographic region. Click the
Map to Zoom and pan to the project locations for various market types.
</span>
<div className="map-wrapper">
<GoogleMap
zoom={8}
center={Indianapolis}
mapContainerStyle={mapContainerStyle}
options={options}
onUnmount={onUnmount}
onLoad={onMapLoad}
>
{frpLocation.map(marker => (
<Marker
key={marker.node.id}
position={{
lat: parseFloat(marker.node.properties.Latitude),
lng: parseFloat(marker.node.properties.Longitude),
}}
icon={{
url: `icon_${marker.node.properties.styleUrl.slice(-6)}.svg`,
origin: new window.google.maps.Point(0, 0),
anchor: new window.google.maps.Point(15, 15),
scaledSize: new window.google.maps.Size(30, 30),
}}
onClick={() => {
setSelected(marker)
}}
/>
))}
{selected ? (
<InfoWindow
position={{
lat: parseFloat(selected.node.properties.Latitude),
lng: parseFloat(selected.node.properties.Longitude),
}}
onCloseClick={() => {
setSelected(null)
}}
>
<div>
<p>{selected.node.properties.name}</p>
</div>
</InfoWindow>
) : null}
</GoogleMap>
</div>
</div>
)
}
export default Map
The page works just fine. However, when I try to move away from the page (which has the google map) to another page (in Gatsby), the page transition is not smooth. Gatsby reloads the new page entirely. The console gives me the following error:
Uncaught TypeError: a is undefined
ZU marker.js:48
<anonymous> marker.js:45
setTimeout handler*_.bn common.js:17
<anonymous> marker.js:45
H js:207
trigger js:204
remove js:207
removeListener js:203
unregisterEvent reactgooglemapsapi.esm.js:142
unregisterEvents reactgooglemapsapi.esm.js:150
componentWillUnmount reactgooglemapsapi.esm.js:2118
wrappedMethod react-hot-loader.development.js:707
React 27
unlisten index.js:103
unlisten index.js:101
promise callback*componentDidMount/refs.unlisten< index.js:99
navigate history.js:100
navigate history.js:99
navigate navigation.js:120
promise callback*navigate navigation.js:84
___navigate navigation.js:162
onClick index.js:256
onClick index.js:477
React 22
marker.js:48:38
There are several instances of this error on the console (I think as many as the number of markers I have on my map).
I am sure it is a simple fix to get rid of this error. Can someone help
UPDATE:Based on what #Ferran said, I used the following code, Still does not work:
I created a useState hook as you said.
const [frpMap, setFrpMap] = useState(null)
mapRef.current = map
...
const onLoad = React.useCallback(function callback(map) {
setFrpMap(map)
}, [])
const onUnmount = React.useCallback(function callback(map) {
setFrpMap(null)
mapRef.current = null
//console.log(map)
}, [])
I think I am not sure how to use the map variable set in the setFrpMap hook to render the GoogleMap.
So, when I do setFrpMap(null) on unmount nothing really happens.
You aren't unmounting your map so it breaks when the routing changes. This is not doing anything:
const onUnmount = React.useCallback(function callback(map) {
console.log(map)
}, [])
I would suggest an approach using useState hook, in order to mount and unmount/dispose the map when needed:
import React, { useState } from "react"
import {
GoogleMap,
useLoadScript,
Marker,
InfoWindow,
} from "#react-google-maps/api"
import { useStaticQuery, graphql } from "gatsby"
import mapStyles from "./mapStyles"
const Indianapolis = {
lat: 39.768402,
lng: -86.158066,
}
const mapContainerStyle = {
height: "100%",
width: "100%",
}
const options = {
styles: mapStyles,
disableDefaultUI: true,
zoomControl: true,
}
const Map = () => {
const [map, setMap] = React.useState(null)
const data = useStaticQuery(graphql`
{
allKmlPoint {
edges {
node {
properties {
name
Longitude
Latitude
FRP_Project_Numbers
description
styleUrl
styleHash
}
id
}
}
}
}
`)
const [selected, setSelected] = useState(null)
const frpLocation = data.allKmlPoint.edges
//console.log(process.env.GATSBY_GOOGLE_MAPS_API_KEY)
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: process.env.GATSBY_GOOGLE_MAPS_API_KEY,
})
const mapRef = React.useRef()
const onMapLoad = React.useCallback(map => {
mapRef.current = map
setMap(map)
console.log(map)
}, [])
const onUnmount = React.useCallback(function callback(map) {
console.log(map)
setMap(null)
}, [])
if (loadError) return "Error"
if (!isLoaded) {
return "Loading..."
}
//console.log("comes here")
return (
<div className="map-container">
<span className="top-text">Project</span>
<span className="horizontal-line"></span>
<span className="bottom-text">
Locati<span className="full-color">o</span>ns
</span>
<span className="map-blurb">
FRP has a project portfolio across a wide geographic region. Click the
Map to Zoom and pan to the project locations for various market types.
</span>
<div className="map-wrapper">
<GoogleMap
zoom={8}
center={Indianapolis}
mapContainerStyle={mapContainerStyle}
options={options}
onUnmount={onUnmount}
onLoad={onMapLoad}
>
{frpLocation.map(marker => (
<Marker
key={marker.node.id}
position={{
lat: parseFloat(marker.node.properties.Latitude),
lng: parseFloat(marker.node.properties.Longitude),
}}
icon={{
url: `icon_${marker.node.properties.styleUrl.slice(-6)}.svg`,
origin: new window.google.maps.Point(0, 0),
anchor: new window.google.maps.Point(15, 15),
scaledSize: new window.google.maps.Size(30, 30),
}}
onClick={() => {
setSelected(marker)
}}
/>
))}
{selected ? (
<InfoWindow
position={{
lat: parseFloat(selected.node.properties.Latitude),
lng: parseFloat(selected.node.properties.Longitude),
}}
onCloseClick={() => {
setSelected(null)
}}
>
<div>
<p>{selected.node.properties.name}</p>
</div>
</InfoWindow>
) : null}
</GoogleMap>
</div>
</div>
)
}
export default Map
The idea is to initially set as null your map and set it in your onLoad function with:
const onMapLoad = React.useCallback(map => {
mapRef.current = map
setMap(map)
console.log(map)
}, [])
Note: adapt the snippet to your needs.
Since the callback is receiving the map as a parameter, you are able to use it along with useState hook.
On the other hand, use the opposite way when unmounting the map (onUnmount):
const onUnmount = React.useCallback(function callback(map) {
console.log(map)
setMap(null) // alternatively use map.data=null
}, [])
The same approach, your callback is receiving the map though you don't need it so, you can set the map object as null.
You can check the docs for further details.
const onUnmount = React.useCallback(function callback(map) {
map.data = null
}, [])
did the trick
Thanks in-advance. I am very new to React.
I'm trying to build an android application with React Native (Expo), PHP and MySQL, which requires live location tracking of salesmen for Admin to monitor.
Can any one please suggest me any idea on Live Location Tracking, even when the salesman's mobile screen is off/screen is locked with application running in background.
Salesman don't need any map component as they have nothing to do with their location. Just a Background Task sending their location details for the Admin, where he can track all his salesman's movement (for whole day) on their field job.
Only one application for both(Admin & Salesman), with dynamic menu based on user type which hides menu items for salesman login.
What is the standard method/process for this job ?
Is their any tutorial which i can follow ?
Any extra suggestions/points which i might be missing.
I have searched the whole internet for few days and i am having difficulty understanding the Expo documentation with very less example. Didn't found any suitable solution.
I just found a solution for my problem, sharing it for anybody who is stuck with the same problem.
Get Users Live Location (every step he takes) with React Native.
Thanks
import React, { Component } from "react";
import { StyleSheet, View } from "react-native";
import MapView from "react-native-maps";
import * as Location from "expo-location";
import * as Permissions from "expo-permissions";
import * as TaskManager from "expo-task-manager";
const LOCATION_TASK_NAME = "background-location-task";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
region: null,
error: '',
};
}
_getLocationAsync = async () => {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
enableHighAccuracy: true,
distanceInterval: 1,
timeInterval: 5000
});
// watchPositionAsync Return Lat & Long on Position Change
this.location = await Location.watchPositionAsync(
{
enableHighAccuracy: true,
distanceInterval: 1,
timeInterval: 10000
},
newLocation => {
let { coords } = newLocation;
// console.log(coords);
let region = {
latitude: coords.latitude,
longitude: coords.longitude,
latitudeDelta: 0.045,
longitudeDelta: 0.045
};
this.setState({ region: region });
},
error => console.log(error)
);
return this.location;
};
async componentWillMount() {
// Asking for device location permission
const { status } = await Permissions.askAsync(Permissions.LOCATION);
if (status === "granted") {
this._getLocationAsync();
} else {
this.setState({ error: "Locations services needed" });
}
userId = (await AsyncStorage.getItem("userId")) || "none";
userName = (await AsyncStorage.getItem("userName")) || "none";
}
render() {
return (
<View style={styles.container}>
<MapView
initialRegion={this.state.region}
showsCompass={true}
showsUserLocation={true}
rotateEnabled={true}
ref={map => {
this.map = map;
}}
style={{ flex: 1 }}
/>
</View>
);
}
}
TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
if (error) {
console.log(error);
return;
}
if (data) {
const { locations } = data;
let lat = locations[0].coords.latitude;
let long = locations[0].coords.longitude;
userId = (await AsyncStorage.getItem("userId")) || "none";
// Storing Received Lat & Long to DB by logged In User Id
axios({
method: "POST",
url: "http://000.000.0.000/phpServer/ajax.php",
data: {
action: "saveLocation",
userId: userId,
lat,
long
}
});
// console.log("Received new locations for user = ", userId, locations);
}
});
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff"
}
});
I have a React app which uses Google Maps API. I am using Foursquare API also, to fetch data about venues. Currently i am fetching about venues near Nashville, TN, keywords "yoga" and "coffee". I want to use the user's current location, and Nashville as a fallback in case they do not allow.
i've got this from MDN:
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function success(pos) {
var crd = pos.coords;
console.log('Your current position is:');
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
}
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
navigator.geolocation.getCurrentPosition(success, error, options);
and am looking for help implementing this in my code. How do i start with replacing the near: "Nashville, TN", below with the geolocation code? This is my app.js:
import React, { Component } from 'react';
import './App.css';
import SquareAPI from './API/';
import Map from './component/Map';
import SideBar from './component/Sidebar';
class App extends Component {
constructor(){
super();
this.state = {
venues: [],
markers: [],
center: [],
zoom: 14,
updateSuperState: obj => {
this.setState(obj);
}
};
}
closeAllMarkers = () => {
const markers = this.state.markers.map(marker => {
marker.isOpen = false;
return marker;
});
this.setState({ markers: Object.assign(this.state.markers, markers) });
};
handleMarkerClick = marker => {
this.closeAllMarkers();
marker.isOpen = true;
this.setState({ markers: Object.assign(this.state.markers, marker) });
const venue =this.state.venues.find(venue => venue.id === marker.id);
SquareAPI.getVenueDetails(marker.id).then(res => {
const newVenue = Object.assign(venue, res.response.venue);
this.setState({ venues: Object.assign(this.state.venues, newVenue) })
console.log(newVenue);
});
};
handleListItemClick = venue =>{
const marker = this.state.markers.find(marker => marker.id === venue.id)
this.handleMarkerClick(marker)
}
componentDidMount(){
SquareAPI.search({
near:"Nashville, TN",
query: "yoga",
limit: 10
}).then(results => {
const { venues } = results.response;
const { center } = results.response.geocode.feature.geometry;
const markers = venues.map(venue => {
return {
lat: venue.location.lat,
lng: venue.location.lng,
isOpen: false,
isVisible: true,
id: venue.id
};
})
this.setState({ venues, center, markers });
}).catch(error =>{
console.log("Error: " + error)
})
}
render() {
return (
<div className="App">
<SideBar {...this.state} handleListItemClick={this.handleListItemClick}/>
<Map {...this.state}
handleMarkerClick={this.handleMarkerClick}/>
</div>
);
}
}
export default App;
and my Map.js - i may also need to do it at line 10, defaultCenter=...
/* global google */
import React, { Component } from 'react';
import { withScriptjs, withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps';
const MyMapComponent = withScriptjs(
withGoogleMap(props => (
<GoogleMap
defaultZoom={8}
zoom={props.zoom}
defaultCenter={{ lat: -36.186, lng: -87.066 }}
// defaultCenter={
// }
center={{
lat: parseFloat(props.center.lat),
lng: parseFloat(props.center.lng)
}}
>
{props.markers &&
props.markers.filter(marker => marker.isVisible).map((marker, idx, arr) => {
const venueInfo = props.venues.find(venue => venue.id === marker.id);
return (
<Marker
key={idx}
position={{ lat: marker.lat, lng: marker.lng }}
onClick={() => props.handleMarkerClick(marker)}
animation={arr.length === 1
? google.maps.Animation.BOUNCE
: google.maps.Animation.DROP}
>
{marker.isOpen &&
venueInfo.bestPhoto && (
<InfoWindow>
<React.Fragment>
<img src={`${venueInfo.bestPhoto.prefix}300x300${venueInfo.bestPhoto.suffix}`} alt={venueInfo.name} />
<p>{venueInfo.name}</p>
</React.Fragment>
</InfoWindow>
)}
</Marker>
);
})}
</GoogleMap>
))
);
export default class Map extends Component {
render() {
return (
<MyMapComponent
{...this.props}
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=API_REMOVED"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%`, width: `65%` }} />}
mapElement={<div style={{ height: `100%`}} />}
/>
);
}
}
thanks!
Use the browsers geolocation.
There is an example in the docs.
In terms of React, you would set locations to state, (add a field), pass them to the Map component via prop.
Something like this
class Anything extends Component{
state = {
location : ''
} //no need for constructor no more, these are called class fields.
getPosition= ()=> {
console.log(navigator.gelocation)
//look at example in the docs and then
this.setState(response from navigator)
}
render(){
return (
<Map {...this.state}> // as you are spreading you are good here, access to
// geolocation via this.props.location in map
// component
)
}
}
https://developers.google.com/maps/documentation/javascript/geolocation