Currently, I have rendered the map component into a reusables component successfully using InfoModal to show an icon, however, the standard red Google Map icon I have not modified, and I want to create a custom icon myself. I'm not sure with ES6 and JSX syntax what I need to do. I looked into react-google-maps Issues and attempted to see if there were any current or updated material anywhere for how to do this (which is probably simple), but I'm not sure if react-google-maps has something for custom marker creation in addons or the correct format.
import React, { Component } from 'react'
import { withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps'
import { DEFAULT_MARKER } from '../../constants/mapDefaults'
const MapGoogleMap = withGoogleMap(props => (
<GoogleMap
defaultZoom={16}
center={props.center}
>
{props.markers.map((marker, index) => (
<Marker
key={index}
position={marker.position}
onClick={() => props.onMarkerClick(marker)}
>
{marker.showInfo && (
<InfoWindow onCloseClick={() => props.onMarkerClose(marker)}>
<div>{marker.infoContent}</div>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
))
export default class Map extends Component {
state = {
center: {
lat: 28.3421135,
lng: -80.6149092
},
markers: [
{
position: new google.maps.LatLng(28.3431165, -80.6135908),
showInfo: false,
infoContent: (
<svg
id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
>
<path
d="M3.5 0c-1.7 0-3 1.6-3 3.5 0 1.7 1 3 2.3 3.4l-.5 8c0
.6.4 1 1 1h.5c.5 0 1-.4 1-1L4 7C5.5 6.4 6.5 5 6.5
3.4c0-2-1.3-3.5-3-3.5zm10 0l-.8 5h-.6l-.3-5h-.4L11
5H10l-.8-5H9v6.5c0 .3.2.5.5.5h1.3l-.5 8c0 .6.4 1 1 1h.4c.6 0
1-.4 1-1l-.5-8h1.3c.3 0 .5-.2.5-.5V0h-.4z"
/>
</svg>
)
}, DEFAULT_MARKER
]
}
handleMarkerClick = this.handleMarkerClick.bind(this);
handleMarkerClose = this.handleMarkerClose.bind(this);
handleMarkerClick (targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker === targetMarker) {
return {
...marker,
showInfo: true
}
}
return marker
})
})
}
handleMarkerClose (targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false
}
}
return marker
})
})
}
render () {
return (
<MapGoogleMap
containerElement={
<div style={{ height: `500px` }} />
}
mapElement={
<div style={{ height: `500px` }} />
}
center={this.state.center}
markers={this.state.markers}
onMarkerClick={this.handleMarkerClick}
onMarkerClose={this.handleMarkerClose}
/>
)
}
}
this is how I fixed that
let iconMarker = new window.google.maps.MarkerImage(
"https://lh3.googleusercontent.com/bECXZ2YW3j0yIEBVo92ECVqlnlbX9ldYNGrCe0Kr4VGPq-vJ9Xncwvl16uvosukVXPfV=w300",
null, /* size is determined at runtime */
null, /* origin is 0,0 */
null, /* anchor is bottom center of the scaled image */
new window.google.maps.Size(32, 32)
);
return(
<Marker
icon={iconMarker}
key={marker.id}
onClick={onClick}
position={{ lat: parseInt(marker.latitude), lng: parseInt(marker.longitude)}}>
{props.selectedMarker === marker &&
<InfoWindow>
<div style={{'color':'black'}}>
Shop {marker.name} {stretTexte}
</div>
</InfoWindow>}
</Marker>
)
Franklin you can use in react google maps. It has two advantages that takes it to use over info window or simple Marker component. We have Icon options to customize our marker. We have div elements that are fully customizable. You just pass icon url. LabelStyling is optional. Feel free to ask any question.
import { MarkerWithLabel } from 'react-google-maps/lib/components/addons/MarkerWithLabel';
var markerStyling= {
clear: "both", display: "inline-block", backgroundColor: "#00921A", fontWeight: '500',
color: "#FFFFFF", boxShadow: "0 6px 8px 0 rgba(63,63,63,0.11)", borderRadius: "23px",
padding: "8px 16px", whiteSpace: "nowrap", width: "160px", textAlign: "center"
};
<MarkerWithLabel
key={i}
position={marker.position}
labelAnchor={new google.maps.Point(75, 90)}
labelStyle={markerStyling}
icon={{
url: '/build/icon/markPin.svg',
anchor: new google.maps.Point(5, 58),
}}
>
<div>
<p> My Marker </p>
</div>
</MarkerWithLabel>
The Marker spread operator was missing above key={index}. This is the correct code. The icon itself is defined in another file called mapDefaults.js if anyone comes across this issue don't hesitate to reach out to me.
<Marker
{...marker}
key={index}
position={marker.position}
onClick={() => props.onMarkerClick(marker)}
>
Related
right now I'm trying to build a map that shows all the hospitals in Indonesia (and later on about covid cases) and so far I've been able to successfully grab locations from a json file and map it onto a map. My map has a button such that if you click it all the hospitals in Indonesia will show up on the map as markers. What I want to do now is to have an InfoWindow pop-up of the hospital name when a user clicks on a specific marker.
How I tried to approach it:
Create a state boolean array for all hospital markers to see if the hospital has been clicked
If the hospital has been clicked, output an InfoWindow with the Hospitals name.
Issue:
It seems that when I click the button to show all hospitals in Indonesia, it updates the state boolean array to all true. I'm not sure why that is the case, and when I click on a specific marker the state array is unchanged.
This is my git repo if you need the full code: https://github.com/ktanojo17505/google-map-react
Here is my state:
state = {
address: "",
city: "",
area: "",
state: "",
zoom: 11,
height: 400,
mapPosition: {
lat: 0,
lng: 0
},
markerPosition: {
lat: 0,
lng: 0
},
placeHospitals: false,
Hospitals: [],
didClickHospital: []
};
This is my constructor:
constructor(props) {
super(props);
var HospitalLocations = [];
var clickHospital = [];
var position;
var hospitalName;
var id;
for (let index = 0; index < HospitalData.hospitals.length; ++index) {
id = index;
var latitude = HospitalData.hospitals[index].latitude;
var longitude = HospitalData.hospitals[index].longitude;
position = { latitude, longitude };
hospitalName = HospitalData.hospitals[index].nama;
var entry = { id, position, hospitalName };
HospitalLocations.push(entry);
clickHospital.push(false);
}
this.state.Hospitals = HospitalLocations;
this.state.didClickHospital = clickHospital;
}
This is my return
return (
<div style={{ padding: "1rem", margin: "0 auto", maxWidth: 1000 }}>
<h1>Google Maps Basic</h1>
<Descriptions bordered>
<Descriptions.Item label="City">{this.state.city}</Descriptions.Item>
<Descriptions.Item label="Area">{this.state.area}</Descriptions.Item>
<Descriptions.Item label="State">
{this.state.state}
</Descriptions.Item>
<Descriptions.Item label="Address">
{this.state.address}
</Descriptions.Item>
</Descriptions>
<MapWithAMarker
googleMapURL={
"https://maps.googleapis.com/maps/api/js?key=" +
config.GOOGLE_API_KEY +
"&v=3.exp&libraries=geometry,drawing,places"
}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
<div style={{ marginTop: "2.5rem" }}>
<Button onClick={this.placeHospitals}>Hospitals</Button>
</div>
</div>
);
MapwithMarker
const MapWithAMarker = withScriptjs(
withGoogleMap(props => (
<div>
<GoogleMap
defaultZoom={this.state.zoom}
defaultCenter={{
lat: this.state.mapPosition.lat,
lng: this.state.mapPosition.lng
}}
options={options}
onClick={this.placeMarker}
>
<Marker
draggable={true}
onDragEnd={this.onMarkerDragEnd}
position={{
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng
}}
>
<InfoWindow>
<div>{this.state.address}</div>
</InfoWindow>
</Marker>
{this.state.placeHospitals &&
this.state.Hospitals.map(hospitalLoc => ( // Place the locations if Hospitals Button is clicked
<Marker
draggable={false}
position={{
lat: hospitalLoc.position.latitude,
lng: hospitalLoc.position.longitude
}}
key={hospitalLoc.id}
onClick={this.clickHospital(hospitalLoc.id)} // Change the state of the Hospital InfoWindow
>
{/* {this.state.didClickHospital[index] && ( // If true output an infowindow of the hospital name
<InfoWindow>
<div>{hospitalLoc.name}</div>
</InfoWindow>
)} */}
</Marker>
))}
<AutoComplete
style={{
width: "100%",
height: "40px",
paddingLeft: 16,
marginTop: 2,
marginBottom: "2rem"
}}
types={["(regions)"]}
onPlaceSelected={this.onPlaceSelected}
/>
</GoogleMap>
</div>
))
);
clickHospital
clickHospital = id => {
console.log("clicked");
// var tempClickHospital = this.state.didClickHospital;
// console.log(tempClickHospital[index]);
// tempClickHospital[index] = !tempClickHospital[index];
// console.log(tempClickHospital[index]);
// this.setState({ didClickHospital: tempClickHospital });
// console.log(this.state.didClickHospital);
};
This is the output of my code (before clicking Hospitals)1
This is the output of my code (after clicking Hospitals)2
If anyone could point out what I'm doing wrong that would be helpful thank you!
You can directly map each data from the json file to create an individual <Marker> with <InfoWindow> inside it.
Here's a working sample code and the code snippet below on how to do this:
import React, { Component } from "react";
import {
withGoogleMap,
GoogleMap,
Marker,
InfoWindow
} from "react-google-maps";
//import the json data of your hospital info
import data from "./data.json";
import "./style.css";
class Map extends Component {
constructor(props) {
super(props);
this.state = {
hospitalId: "",
addMarkerBtn: false
};
}
addMarkerFunction = () => {
this.setState({
addMarkerBtn: true
});
};
handleToggleOpen = id => {
this.setState({
hospitalId: id
});
};
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
defaultCenter={{ lat: -6.208763, lng: 106.845599 }}
defaultZoom={16}
>
{this.state.addMarkerBtn === true &&
data.map(hospital => (
<Marker
key={hospital.id}
position={{ lat: hospital.lat, lng: hospital.lng }}
onClick={() => this.handleToggleOpen(hospital.id)}
>
{this.state.hospitalId === hospital.id && (
<InfoWindow
onCloseClick={this.props.handleCloseCall}
options={{ maxWidth: 100 }}
>
<span>{hospital.id}</span>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
));
return (
<div>
<button id="addMarker" onClick={() => this.addMarkerFunction()}>
Add Marker
</button>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: "500px" }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;
I am trying to get my button onPress function to call a function that will open apple maps or google maps depending on the device. For some reason nothing is happening when I press the button.
Here is my function:
openMap= () => {
console.log('open directions')
Platform.select({
ios: () => {
Linking.openURL('http://maps.apple.com/maps?daddr=');
},
android: () => {
Linking.openURL('http://maps.google.com/maps?daddr=');
}
});
}
Here is the button:
<TouchableOpacity
onPress={this.openMap}
style={styles.navigateBtn}>
<Icon name="md-navigate" style={{ fontSize: 24 }} />
<Text
style={{ fontSize: 13, fontWeight: "700", lineHeight: 14 }}
>
NAVIGATE
</Text>
</TouchableOpacity>
Eventually I want to pass longitude and latitude into the openMap function to get directions but first I need to get the map to open.
Here is my import
import { View, TouchableOpacity, Modal, Platform, Alert, StyleSheet, Linking } from "react-native";
import {Header, Content, Text, Button, Icon, Card,CardItem, Title, Left, Right, Body, Container
} from "native-base";
import { Constants } from 'expo
Your button seem to call this.Map in the onPress of your TouchableOpacity. It should not be this.openMap ?
Hope it's help you!
EDIT:
Try to declare your function like this inside of your component:
openMap() {
console.log('open directions')
Platform.select({
ios: () => {
Linking.openURL('http://maps.apple.com/maps?daddr=');
},
android: () => {
Linking.openURL('http://maps.google.com/maps?daddr=');
}
});
}
And for your TouchableOpacity try this
<TouchableOpacity
onPress={() => this.openMap() }
style={styles.navigateBtn}>
<Icon name="md-navigate" style={{ fontSize: 24 }} />
<Text
style={{ fontSize: 13, fontWeight: "700", lineHeight: 14 }}
>
This will oepn maps in the web, then redirect to the app (if it is installed):
const openMaps = (latitude, longitude) => {
const daddr = `${latitude},${longitude}`;
const company = Platform.OS === "ios" ? "apple" : "google";
Linking.openURL(`http://maps.${company}.com/maps?daddr=${daddr}`);
}
Although i would just use this library, which uses deep linking instead:
openMap= () => {
console.log('open directions')
let f = Platform.select({
ios: () => {
Linking.openURL('http://maps.apple.com/maps?daddr=38.7875851,-9.3906089');
},
android: () => {
console.log('ANDROID')
Linking.openURL('http://maps.google.com/maps?daddr=38.7875851,-9.3906089').catch(err => console.error('An error occurred', err));;
}
});
f();
}
I am trying to plot Polyline between 4 GPS coordinates using react-google-maps library. Nothing is rendering on the map
import React from 'react';
import { withGoogleMap, GoogleMap, Marker, InfoWindow,Polyline } from 'react-google-maps';
class googleMapComponent extends React.Component {
//Higher order components: withGoogleMap is employed as a function call. This fucntion returns another component defination which is later mounted in render
// maintain a refernce to a map inside the component, so that
constructor(){
super()
this.state ={
map:null
}
}
mapMoved(){
console.log('mapMoved: ' + JSON.stringify(this.state.map.getCenter()))
}
mapLoaded(map){
//console.log('mapLoaded: ' + JSON.stringify(map.getCenter()))
if(this.state.map !==null)
return
this.setState({
map:map
})
}
zoomchanged(){
console.log('mapZoomed: ' + JSON.stringify(this.state.map.getZoom()))
}
handleMarkerClick(targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker === targetMarker) {
return {
...marker,
showInfo: true,
};
}
return marker;
}),
});
}
handleMarkerClose(targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false,
};
}
return marker;
}),
});
}
render() {
const markers= [
{
position: new google.maps.LatLng(36.05298766, -112.0837566),
showInfo: false,
infoContent: false,
},
{
position: new google.maps.LatLng(36.21698848, -112.0567275),
showInfo: false,
infoContent: false,
},
]
const lineCoordinates= [
{coordinate: new google.maps.LatLng(36.05298766, -112.0837566)},
{coordinate: new google.maps.LatLng(36.0529832169413, -112.083731889724)},
{coordinate: new google.maps.LatLng(36.0529811214655, -112.083720741793)},
{coordinate: new google.maps.LatLng(36.0529811214655, -112.083720741793)},
]
return (
<GoogleMap
ref={this.mapLoaded.bind(this)}
onDragEnd={this.mapMoved.bind(this)}
onZoomChanged={this.zoomchanged.bind(this)}
defaultZoom={this.props.zoom}
defaultCenter={this.props.center}
>
{markers.map((marker, index) => (
<Marker
position={marker.position}
title="click on it Sir..!!"
defaultPosition={this.props.center}
style={{height: '2xpx', width: '2px'}}
/>
))}
{lineCoordinates.map((polyline,index)=>(
<Polyline
defaultPosition={this.props.center}
path= {polyline.coordinate}
geodesic= {true}
strokeColor= {#FF0000}
strokeOpacity= {1.0}
strokeWeight= {2}
/>
</GoogleMap>
)
}
}
export default withGoogleMap(googleMapComponent);
Any suggestion on it will be helpful. If the library does not support this functionality. I can swtich the library too.
Yes. Example:
render() {
const pathCoordinates = [
{ lat: 36.05298765935, lng: -112.083756616339 },
{ lat: 36.2169884797185, lng: -112.056727493181 }
];
return (
<GoogleMap
defaultZoom={this.props.zoom}
defaultCenter={this.props.center}
>
{/*for creating path with the updated coordinates*/}
<Polyline
path={pathCoordinates}
geodesic={true}
options={{
strokeColor: "#ff2527",
strokeOpacity: 0.75,
strokeWeight: 2,
icons: [
{
icon: lineSymbol,
offset: "0",
repeat: "20px"
}
]
}}
/>
</GoogleMap>
);
}
When you run the mapping function, are you creating a new polyline for each set of coordinates? Looking at the Google Maps docs, the polyline takes an array of objects as a path argument. google-maps-react is just a wrapper around that API, so you should be able to create your polyline just by passing in the array of objects as the path. Currently, you're trying to generate a bunch of polyline objects based on tiny coordinate fragments.
A simpler example to show just one polyline being drawn:
<GoogleMap defaultZoom={7} defaultCenter={{ lat: -34.897, lng: 151.144 }}>
<Polyline path={[{ lat: -34.397, lng: 150.644 }, { lat: -35.397, lng: 151.644 }]}/>
</GoogleMap>
Entire snippet for anyone unclear about the correct imports and setup (with recompose):
import React from "react";
import ReactDOM from "react-dom";
import { compose, withProps } from "recompose";
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
Polyline
} from "react-google-maps";
const MyMapComponent = compose(
withProps({
googleMapURL:
"https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />
}),
withScriptjs,
withGoogleMap
)(props => (
<GoogleMap defaultZoom={7} defaultCenter={{ lat: -34.897, lng: 151.144 }}>
<Polyline path={[{ lat: -34.397, lng: 150.644 }, { lat: -35.397, lng: 151.644 }]}/>
</GoogleMap>
));
ReactDOM.render(<MyMapComponent />, document.getElementById("root"));
Same example as above, without recompose:
import React from "react";
import ReactDOM from "react-dom";
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Polyline
} from "react-google-maps";
const InternalMap = props => (
<GoogleMap defaultZoom={7} defaultCenter={{ lat: -34.897, lng: 151.144 }}>
<Polyline
path={[{ lat: -34.397, lng: 150.644 }, { lat: -35.397, lng: 151.644 }]}
/>
</GoogleMap>
);
const MapHoc = withScriptjs(withGoogleMap(InternalMap));
const MyMapComponent = props => (
<MapHoc
googleMapURL="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
);
ReactDOM.render(
<MyMapComponent />,
document.getElementById("root")
);
I am using react-google-maps and I followed that example : LINK . I am fetchng data which comes from GPS device and I would like to center when new data is fetched.
Here is code of the whole map component:
const GettingStartedGoogleMap = withGoogleMap(props => (
<GoogleMap
ref={props.onMapLoad}
defaultZoom={18}
defaultCenter={props.defCenter}
onClick={props.onMapClick}
>
{props.markers.map((marker,i) => (
<Marker
key={i}
position={marker.location}
time={marker.time}
onClick={() => props.onMarkerClick(marker)}
>
{ marker.isShown &&
<InfoWindow onCloseClick={() => props.onMarkerClick(marker)}>
<div className="marker-text">{marker.time} </div>
</InfoWindow>
}
</Marker>
))}
</GoogleMap>
));
class GettingStartedExample extends Component {
componentDidMount(){
this.props.fetchMarkers();
console.log("MONT");
console.log(this.props.markers.length);
}
componentWillReceiveProps(){
console.log(this.props.markers);
console.log(this.props.markers.length);
}
state = {
markers: this.props.markers,
center: {lat: 50.07074, lng: 19.915718},
};
handleMapLoad = this.handleMapLoad.bind(this);
handleMarkerClick = this.handleMarkerClick.bind(this);
handleMapLoad(map) {
this._mapComponent = map;
if (map) {
console.log(map.getZoom());
}
}
handleMarkerClick(targetMarker) {
/*
* All you modify is data, and the view is driven by data.
* This is so called data-driven-development. (And yes, it's now in
* web front end and even with google maps API.)
*/
const nextMarkers = this.state.markers.filter(marker => marker !== targetMarker);
if(targetMarker.isShown==true)
{
targetMarker.isShown=false;
}
else
{
targetMarker.isShown=true;
}
this.setState({
markers: nextMarkers,
center: {lat: 5.07074, lng: 19.915718}
});
}
render() {
const markers = this.props.markers.map((marker,i) => {
return (
<Marker key={i} position={marker.location} time={marker.time} onClick={this.handleMarkerClick} />
)});
var centerPos;
var lastMark;
if(markers[markers.length-1]!== undefined)
{
centerPos=markers[markers.length-1].props.position;
lastMark=markers[markers.length-1].props;
console.log(centerPos);
}
else {
centerPos={lat: 5.07074, lng: 19.915718};
}
return (
<div className='container map-container'>
<GettingStartedGoogleMap
containerElement={
<div style={{ height: `100%` }} />
}
mapElement={
<div style={{ height: `100%` }} />
}
onMapLoad={this.handleMapLoad}
markers={this.props.markers}
onMarkerClick={this.handleMarkerClick}
defCenter={this.state.center}
lastMarker={lastMark}
/>
</div>
);
}
}
GettingStartedExample.propTypes={
markers: React.PropTypes.array.isRequired,
fetchMarkers: React.PropTypes.func.isRequired
}
function mapStateToProps(state){
return{
markers:state.markers
}
}
export default connect(mapStateToProps,{fetchMarkers})(GettingStartedExample);
Probably I have to set state of center to the last object in this.props.markers, I tried to do it on componentWillReceiveProps(), but I have no idea how to that.I also tried here in render():
if(markers[markers.length-1]!== undefined)
{
centerPos=markers[markers.length-1].props.position;
lastMark=markers[markers.length-1].props;
console.log(centerPos);
}
else {
centerPos={lat: 5.07074, lng: 19.915718};
}
and tried to pass it to the state, but it didn't work. I am sure the solution is simple, but I have no experience with React.If it would be helpful I am adding code of actions.js where redux action for fetching markers is defined:
export const SET_MARKERS='SET_MARKERS';
/*markers*/
export function setMarkers(markers){
return{
type:SET_MARKERS,
markers
}
}
export function fetchMarkers(){
return dispatch => {
fetch('/api/markers')
.then(res=>res.json())
.then(data=>dispatch(setMarkers(data.markers)));
;
}
}
Just add center property to GoogleMap component.
<GoogleMap
center={props.center}
/>
I am trying to have same effect on my page as here react-google-map demo. I used react-google-maps. The thing is I am fetching data with markers' informations and I don't know how can I handle click that will show/hide InfoWindow. Probably the reason is somewhere with state, I don't know how to make variable "isShown" true/false for each marker in markers array. Here is my code:
const GettingStartedGoogleMap = withGoogleMap(props => (
<GoogleMap
ref={props.onMapLoad}
defaultZoom={16}
defaultCenter={props.defCenter}
onClick={props.onMapClick}
>
{props.markers.map((marker,i) => (
<Marker
key={i}
position={marker.location}
time={marker.time}
onClick={() => props.onMarkerClick(marker)}
// HERE I TRIED SOMETHING LIKE marker.isShown=true; but it is NOT WORKING
>
{
<InfoWindow>
<div className="marker-text">{marker.time}</div>
</InfoWindow>
}
</Marker>
))}
</GoogleMap>
));
class GettingStartedExample extends Component {
componentDidMount(){
this.props.fetchMarkers();
}
state = {
markers: this.props.markers,
};
handleMapLoad = this.handleMapLoad.bind(this);
handleMarkerClick = this.handleMarkerClick.bind(this);
handleMapLoad(map) {
this._mapComponent = map;
if (map) {
console.log(map.getZoom());
}
}
handleMarkerClick(targetMarker) {
/*
* All you modify is data, and the view is driven by data.
* This is so called data-driven-development. (And yes, it's now in
* web front end and even with google maps API.)
*/
const nextMarkers = this.state.markers.filter(marker => marker !== targetMarker);
console.log(targetMarker.showInfo)
this.setState({
markers: nextMarkers,
});
}
render() {
return (
<div className='container map-container'>
<GettingStartedGoogleMap
containerElement={
<div style={{ height: `100%` }} />
}
mapElement={
<div style={{ height: `100%` }} />
}
onMapLoad={this.handleMapLoad}
markers={this.props.markers}
onMarkerClick={this.handleMarkerClick}
defCenter={{lat: 50.07074, lng: 19.915718}}
/>
</div>
);
}
}
GettingStartedExample.propTypes={
markers: React.PropTypes.array.isRequired,
fetchMarkers: React.PropTypes.func.isRequired
}
function mapStateToProps(state){
return{
markers:state.markers
}
}
export default connect(mapStateToProps,{fetchMarkers})(GettingStartedExample);
Currently it looks like this:
Markers with InfoWindow
On my final effect I would like to have InfoWindow on the newest marker and handle click that allows you to show/hide InfoWindows on all markers.
How can I achieve that showing/hiding InfoWindow on each marker?
Thanks a lot for any help!
you can try this
i am getting markers array in nextProps and so set it into the state
you can use your own markers array
import React from 'react'
import { Link } from 'react-router'
import { withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps'
const num10 = 10
const GettingStartedGoogleMap = withGoogleMap((props) => (
<GoogleMap
ref={props.onMapLoad}
defaultZoom={10}
center={props.center}
onClick={props.onMapClick}
>
{props.markers.map((marker, index) => (
<Marker
key={index}
position={marker.position}
onClick={() => props.onMarkerClick(marker)}
{...marker}
//onRightClick={() => props.onMarkerRightClick(index)}
>
{marker.showInfo && (
<InfoWindow onCloseClick={() => props.onMarkerClose(marker)}>
<div className="">
myinfowindow
</div>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
))
class GoogleMaps extends React.Component {
constructor(props) {
super(props)
this.state = {
center: {
lat: 33.6890603,
lng: -78.8866943
},
markers: [],
true: true
}
}
componentWillReceiveProps(nextProps) {
this.setState({ markers: [] }, () => {
const m = nextProps.pageNo - 1
if (nextProps.markers[0] !== undefined) {
let obj = {}
let newArray = []
for (let i = m * num10; i <= nextProps.markers.length; i++) {
if (i === m * num10 + num10) { break }
obj = {
position: { lat: nextProps.markers[i].loc[1], lng: nextProps.markers[i].loc[0] },
rate: nextProps.markers[i].spaces[0].rate,
infoContent: nextProps.markers[i].listingName || nextProps.markers[i].spaces[0].name,
showInfo: false,
photos: nextProps.markers[i].photos[0],
description: nextProps.markers[i].basic_details.notes,
secured: nextProps.markers[i].isSecured,
markerIcon: false, id: nextProps.markers[i]._id
}
newArray = this.state.markers
newArray.push(obj)
this.setState({ markers: newArray,
center: { lat: nextProps.markers[0].loc[1],
lng: nextProps.markers[0].loc[0]
}
})
}
} else {
this.setState({ markers: this.props.markers })
}
})
}
handleMarkerClick(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: true,
markerIcon: true
}
} else {
return {
...marker,
showInfo: false
}
}
})
})
}
handleMarkerClose(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false
}
}
return marker
})
})
}
handleMarkerClose2(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (targetMarker) {
return {
...marker,
showInfo: false
}
}
return marker
})
})
}
render() {
return (<div>
<div id="mapcanvas"
className="col-md-6"
style={{ 'height': '556px', 'width': '674px', paddingLeft: '0px', paddingRight: '0px' }}
>
<GettingStartedGoogleMap
containerElement={<div style={{ height: '100%' }} />}
mapElement={<div style={{ height: '100%' }} />}
onMapClick={this.handleMarkerClose2.bind(this)}
onMarkerClick={this.handleMarkerClick.bind(this)}
markers={this.state.markers}
center={this.state.center}
onMarkerClose={this.handleMarkerClose.bind(this)}
/>
</div>
<style>{'\
.gm-style-iw + div {\
display: none;\
left: 26px;}\
'}</style>
</div>)}
}
GoogleMaps.propTypes = {
markers: React.PropTypes.array
}
export default GoogleMaps
try this: (props.showInfoIndex == index ) instead of ( props.isOpen )
{props.nhatro.map((nhatro, index) =>
<Marker
key={index}
options={{icon: 'https://i.imgur.com/9G5JOp8.png'}}
position={nhatro}
onClick={()=>{ props.showInfo(index)} }
>
{ (props.showInfoIndex == index ) &&
<InfoWindow onCloseClick={props.onToggleOpen}>
<div>
<div>nhà trọ cho thuê</div>
<div >1.500.000đ</div>
</div>
</InfoWindow>}
</Marker>
)}
use showInfo fnc to setState :
showInfo(a){
setState({showInfoIndex: a })
}
hey your info window is child component, if u want to open infowindow just make info window equivalent to the marker class and make any child component as you want
try this:
<Map
google={this.props.google}
style={style}
initialCenter={{
lat: lat,
lng: lng
}}
zoom={zoom}
onClick={this.onMapClicked}
>
{marker && marker.map((marker, index) => (
<Marker
key={index}
onClick={this.onMarkerClick}
title={marker.place_id}
name={marker.place_name}
position={{ lat: marker.place_latitude, lng: marker.place_longitude }} >
{
<div></div>
}
</Marker>
))}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}>
<div>
<h3>{this.state.selectedPlace.name}</h3>
</div>
</InfoWindow>
</Map>