packages/jsx/src/lib/components/map/google/index.jsx
import PropTypes from "prop-types";
import React, {PureComponent} from "react";
import {GoogleMap, withGoogleMap, withScriptjs} from "react-google-maps";
import {LoadingSpinner} from "../../loadingSpinner";
import {MAP_CONTAINER_HEIGHT_PX} from "../util";
import {GoogleMapStyles} from "./styles";
export const MAP_API_URL = `https://maps.googleapis.com/maps/api/js?key=${__GCP_API_KEY__}&v=3.exp&libraries=geometry,drawing,places`;
export * from "./markerClusterer";
export const ComposedGoogleMap = withScriptjs(withGoogleMap(({googleMapRef, ...props}) => <GoogleMap
ref={googleMapRef} {...props}/>));
ComposedGoogleMap.defaultProps = {
googleMapURL: MAP_API_URL,
defaultZoom: 10,
defaultCenter: {
lat: 52.5018708,
lng: 13.3655289
},
// defaultMapTypeId: "terrain", // NOTE-RT: google.maps.MapTypeId.TERRAIN
defaultOptions: {
minZoom: 2,
styles: GoogleMapStyles,
streetViewControl: true,
streetViewControlOptions: {
position: 6 // NOTE-RT: google.maps.ControlPosition.BOTTOM_LEFT
},
zoomControl: true,
zoomControlOptions: {
position: 6 // NOTE-RT: google.maps.ControlPosition.BOTTOM_LEFT
},
gestureHandling: "greedy"
}
};
const googleMapCallbacks = [
"onDblClick",
"onDragEnd",
"onDragStart",
"onMapTypeIdChanged",
"onMouseMove",
"onMouseOut",
"onMouseOver",
"onRightClick",
"onTilesLoaded",
"onBoundsChanged",
"onCenterChanged",
"onClick",
"onDrag",
"onHeadingChanged",
"onIdle",
"onProjectionChanged",
"onResize",
"onTiltChanged",
"onZoomChanged"
];
export class GoogleMapComponent extends PureComponent {
constructor(passedProps) {
const {googleMapRef, ...props} = passedProps;
const propsKeys = Object.keys(props);
super(passedProps);
this.googleMapRef = googleMapRef || React.createRef();
this.getGoogleMap = this.getGoogleMap.bind(this);
this.passedGoogleMapCallbackProps = propsKeys.reduce((passedGoogleMapCallbackProps, propKey) => {
if (googleMapCallbacks.includes(propKey)) {
passedGoogleMapCallbackProps[propKey] = props[propKey].bind(this, this.getGoogleMap, props.id);
}
return passedGoogleMapCallbackProps;
}, {});
if (this.props.instantiateMap) {
this.props.instantiateMap(this.getGoogleMap, props.id);
}
}
get googleMap() {
return this.googleMapRef && this.googleMapRef.current;
}
componentWillUnmount() {
if (!this.props.persistentMap) {
if (this.props.clearMap) {
this.props.clearMap(this.props.id);
}
}
}
getGoogleMap() {
return this.googleMap;
}
render() {
const {
className,
mapContainerHeight,
mapContainerHeightPx,
containerElement,
loadingElement,
mapElement,
...props
} = this.props;
const actualMapContainerHeight = mapContainerHeight
? mapContainerHeight
: `${mapContainerHeightPx}px`;
return <ComposedGoogleMap
googleMapRef={this.googleMapRef}
{...{
containerElement: containerElement
? containerElement
: <div
className="map__container map__container--google"
style={{height: actualMapContainerHeight, minHeight: actualMapContainerHeight}}
/>,
loadingElement: loadingElement
? loadingElement
: <div className={["map__loading"].concat(className).join(" ")} style={{height: "100%"}}>
<LoadingSpinner/>
</div>,
mapElement: mapElement
? mapElement
: <div className={["map map--google"].concat(className).join(" ")}/>,
...props,
...this.passedGoogleMapCallbackProps
}}
/>;
}
}
GoogleMapComponent.defaultProps = {
mapContainerHeightPx: MAP_CONTAINER_HEIGHT_PX,
persistentMap: true
};
GoogleMapComponent.propTypes = {
id: PropTypes.string.isRequired,
googleMapRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({current: PropTypes.object})
]),
className: PropTypes.string,
mapContainerHeight: PropTypes.string,
mapContainerHeightPx: PropTypes.number,
containerElement: PropTypes.node,
loadingElement: PropTypes.node,
mapElement: PropTypes.node,
instantiateMap: PropTypes.func,
clearMap: PropTypes.func,
persistentMap: PropTypes.bool.isRequired
};
export default GoogleMapComponent;