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
JavaScript
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
;