mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-27 09:13:14 +10:00
SearchMap
This commit is contained in:
parent
add8052e4a
commit
06a9da19d0
3 changed files with 135 additions and 0 deletions
4
src/components/SearchMap/SearchMap.css
Normal file
4
src/components/SearchMap/SearchMap.css
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
129
src/components/SearchMap/SearchMap.js
Normal file
129
src/components/SearchMap/SearchMap.js
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import React, { Component, PropTypes } from 'react';
|
||||
import { isEqualWith, sortBy } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import { types as sdkTypes } from '../../util/sdkLoader';
|
||||
import * as propTypes from '../../util/propTypes';
|
||||
import { MapPriceMarker } from '../../components';
|
||||
|
||||
import css from './SearchMap.css';
|
||||
|
||||
const fitMapToBounds = (map, bounds) => {
|
||||
const { ne, sw } = bounds || {};
|
||||
// map bounds as string literal for google.maps
|
||||
const mapBounds = bounds ? { north: ne.lat, east: ne.lng, south: sw.lat, west: sw.lng } : null;
|
||||
|
||||
if (mapBounds) {
|
||||
map.fitBounds(mapBounds);
|
||||
}
|
||||
};
|
||||
|
||||
// Compare listing arrays (if listings are the same, there's no need to rerender google maps).
|
||||
const hasSameListings = (prevListings, nextListings) => {
|
||||
return isEqualWith(sortBy(prevListings, l => l.id.uuid), sortBy(nextListings, l => l.id.uuid));
|
||||
};
|
||||
|
||||
class SearchMap extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.map = null;
|
||||
this.state = { overlays: [] };
|
||||
this.addOverlay = this.addOverlay.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const mapsLibLoaded = window.google && window.google.maps;
|
||||
if (!mapsLibLoaded) {
|
||||
throw new Error('Google Maps API must be loaded for the SearchMap component');
|
||||
}
|
||||
|
||||
const { bounds, center, zoom } = this.props;
|
||||
const centerLocation = { lat: center.lat, lng: center.lng };
|
||||
const mapOptions = {
|
||||
center: centerLocation,
|
||||
zoom,
|
||||
|
||||
// Disable map type (ie. Satellite etc.)
|
||||
mapTypeControl: false,
|
||||
|
||||
// Disable zooming by scrolling
|
||||
scrollwheel: false,
|
||||
};
|
||||
this.map = new window.google.maps.Map(this.el, mapOptions);
|
||||
|
||||
// If bounds are given, use it (defaults to center & zoom).
|
||||
fitMapToBounds(this.map, bounds);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { bounds, listings } = nextProps;
|
||||
|
||||
fitMapToBounds(this.map, bounds);
|
||||
|
||||
if (!hasSameListings(listings, nextProps.listings)) {
|
||||
// Clear markers from map
|
||||
this.state.overlays.forEach(o => o.setMap(null));
|
||||
}
|
||||
}
|
||||
|
||||
addOverlay(overlay) {
|
||||
this.setState(prevState => {
|
||||
// Track map overlays, in case we need to clear them from map
|
||||
const overlays = prevState.overlays.concat([overlay]);
|
||||
return { overlays };
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, rootClassName, listings } = this.props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
|
||||
// Add listing markers to map if listings prop is passed
|
||||
// By reversing the order, we can show the nearest price labels on top of more distant ones.
|
||||
const currentMarkers = listings
|
||||
.map(l => {
|
||||
return (
|
||||
<MapPriceMarker
|
||||
key={l.id.uuid}
|
||||
map={this.map}
|
||||
listing={l}
|
||||
onAddOverlay={this.addOverlay}
|
||||
/>
|
||||
);
|
||||
})
|
||||
.reverse();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes}
|
||||
ref={el => {
|
||||
this.el = el;
|
||||
}}
|
||||
>
|
||||
{currentMarkers}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchMap.defaultProps = {
|
||||
className: '',
|
||||
rootClassName: null,
|
||||
bounds: null,
|
||||
center: new sdkTypes.LatLng(0, 0),
|
||||
listings: [],
|
||||
zoom: 11,
|
||||
};
|
||||
|
||||
const { arrayOf, number, string } = PropTypes;
|
||||
|
||||
SearchMap.propTypes = {
|
||||
bounds: propTypes.latlngBounds,
|
||||
center: propTypes.latlng,
|
||||
className: string,
|
||||
listings: arrayOf(propTypes.listing),
|
||||
rootClassName: string,
|
||||
zoom: number,
|
||||
};
|
||||
|
||||
export default SearchMap;
|
||||
|
|
@ -42,6 +42,7 @@ import ResponsiveImage from './ResponsiveImage/ResponsiveImage';
|
|||
import RoutesProvider from './RoutesProvider/RoutesProvider';
|
||||
import SaleDetailsPanel from './SaleDetailsPanel/SaleDetailsPanel';
|
||||
import SearchIcon from './SearchIcon/SearchIcon';
|
||||
import SearchMap from './SearchMap/SearchMap';
|
||||
import SearchResultsPanel from './SearchResultsPanel/SearchResultsPanel';
|
||||
import SelectField from './SelectField/SelectField';
|
||||
import StripeBankAccountTokenInputField
|
||||
|
|
@ -102,6 +103,7 @@ export {
|
|||
RoutesProvider,
|
||||
SaleDetailsPanel,
|
||||
SearchIcon,
|
||||
SearchMap,
|
||||
SearchResultsPanel,
|
||||
SecondaryButton,
|
||||
SelectField,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue