<Map
youAreHereCoords={youAreHereCoords /* map origin (coordinates) */}
selectedLocation={selectedLocation /* location to drop a pin (coordinates) */}
/>
Last active
September 13, 2022 01:00
-
-
Save silesky/05bd33566bbc7eb30be3b6b686336955 to your computer and use it in GitHub Desktop.
React custom Google Maps component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import ReactDOM from 'react-dom'; | |
import { iconYouAreHere, iconPin } from 'icons'; | |
import styles from './styles.css'; | |
const loadScript = src => { | |
const ref = global.document.getElementsByTagName('script')[0]; | |
const script = global.document.createElement('script'); | |
script.src = src; | |
script.async = false; | |
ref.parentNode.insertBefore(script, ref); | |
}; | |
// default gps coordinates (for demo purposes). | |
class GoogleMap extends Component { | |
static defaultProps = { | |
selectedLocation: { | |
geolocation: [], | |
title: '', | |
}, | |
zoom: 16, | |
mapCenterCoords: [27.70818068675375, -97.3250101343628], | |
youAreHereCoords: [27.716433466839, -97.328835725784], | |
gmApiKey: 'xxx', | |
}; | |
static removeAllMarkers() { | |
global.mapMarkers.forEach(eachMarker => eachMarker.setMap(null)); | |
global.mapMarkers = []; | |
} | |
static createMarkerIcon(url) { | |
const { Point } = global.google.maps; | |
return { | |
url, // many more options exist in the google maps api docs. | |
origin: new Point(0, 0), | |
anchor: new Point(35, 90), | |
}; | |
} | |
static changeMarkerPosition(coords = [], title = '') { | |
const { Marker, LatLng, Animation } = global.google.maps; | |
GoogleMap.removeAllMarkers(); | |
const marker = new Marker({ | |
position: new LatLng(...coords), | |
icon: GoogleMap.createMarkerIcon(iconPin), | |
title, | |
animation: Animation.DROP, // bounce is also cool | |
optimized: false, // make markers higher up go on bottom (enables proper ZIndex behavior) | |
}); | |
global.mapMarkers = [marker]; | |
marker.setMap(global.MapInstance); // display current marker | |
} | |
static setCenter([lat, lng], animated = true) { | |
const offset = 0.008; // increase to move the center up. | |
const latWithOffset = lat - offset; | |
global.MapInstance.setOptions({ zoom: 16 }); | |
if (!animated) { | |
global.MapInstance.setCenter({ lat: latWithOffset, lng }); | |
} else { | |
global.MapInstance.panTo({ lat: latWithOffset, lng }); | |
} | |
componentDidMount() { | |
global.mapLoadedCallback = this.mapLoadedCallback; // assign instance method to glonal so it can be called by loaded script | |
const { gmApiKey } = this.props; | |
const apiUrl = `http://maps.googleapis.com/maps/api/js?&callback=mapLoadedCallback&key=${gmApiKey}`; | |
if (!global.google || !global.google.maps) { | |
// don't load twice | |
loadScript(apiUrl); // load script and trigger callback | |
} else { | |
this.mapLoadedCallback(); // manually trigger callback | |
} | |
global.mapMarkers = []; | |
} | |
componentWillReceiveProps({ selectedLocation: { geolocation, title } }) { | |
const userSelectedNewLocation = title !== this.props.selectedLocation.title; | |
if (userSelectedNewLocation) { | |
GoogleMap.setCenter(geolocation); | |
GoogleMap.changeMarkerPosition(geolocation, title); | |
} | |
} | |
setYouAreHere = () => { | |
const { Marker, LatLng } = global.google.maps; | |
const marker = new Marker({ | |
position: new LatLng(...this.props.youAreHereCoords), | |
icon: GoogleMap.createMarkerIcon(iconYouAreHere), | |
title: 'You are Here', | |
optimized: false, | |
}); | |
marker.setMap(global.MapInstance); | |
} | |
getMapOptions = () => { | |
const { LatLng } = global.google.maps; | |
return { | |
zoom: this.props.zoom, | |
minZoom: 4, | |
center: new LatLng(...this.props.mapCenterCoords), | |
mapTypeControl: false, // Map / satellite button | |
streetViewControl: false, // little person button | |
zoomControl: false, // zoom button | |
fullscreenControl: false, // remove [__] button | |
clickableIcons: false, | |
}; | |
} | |
mapLoadedCallback = () => { | |
const { Map } = global.google.maps; | |
global.MapInstance = new Map( | |
ReactDOM.findDOMNode(this), | |
this.getMapOptions(), | |
); | |
this.setYouAreHere(iconYouAreHere); | |
} | |
render() { | |
return <div className="maps__google_maps" />; | |
} | |
} | |
const Map = props => | |
(<div className={styles.mapContainer}> | |
<GoogleMap {...props} /> | |
</div>); | |
export default Map; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment