Skip to content

Commit f909321

Browse files
byeokimitsmichaeldiego
authored andcommitted
Add Marker and Info Window examples (#21)
* Add Marker and Info Window examples 1. added two examples - Marker and Info Window using React Component - Marker and Info Window using Google Maps API Object 2. modified README.md to - include above two examples - parenthesize `source` in `Examples:` section - remove `:` in `Examples:` * Change code to pass The Travis CI build * Change code to avoid CI err (no-param-reassign)
1 parent d5c82db commit f909321

File tree

5 files changed

+269
-6
lines changed

5 files changed

+269
-6
lines changed

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
88
- [React-router](https://reacttraining.com/react-router/) for routing
99
- [Styled components](https://www.styled-components.com/) for styling our components
1010

11-
## Examples:
12-
13-
- [Main](https://google-map-react.github.io/google-map-react-examples/default), [source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Main.js)
14-
- [Heatmap](https://google-map-react.github.io/google-map-react-examples/heatmap), [source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Heatmap.js)
15-
- [Searchbox](https://google-map-react.github.io/google-map-react-examples/searchbox), [source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Searchbox.js)
16-
- [Autocomplete](https://google-map-react.github.io/google-map-react-examples/autocomplete), [source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Searchbox.js)
11+
## Examples
12+
13+
- [Main](https://google-map-react.github.io/google-map-react-examples/default) ([source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Main.js))
14+
- [Heatmap](https://google-map-react.github.io/google-map-react-examples/heatmap) ([source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Heatmap.js))
15+
- [Searchbox](https://google-map-react.github.io/google-map-react-examples/searchbox) ([source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Searchbox.js))
16+
- [Autocomplete](https://google-map-react.github.io/google-map-react-examples/autocomplete) ([source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/Searchbox.js))
17+
- [Marker and Info Window using React Component](https://google-map-react.github.io/google-map-react-examples/marker-info-window) ([source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/MarkerInfoWindow.js))
18+
- [Marker and Info Window using Google Maps API Object](https://google-map-react.github.io/google-map-react-examples/marker-info-window-gmaps-obj) ([source](https://github.com/google-map-react/google-map-react-examples/blob/master/src/examples/MarkerInfoWindowGmapsObj.js))
1719

1820
## Getting started
1921

src/Home.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ const Home = () => (
6464
<ListItem>
6565
<StyledLink to={`${defaultPath}autocomplete`}>Autocomplete</StyledLink>
6666
</ListItem>
67+
<ListItem>
68+
<StyledLink to={`${defaultPath}marker-info-window`}>Marker and Info Window (React Component)</StyledLink>
69+
</ListItem>
70+
<ListItem>
71+
<StyledLink to={`${defaultPath}marker-info-window-gmaps-obj`}>Marker and Info Window (Google Maps API Object)</StyledLink>
72+
</ListItem>
6773
</List>
6874
</Wrapper>
6975
);

src/examples/MarkerInfoWindow.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import React, { Component, Fragment } from 'react';
2+
import PropTypes from 'prop-types';
3+
import isEmpty from 'lodash.isempty';
4+
5+
// examples:
6+
import GoogleMap from '../components/GoogleMap';
7+
8+
// consts: [34.0522, -118.2437]
9+
import LOS_ANGELES_CENTER from '../const/la_center';
10+
11+
// InfoWindow component
12+
const InfoWindow = (props) => {
13+
const { place } = props;
14+
const infoWindowStyle = {
15+
position: 'relative',
16+
bottom: 150,
17+
left: '-45px',
18+
width: 220,
19+
backgroundColor: 'white',
20+
boxShadow: '0 2px 7px 1px rgba(0, 0, 0, 0.3)',
21+
padding: 10,
22+
fontSize: 14,
23+
zIndex: 100,
24+
};
25+
26+
return (
27+
<div style={infoWindowStyle}>
28+
<div style={{ fontSize: 16 }}>
29+
{place.name}
30+
</div>
31+
<div style={{ fontSize: 14 }}>
32+
<span style={{ color: 'grey' }}>
33+
{place.rating}{' '}
34+
</span>
35+
<span style={{ color: 'orange' }}>
36+
{String.fromCharCode(9733).repeat(Math.floor(place.rating))}
37+
</span>
38+
<span style={{ color: 'lightgrey' }}>
39+
{String.fromCharCode(9733).repeat(5 - Math.floor(place.rating))}
40+
</span>
41+
</div>
42+
<div style={{ fontSize: 14, color: 'grey' }}>
43+
{place.types[0]}
44+
</div>
45+
<div style={{ fontSize: 14, color: 'grey' }}>
46+
{'$'.repeat(place.price_level)}
47+
</div>
48+
<div style={{ fontSize: 14, color: 'green' }}>
49+
{place.opening_hours.open_now ? 'Open' : 'Closed'}
50+
</div>
51+
</div>
52+
);
53+
};
54+
55+
// Marker component
56+
const Marker = (props) => {
57+
const markerStyle = {
58+
border: '1px solid white',
59+
borderRadius: '50%',
60+
height: 10,
61+
width: 10,
62+
backgroundColor: props.show ? 'red' : 'blue',
63+
cursor: 'pointer',
64+
zIndex: 10,
65+
};
66+
67+
return (
68+
<Fragment>
69+
<div style={markerStyle} />
70+
{props.show && <InfoWindow place={props.place} />}
71+
</Fragment>
72+
);
73+
};
74+
75+
class MarkerInfoWindow extends Component {
76+
constructor(props) {
77+
super(props);
78+
79+
this.state = {
80+
places: [],
81+
};
82+
}
83+
84+
componentDidMount() {
85+
fetch('places.json')
86+
.then(response => response.json())
87+
.then((data) => {
88+
data.results.forEach((result) => {
89+
result.show = false; // eslint-disable-line no-param-reassign
90+
});
91+
this.setState({ places: data.results });
92+
});
93+
}
94+
95+
// onChildClick callback can take two arguments: key and childProps
96+
onChildClickCallback = (key) => {
97+
this.setState((state) => {
98+
const index = state.places.findIndex(e => e.id === key);
99+
state.places[index].show = !state.places[index].show; // eslint-disable-line no-param-reassign
100+
return { places: state.places };
101+
});
102+
};
103+
104+
render() {
105+
const { places } = this.state;
106+
107+
return (
108+
<Fragment>
109+
{!isEmpty(places) && (
110+
<GoogleMap
111+
defaultZoom={10}
112+
defaultCenter={LOS_ANGELES_CENTER}
113+
bootstrapURLKeys={{ key: process.env.REACT_APP_MAP_KEY }}
114+
onChildClick={this.onChildClickCallback}
115+
>
116+
{places.map(place =>
117+
(<Marker
118+
key={place.id}
119+
lat={place.geometry.location.lat}
120+
lng={place.geometry.location.lng}
121+
show={place.show}
122+
place={place}
123+
/>))}
124+
</GoogleMap>
125+
)}
126+
</Fragment>
127+
);
128+
}
129+
}
130+
131+
InfoWindow.propTypes = {
132+
place: PropTypes.shape({
133+
name: PropTypes.string,
134+
formatted_address: PropTypes.string,
135+
rating: PropTypes.number,
136+
types: PropTypes.array,
137+
price_level: PropTypes.number,
138+
opening_hours: PropTypes.object,
139+
}).isRequired,
140+
};
141+
142+
Marker.propTypes = {
143+
show: PropTypes.bool.isRequired,
144+
place: PropTypes.shape({
145+
name: PropTypes.string,
146+
formatted_address: PropTypes.string,
147+
rating: PropTypes.number,
148+
types: PropTypes.array,
149+
price_level: PropTypes.number,
150+
opening_hours: PropTypes.object,
151+
}).isRequired,
152+
};
153+
154+
export default MarkerInfoWindow;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import React, { Component, Fragment } from 'react';
2+
import isEmpty from 'lodash.isempty';
3+
4+
// examples:
5+
import GoogleMap from '../components/GoogleMap';
6+
7+
// consts: [34.0522, -118.2437]
8+
import LOS_ANGELES_CENTER from '../const/la_center';
9+
10+
const getInfoWindowString = place => `
11+
<div>
12+
<div style="font-size: 16px;">
13+
${place.name}
14+
</div>
15+
<div style="font-size: 14px;">
16+
<span style="color: grey;">
17+
${place.rating}
18+
</span>
19+
<span style="color: orange;">${String.fromCharCode(9733).repeat(Math.floor(place.rating))}</span><span style="color: lightgrey;">${String.fromCharCode(9733).repeat(5 - Math.floor(place.rating))}</span>
20+
</div>
21+
<div style="font-size: 14px; color: grey;">
22+
${place.types[0]}
23+
</div>
24+
<div style="font-size: 14px; color: grey;">
25+
${'$'.repeat(place.price_level)}
26+
</div>
27+
<div style="font-size: 14px; color: green;">
28+
${place.opening_hours.open_now ? 'Open' : 'Closed'}
29+
</div>
30+
</div>`;
31+
32+
// Refer to https://github.com/google-map-react/google-map-react#use-google-maps-api
33+
const handleApiLoaded = (map, maps, places) => {
34+
const markers = [];
35+
const infowindows = [];
36+
37+
places.forEach((place) => {
38+
markers.push(new maps.Marker({
39+
position: {
40+
lat: place.geometry.location.lat,
41+
lng: place.geometry.location.lng,
42+
},
43+
map,
44+
}));
45+
46+
infowindows.push(new maps.InfoWindow({
47+
content: getInfoWindowString(place),
48+
}));
49+
});
50+
51+
markers.forEach((marker, i) => {
52+
marker.addListener('click', () => {
53+
infowindows[i].open(map, marker);
54+
});
55+
});
56+
};
57+
58+
class MarkerInfoWindowGmapsObj extends Component {
59+
constructor(props) {
60+
super(props);
61+
62+
this.state = {
63+
places: [],
64+
};
65+
}
66+
67+
componentDidMount() {
68+
fetch('places.json')
69+
.then(response => response.json())
70+
.then((data) => {
71+
data.results.forEach((result) => {
72+
result.show = false; // eslint-disable-line no-param-reassign
73+
});
74+
this.setState({ places: data.results });
75+
});
76+
}
77+
78+
render() {
79+
const { places } = this.state;
80+
81+
return (
82+
<Fragment>
83+
{!isEmpty(places) && (
84+
<GoogleMap
85+
defaultZoom={10}
86+
defaultCenter={LOS_ANGELES_CENTER}
87+
bootstrapURLKeys={{ key: process.env.REACT_APP_MAP_KEY }}
88+
yesIWantToUseGoogleMapApiInternals
89+
onGoogleApiLoaded={({ map, maps }) => handleApiLoaded(map, maps, places)}
90+
/>
91+
)}
92+
</Fragment>
93+
);
94+
}
95+
}
96+
97+
export default MarkerInfoWindowGmapsObj;

src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Main from './examples/Main';
88
import Heatmap from './examples/Heatmap';
99
import SearchBox from './examples/Searchbox';
1010
import Autocomplete from './examples/Autocomplete';
11+
import MarkerInfoWindow from './examples/MarkerInfoWindow';
12+
import MarkerInfoWindowGmapsObj from './examples/MarkerInfoWindowGmapsObj';
1113

1214
// styles
1315
import './index.css';
@@ -30,6 +32,8 @@ ReactDOM.render(
3032
<Route path={`${defaultPath}heatmap`} component={Heatmap} />
3133
<Route path={`${defaultPath}searchbox`} component={SearchBox} />
3234
<Route path={`${defaultPath}autocomplete`} component={Autocomplete} />
35+
<Route path={`${defaultPath}marker-info-window`} component={MarkerInfoWindow} />
36+
<Route path={`${defaultPath}marker-info-window-gmaps-obj`} component={MarkerInfoWindowGmapsObj} />
3337
<Redirect exact from="*" to={defaultPath} />
3438
</Switch>
3539
</App>

0 commit comments

Comments
 (0)