UNPKG

google-react-maps

Version:

A more powerfully custom version of the Google Maps Javascript API built for React. Multiple Datalayer support. GEOJSON Enabled.

399 lines (342 loc) 16 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _utils = require('../utils/utils'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** * See [Google Maps Javascript API]{@link https://developers.google.com/maps/documentation/javascript/3.exp/reference} * @namespace google.maps * @memberof google */ /** * See [LatLngLiteral object specification]{@link https://developers.google.com/maps/documentation/javascript/3.exp/reference#LatLngLiteral} * @class google.maps.LatLngLiteral * @memberof google.maps * * @property {number} lat * @property {number} lng */ /** * The Map Component in the root component for the google maps library. It handles the interface between the google maps javascript api and the implementation of the other components. * @class Map * * @property {string} api-key Required. The javascript api key from your [google console]{@link http://console.developer.google.com}. * @property {object} mapOptions Optional. A google.maps.MapOptions object. * * @property {object} props * @property {function} props.onMount callback(map, maps) Get's called right after the component is done it's initial render. (Key for triggering outside events that require google maps api to be instantiated.) * @property {number} props.zoom * @property {google.maps.LatLngLiteral} props.center * @property {object} props.latLngBounds * @property {google.maps.LatLngLiteral} props.latLngBounds.sw * @property {google.maps.LatLngLiteral} props.latLngBounds.ne */ var Map = function (_React$Component) { _inherits(Map, _React$Component); function Map(props) { _classCallCheck(this, Map); var _this = _possibleConstructorReturn(this, (Map.__proto__ || Object.getPrototypeOf(Map)).call(this, props)); _this.displayName = 'Map'; var _div_id = "map_div_" + Math.floor(Date.now() * Math.random()).toString(); /** * @property {object} state The Map component's internal state. * @property {object} state.maps A google maps javascript api reference. * @property {object} state._div_id The div id of this map. */ _this.state = { maps: null, map: null, _div_id: _div_id }; _this.listeners = []; _this.ref = _this.ref.bind(_this); _this.getGeocoder = _this.getGeocoder.bind(_this); _this.getGoogleMapsApi = _this.getGoogleMapsApi.bind(_this); _this.getGoogleMap = _this.getGoogleMap.bind(_this); _this.getOptions = _this.getOptions.bind(_this); _this.refreshComponentFromProps = _utils.refreshComponentFromProps.bind(_this); _this.centerPropDidChange = _this.centerPropDidChange.bind(_this); _this.boundsPropDidChange = _this.boundsPropDidChange.bind(_this); _this.zoomPropDidChange = _this.zoomPropDidChange.bind(_this); _this.addListener = _this.addListener.bind(_this); _this.removeListeners = _this.removeListeners.bind(_this); _this.setupMapListenerHooks = _this.setupMapListenerHooks.bind(_this); return _this; } /** Gets the instance of the geocoder tied to this google map. */ _createClass(Map, [{ key: 'getGeocoder', value: function getGeocoder() { return this.state.geocoder; } /** Gets the google maps api reference from within the component. (Could be used to do google maps api stuff outside of the component) */ }, { key: 'getGoogleMapsApi', value: function getGoogleMapsApi() { return this.state.maps; } /** Gets the google maps instance created by `new maps.Map()` keyword. */ }, { key: 'getGoogleMap', value: function getGoogleMap() { return this.state.map; } }, { key: 'getOptions', value: function getOptions(maps) { var mapOptions = { zoom: 4, mapTypeId: maps.MapTypeId[!this.props.mapType ? "ROADMAP" : this.props.mapType], data: null }; if (this.props.optionsConstructor) mapOptions = Object.assign(mapOptions, new this.props.optionsConstructor(maps)); return mapOptions; } }, { key: 'centerPropDidChange', value: function centerPropDidChange() { var _state = this.state, maps = _state.maps, map = _state.map; var center = this.props.center; if (center) return !new maps.LatLng(center.lat, center.lng).equals(map.getCenter());else return false; } }, { key: 'centerHandleChange', value: function centerHandleChange() { var center = this.state.map.getCenter(); if (this.props.center.lat != center.lat && this.props.center.lng != center.lng) { this.state.map.setCenter(this.props.center); } } }, { key: 'boundsPropDidChange', value: function boundsPropDidChange() { var bounds = this.props.bounds; if (bounds && bounds.sw && bounds.ne) { bounds = new this.state.maps.LatLngBounds(bounds.sw, bounds.ne); } var mapBounds = this.state.map.getBounds(); return bounds && mapBounds ? !mapBounds.equals(bounds) : false; } }, { key: 'boundsHandleChange', value: function boundsHandleChange() { var bounds = this.props.bounds; if (bounds && bounds.sw && bounds.ne) { bounds = new this.state.maps.LatLngBounds(bounds.sw, bounds.ne); this.state.map.panToBounds(bounds); } //TODO: Handle bounds change. } }, { key: 'zoomPropDidChange', value: function zoomPropDidChange() { var map = this.state.map; var zoom = this.props.zoom; return typeof zoom !== 'undefined' ? zoom != map.getZoom() : false; } }, { key: 'zoomHandleChange', value: function zoomHandleChange() { var map = this.state.map; var zoom = this.props.zoom; try { map.setZoom(zoom); } catch (e) { console.error(e); } } }, { key: 'addListener', value: function addListener(listener) { this.listeners.push(listener); } }, { key: 'removeListeners', value: function removeListeners() { while (this.listeners.length > 0) { this.listeners.pop().remove(); } } }, { key: 'setupMapListenerHooks', value: function setupMapListenerHooks() { var _this2 = this; var _state2 = this.state, maps = _state2.maps, map = _state2.map; if (maps && map) { this.removeListeners(); var assemble = function assemble(name, callback) { return _this2.addListener(maps.event.addListener(map, name, callback)); }; var props = Object.getOwnPropertyNames(this.props); props.forEach(function (prop) { if (/^on.*$/.test(prop)) { var action = prop.slice(2, prop.length); //Remove the 'on' in front of the prop-name. if ((0, _utils.isValidMapListener)(action)) { switch (action.toLowerCase()) { case 'bounds_changed':case 'boundschanged': assemble('bounds_changed', function (event) { var bounds = map.getBounds() ? { ne: map.getBounds().getNorthEast().toJSON(), sw: map.getBounds().getSouthWest().toJSON() } : null; _this2.props[prop](bounds, event); }); break; case 'center_changed':case 'centerchanged': assemble('center_changed', function (event) { var center = map.getCenter(); _this2.props[prop](center, event); }); break; case 'zoom_changed':case 'zoomchanged': assemble('zoom_changed', function (event) { var zoom = map.getZoom(); _this2.props[prop](zoom, event); }); default: assemble(action.toLowerCase(), _this2.props[prop]); break; } } else { if (action.toLowerCase() !== 'mount') { console.warn(new Error("You tried adding " + prop + " which is not a valid action for a <Map /> component.")); } } } }); } } }, { key: 'ref', value: function ref(name) { var _this3 = this; return function (item) { _this3[name] = item; }; } }, { key: 'componentDidMount', value: function componentDidMount() { var _this4 = this; var initMapComponentWithLibrary = function initMapComponentWithLibrary(maps) { // window.maps = maps; var mapOptions = _this4.getOptions(maps); try { var geocoder = new maps.Geocoder(); var map = new maps.Map(_reactDom2.default.findDOMNode(_this4.mapDiv), mapOptions); map.setCenter(!_this4.props.center ? new maps.LatLng(39.5, -98.35) : new maps.LatLng(_this4.props.center.lat, _this4.props.center.lng)); if (_this4.props.bounds && _this4.props.bounds.sw && _this4.props.bounds.ne) { var bounds = new maps.LatLngBounds(_this4.props.bounds.sw, _this4.props.bounds.ne); map.panToBounds(bounds); } } catch (e) { console.error(e); } _this4.setState({ map: map, maps: maps, geocoder: geocoder }, function () { _this4.refreshComponentFromProps(); if (typeof _this4.props.onMount === 'function') { _this4.props.onMount(_this4.getGoogleMap(), _this4.getGoogleMapsApi()); } }); _this4.setupMapListenerHooks(); }; if (this.props["api-key"]) { var mapsapi = require('google-maps-api'); // if(!window.maps) mapsapi(this.props["api-key"], ['drawing', 'geometry', 'places'])().then(initMapComponentWithLibrary); // else // initMapComponentWithLibrary(window.maps); } } }, { key: 'componentDidUpdate', value: function componentDidUpdate() { if (this.state.map) { this.refreshComponentFromProps(); this.setupMapListenerHooks(); // ?? This may not be necessary. Only on didMount. } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this.removeListeners(); } }, { key: 'render', value: function render() { var _this5 = this; var children = []; var controls = []; if (this.state.maps && this.state.map && this.props.children) children = _react2.default.Children.map(this.props.children, function (child) { return child ? _react2.default.cloneElement(child, { maps: _this5.state.maps, map: _this5.state.map }) : undefined; }); if (this.state.maps && this.state.map && this.props.controls && this.props.controls.constructor.name === 'Array') { controls = _react2.default.Children.map(this.props.controls, function (control) { return control ? _react2.default.cloneElement(control, { maps: _this5.state.maps, map: _this5.state.map }) : undefined; }); } return _react2.default.createElement( 'div', { ref: this.ref('mapDiv'), id: this.state._div_id, style: this.props.style }, _react2.default.createElement( 'div', null, children ), _react2.default.createElement( 'div', null, controls ) ); } }]); return Map; }(_react2.default.Component); Map.propTypes = { didMount: _propTypes2.default.func, optionsConstructor: _propTypes2.default.func, "api-key": _propTypes2.default.string.isRequired, style: _propTypes2.default.object, mapType: _propTypes2.default.string, zoom: _propTypes2.default.number, center: _propTypes2.default.shape({ lat: _propTypes2.default.number, lng: _propTypes2.default.number }), bounds: _propTypes2.default.shape({ sw: _propTypes2.default.shape({ lat: _propTypes2.default.number, lng: _propTypes2.default.number }), ne: _propTypes2.default.shape({ lat: _propTypes2.default.number, lng: _propTypes2.default.number }) }) }; exports.default = Map; module.exports = exports['default']; //# sourceMappingURL=map.js.map