UNPKG

google-react-maps

Version:

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

474 lines (394 loc) 15.9 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>Google React Maps Source: components/feature.js</title> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/sunlight.default.css"> <link type="text/css" rel="stylesheet" href="styles/site.cosmo.css"> </head> <body> <div class="navbar navbar-default navbar-fixed-top navbar-inverse"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="index.html">Google React Maps</a> <button class="navbar-toggle" type="button" data-toggle="collapse" data-target="#topNavigation"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> </div> <div class="navbar-collapse collapse" id="topNavigation"> <ul class="nav navbar-nav"> <li class="dropdown"> <a href="namespaces.list.html" class="dropdown-toggle" data-toggle="dropdown">Namespaces<b class="caret"></b></a> <ul class="dropdown-menu "> <li><a href="google.maps.html">google.maps</a></li><li><a href="Utils.html">Utils</a></li> </ul> </li> <li class="dropdown"> <a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b class="caret"></b></a> <ul class="dropdown-menu "> <li><a href="Circle.html">Circle</a></li><li><a href="Cluster.html">Cluster</a></li><li><a href="ClusterIconInfo.html">ClusterIconInfo</a></li><li><a href="ClusterIconStyle.html">ClusterIconStyle</a></li><li><a href="Feature.html">Feature</a></li><li><a href="google.maps.LatLngLiteral.html">google.maps.LatLngLiteral</a></li><li><a href="Map.html">Map</a></li><li><a href="Map.InfoWindow.html">Map.InfoWindow</a></li><li><a href="Map.Marker.html">Map.Marker</a></li><li><a href="Map.MarkerCluster.html">Map.MarkerCluster</a></li><li><a href="MapControl.html">MapControl</a></li><li><a href="MarkerClusterer.html">MarkerClusterer</a></li><li><a href="MarkerClustererOptions.html">MarkerClustererOptions</a></li> </ul> </li> <li class="dropdown"> <a href="events.list.html" class="dropdown-toggle" data-toggle="dropdown">Events<b class="caret"></b></a> <ul class="dropdown-menu "> <li><a href="MarkerClusterer.html#event:click">MarkerClusterer#event:click</a></li><li><a href="MarkerClusterer.html#event:clusteringbegin">MarkerClusterer#event:clusteringbegin</a></li><li><a href="MarkerClusterer.html#event:clusteringend">MarkerClusterer#event:clusteringend</a></li><li><a href="MarkerClusterer.html#event:mouseout">MarkerClusterer#event:mouseout</a></li><li><a href="MarkerClusterer.html#event:mouseover">MarkerClusterer#event:mouseover</a></li> </ul> </li> <li class="dropdown"> <a href="global.html" class="dropdown-toggle" data-toggle="dropdown">Global<b class="caret"></b></a> <ul class="dropdown-menu "> <li><a href="global.html#processPoints">processPoints</a></li> </ul> </li> </ul> <div class="col-sm-3 col-md-3"> <form class="navbar-form" role="search"> <div class="input-group"> <input type="text" class="form-control" placeholder="Search" name="q" id="search-input"> <div class="input-group-btn"> <button class="btn btn-default" id="search-submit"><i class="glyphicon glyphicon-search"></i></button> </div> </div> </form> </div> </div> </div> </div> <div class="container" id="toc-content"> <div class="row"> <div class="col-md-12"> <div id="main"> <h1 class="page-title">Source: components/feature.js</h1> <section> <article> <pre class="sunlight-highlight-javascript linenums">import React from 'react'; import PropTypes from 'prop-types'; import { GeoJSON } from '../utils/utils'; window.GeoJSON = GeoJSON; //Rational: This component emulates the google Data.Feature. //It lives in the context of a &lt;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. */ class Feature extends React.Component { constructor(props) { super(props); this.displayName = 'Feature'; this.state = { feature: null, listeners: [], geoJson: null } 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.updateFeatureGeometry = this.updateFeatureGeometry.bind(this); this.getGeometryForFeature = this.getGeometryForFeature.bind(this); this.generateFeatureFromGeoJson = this.generateFeatureFromGeoJson.bind(this); } ///--------------------------------Listener Management Methods-----------------------------------/// initListeners() { //Set geometry listener. if (typeof this.props.onChange === 'function') this.addListener(this.props.data.addListener('setgeometry', (event) => { var { feature } = event; if (feature.getId() == this.state.feature.getId()) { feature.toGeoJson(geoJson => this.setState({ geoJson: JSON.parse(JSON.stringify(geoJson)) }, () => { if (typeof this.props.onChange === 'function') this.props.onChange(geoJson); })); } })); //Polygon clicked. if (typeof this.props.onClick === 'function') this.addListener(this.props.data.addListener('click', (event) => { var { feature } = event; if (feature.getId() == this.state.feature.getId()) { event.stop(); var coords = event.latLng.toJSON() coords[0] = coords.lng; coords[1] = coords.lat; if (this.props.onClick) this.props.onClick(Object.assign({}, event, { id: this.props.id, coords, geoJson: this.state.geoJson })); } })); if (typeof this.props.onRightClick === 'function') this.addListener(this.props.data.addListener('rightclick', (event) => { var { feature } = event; if (feature.getId() == this.state.feature.getId()) { event.stop(); var coords = event.latLng.toJSON() coords[0] = coords.lng; coords[1] = coords.lat; if (this.props.onRightClick) this.props.onRightClick(Object.assign({}, event, { id: this.props.id, coords, geoJson: this.state.geoJson })); } })); } removeListeners(callback) { this.state.listeners.forEach(listener => listener.remove()); this.setState({ listeners: [] }, callback ? callback : () => { }); } addListener(listener, callback) { var listeners = this.state.listeners.slice(); listeners.push(listener); this.setState({ listeners }, callback ? callback : () => { }); } ///--------------------------------Lifecycle Methods-----------------------------------/// componentWillReceiveProps(nextProps) { // console.log("F: componentWillRecieveProps"); if (nextProps.data &amp;&amp; this.state.feature) { this.checkPropEditable(nextProps); this.updateFeatureGeometry(nextProps.geoJson) } // console.log("Feature will recieve props."); } componentWillUpdate(nextProps, nextState) { // console.log("F: componentWillUpdate") } // shouldComponentUpdate(nextProps, nextState) { // return false; // } componentDidMount() { // console.log("F: componentDidMount") 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, geoJson: JSON.parse(JSON.stringify(this.props.geoJson)) //Deep copy }, () => { this.props.data.add(feature); this.initListeners(); this.checkPropEditable(this.props); }) } else console.error(new Error("You must put this &lt;Feature /> component within the context of a &lt;DataLayer /> Component.")) } componentWillUnmount() { if (this.props.data) this.props.data.remove(this.state.feature); if (this.state.listeners) this.removeListeners(); } ///--------------------------------Google Data.Feature Managmenent Methods-----------------------------------/// updateFeatureGeometry(geoJson) { //resets the geometry to match the geojson. var resetGeometry = f => { // this.removeListeners(() => { var geometry = this.getGeometryForFeature(geoJson); this.state.feature.setGeometry(geometry); // 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; } } } getGeometryForFeature(geoJson) { var { map, maps } = this.props; switch (geoJson.geometry.type) { case "Polygon": var latLngs = geoJson.geometry.coordinates[0].map(coordinate => 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; } generateFeatureFromGeoJson(geoJson) { var { map, maps } = this.props; var geometry = this.getGeometryForFeature(geoJson); var feature = new maps.Data.Feature({ geometry, id: this.props.id, properties: geoJson.properties }); return feature; } checkPropEditable(props) { // console.log("Checking editable."); try { if (typeof props.editable !== 'undefined' &amp;&amp; props.editable) { props.data.overrideStyle(this.state.feature, { editable: true }); } else props.data.overrideStyle(this.state.feature, { editable: false }); } catch (e) { console.error(e); } } render() { if (this.props.data &amp;&amp; this.state.feature) { this.checkPropEditable(this.props); } // console.log("F: feature Rendered"); return &lt;noscript />; } } Feature.propTypes = { maps: PropTypes.object, map: PropTypes.object, data: PropTypes.object, geoJson: PropTypes.object.isRequired, id: PropTypes.string.isRequired, onChange: PropTypes.func, onClick: PropTypes.func } export default Feature; </pre> </article> </section> </div> </div> <div class="clearfix"></div> </div> </div> <div class="modal fade" id="searchResults"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> <h4 class="modal-title">Search results</h4> </div> <div class="modal-body"></div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div> <footer> <span class="copyright"> This is a Austin Hunt project. </span> <span class="jsdoc-message"> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Tue May 30th 2017 using the <a href="https://github.com/docstrap/docstrap">DocStrap template</a>. </span> </footer> <script src="scripts/docstrap.lib.js"></script> <script src="scripts/toc.js"></script> <script type="text/javascript" src="scripts/fulltext-search-ui.js"></script> <script> $( function () { $( "[id*='$']" ).each( function () { var $this = $( this ); $this.attr( "id", $this.attr( "id" ).replace( "$", "__" ) ); } ); $( ".tutorial-section pre, .readme-section pre" ).each( function () { var $this = $( this ); var example = $this.find( "code" ); exampleText = example.html(); var lang = /{@lang (.*?)}/.exec( exampleText ); if ( lang && lang[1] ) { exampleText = exampleText.replace( lang[0], "" ); example.html( exampleText ); lang = lang[1]; } else { var langClassMatch = example.parent()[0].className.match(/lang\-(\S+)/); lang = langClassMatch ? langClassMatch[1] : "javascript"; } if ( lang ) { $this .addClass( "sunlight-highlight-" + lang ) .addClass( "linenums" ) .html( example.html() ); } } ); Sunlight.highlightAll( { lineNumbers : true, showMenu : true, enableDoclinks : true } ); $.catchAnchorLinks( { navbarOffset: 10 } ); $( "#toc" ).toc( { anchorName : function ( i, heading, prefix ) { var id = $( heading ).attr( "id" ); return id && id.replace(/\~/g, '-inner-').replace(/\./g, '-static-') || ( prefix + i ); }, selectors : "#toc-content h1,#toc-content h2,#toc-content h3,#toc-content h4", showAndHide : false, smoothScrolling: true } ); $( "#main span[id^='toc']" ).addClass( "toc-shim" ); $( '.dropdown-toggle' ).dropdown(); $( "table" ).each( function () { var $this = $( this ); $this.addClass('table'); } ); } ); </script> <!--Navigation and Symbol Display--> <!--Google Analytics--> <script type="text/javascript"> $(document).ready(function() { SearcherDisplay.init(); }); </script> </body> </html>