I am building a simple project that if a user clicks a button it should show directions from the user's location to the destination which I mark. Here is my code.
I have just implemented some parts but I did not understand how to implement DirectionsRenderer and could not learn from articles, docs. Now I have no idea what to do. Can anyone explain me in a easier way? Thank you!
GoogleMap,
withGoogleMap,
withScriptjs,
DirectionsRenderer,
} from 'react-google-maps';
import Marker from 'react-google-maps/lib/components/Marker';
function Map() {
return (
<div className='App'>
<GoogleMap
defaultZoom={10}
defaultCenter={{ lat: 51.507351, lng: -0.127758 }}
>
<Marker position={{ lat: 51.4666, lng: -0.213 }} />
</GoogleMap>
</div>
);
}
const DirectionsService = new window.google.maps.DirectionsService();
DirectionsService.route({
origin: new window.google.maps.LatLng(41.85073, -87.65126),
destination: new window.google.maps.LatLng(41.85258, -87.65141),
travelMode: window.google.maps.TravelMode.DRIVING,
});
const WrappedMap = withScriptjs(withGoogleMap(Map));
function App() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<WrappedMap
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${process.env.REACT_APP_MAP_KEY}`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
export default App;
Here are the steps I made to achieve your use-case:
Use the browser's HTML5 Geolocation feature to get the user's current position inside the componentDidMount.
Then use state variables to hold the value of the current location. You also put the value of the user current location state to center parameter of your GoogleMap object so that the map will show the area of the map where the user is. This will be used as the origion of your Directions service.
3.Also use another state to hold the user current location. This is to be used as state to put a marker in the user current location.
Call a function inside the onClick parameter of your GoogleMap object. Then use another state variable that will hold the value of the clicked coordinates. This will be used as the destination of the Directions Service.
Put a button on top of your map div and call a function inside its OnClick parameter.The function will call the GoogleMaps directionsService and will calculate a route between your origin and destination. If there's a route, you use another state variable to hold the result of the Directions service.
Use the DirectionsRenderer object inside the GoogleMap object to display the polyline of the route.
Here's the sample code (Note: Make sure to put your API key in the index.js for the sample to work) and the code snippet below:
/*global google*/
import React, { Component } from 'react';
import Button from 'react-bootstrap/Button';
import {
withGoogleMap,
Marker,
GoogleMap,
DirectionsRenderer
} from 'react-google-maps';
class Map extends Component {
state = {
directions: null,
markerPos: null,
centerMarker: null,
currentLocation: null
};
componentDidMount = () => {
navigator?.geolocation.getCurrentPosition(
({ coords: { latitude: lat, longitude: lng } }) => {
const pos = { lat, lng };
this.setState({ currentLocation: pos, centerMarker: pos });
}
);
};
onMapClick = e => {
this.setState({ markerPos: e.latLng });
};
getDirections = () => {
const directionsService = new google.maps.DirectionsService();
const origin = this.state.currentLocation;
const destination = this.state.markerPos;
if (origin !== null && destination !== null) {
directionsService.route(
{
origin: origin,
destination: destination,
travelMode: google.maps.TravelMode.DRIVING
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result
});
} else {
console.error(`error fetching directions ${result}`);
}
}
);
} else {
console.log('Please mark your destination in the map first!');
}
};
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={13}
center={this.state.currentLocation}
onClick={this.onMapClick}
>
{this.state.centerMarker !== null && (
<Marker position={this.state.centerMarker} label={'userloc'} />
)}
{this.state.markerPos !== null && (
<Marker position={this.state.markerPos} />
)}
{this.state.directions !== null && (
<DirectionsRenderer
directions={this.state.directions}
defaultOptions={{
suppressMarkers: true
}}
/>
)}
</GoogleMap>
));
return (
<div>
<Button onClick={this.getDirections}>Get Direction</Button>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: '500px' }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;
Related
I am using the react-google-maps/api library. I have an array with 8 locations and I am displaying different custom svg markers on all those locations. Till here all works great. Now I am stuck with the implementation of infoWindow on click of each marker. I tried to go through the documentation but never get get it right though.
import React from 'react'
import { GoogleMap, useJsApiLoader, OverlayView, InfoWindow } from '#react-google-maps/api';
const MapSearch = React.memo(({latitude, longtitude, locations}) =>{
const containerStyle = {
width: '100%',
height: '100%'
};
const center = {
lat: JSON.parse(latitude),
lng: JSON.parse(longtitude)
};
const options = {
streetViewControl: false,
fullscreenControl:false,
mapTypeControl: false,
zoomControlOptions: {
position: google.maps.ControlPosition.RIGHT_TOP
}
}
const { isLoaded } = useJsApiLoader({
id: 'google-map-script',
googleMapsApiKey: config.googleMapsApiKey
});
return(
isLoaded ? (
<GoogleMap
mapContainerStyle={containerStyle}
center={center}
zoom={8}
options={options}
>
{ /* Child components, such as markers, info windows, etc. */ }
{locations &&
locations.map((marker, i) => {
return <OverlayView
position={{lat:marker.latitude, lng:marker.longitude}}
mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET}
>
<svg className='map-icon' width="44" height="64" viewBox="0 0 44 64" fill="none" xmlns="http://www.w3.org/2000/svg">
---- Path not putting here to avoid code length -----
</svg>
</OverlayView>
})
}
</GoogleMap>
) : <></>
)
});
export default React.memo(MapSearch)
Try to use this way
import { InfoWindow, Marker } from '#react-google-maps/api';
const [infoWindowOpen, setInfoWindowOpen] = useState(false);
const showInfoWindow = () => {
setInfoWindowOpen(true);
};
return (
<Marker
title='Marker Name'
position={{lat:marker.latitude, lng:marker.longitude}}
icon={markerIcon}
onClick={showInfoWindow}
>
{infoWindowOpen && (
<InfoWindow onCloseClick={() => setInfoWindowOpen(false)}>
<h1>Hi I am Info Window</h1>
</InfoWindow>
)}
</Marker>
);
I want to work with draggable marker to collect lat and lang and after marker moving, want to take lat and lng from select using marker. My googlemap react js code is
class GoogleMaps extends Component {
constructor(props) {
super(props);
this.getLangLat = this.getLangLat.bind(this);
}
loadMap = (map, maps) => {
let marker = new maps.Marker({
position: { lat: 40.856795, lng: -73.954298 },
map,
draggable: true
});
};
getLangLat(e) {
//this.lat = e
console.log("Lat",e.lat);
console.log("Lng",e.lng);
this.lat = e.lat
this.lng = e.lng
// this.props.lat = e.lat;
//this.props.lng = e.lng;
}
render() {
return (
<div style={{ height: "400px", width: "400px" }}>
<GoogleMapReact
bootstrapURLKeys={{ key: "xxxxxxx" }}
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={10}
onClick={this.getLangLat}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => this.loadMap(map, maps)}
/>
</div>
);
}
}
export default GoogleMaps;
My another page, from where is called
import GoogleMaps from './GoogleMaps';
const SignUp = ({ handleChange, newState, alert }) => {
return(
<GoogleMaps></GoogleMaps>
)
}
How can I get lang and lat from draggable marker in google map? In react Js
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have the following code that displays markers around a certain area and I want to have an info window pop up when the marker is clicked on. Currently, all the markers refresh when clicked on and the info window does not pop up. How can I change my code for the info window to pop up and display the name of each marker?
const mapStyles = {
width: '100%',
height: '100%'
};
export class MapContainer extends Component {
constructor(props) {
super(props)
this.state = {
selectedPlace : '',
isSelected: false
}
}
onClose = props => {
this.setState({
selectedPlace: '',
isSelected: false
});
};
render() {
return (
<Map
google = {this.props.google}
zoom = {16}
style = {mapStyles}
initialCenter = {
{ lat: 1.296643,
lng: 103.776398}
}>
{data.carpark.map(park =>(
<Marker
key = {park.id}
position = {{
lat: park.latitude,
lng: park.longitude
}}
name = {park.caption}
onClick={() => {this.setState(
{selectedPlace: park.caption,
isSelected: true}
)}}
/>
))}
{this.selectedPlace && (
<InfoWindow>park details</InfoWindow>
) }
</Map>
)
}
}
Can you provide which library you are using?
I successfully implemented this on my code using the react-google-maps library. The logic I made involves storing the park.id to a parkid state handler every time the marker is clicked. Then I used a condition that check if the value of parkid state is equal to the park.id.
Here is my sample code and below is the snippet:
import React, { Component } from "react";
import {
withGoogleMap,
withScriptjs,
GoogleMap,
Marker,
InfoWindow,
} from "react-google-maps";
import data from "./data.json";
class Map extends Component {
constructor(props) {
super(props);
this.state = {
parkid: "",
};
}
render() {
const GoogleMapExample = withGoogleMap((props) => (
<GoogleMap
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={13}
>
{data.map((park) => (
<Marker
position={{ lat: park.lat, lng: park.lng }}
onClick={() =>
this.setState({
parkid: park.id,
})
}
>
{this.state.parkid === park.id && (
<InfoWindow
onCloseClick={this.props.handleCloseCall}
options={{ maxWidth: 100 }}
>
<span>{park.id}</span>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
));
return (
<div>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: "500px" }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;
Note: To make the sample code work, change the value of YOUR_API_KEY in the index.js file.
You try to access this.selectedPlace when you probably meant to access this.state.selectedPlace:
{this.state.selectedPlace && (
<InfoWindow>park details</InfoWindow>
)}
I am using react-google-maps. I have created map and displayed 3 types of markers in it.
I can now draw polygons on map but not able to get the details of markers covered under the drawn shape.
Any help would be appreciated.
This is my code of map jsx.
I am creating 3 different markers with different icons to identify on map.
When i draw a shape on map, i want to get the details of every sort of marker which comes under the drawn shape.
import React from "react";
import DrawingManager from "react-google-maps/lib/components/drawing/DrawingManager";
import {GoogleMap, InfoWindow, Marker, withGoogleMap, withScriptjs} from "react-google-maps";
import UploadApis from "../../service/rest/upload";
import "./index.scss";
let selectedShape;
function clearSelection() {
if (selectedShape) {
if (selectedShape.type !== 'marker') {
selectedShape.setEditable(false);
}
selectedShape = null;
}
}
function setSelection(shape) {
if (shape.type !== 'marker') {
clearSelection();
shape.setEditable(true);
}
selectedShape = shape;
}
class Map extends React.Component {
constructor(props) {
super(props);
this.shapes = [];
this.state = {
fiberData: [],
subscriberData: [],
sitesData: [],
fetchData: false,
selected: null
};
this.handleOverlayComplete = this.handleOverlayComplete.bind(this);
this.data();
}
handleOverlayComplete(e) {
console.log("overlay",e);
const newShape = e.overlay;
newShape.type = e.type;
if (e.type !== window.google.maps.drawing.OverlayType.MARKER) {
window.google.maps.event.addListener(newShape, 'click', function (e) {
if (e.vertex !== undefined) {
if (newShape.type === window.google.maps.drawing.OverlayType.POLYGON) {
let path = newShape.getPaths().getAt(e.path);
path.removeAt(e.vertex);
if (path.length < 3) {
newShape.setMap(null);
}
}
if (newShape.type === window.google.maps.drawing.OverlayType.POLYLINE) {
let path = newShape.getPath();
path.removeAt(e.vertex);
if (path.length < 2) {
newShape.setMap(null);
}
}
}
setSelection(newShape);
});
setSelection(newShape);
} else {
window.google.maps.event.addListener(newShape, 'click', function (e) {
setSelection(newShape);
});
setSelection(newShape);
}
this.shapes.push(newShape);
}
data = async () => {
let fiberData = await UploadApis.getMetaDataById("fiber",this.props.projectId);
let sitesData = await UploadApis.getMetaDataById("sites",this.props.projectId);
let subscriberData = await UploadApis.getMetaDataById("subscriber",this.props.projectId);
this.setState({fiberData: fiberData, sitesData: sitesData, subscriberData: subscriberData, fetchData: true})
};
deleteSelectedShape = () => {
if (selectedShape) {
selectedShape.setMap(null);
}
};
setSelected(selected) {
this.setState({selected: selected})
}
render() {
return (
<div>
<button className="btn-container" onClick={this.deleteSelectedShape}>Delete Shape
</button>
{this.state.fetchData ?
<div>
<GoogleMap
defaultZoom={6}
defaultCenter={{lat: 22.5106879, lng: 79.9189213}}
>
<DrawingManager
defaultDrawingMode={null}
defaultOptions={{
drawingControl: true,
drawingControlOptions: {
position: window.google.maps.ControlPosition.TOP_CENTER,
drawingModes: [ 'circle', 'polygon', 'polyline', 'rectangle']
},
polygonOptions: {editable: true},
circleOptions: {editable: true},
rectangleOptions: {editable: true},
markerOptions: {editable: true},
polylineOptions: {editable: true}
}}
onOverlayComplete={this.handleOverlayComplete}
/>
{this.state.fiberData.map((fiber) => (
<Marker
key={fiber.id}
position={{lat: fiber.latitude, lng: fiber.longitude}}
onClick={() => {
this.setSelected(fiber);
}}
icon={{
url: "../assets/svg/fiber.png",
scaledSize: new window.google.maps.Size(25, 25)
}}
/>
))}
{this.state.sitesData.map((site) => (
<Marker
key={site.id}
position={{lat: site.latitude, lng: site.longitude}}
onClick={() => {
this.setSelected(site);
}}
icon={{
url: "../assets/svg/tower.png",
scaledSize: new window.google.maps.Size(25, 25)
}}
/>
))}
{this.state.subscriberData.map((subscriber) => (
<Marker
key={subscriber.id}
position={{lat: subscriber.latitude, lng: subscriber.longitude}}
onClick={() => {
this.setSelected(subscriber);
}}
icon={{
url: "../assets/svg/subscriber.svg",
scaledSize: new window.google.maps.Size(25, 25)
}}
/>
))}
{this.state.selected && (
<InfoWindow
position={{lat: this.state.selected.latitude, lng: this.state.selected.longitude}}
onCloseClick={() => {
this.setSelected(null);
}}>
<div>
<h4>{this.state.selected.name}</h4>
<p>{this.state.selected.description}</p>
</div>
</InfoWindow>
)}
</GoogleMap>
</div> : null
}
</div>
);
}
}
export default withScriptjs(withGoogleMap(Map));
This is the first file which i have called. Index file which renders the map is -
import React from "react";
import Map from './map.jsx';
export default class MapContainer extends React.Component {
_projectId="";
constructor(props) {
super(props);
console.log(props);
if(props.location.state.project){
this._projectId = props.location.state.project.id;
}
}
render() {
return (
<div>
<Map
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=API_KEY`}
loadingElement={<div style={{height: `100%`}}/>}
containerElement={<div style={{height: `480px`}}/>}
mapElement={<div style={{height: `100%`}}/>}
projectId ={this._projectId}
/>
</div>
);
}
}```
import React,{Component } from 'react';
import {
withGoogleMap,
GoogleMap,
withScriptjs,
Marker,
InfoWindow,
} from 'react-google-maps';
import {compose, withProps, withStateHandlers} from 'recompose';
import places from 'places.json';
class MapComponent extends Component {
constructor (props) {
super (props);
this.state = {
zoom: 11,
center: {lat: 29.969516, lng: -90.103866},
markers: [],
lat:'',
lng:'',
markersLoaded: false,
};
}
componentDidMount () {
let geocoder = new window.google.maps.Geocoder ();
geocoder.geocode ({address: 'Bakerstreet, 2'}, function (results, status) {
if (status == 'OK') {
this.setState ({
lat: results[0].geometry.location.lat (),
lng: results[0].geometry.location.lng (),
});
} else {
console.log (
'Geocode was not successful for the following reason:',
status
);
}
});
}
render () {
const { lat, lng } = this.state;
const GoogleMapExample = withGoogleMap (props => (
<GoogleMap
defaultZoom={props.zoom}
defaultCenter={props.center}
options={{styles: props.mapdynamic ? darkThemeStyle : lightThemeStyle}}
>
{props.places &&
props.places.map ((place, i) => {
let lat = parseFloat (place.latitude, 10);
let lng = parseFloat (place.longitude, 10);
return (
<Marker
id={place.id}
key={place.id}
position={{lat: lat, lng: lng}}
icon="http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
onMouseOver={props.onToggleOpen.bind (this, i)}
>
{props.infoWindows[i].isOpen &&
<InfoWindow onCloseClick={props.onToggleOpen.bind (i)}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>
));
return (
<div>
<GoogleMapExample
center={{lat: 40.6451594, lng: -74.0850826}}
zoom={10}
places={places} />
</div>
);
}
}
export default compose (
withProps ({
googleMapURL: 'https://maps.googleapis.com/maps/api/js?key=YOUR KEY&libraries=geometry,drawing,places',
loadingElement: <div style={{height: `100%`}} />,
containerElement: (
<div style={{height: '100%', width: '100%', padding: '10px'}} />
),
mapElement: <div style={{height: '100%'}} />,
}),
withStateHandlers (
props => ({
infoWindows: props.places.map (p => {
return {isOpen: false};
}),
}),
{
onToggleOpen: ({infoWindows}) => selectedIndex => ({
infoWindows: infoWindows.map ((iw, i) => {
iw.isOpen = selectedIndex === i;
return iw;
}),
}),
}
),
withScriptjs,
withGoogleMap
) (MapComponent);
I am here by writing the google map component using the react order component.
But when I am trying to run this I am getting some kind of error.
Could you some one take a look into it and let me know what are the
issues here. I am getting following error like Invariant Violation:
Required props containerElement or mapElement is missing. You need to
provide both of them. The google.maps.Map instance will be
initialized on mapElement and it's wrapped by containerElement. You
need to provide both of them since Google Map requires the DOM to have
height when initialized.
Regards
You have additionally used withGoogleMap hoc in render method which you don't need
render () {
const { lat, lng } = this.state;
return (
<GoogleMap
defaultZoom={10}
defaultCenter={{lat: 40.6451594, lng: -74.0850826}}
options={{styles: props.mapdynamic ? darkThemeStyle : lightThemeStyle}}
>
{places &&
places.map ((place, i) => {
let lat = parseFloat (place.latitude, 10);
let lng = parseFloat (place.longitude, 10);
return (
<Marker
id={place.id}
key={place.id}
position={{lat: lat, lng: lng}}
icon="http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
onMouseOver={props.onToggleOpen.bind (this, i)}
>
{props.infoWindows[i].isOpen &&
<InfoWindow onCloseClick={props.onToggleOpen.bind (i)}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>
);
}