import React from 'react'; import ReactDom from 'react-dom'; /** The component designed to implement the google.maps.InfoWindow class. This component can be the child of either the `<Map />` or `<Marker />` components, but if you decide to put it within the `<Map />` component you must set its coordinate property so that it has an anchor point. * @memberof Map * * @property {object} props * @property {google.maps} props.maps Required. * @property {google.maps.Map} props.map Required. * @property {google.maps.MVCObject} props.anchor Required if coordinates aren't provided. * @property {object} props.coords Required if anchor isn't provided. * @property {number} props.coords.lng * @property {number} props.coords.lat * @property {bool} props.disableAutopan * @property {number} props.maxWidth * @property {object} props.pixelOffset * @property {object} props.pixelOffset.width * @property {object} props.pixelOffset.height * @property {google.maps.InfoWindowOptions} props.options These will overwrite any of the convenience props above. See [google.maps.InfoWindowOptions]{@link https://developers.google.com/maps/documentation/javascript/3.exp/reference#InfoWindowOptions} documentation for all the options. * @property {bool} props.open Allows you to open and close a window without fully unmounting it. * @property {object} state * @property {google.maps.InfoWindow} state.infoWindow The internal instance of the infoWindow. * @property {function} props.onCloseClick Use this to listen for the close click event. When someone tries to close the infowindow. Implement closing. */ class InfoWindow extends React.Component { constructor(props) { super(props); this.displayName = 'InfoWindow'; this.state = { infoWindow : null, anchor : null } this.loadInfoWindowContent = this.loadInfoWindowContent.bind(this); this.node = null; } componentWillMount() { var {maps, map, anchor, coords} = this.props; if(maps && map) { var options = { position : anchor? undefined : coords } var infoWindow = new maps.InfoWindow(options) infoWindow.open(map, anchor); //Don't let the infowindow do it's default thing when a user tries to close it. maps.event.addListener(infoWindow, 'closeclick', e => { if(this.props.open) infoWindow.open(map, anchor); if(this.props.onCloseClick) this.props.onCloseClick }); this.setState({infoWindow}) } else { console.error("InfoWindow must live inside of a <Map /> component context.") } } /** Load rendered children into infoWindow. * @return {undefined} */ loadInfoWindowContent() { if(this.state.infoWindow) { this.node = ReactDom.findDOMNode(this.refs.infoWindowChildren); this.state.infoWindow.setContent(this.node); //Set infowindow content } } /** Place rendered children back into their normal location to await their destruction. * @return {undefined} */ cleanInfoWindowContentForUnmount() { //Undo our previous dom manipulation. var parent = ReactDom.findDOMNode(this); var child = this.node; parent.appendChild(child); } componentDidMount() { console.log("IW: Mounted Info window."); this.loadInfoWindowContent() } componentWillUnmount() { if(this.state.infoWindow) this.state.infoWindow.open(null); this.setState({infoWindow : null}); this.cleanInfoWindowContentForUnmount(); console.log("IW: Unmounted info window.") } componentDidUpdate(prevProps, prevState) { if(this.props.infoWindow) { if(this.props.open) this.props.infoWindow.open(this.props.map); else this.props.infoWindow.open(null); } } render() { console.log("IW: Rendered infowindow") return <div><div ref="infoWindowChildren">{this.props.children}</div></div>; } } InfoWindow.propTypes = { maps : React.PropTypes.object, map : React.PropTypes.object, coords : React.PropTypes.object, onCloseClick : React.PropTypes.func } export default InfoWindow;