UNPKG

google-react-maps

Version:

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

514 lines (450 loc) 19.4 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 _utils = require('../utils/utils'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 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; } //Rational: This component emulates the google Data.Feature. //It lives in the context of a <DataLayer /> Component and interfaces with it's Data object that has been passed as prop to it. /** The component that handles individual features within a data layer. */ var Feature = function (_React$Component) { _inherits(Feature, _React$Component); function Feature(props) { _classCallCheck(this, Feature); var _this = _possibleConstructorReturn(this, (Feature.__proto__ || Object.getPrototypeOf(Feature)).call(this, props)); _this.displayName = 'Feature'; _this.state = { selected_point: null, feature: null, geoJson: null }; _this.listeners = []; //Editor helper functions _this.addPoint = _this.addPoint.bind(_this); _this.findPoint = _this.findPoint.bind(_this); _this.selectPoint = _this.selectPoint.bind(_this); _this.deletePoint = _this.deletePoint.bind(_this); _this.initListeners = _this.initListeners.bind(_this); _this.addListener = _this.addListener.bind(_this); _this.removeListeners = _this.removeListeners.bind(_this); //Check props. _this.checkPropEditable = _this.checkPropEditable.bind(_this); _this.setDraggable = _this.setDraggable.bind(_this); _this.setIcon = _this.setIcon.bind(_this); _this.updateFeatureGeometry = _this.updateFeatureGeometry.bind(_this); _this.getGeometryForFeature = _this.getGeometryForFeature.bind(_this); _this.generateFeatureFromGeoJson = _this.generateFeatureFromGeoJson.bind(_this); _this.updateProperties = _this.updateProperties.bind(_this); _this.mounted = false; return _this; } ///--------------------------------Editor Helper Methods-----------------------------------/// _createClass(Feature, [{ key: 'addPoint', value: function addPoint(latLng) { var feature = this.state.feature; var _props = this.props, editable = _props.editable, fastEditing = _props.fastEditing; var point = this.state.selected_point ? this.state.selected_point : null; if (!feature || !latLng || !point || !editable || !fastEditing) { return; } var type = feature.getGeometry().getType(); switch (type) { case 'Polygon': { var pointArray = feature.getGeometry().getAt(0).getArray(); var newGeometry = new this.props.maps.Data.Polygon([[].concat(_toConsumableArray(pointArray.slice(0, point.index + 1)), [latLng], _toConsumableArray(pointArray.slice(point.index + 1, pointArray.length)))]); feature.setGeometry(newGeometry); if (this.mounted) { this.setState({ selected_point: { index: point.index + 1, latLng: latLng } }); } break; } } } }, { key: 'findPoint', value: function findPoint(latLng) { var feature = this.state.feature; if (!feature || !latLng) { return false; } switch (feature.getGeometry().getType()) { case 'Polygon': { var geometry = feature.getGeometry(); var linearRing = geometry.getAt(0); var pointArray = linearRing.getArray(); for (var i = 0; i < pointArray.length; i++) { var point = pointArray[i]; if (point.lat() == latLng.lat() && point.lng() == latLng.lng()) { //Match found! return { index: i, latLng: point }; break; } } break; } } return false; } }, { key: 'selectPoint', value: function selectPoint(latLng) { var foundPoint = this.findPoint(latLng); if (foundPoint && this.mounted) { this.setState({ selected_point: foundPoint }); } } }, { key: 'deletePoint', value: function deletePoint(latLng) { var feature = this.state.feature; var _props2 = this.props, editable = _props2.editable, fastEditing = _props2.fastEditing; var point = this.state.selected_point; if (!feature || !latLng || !point || !editable || !fastEditing) { return; } var type = feature.getGeometry().getType(); switch (type) { case 'Polygon': { var pointArray = feature.getGeometry().getAt(0).getArray(); if (pointArray.length - 1 < 3) { if (this.props.onDelete) { this.props.onDelete(this.state.geoJson); } return; } var newGeometry = new this.props.maps.Data.Polygon([[].concat(_toConsumableArray(pointArray.slice(0, point.index)), _toConsumableArray(pointArray.slice(point.index + 1, pointArray.length)))]); feature.setGeometry(newGeometry); if (point.index - 1 > -1) { this.selectPoint(pointArray[point.index - 1]); } else { this.selectPoint(pointArray[0]); } break; } } } ///--------------------------------Listener Management Methods-----------------------------------/// }, { key: 'initListeners', value: function initListeners() { var _this2 = this; //Set geometry listener. if (typeof this.props.onChange === 'function') this.addListener(this.props.data.addListener('setgeometry', function (event) { var feature = event.feature; if (feature.getId() == _this2.state.feature.getId()) { feature.toGeoJson(function (geoJson) { if (_this2.mounted) { _this2.setState({ geoJson: JSON.parse(JSON.stringify(geoJson)) }, function () { if (typeof _this2.props.onChange === 'function') _this2.props.onChange(geoJson); }); } }); } })); //Polygon clicked. if (this.state.feature && this.props.infoWindow) { this.addListener(this.props.data.addListener('click', function (e) { var feature = e.feature; if (feature.getId() == _this2.state.feature.getId()) { var infoWindow = new _this2.props.maps.InfoWindow({ content: _this2.props.infoWindow, position: e.latLng.toJSON() }); infoWindow.open(_this2.props.map); } })); } else if (typeof this.props.onClick === 'function') this.addListener(this.props.data.addListener('click', function (event) { var feature = event.feature; if (feature.getId() == _this2.state.feature.getId()) { //Select the point. (Used in fastEditing mode.) _this2.selectPoint(event.latLng); // event.stop(); var coords = event.latLng.toJSON(); coords[0] = coords.lng; coords[1] = coords.lat; if (_this2.props.onClick) _this2.props.onClick(Object.assign({}, event, { id: _this2.props.id, coords: coords, geoJson: _this2.state.geoJson })); } })); this.addListener(this.props.data.addListener('rightclick', function (event) { var feature = event.feature; if (feature.getId() == _this2.state.feature.getId()) { event.stop(); var coords = event.latLng.toJSON(); coords[0] = coords.lng; coords[1] = coords.lat; if (_this2.props.onRightClick) _this2.props.onRightClick(Object.assign({}, event, { id: _this2.props.id, coords: coords, geoJson: _this2.state.geoJson })); } })); this.addListener(this.props.maps.event.addListener(this.props.map, 'click', function (_ref) { var latLng = _ref.latLng; return _this2.addPoint(latLng); })); this.addListener(this.props.maps.event.addListener(this.props.map, 'rightclick', function () { return _this2.deletePoint(_this2.state.selected_point); })); this.addListener(this.props.data.addListener('click', function (event) { var latLng = event.latLng; _this2.addPoint(latLng); })); } }, { key: 'removeListeners', value: function removeListeners(callback) { this.listeners.forEach(function (listener) { return listener.remove(); }); this.listeners = []; } }, { key: 'addListener', value: function addListener(listener, callback) { var listeners = this.listeners.slice(); listeners.push(listener); this.listeners = listeners; } ///--------------------------------Lifecycle Methods-----------------------------------/// }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { // console.log("F: componentWillRecieveProps"); if (nextProps.data && this.state.feature) { this.checkPropEditable(nextProps); this.updateProperties(nextProps.geoJson.properties); this.updateFeatureGeometry(nextProps.geoJson); } // console.log("Feature will recieve props."); } }, { key: 'componentWillUpdate', value: function componentWillUpdate(nextProps, nextState) { this.removeListeners(); } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prev_props) { this.initListeners(); if (prev_props.draggable != this.props.draggable) { this.setDraggable(); } if (prev_props.icon != this.props.icon) { this.setIcon(); } } }, { key: 'componentDidMount', value: function componentDidMount() { var _this3 = this; // console.log("F: componentDidMount") this.mounted = true; if (this.props.data) { var id = undefined; // console.log("Feature Mounted with ID:", this.props.id); if (this.props.id) { id = this.props.id; } //Force the user to supply the property to use as the id. var feature; try { feature = this.generateFeatureFromGeoJson(this.props.geoJson); } catch (e) { console.error(e); } this.setState({ feature: feature, geoJson: JSON.parse(JSON.stringify(this.props.geoJson)) //Deep copy }, function () { _this3.props.data.add(feature); _this3.initListeners(); _this3.checkPropEditable(_this3.props); _this3.setDraggable(); _this3.setIcon(); }); } else console.error(new Error("You must put this <Feature /> component within the context of a <DataLayer /> Component.")); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this.mounted = false; if (this.props.data) this.props.data.remove(this.state.feature); if (this.state.listeners) this.removeListeners(); } ///--------------------------------Google Data.Feature Managmenent Methods-----------------------------------/// }, { key: 'updateProperties', value: function updateProperties(properties) { var _this4 = this; if (!properties) return; var names = Object.keys(properties); names.forEach(function (name) { switch (name) { case 'fillColor': { _this4.props.data.overrideStyle(_this4.state.feature, { fillColor: properties[name] }); break; } } _this4.state.feature.setProperty(name, properties[name]); }); } }, { key: 'updateFeatureGeometry', value: function updateFeatureGeometry(geoJson) { var _this5 = this; //resets the geometry to match the geojson. var resetGeometry = function resetGeometry(f) { // this.removeListeners(() => { _this5.removeListeners(); var geometry = _this5.getGeometryForFeature(geoJson); _this5.state.feature.setGeometry(geometry); _this5.initListeners(); // console.log("F: refreshed geometry for id: ", this.props.id); // this.initListeners(); //Restart the listening on this geometry. // }); //Stop all listening on this geometry. }; //Diff: this logic block makes sure that we have to reset the geometry. if (this.state.feature) { var type = this.state.feature.getGeometry().getType(); switch (type) { case "Polygon": var currGeoJson = this.state.geoJson; //If the coordinates length is not the same, obviously something changed so reset the geometry. if ((geoJson.geometry.coordinates[0] || []).length != (currGeoJson.geometry.coordinates[0] || []).length) { // console.log("F: Entered unequal coordinate block for id: ", this.props.id); resetGeometry(); } //If the coordinate lengths are the same, check to see if all of the points are equal. If any of them are not equal, obviously something changed so reset the geometry. else { // console.log("F: Starting coordinate comparison for id: ", this.props.id , currGeoJson.geometry.coordinates[0], geoJson.geometry.coordinates[0]); for (var i = (currGeoJson.geometry.coordinates[0] || []).length - 1; i >= 0; i--) { var currPoint = currGeoJson.geometry.coordinates[0][i]; var newPoint = geoJson.geometry.coordinates[0][i]; if (currPoint[0] != newPoint[0] || currPoint[1] != newPoint[1]) { // console.log("F: Entered modified point block for id: ", this.props.id); resetGeometry(); break; } }; } break; case "Point": var currGeoJson = this.state.geoJson; if (currGeoJson.geometry.coordinates[0] != geoJson.geometry.coordinates[0] || currGeoJson.geometry.coordinates[1] != geoJson.geometry.coordinates[1]) { resetGeometry(); break; } break; } } } }, { key: 'getGeometryForFeature', value: function getGeometryForFeature(geoJson) { var _props3 = this.props, map = _props3.map, maps = _props3.maps; switch (geoJson.geometry.type) { case "Polygon": var latLngs = (geoJson.geometry.coordinates[0] || []).map(function (coordinate) { return new maps.LatLng({ lng: coordinate[0], lat: coordinate[1] }); }); latLngs.pop(); //Remove the last item. var properties = geoJson.properties; var polygon = new maps.Data.Polygon([latLngs]); return polygon; case "Point": var latLng = new maps.LatLng({ lng: geoJson.geometry.coordinates[0], lat: geoJson.geometry.coordinates[1] }); var properties = geoJson.properties; var point = new maps.Data.Point(latLng); return point; default: console.warn("You cannot use anything other than Polygons or Points for features currently."); } return null; } }, { key: 'generateFeatureFromGeoJson', value: function generateFeatureFromGeoJson(geoJson) { var _props4 = this.props, map = _props4.map, maps = _props4.maps; var geometry = this.getGeometryForFeature(geoJson); var feature = new maps.Data.Feature({ geometry: geometry, id: this.props.id, properties: geoJson.properties }); return feature; } }, { key: 'checkPropEditable', value: function checkPropEditable(props) { // console.log("Checking editable."); try { if (typeof props.editable !== 'undefined' && props.editable) { props.data.overrideStyle(this.state.feature, { editable: true }); } else props.data.overrideStyle(this.state.feature, { editable: false }); } catch (e) { console.error(e); } } }, { key: 'setDraggable', value: function setDraggable() { if (this.props.draggable) { this.props.data.overrideStyle(this.state.feature, { draggable: true }); } else { this.props.data.overrideStyle(this.state.feature, { draggable: false }); } } }, { key: 'setIcon', value: function setIcon() { if (this.props.geoJson.geometry.type == 'Point') { if (this.props.icon) { this.props.data.overrideStyle(this.state.feature, { icon: this.props.icon }); } } } }, { key: 'render', value: function render() { if (this.props.data && this.state.feature) { this.checkPropEditable(this.props); } // console.log("F: feature Rendered"); return _react2.default.createElement('noscript', null); } }]); return Feature; }(_react2.default.Component); Feature.propTypes = { editable: _propTypes2.default.bool, fastEditing: _propTypes2.default.bool, //This mode enables point creation by right clicking on the map. maps: _propTypes2.default.object, map: _propTypes2.default.object, data: _propTypes2.default.object, geoJson: _propTypes2.default.object.isRequired, id: _propTypes2.default.string.isRequired, onDelete: _propTypes2.default.func, onChange: _propTypes2.default.func, onClick: _propTypes2.default.func }; exports.default = Feature; module.exports = exports['default']; //# sourceMappingURL=feature.js.map