Google Maps API - How to center marker and map - javascript

I have played around with the geolocation of javascript. So I created a react component, which shows your current location. I want to visualize this with Google Maps. It works fine so far, but however, if the current position moves outside the start map, the map does not pan. My goal is that the marker is always centered, and the map scrolls.
This is what I have so far. The current position is being passed to the component via the props props.latitude and props.longitude.
UPDATE
Now I know why this is not working.
window.google.maps.Map(document.getElementsByClassName("google-map"))
is not working. It does not find the map this way. So it cannot update its properties.
Anybody an idea how to access the current map?
Here is the code:
import React, {useState,useRef,useCallback} from 'react';
import { compose, withProps } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"
function Map(props) {
const [center, setCenter] = useState({ lat: props.latitude, lng: props.longitude });
const refMap = useRef(null);
const handlePositionChanged = () => {
let position = new window.google.maps.LatLng(parseInt(props.latitude), parseInt(props.longitude));
window.google.maps.Marker(document.getElementsByClassName("google-map-marker")).setPosition(position);
window.google.maps.Map(document.getElementsByClassName("google-map")).setCenter(position);
};
return (
<GoogleMap
className="google-map"
ref={refMap}
defaultZoom={19}
mapTypeId='satellite'
defaultCenter={{ lat: props.latitude, lng: props.longitude }}
onBoundsChanged={useCallback(handlePositionChanged)}
>
<Marker className="google-map-marker" position={{ lat: props.latitude, lng: props.longitude }} position_changed={useCallback(handlePositionChanged)} />
</GoogleMap>
);
}
export default compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIz&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `500px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) => <Map latitude={props.latitude} longitude={props.longitude} />);

Instead of setting the center of the map and the marker using window.google.maps., you can use state values to change the <GoogleMap/> center parameter and the <Marker/> position parameter. So every time there's a change in the coordinates from geolocation, you need to change the state value of the Map's center and Marker's position and it the changes will then be reflected to the map. Here's a sample code snippet:
import React, { Component } from 'react';
import { withGoogleMap, GoogleMap, Marker } from 'react-google-maps';
class Map extends Component {
constructor(props) {
super(props);
this.state = {
userPosition: { lat: 40.756795, lng: -73.954298 }
};
}
onMapLoad = () => {
navigator.geolocation.getCurrentPosition(position => {
const { latitude, longitude } = position.coords;
this.setState({
userPosition: { lat: latitude, lng: longitude }
});
});
};
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
center={this.state.userPosition}
defaultZoom={13}
onLoad={this.onMapLoad()}
>
<Marker position={this.state.userPosition} />
</GoogleMap>
));
return (
<div>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: '500px' }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;

Related

How to implement adding markers to a map in React

I have a map embedded on my site using "google-map-react". I need to implement adding custom markers to the map. To prescribe coordinates in the code and after saving the marker appears on the map. How can this be implemented?
import GoogleMapReact from "google-map-react";
const Map = () => {
const defaultProps = {
center: {
lat: 10.99835602,
lng: 77.01502627,
},
zoom: 11,
};
return (
<div>
<div style={{ height: "100vh", width: "100%" }}>
<GoogleMapReact
bootstrapURLKeys={{ key: "" }}
defaultCenter={defaultProps.center}
defaultZoom={defaultProps.zoom}
></GoogleMapReact>
</div>
</div>
);
};
export default Map;
you can use #react-google-maps/api library and implement it like this:
import React from 'react'
import { GoogleMap, Marker, useJsApiLoader } from '#react-google-maps/api';
const MapComponent = (props) => {
const { location, zoom } = props;
const containerStyle = {
width: '100%',
height: '95vh'
};
var { isLoaded } = useJsApiLoader({
id: 'google-map-script',
googleMapsApiKey: /* Your API key */
})
return isLoaded ?
<GoogleMap
mapContainerStyle={containerStyle}
defaultCenter={location}
defaultZoom={zoom}
>
<Marker
position={location}
/>
</GoogleMap>
: <></>
}
export default MapComponent;

Why is no 3rd marker being created on map?

I have the below JS code
A map renders just fine and when clicking the 1st click on the map, it creates and pins a marker on the place it was clicked. The 2nd time I click, it creates a 2nd marker and pins to the position that was clicked. Great!
However, when clicking the 3rd time, it doesn't create another marker! It instead moves the 2nd marker to the position of the 3rd click! Why is it doing that? It's supposed to create a 3rd marker, but for some reason, it moves the 2nd marker to a new position which should not be the case.
The marker is inside the tags too <Marker key={i} position={latLng} so it should work properly...
It seems that {props.isMarkerShown && <Marker position={props.markerPosition} />} is not creating a new instance for the marker after the 2nd marker is created for some reason...
import React from 'react';
import { compose, withStateHandlers } from "recompose";
import { InfoWindow, withGoogleMap, withScriptjs, GoogleMap, Marker } from 'react-google-maps';
const Map = compose(
withStateHandlers(() => ({
isMarkerShown: false,
markerPosition: null
}), {
onMapClick: ({ isMarkerShown }) => (e) => ({
markerPosition: e.latLng,
isMarkerShown:true
})
}),
withScriptjs,
withGoogleMap
)
(props =>
<GoogleMap
defaultZoom={8}
defaultCenter={{ lat: -34.397, lng: 150.644 }}
onClick={props.onMapClick}
>
{props.isMarkerShown && <Marker position={props.markerPosition} />}
</GoogleMap>
)
export default class MapContainer extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div style={{ height: '100%' }}>
<Map
googleMapURL="https://maps.googleapis.com/maps/api/js?key=VALIDAPIKEY"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
{clicks.map((latLng, i) => (
<Marker key={i} position={latLng} />
))}
</div>
)
}
}
https://developers.google.com/maps/documentation/javascript/react-map

Don't want to re-render even if the state is changed in react-google-maps

I am using an application that displays a Google map with react Google Maps have multiple pins installed, and the state changes by scrolling, and the active flight changes according to the state.
At that time, the center of the Google map is set to be an activity, but the Google map is re-rendered when the state changes. I don't know how to prevent rendering.
  Google Maps has NPM library. It uses react-google-maps and is implemented using hooks. I tried to return false with useEffect (), but I didn't hear it as it is. Please tell me
MapComponent(HOC)
import React from "react";
import { withGoogleMap, GoogleMap, withScriptjs, Marker, InfoWindow } from "react-google-maps";
import { compose, withProps, withHandlers, withStateHandlers } from "recompose";
const MapWithPlaces = compose(
withProps({
googleMapURL:
`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_PLACE_API_KEY}&libraries=geometry,drawing,places`,
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: "400px", width: "100%" }} />,
mapElement: <div style={{ height: "100%" }} />
}),
withStateHandlers(
props => ({
infoWindows: props.places.map(p => {
return { isOpen: false };
}),
defaultCenter: { 'lat': props.lat, 'lng': props.lng }
}),
{
onToggleOpen: ({ infoWindows }) => selectedIndex => ({
infoWindows: infoWindows.map((iw, i) => {
iw.isOpen = selectedIndex === i;
return iw;
})
})
}
),
withHandlers(() => {
const refs = {
map: undefined,
}
console.log(refs);
return {
onMapMounted: () => ref => {
refs.map = ref
},
onZoomChanged: ({ onZoomChange }) => (props) => {
const center = { 'lat': parseFloat(props.lat, 10), 'lng': parseFloat(props.lng, 10) }
refs.map.pantTo(center)
}
}
}),
withScriptjs,
withGoogleMap
)(props => (
<GoogleMap defaultZoom={props.zoom} defaultCenter={props.center} key={props.key} ref={map}>
{props.places &&
props.places.map((place, i) => {
let lat = parseFloat(place.lat, 10);
let lng = parseFloat(place.lng, 10);
return (
<Marker
id={place.id}
key={place.key}
position={{ lat: lat, lng: lng }}
title={place.name}
onClick={props.onToggleOpen.bind(this, i)}
opacity={place.key === props.step ? 1 : 0.5}
label={place.day === props.currentDay ? place.dayIndex.toString() : ''}
>
{props.infoWindows[i].isOpen && (
<InfoWindow onCloseClick={props.onToggleOpen.bind(i)}>
<div>{place.name}</div>
</InfoWindow>
)}
</Marker>
);
})}
</GoogleMap>
));
export default MapWithPlaces;
MapComponent(hooks)
import React, { useState, useEffect, useRef } from "react";
import { withGoogleMap, withScriptjs, GoogleMap, Marker, InfoWindow } from "react-google-maps";
// import mapStyles from "./mapStyles";
const MapCreate = React.memo((props) => {
// const [selectedPark, setSelectedPark] = useState(null);
const mapRef = useRef()
useEffect(() => {
console.log("props updates")
console.log(props);
const mapCenter = {
lat: parseFloat(props.places[props.step].lat, 10),
lng: parseFloat(props.places[props.step].lng, 10)
}
return false
// refMap.current.panTo(mapCenter) //move the map to new location
}, [props]);
return (
<GoogleMap defaultZoom={14} center={{ lat: props.center.lat, lng: props.center.lng }} ref={mapRef}>
{props.places && props.places.map((place, i) => {
let lat = parseFloat(place.lat, 10);
let lng = parseFloat(place.lng, 10);
return (
<Marker
id={place.id}
key={place.key}
position={{ lat: lat, lng: lng }}
title={place.name}
opacity={place.key === props.step ? 1 : 0.5}
label={place.day === props.currentDay ? place.dayIndex.toString() : ''}
>
</Marker>
)
})}
</GoogleMap>
)
})
const MapWrapped = withScriptjs(withGoogleMap(MapCreate));
export default function Map(props) {
const mapRef = useRef(null)
return (
<div style={{ width: "100%", height: "400px" }}>
<MapWrapped
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${process.env.REACT_APP_GOOGLE_PLACE_API_KEY}`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: "400px", width: "100%" }} />}
mapElement={<div style={{ height: `100%` }} />}
{...props}
/>
</div>
);
}
Try #shouldcomponentupdate
shouldComponentUpdate(nextProps, nextState)
Use shouldComponentUpdate() to let React know if a component’s output
is not affected by the current change in state or props. The default
behavior is to re-render on every state change, and in the vast
majority of cases you should rely on the default behavior.
shouldComponentUpdate() is invoked before rendering when new props or
state are being received. Defaults to true. This method is not called
for the initial render or when forceUpdate() is used

How to add marker onClick and show my geolocation in google-maps-react?

I found a lot of useful information on google maps documentation but with simple use of js in html, in case of react honestly I don't understand it.
Source code:
import React, { Component } from 'react';
import {Map, InfoWindow, Marker, GoogleApiWrapper} from 'google-maps-react';
export class MainMap extends Component {
render() {
return (
<div>
<h1 className="text-center">My Maps</h1>
<Map google={this.props.google}
style={{width: '80%', margin: 'auto'}}
className={'map'}
zoom={14}>
<Marker
title={'The marker`s title will appear as a tooltip.'}
name={'SOMA'}
position={{lat: 37.778519, lng: -122.405640}} />
<Marker
name={'Dolores park'}
position={{lat: 37.759703, lng: -122.428093}} />
<Marker />
<Marker
name={'Your position'}
position={{lat: 46.475640, lng: 30.759497}}/>
</Map>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: (MY-API-KEY)
})(MainMap);
i want to add marker by clicking on map and don't know how...
help please!
The map has an onClick prop which you can give a function to handle clicks on the map. The third argument to this function includes the coordinates of the click.
You could use these coordinates to add a marker to your state that you use in the render method.
Example
class MainMap extends Component {
constructor(props) {
super(props);
this.state = {
markers: [
{
title: "The marker`s title will appear as a tooltip.",
name: "SOMA",
position: { lat: 37.778519, lng: -122.40564 }
}
]
};
this.onClick = this.onClick.bind(this);
}
onClick(t, map, coord) {
const { latLng } = coord;
const lat = latLng.lat();
const lng = latLng.lng();
this.setState(previousState => {
return {
markers: [
...previousState.markers,
{
title: "",
name: "",
position: { lat, lng }
}
]
};
});
}
render() {
return (
<div>
<h1 className="text-center">My Maps</h1>
<Map
google={this.props.google}
style={{ width: "80%", margin: "auto" }}
className={"map"}
zoom={14}
onClick={this.onClick}
>
{this.state.markers.map((marker, index) => (
<Marker
key={index}
title={marker.title}
name={marker.name}
position={marker.position}
/>
))}
</Map>
</div>
);
}
}
const App = GoogleApiWrapper({
apiKey: (MY-API-KEY)
})(MainMap);

When displaying multiple markers on a map, how to open just one info window, when clicking on a marker?

I'm using react-google-maps to display a map with markers, and when you click on a marker, all the info windows open up. I would like to display only one marker's info window when I click on it, and for the others to stay closed.
Here is my code:
<GoogleMap
defaultZoom={15}
defaultCenter={{ lat: 51.508530, lng: -0.076132 }}
>
{props.places && props.places.map((place, i) =>
<Marker onClick={props.onToggleOpen} key={i} position={{ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }} >
{props.isOpen && <InfoWindow onCloseClick={props.onToggleOpen}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
)}
</GoogleMap>
And I'm opening and closing the InfoWindow with this
import { compose, withProps, withStateHandlers, withHandlers, withState } from "recompose";
...
withStateHandlers(() => ({
isOpen: false,
}), {
onToggleOpen: ({ isOpen, id }) => () => ({
isOpen: !isOpen,
})
}),
I'm mapping over all the markers, and displaying them on the map. How could I click open just one marker InfoWindow?
Here is a related question, but it's not made with React, and doesn't use the react-google-maps.
It's more of a React question. You can pass the index of a clicked Marker to onToggleOpen and instead of isOpen you use a selectedPlace state that holds the index of a clicked Marker and use this index to render the right InfoWindow.
Here is an example (not fully tested, but you can get the idea):
/*global google*/
import React from "react"
import { compose, withProps, withHandlers, withState, withStateHandlers } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker, InfoWindow } from "react-google-maps"
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap,
withState('places', 'updatePlaces', ''),
withState('selectedPlace', 'updateSelectedPlace', null),
withHandlers(() => {
const refs = {
map: undefined,
}
return {
onMapMounted: () => ref => {
refs.map = ref
},
fetchPlaces: ({ updatePlaces }) => {
let places;
const bounds = refs.map.getBounds();
const service = new google.maps.places.PlacesService(refs.map.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED);
const request = {
bounds: bounds,
type: ['hotel']
};
service.nearbySearch(request, (results, status) => {
if (status == google.maps.places.PlacesServiceStatus.OK) {
console.log(results);
updatePlaces(results);
}
})
},
onToggleOpen: ({ updateSelectedPlace }) => key => {
updateSelectedPlace(key);
}
}
}),
)((props) => {
console.log(props);
return (
<GoogleMap
onTilesLoaded={props.fetchPlaces}
ref={props.onMapMounted}
onBoundsChanged={props.fetchPlaces}
defaultZoom={15}
defaultCenter={{ lat: 51.508530, lng: -0.076132 }}
>
{props.places && props.places.map((place, i) =>
<Marker onClick={() => props.onToggleOpen(i)} key={i} position={{ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }}>
{props.selectedPlace === i && <InfoWindow onCloseClick={props.onToggleOpen}>
<div>
{props.places[props.selectedPlace].name}
</div>
</InfoWindow>}
</Marker>
)}
</GoogleMap>
)
})
export default class MyFancyComponent extends React.PureComponent {
render() {
return (
<MyMapComponent />
)
}
}

Categories