From 765d7672b8e473760199fd963a92863b0c7fb75d Mon Sep 17 00:00:00 2001 From: cybice Date: Sat, 3 Oct 2015 22:16:40 +0300 Subject: [PATCH] Support center prop as {lat, lng} object Closes #15 --- src/google_map.js | 39 +++++++++++++++++------- src/utils/lib_geo/lat_lng.js | 6 ++++ test/components/GoogleMap.spec.js | 49 +++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/src/google_map.js b/src/google_map.js index 7e3453b..73e8196 100644 --- a/src/google_map.js +++ b/src/google_map.js @@ -49,11 +49,21 @@ const style = { position: 'relative', }; +const latLng2Obj = (latLng) => isPlainObject(latLng) + ? latLng + : {lat: latLng[0], lng: latLng[1]}; + export default class GoogleMap extends Component { static propTypes = { apiKey: PropTypes.string, - center: PropTypes.array.isRequired, + center: React.PropTypes.oneOfType([ + PropTypes.array, + PropTypes.shape({ + lat: PropTypes.number, + lng: PropTypes.number, + }), + ]).isRequired, zoom: PropTypes.number.isRequired, onBoundsChange: PropTypes.func, onClick: PropTypes.func, @@ -101,8 +111,11 @@ export default class GoogleMap extends Component { this.markersDispatcher_ = new MarkerDispatcher(this); this.geoService_ = new Geo(K_GOOGLE_TILE_SIZE); + this.centerIsObject_ = isPlainObject(this.props.center); + if (this._isCenterDefined(this.props.center)) { - this.geoService_.setView(this.props.center, this.props.zoom, 0); + const propsCenter = latLng2Obj(this.props.center); + this.geoService_.setView(propsCenter, this.props.zoom, 0); } this.zoomAnimationInProgress_ = false; @@ -135,9 +148,10 @@ export default class GoogleMap extends Component { if (this.map_) { const centerLatLng = this.geoService_.getCenter(); if (nextProps.center) { - if (Math.abs(nextProps.center[0] - centerLatLng.lat) + - Math.abs(nextProps.center[1] - centerLatLng.lng) > kEPS) { - this.map_.panTo({lat: nextProps.center[0], lng: nextProps.center[1]}); + const nextPropsCenter = latLng2Obj(nextProps.center); + if (Math.abs(nextPropsCenter.lat - centerLatLng.lat) + + Math.abs(nextPropsCenter.lng - centerLatLng.lng) > kEPS) { + this.map_.panTo({lat: nextPropsCenter.lat, lng: nextPropsCenter.lng}); } } @@ -179,8 +193,8 @@ export default class GoogleMap extends Component { } _initMap = () => { - const center = this.props.center; - this.geoService_.setView(center, this.props.zoom, 0); + const propsCenter = latLng2Obj(this.props.center); + this.geoService_.setView(propsCenter, this.props.zoom, 0); this._onBoundsChanged(); // now we can calculate map bounds center etc... @@ -405,7 +419,9 @@ export default class GoogleMap extends Component { if (callExtBoundsChange !== false) { const marginBounds = this.geoService_.getBounds(this.props.margin); this.props.onBoundsChange( - [centerLatLng.lat, centerLatLng.lng], + this.centerIsObject_ + ? {...centerLatLng} + : [centerLatLng.lat, centerLatLng.lng], zoom, bounds, marginBounds @@ -493,9 +509,10 @@ export default class GoogleMap extends Component { } } - _isCenterDefined = (center) => { - return center && center.length === 2 && isNumber(center[0]) && isNumber(center[1]); - } + _isCenterDefined = (center) => center && ( + (isPlainObject(center) && isNumber(center.lat) && isNumber(center.lng)) || + (center.length === 2 && isNumber(center[0]) && isNumber(center[1])) + ) render() { const mapMarkerPrerender = !this.state.overlayCreated ? ( diff --git a/src/utils/lib_geo/lat_lng.js b/src/utils/lib_geo/lat_lng.js index ab8cfcd..8fb89c7 100644 --- a/src/utils/lib_geo/lat_lng.js +++ b/src/utils/lib_geo/lat_lng.js @@ -5,9 +5,15 @@ export default class LatLng { if (a instanceof LatLng) { return a; } + if (Array.isArray(a)) { return new LatLng(a[0], a[1]); } + + if ('lng' in a && 'lat' in a) { + return new LatLng(a.lat, a.lng); + } + return a; } diff --git a/test/components/GoogleMap.spec.js b/test/components/GoogleMap.spec.js index 809d993..4e38021 100644 --- a/test/components/GoogleMap.spec.js +++ b/test/components/GoogleMap.spec.js @@ -56,6 +56,55 @@ describe('Components', () => { expect(marker.parentNode.style.top).toEqual('-12.62811732746195px'); }); + it('Should accept center prop as lat lng object', () => { + const mapMarkerClassName = 'mapMarkerClassName'; + + class MapMarker extends Component { // eslint-disable-line react/no-multi-comp + render() { + return ( +
Marker
+ ); + } + } + + class MapHolder extends Component { // eslint-disable-line react/no-multi-comp + static propTypes = { + center: PropTypes.array, + zoom: PropTypes.number, + greatPlaceCoords: PropTypes.any, + }; + + static defaultProps = { + center: {lat: 59.938043, lng: 30.337157}, + zoom: 9, + }; + + constructor(props) { + super(props); + } + + render() { + return ( + + + + ); + } + } + + const mapHolder = TestUtils.renderIntoDocument( + + ); + + const marker = TestUtils.findRenderedDOMComponentWithClass(mapHolder, 'mapMarkerClassName'); + expect(marker.parentNode.style.left).toEqual('0.250129066669615px'); + expect(marker.parentNode.style.top).toEqual('-12.62811732746195px'); + }); + + it('Should call custom loader', () => { const API_KEY = 'API_KEY'; const spy = expect.createSpy(() => {});