mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
Reorganize maps configuration
This commit is contained in:
parent
28078d0912
commit
669e1a7edb
13 changed files with 235 additions and 206 deletions
|
|
@ -1,39 +1,21 @@
|
|||
import React from 'react';
|
||||
// import { types as sdkTypes } from '../../util/sdkLoader';
|
||||
import classNames from 'classnames';
|
||||
import { getPlacePredictions, getPlaceDetails, locationBounds } from '../../util/googleMaps';
|
||||
import { userLocation } from '../../util/maps';
|
||||
import config from '../../config';
|
||||
|
||||
import css from './LocationAutocompleteInput.css';
|
||||
|
||||
// const { LatLng: SDKLatLng, LatLngBounds: SDKLatLngBounds } = sdkTypes;
|
||||
|
||||
export const CURRENT_LOCATION_ID = 'current-location';
|
||||
const CURRENT_LOCATION_BOUNDS_DISTANCE = 1000; // meters
|
||||
|
||||
// A list of default predictions that can be shown when the user
|
||||
// focuses on the autocomplete input without typing a search. This can
|
||||
// be used to reduce typing and Geocoding API calls for common
|
||||
// searches.
|
||||
export const defaultPredictions = [
|
||||
// Examples:
|
||||
// Current user location from the browser geolocation API
|
||||
// {
|
||||
// id: CURRENT_LOCATION_ID,
|
||||
// predictionPlace: {},
|
||||
// },
|
||||
// Helsinki
|
||||
// {
|
||||
// id: 'default-helsinki',
|
||||
// predictionPlace: {
|
||||
// address: 'Helsinki, Finland',
|
||||
// origin: new SDKLatLng(60.16985, 24.93837),
|
||||
// bounds: new SDKLatLngBounds(
|
||||
// new SDKLatLng(60.29783, 25.25448),
|
||||
// new SDKLatLng(59.92248, 24.78287)
|
||||
// ),
|
||||
// },
|
||||
// },
|
||||
];
|
||||
export const defaultPredictions = (config.maps.search.suggestCurrentLocation
|
||||
? [{ id: CURRENT_LOCATION_ID, predictionPlace: {} }]
|
||||
: []
|
||||
).concat(config.maps.search.defaults);
|
||||
|
||||
// When displaying data from the Google Maps Places API, and
|
||||
// attribution is required next to the results.
|
||||
|
|
@ -117,7 +99,7 @@ class GeocoderGoogleMaps {
|
|||
return {
|
||||
address: '',
|
||||
origin: latlng,
|
||||
bounds: locationBounds(latlng, CURRENT_LOCATION_BOUNDS_DISTANCE),
|
||||
bounds: locationBounds(latlng, config.maps.search.currentLocationBoundsDistance),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import config from '../../config';
|
|||
const { LatLng: SDKLatLng, LatLngBounds: SDKLatLngBounds } = sdkTypes;
|
||||
|
||||
export const CURRENT_LOCATION_ID = 'current-location';
|
||||
const CURRENT_LOCATION_BOUNDS_DISTANCE = 1000; // meters
|
||||
|
||||
const locationBounds = (latlng, distance) => {
|
||||
const bounds = new window.mapboxgl.LngLat(latlng.lng, latlng.lat).toBounds(distance);
|
||||
|
|
@ -38,26 +37,10 @@ const placeBounds = prediction => {
|
|||
// focuses on the autocomplete input without typing a search. This can
|
||||
// be used to reduce typing and Geocoding API calls for common
|
||||
// searches.
|
||||
export const defaultPredictions = [
|
||||
// Examples:
|
||||
// Current user location from the browser geolocation API
|
||||
// {
|
||||
// id: CURRENT_LOCATION_ID,
|
||||
// predictionPlace: {},
|
||||
// },
|
||||
// Helsinki
|
||||
// {
|
||||
// id: 'default-helsinki',
|
||||
// predictionPlace: {
|
||||
// address: 'Helsinki, Finland',
|
||||
// origin: new SDKLatLng(60.16985, 24.93837),
|
||||
// bounds: new SDKLatLngBounds(
|
||||
// new SDKLatLng(60.29783, 25.25448),
|
||||
// new SDKLatLng(59.92248, 24.78287)
|
||||
// ),
|
||||
// },
|
||||
// },
|
||||
];
|
||||
export const defaultPredictions = (config.maps.search.suggestCurrentLocation
|
||||
? [{ id: CURRENT_LOCATION_ID, predictionPlace: {} }]
|
||||
: []
|
||||
).concat(config.maps.search.defaults);
|
||||
|
||||
export const GeocoderAttribution = () => null;
|
||||
|
||||
|
|
@ -140,7 +123,7 @@ class GeocoderMapbox {
|
|||
return {
|
||||
address: '',
|
||||
origin: latlng,
|
||||
bounds: locationBounds(latlng, CURRENT_LOCATION_BOUNDS_DISTANCE),
|
||||
bounds: locationBounds(latlng, config.maps.search.currentLocationBoundsDistance),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import config from '../../config';
|
|||
* It handles some of the google map initialization states.
|
||||
*/
|
||||
const DynamicGoogleMap = withGoogleMap(props => {
|
||||
const { center, zoom, address, coordinatesConfig } = props;
|
||||
const { center, zoom, address, mapsConfig } = props;
|
||||
|
||||
const { markerURI, anchorX, anchorY, width, height } = coordinatesConfig.customMarker || {};
|
||||
const markerIcon = coordinatesConfig.customMarker
|
||||
const { enabled, url, anchorX, anchorY, width, height } = mapsConfig.customMarker;
|
||||
const markerIcon = enabled
|
||||
? {
|
||||
icon: {
|
||||
url: markerURI,
|
||||
url,
|
||||
|
||||
// The origin for this image is (0, 0).
|
||||
origin: new window.google.maps.Point(0, 0),
|
||||
|
|
@ -27,8 +27,15 @@ const DynamicGoogleMap = withGoogleMap(props => {
|
|||
const marker = <Marker position={center} {...markerIcon} title={address} />;
|
||||
|
||||
const circleProps = {
|
||||
options: coordinatesConfig.circleOptions,
|
||||
radius: coordinatesConfig.coordinateOffset,
|
||||
options: {
|
||||
fillColor: mapsConfig.fuzzy.circleColor,
|
||||
fillOpacity: 0.2,
|
||||
strokeColor: mapsConfig.fuzzy.circleColor,
|
||||
strokeOpacity: 0.5,
|
||||
strokeWeight: 1,
|
||||
clickable: false,
|
||||
},
|
||||
radius: mapsConfig.fuzzy.offset,
|
||||
center,
|
||||
};
|
||||
|
||||
|
|
@ -59,7 +66,7 @@ const DynamicGoogleMap = withGoogleMap(props => {
|
|||
},
|
||||
}}
|
||||
>
|
||||
{coordinatesConfig.fuzzy ? circle : marker}
|
||||
{mapsConfig.fuzzy.enabled ? circle : marker}
|
||||
</GoogleMap>
|
||||
);
|
||||
});
|
||||
|
|
@ -67,8 +74,8 @@ const DynamicGoogleMap = withGoogleMap(props => {
|
|||
DynamicGoogleMap.defaultProps = {
|
||||
address: '',
|
||||
center: null,
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
zoom: config.maps.fuzzy.enabled ? config.maps.fuzzy.defaultZoomLevel : 11,
|
||||
mapsConfig: config.maps,
|
||||
};
|
||||
|
||||
DynamicGoogleMap.propTypes = {
|
||||
|
|
@ -78,7 +85,7 @@ DynamicGoogleMap.propTypes = {
|
|||
lng: number.isRequired,
|
||||
}).isRequired,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
mapsConfig: object,
|
||||
};
|
||||
|
||||
export default DynamicGoogleMap;
|
||||
|
|
|
|||
|
|
@ -4,25 +4,21 @@ import uniqueId from 'lodash/uniqueId';
|
|||
import { circlePolyline } from '../../util/maps';
|
||||
import config from '../../config';
|
||||
|
||||
const mapMarker = coordinatesConfig => {
|
||||
const { customMarker } = coordinatesConfig;
|
||||
if (customMarker) {
|
||||
const mapMarker = mapsConfig => {
|
||||
const { enabled, url, width, height } = mapsConfig.customMarker;
|
||||
if (enabled) {
|
||||
const element = document.createElement('div');
|
||||
element.style.backgroundImage = `url(${customMarker.markerURI})`;
|
||||
element.style.width = `${customMarker.width}px`;
|
||||
element.style.height = `${customMarker.height}px`;
|
||||
element.style.backgroundImage = `url(${url})`;
|
||||
element.style.width = `${width}px`;
|
||||
element.style.height = `${height}px`;
|
||||
return new window.mapboxgl.Marker({ element });
|
||||
} else {
|
||||
return new window.mapboxgl.Marker();
|
||||
}
|
||||
};
|
||||
|
||||
const circleLayer = (center, coordinatesConfig, layerId) => {
|
||||
const { fillColor, fillOpacity } = coordinatesConfig.circleOptions;
|
||||
const path = circlePolyline(center, coordinatesConfig.coordinateOffset).map(([lat, lng]) => [
|
||||
lng,
|
||||
lat,
|
||||
]);
|
||||
const circleLayer = (center, mapsConfig, layerId) => {
|
||||
const path = circlePolyline(center, mapsConfig.fuzzy.offset).map(([lat, lng]) => [lng, lat]);
|
||||
return {
|
||||
id: layerId,
|
||||
type: 'fill',
|
||||
|
|
@ -37,8 +33,8 @@ const circleLayer = (center, coordinatesConfig, layerId) => {
|
|||
},
|
||||
},
|
||||
paint: {
|
||||
'fill-color': fillColor,
|
||||
'fill-opacity': fillOpacity,
|
||||
'fill-color': mapsConfig.fuzzy.circleColor,
|
||||
'fill-opacity': 0.2,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
@ -59,7 +55,7 @@ class DynamicMapboxMap extends Component {
|
|||
this.updateFuzzyCirclelayer = this.updateFuzzyCirclelayer.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
const { center, zoom, coordinatesConfig } = this.props;
|
||||
const { center, zoom, mapsConfig } = this.props;
|
||||
const position = [center.lng, center.lat];
|
||||
|
||||
this.map = new window.mapboxgl.Map({
|
||||
|
|
@ -71,12 +67,12 @@ class DynamicMapboxMap extends Component {
|
|||
});
|
||||
this.map.addControl(new window.mapboxgl.NavigationControl(), 'top-left');
|
||||
|
||||
if (coordinatesConfig.fuzzy) {
|
||||
if (mapsConfig.fuzzy.enabled) {
|
||||
this.map.on('load', () => {
|
||||
this.map.addLayer(circleLayer(center, coordinatesConfig, this.fuzzyLayerId));
|
||||
this.map.addLayer(circleLayer(center, mapsConfig, this.fuzzyLayerId));
|
||||
});
|
||||
} else {
|
||||
this.centerMarker = mapMarker(coordinatesConfig);
|
||||
this.centerMarker = mapMarker(mapsConfig);
|
||||
this.centerMarker.setLngLat(position).addTo(this.map);
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +88,7 @@ class DynamicMapboxMap extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const { center, zoom, coordinatesConfig } = this.props;
|
||||
const { center, zoom, mapsConfig } = this.props;
|
||||
const { lat, lng } = center;
|
||||
const position = [lng, lat];
|
||||
|
||||
|
|
@ -110,7 +106,7 @@ class DynamicMapboxMap extends Component {
|
|||
}
|
||||
|
||||
// fuzzy circle change
|
||||
if (coordinatesConfig.fuzzy && centerChanged) {
|
||||
if (mapsConfig.fuzzy.enabled && centerChanged) {
|
||||
if (this.map.loaded()) {
|
||||
this.updateFuzzyCirclelayer();
|
||||
} else {
|
||||
|
|
@ -118,14 +114,14 @@ class DynamicMapboxMap extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: coordinatesConfig changes are not handled
|
||||
// NOTE: mapsConfig changes are not handled
|
||||
}
|
||||
updateFuzzyCirclelayer() {
|
||||
if (!this.map) {
|
||||
// map already removed
|
||||
return;
|
||||
}
|
||||
const { center, coordinatesConfig } = this.props;
|
||||
const { center, mapsConfig } = this.props;
|
||||
const { lat, lng } = center;
|
||||
const position = [lng, lat];
|
||||
|
||||
|
|
@ -133,7 +129,7 @@ class DynamicMapboxMap extends Component {
|
|||
|
||||
// We have to use a different layer id to avoid Mapbox errors
|
||||
this.fuzzyLayerId = generateFuzzyLayerId();
|
||||
this.map.addLayer(circleLayer(center, coordinatesConfig, this.fuzzyLayerId));
|
||||
this.map.addLayer(circleLayer(center, mapsConfig, this.fuzzyLayerId));
|
||||
|
||||
this.map.setCenter(position);
|
||||
}
|
||||
|
|
@ -150,8 +146,8 @@ class DynamicMapboxMap extends Component {
|
|||
DynamicMapboxMap.defaultProps = {
|
||||
address: '',
|
||||
center: null,
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
zoom: config.maps.fuzzy.enabled ? config.maps.fuzzy.defaultZoomLevel : 11,
|
||||
mapsConfig: config.maps,
|
||||
};
|
||||
|
||||
DynamicMapboxMap.propTypes = {
|
||||
|
|
@ -161,7 +157,7 @@ DynamicMapboxMap.propTypes = {
|
|||
lng: number.isRequired,
|
||||
}).isRequired,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
mapsConfig: object,
|
||||
};
|
||||
|
||||
export default DynamicMapboxMap;
|
||||
|
|
|
|||
|
|
@ -31,9 +31,12 @@ export const WithObfuscatedLocation = {
|
|||
obfuscatedCenter: new LatLng(60.16502999999999, 24.940064399999983),
|
||||
address: 'Sharetribe',
|
||||
zoom: 14,
|
||||
coordinatesConfig: {
|
||||
...config.coordinates,
|
||||
fuzzy: true,
|
||||
mapsConfig: {
|
||||
...config.maps,
|
||||
fuzzy: {
|
||||
...config.maps.fuzzy,
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -48,9 +51,12 @@ export const WithCircleLocation = {
|
|||
center: new LatLng(60.16502999999999, 24.940064399999983),
|
||||
obfuscatedCenter: obfuscatedCoordinates(new LatLng(60.16502999999999, 24.940064399999983)),
|
||||
address: 'Sharetribe',
|
||||
coordinatesConfig: {
|
||||
...config.coordinates,
|
||||
fuzzy: true,
|
||||
mapsConfig: {
|
||||
...config.maps,
|
||||
fuzzy: {
|
||||
...config.maps.fuzzy,
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,32 +18,27 @@ export class Map extends Component {
|
|||
center,
|
||||
obfuscatedCenter,
|
||||
zoom,
|
||||
coordinatesConfig,
|
||||
mapsConfig,
|
||||
useStaticMap,
|
||||
} = this.props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
const mapClasses = mapRootClassName || css.mapRoot;
|
||||
|
||||
if (coordinatesConfig.fuzzy && !obfuscatedCenter) {
|
||||
if (mapsConfig.fuzzy.enabled && !obfuscatedCenter) {
|
||||
throw new Error(
|
||||
'Map: obfuscatedCenter prop is required when config.coordinates.fuzzy === true'
|
||||
'Map: obfuscatedCenter prop is required when config.maps.fuzzy.enabled === true'
|
||||
);
|
||||
}
|
||||
if (!coordinatesConfig.fuzzy && !center) {
|
||||
throw new Error('Map: center prop is required when config.coordinates.fuzzy === false');
|
||||
if (!mapsConfig.fuzzy.enabled && !center) {
|
||||
throw new Error('Map: center prop is required when config.maps.fuzzy.enabled === false');
|
||||
}
|
||||
|
||||
const location = coordinatesConfig.fuzzy ? obfuscatedCenter : center;
|
||||
const location = mapsConfig.fuzzy.enabled ? obfuscatedCenter : center;
|
||||
|
||||
return !isMapsLibLoaded() ? (
|
||||
<div className={classes} />
|
||||
) : useStaticMap ? (
|
||||
<StaticMap
|
||||
center={location}
|
||||
zoom={zoom}
|
||||
address={address}
|
||||
coordinatesConfig={coordinatesConfig}
|
||||
/>
|
||||
<StaticMap center={location} zoom={zoom} address={address} mapsConfig={mapsConfig} />
|
||||
) : (
|
||||
<DynamicMap
|
||||
containerElement={<div className={classes} />}
|
||||
|
|
@ -53,7 +48,7 @@ export class Map extends Component {
|
|||
center={location}
|
||||
zoom={zoom}
|
||||
address={address}
|
||||
coordinatesConfig={coordinatesConfig}
|
||||
mapsConfig={mapsConfig}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -64,8 +59,8 @@ Map.defaultProps = {
|
|||
rootClassName: null,
|
||||
mapRootClassName: null,
|
||||
address: '',
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
zoom: config.maps.fuzzy.enabled ? config.maps.fuzzy.defaultZoomLevel : 11,
|
||||
mapsConfig: config.maps,
|
||||
useStaticMap: false,
|
||||
};
|
||||
|
||||
|
|
@ -77,7 +72,7 @@ Map.propTypes = {
|
|||
center: propTypes.latlng,
|
||||
obfuscatedCenter: propTypes.latlng,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
mapsConfig: object,
|
||||
useStaticMap: bool,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -34,21 +34,17 @@ const convertOpacity = opacity => {
|
|||
};
|
||||
|
||||
// Draw a circle polyline for fuzzy location.
|
||||
const drawFuzzyCircle = (coordinatesConfig, center) => {
|
||||
if (
|
||||
!(
|
||||
coordinatesConfig &&
|
||||
typeof coordinatesConfig === 'object' &&
|
||||
center &&
|
||||
typeof center === 'object'
|
||||
)
|
||||
) {
|
||||
const drawFuzzyCircle = (mapsConfig, center) => {
|
||||
if (!(mapsConfig && typeof mapsConfig === 'object' && center && typeof center === 'object')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const { fillColor, fillOpacity, strokeColor, strokeWeight } = coordinatesConfig.circleOptions;
|
||||
const fillColor = mapsConfig.fuzzy.circleColor;
|
||||
const fillOpacity = 0.2;
|
||||
const strokeColor = mapsConfig.fuzzy.circleColor;
|
||||
const strokeWeight = 1;
|
||||
|
||||
const circleRadius = coordinatesConfig.coordinateOffset || 500;
|
||||
const circleRadius = mapsConfig.fuzzy.offset || 500;
|
||||
const circleStrokeWeight = strokeWeight || 1;
|
||||
const circleStrokeColor = formatColorFromString(strokeColor);
|
||||
const circleStrokeOpacity = convertOpacity(DEFAULT_STROKE_OPACITY);
|
||||
|
|
@ -70,8 +66,8 @@ const drawFuzzyCircle = (coordinatesConfig, center) => {
|
|||
|
||||
// Get custom marker data for static map URI
|
||||
const customMarker = (options, lat, lng) => {
|
||||
const { anchorX, anchorY, markerURI } = options;
|
||||
return [`anchor:${anchorX},${anchorY}`, `icon:${markerURI}`, `${lat},${lng}`].join('|');
|
||||
const { anchorX, anchorY, url } = options;
|
||||
return [`anchor:${anchorX},${anchorY}`, `icon:${url}`, `${lat},${lng}`].join('|');
|
||||
};
|
||||
|
||||
class StaticGoogleMap extends Component {
|
||||
|
|
@ -84,7 +80,7 @@ class StaticGoogleMap extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { center, zoom, address, coordinatesConfig, dimensions } = this.props;
|
||||
const { center, zoom, address, mapsConfig, dimensions } = this.props;
|
||||
const { lat, lng } = center || {};
|
||||
const { width, height } = dimensions;
|
||||
|
||||
|
|
@ -92,10 +88,10 @@ class StaticGoogleMap extends Component {
|
|||
// 1. if fuzzy coordinates are used, return circle path
|
||||
// 2. if customMarker is defined in config.js, use that
|
||||
// 3. else return default marker
|
||||
const targetMaybe = coordinatesConfig.fuzzy
|
||||
? { path: drawFuzzyCircle(coordinatesConfig, center) }
|
||||
: coordinatesConfig.customMarker
|
||||
? { markers: customMarker(coordinatesConfig.customMarker, lat, lng) }
|
||||
const targetMaybe = mapsConfig.fuzzy.enabled
|
||||
? { path: drawFuzzyCircle(mapsConfig, center) }
|
||||
: mapsConfig.customMarker.enabled
|
||||
? { markers: customMarker(mapsConfig.customMarker, lat, lng) }
|
||||
: { markers: `${lat},${lng}` };
|
||||
|
||||
const srcParams = stringify({
|
||||
|
|
@ -103,7 +99,7 @@ class StaticGoogleMap extends Component {
|
|||
zoom,
|
||||
size: `${width}x${height}`,
|
||||
maptype: 'roadmap',
|
||||
key: config.googleMapsAPIKey,
|
||||
key: config.maps.googleMapsAPIKey,
|
||||
...targetMaybe,
|
||||
});
|
||||
|
||||
|
|
@ -118,8 +114,8 @@ StaticGoogleMap.defaultProps = {
|
|||
rootClassName: null,
|
||||
address: '',
|
||||
center: null,
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
zoom: config.maps.fuzzy.enabled ? config.maps.fuzzy.defaultZoomLevel : 11,
|
||||
mapsConfig: config.maps,
|
||||
};
|
||||
|
||||
StaticGoogleMap.propTypes = {
|
||||
|
|
@ -131,7 +127,7 @@ StaticGoogleMap.propTypes = {
|
|||
lng: number.isRequired,
|
||||
}).isRequired,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
mapsConfig: object,
|
||||
|
||||
// from withDimensions
|
||||
dimensions: shape({
|
||||
|
|
|
|||
|
|
@ -9,42 +9,41 @@ const formatColor = color => {
|
|||
return color.replace(/^#/, '');
|
||||
};
|
||||
|
||||
const fuzzyCircleOverlay = (center, coordinatesConfig) => {
|
||||
const {
|
||||
strokeWeight,
|
||||
strokeColor,
|
||||
strokeOpacity,
|
||||
fillColor,
|
||||
fillOpacity,
|
||||
} = coordinatesConfig.circleOptions;
|
||||
const path = circlePolyline(center, coordinatesConfig.coordinateOffset);
|
||||
const fuzzyCircleOverlay = (center, mapsConfig) => {
|
||||
const strokeWeight = 1;
|
||||
const strokeColor = mapsConfig.fuzzy.circleColor;
|
||||
const strokeOpacity = 0.5;
|
||||
const fillColor = mapsConfig.fuzzy.circleColor;
|
||||
const fillOpacity = 0.2;
|
||||
|
||||
const path = circlePolyline(center, mapsConfig.fuzzy.offset);
|
||||
const styles = `-${strokeWeight}+${formatColor(strokeColor)}-${strokeOpacity}+${formatColor(
|
||||
fillColor
|
||||
)}-${fillOpacity}`;
|
||||
return `path${styles}(${encodeURIComponent(polyline.encode(path))})`;
|
||||
};
|
||||
|
||||
const customMarkerOverlay = (center, coordinatesConfig) => {
|
||||
const { markerURI } = coordinatesConfig.customMarker;
|
||||
return `url-${encodeURIComponent(markerURI)}(${center.lng},${center.lat})`;
|
||||
const customMarkerOverlay = (center, mapsConfig) => {
|
||||
const { url } = mapsConfig.customMarker;
|
||||
return `url-${encodeURIComponent(url)}(${center.lng},${center.lat})`;
|
||||
};
|
||||
|
||||
const markerOverlay = center => {
|
||||
return `pin-s(${center.lng},${center.lat})`;
|
||||
};
|
||||
|
||||
const mapOverlay = (center, coordinatesConfig) => {
|
||||
if (coordinatesConfig.fuzzy) {
|
||||
return fuzzyCircleOverlay(center, coordinatesConfig);
|
||||
const mapOverlay = (center, mapsConfig) => {
|
||||
if (mapsConfig.fuzzy.enabled) {
|
||||
return fuzzyCircleOverlay(center, mapsConfig);
|
||||
}
|
||||
if (coordinatesConfig.customMarker) {
|
||||
return customMarkerOverlay(center, coordinatesConfig);
|
||||
if (mapsConfig.customMarker.enabled) {
|
||||
return customMarkerOverlay(center, mapsConfig);
|
||||
}
|
||||
return markerOverlay(center);
|
||||
};
|
||||
|
||||
const StaticMapboxMap = props => {
|
||||
const { address, center, zoom, coordinatesConfig, dimensions } = props;
|
||||
const { address, center, zoom, mapsConfig, dimensions } = props;
|
||||
const { width, height } = dimensions;
|
||||
|
||||
const libLoaded = typeof window !== 'undefined' && window.mapboxgl;
|
||||
|
|
@ -52,13 +51,13 @@ const StaticMapboxMap = props => {
|
|||
return null;
|
||||
}
|
||||
|
||||
const overlay = mapOverlay(center, coordinatesConfig);
|
||||
const overlay = mapOverlay(center, mapsConfig);
|
||||
const src =
|
||||
'https://api.mapbox.com/styles/v1/mapbox/streets-v10/static' +
|
||||
(overlay ? `/${overlay}` : '') +
|
||||
`/${center.lng},${center.lat},${zoom}` +
|
||||
`/${width}x${height}` +
|
||||
`?access_token=${window.mapboxgl.accessToken}`;
|
||||
`?access_token=${config.maps.mapboxAccessToken}`;
|
||||
|
||||
return <img src={src} alt={address} />;
|
||||
};
|
||||
|
|
@ -66,8 +65,8 @@ const StaticMapboxMap = props => {
|
|||
StaticMapboxMap.defaultProps = {
|
||||
address: '',
|
||||
center: null,
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
zoom: config.maps.fuzzy.enabled ? config.maps.fuzzy.defaultZoomLevel : 11,
|
||||
mapsConfig: config.maps,
|
||||
};
|
||||
|
||||
StaticMapboxMap.propTypes = {
|
||||
|
|
@ -77,7 +76,7 @@ StaticMapboxMap.propTypes = {
|
|||
lng: number.isRequired,
|
||||
}).isRequired,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
mapsConfig: object,
|
||||
|
||||
// from withDimensions
|
||||
dimensions: shape({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { arrayOf, bool, func, number, string, shape } from 'prop-types';
|
||||
import { arrayOf, bool, func, number, string, shape, object } from 'prop-types';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { withGoogleMap, GoogleMap } from 'react-google-maps';
|
||||
import classNames from 'classnames';
|
||||
|
|
@ -279,14 +279,14 @@ export class SearchMapComponent extends Component {
|
|||
onCloseAsModal,
|
||||
onIdle,
|
||||
zoom,
|
||||
coordinatesConfig,
|
||||
mapsConfig,
|
||||
activeListingId,
|
||||
} = this.props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
const mapClasses = mapRootClassName || css.mapRoot;
|
||||
|
||||
const listingsWithLocation = originalListings.filter(l => !!l.attributes.geolocation);
|
||||
const listings = coordinatesConfig.fuzzy
|
||||
const listings = mapsConfig.fuzzy.enabled
|
||||
? withCoordinatesObfuscated(listingsWithLocation)
|
||||
: listingsWithLocation;
|
||||
const infoCardOpen = this.state.infoCardOpen;
|
||||
|
|
@ -345,7 +345,7 @@ SearchMapComponent.defaultProps = {
|
|||
onCloseAsModal: null,
|
||||
useLocationSearchBounds: true,
|
||||
zoom: 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
mapsConfig: config.maps,
|
||||
};
|
||||
|
||||
SearchMapComponent.propTypes = {
|
||||
|
|
@ -361,9 +361,7 @@ SearchMapComponent.propTypes = {
|
|||
onIdle: func.isRequired,
|
||||
useLocationSearchBounds: bool, // eslint-disable-line react/no-unused-prop-types
|
||||
zoom: number,
|
||||
coordinatesConfig: shape({
|
||||
fuzzy: bool.isRequired,
|
||||
}),
|
||||
mapsConfig: object,
|
||||
|
||||
// from withRouter
|
||||
history: shape({
|
||||
|
|
|
|||
109
src/config.js
109
src/config.js
|
|
@ -1,4 +1,5 @@
|
|||
import * as custom from './marketplace-custom-config.js';
|
||||
import defaultLocationSearches from './default-location-searches';
|
||||
|
||||
const env = process.env.REACT_APP_ENV;
|
||||
const dev = process.env.REACT_APP_ENV === 'development';
|
||||
|
|
@ -262,57 +263,74 @@ const siteFacebookPage = 'https://www.facebook.com/Sharetribe/';
|
|||
// You should create one to track social sharing in Facebook
|
||||
const facebookAppId = null;
|
||||
|
||||
// Google Maps API key is needed for static map images.
|
||||
const googleMapsAPIKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY;
|
||||
const maps = {
|
||||
mapboxAccessToken: process.env.REACT_APP_MAPBOX_ACCESS_TOKEN,
|
||||
googleMapsAPIKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
|
||||
|
||||
const coordinates = {
|
||||
// If true, obfuscate the coordinates of the listings that are shown
|
||||
// on a map.
|
||||
fuzzy: false,
|
||||
// The location search input can be configured to show default
|
||||
// searches when the user focuses on the input and hasn't yet typed
|
||||
// anything. This reduces typing and avoids too many Geolocation API
|
||||
// calls for common searches.
|
||||
search: {
|
||||
// When enabled, the first suggestion is "Current location" that
|
||||
// uses the browser Geolocation API to query the user's current
|
||||
// location.
|
||||
suggestCurrentLocation: process.env.REACT_APP_DEFAULT_SEARCHES_ENABLED === 'true',
|
||||
|
||||
// Default zoom level when showing a single circle on a Map. Should
|
||||
// be small enough so the whole circle fits in.
|
||||
fuzzyDefaultZoomLevel: 14,
|
||||
// Distance in meters for calculating the bounding box around the
|
||||
// current location.
|
||||
currentLocationBoundsDistance: 1000,
|
||||
|
||||
// When fuzzy === true, the coordinates on the Map component are
|
||||
// obfuscated and a circle is shown instead of a marker. To decide a
|
||||
// proper value for the offset and the radius, see:
|
||||
//
|
||||
// https://gis.stackexchange.com/a/8674
|
||||
|
||||
// Amount of maximum offset in meters that is applied to obfuscate
|
||||
// the original coordinates. The actual value is random, but the
|
||||
// obfuscated coordinates are withing a circle that has the same
|
||||
// radius as the offset.
|
||||
coordinateOffset: 500,
|
||||
|
||||
// Options to style the circle appearance.
|
||||
//
|
||||
// See: https://developers.google.com/maps/documentation/javascript/reference#CircleOptions
|
||||
circleOptions: {
|
||||
fillColor: '#c0392b',
|
||||
fillOpacity: 0.2,
|
||||
strokeColor: '#c0392b',
|
||||
strokeOpacity: 0.5,
|
||||
strokeWeight: 1,
|
||||
clickable: false,
|
||||
// Example location can be edited in the
|
||||
// `default-location-searches.js` file.
|
||||
defaults: defaultLocationSearches,
|
||||
},
|
||||
|
||||
// An option to use custom marker on static maps. Uncomment to enable it.
|
||||
// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers
|
||||
// When fuzzy locations are enabled, coordinates on maps are
|
||||
// obfuscated randomly around the actual location.
|
||||
//
|
||||
// Note 1: fuzzy coordinate circle overwrites these custom marker settings)
|
||||
// Note 2: markerURI needs to be a public URI accessible by Google Maps API servers.
|
||||
// The easiest place is /public/static/icons/ folder, but then the marker image is not available
|
||||
// while developing through localhost.
|
||||
// NOTE: This only hides the locations in the UI level, the actual
|
||||
// coordinates are still accessible in the HTTP requests and the
|
||||
// Redux store.
|
||||
fuzzy: {
|
||||
enabled: false,
|
||||
|
||||
// customMarker: {
|
||||
// markerURI: encodeURI(`${canonicalRootURL}/static/icons/map-marker-32x32.png`),
|
||||
// anchorX: 16,
|
||||
// anchorY: 32,
|
||||
// width: 32,
|
||||
// height: 32,
|
||||
// },
|
||||
// Amount of maximum offset in meters that is applied to obfuscate
|
||||
// the original coordinates. The actual value is random, but the
|
||||
// obfuscated coordinates are withing a circle that has the same
|
||||
// radius as the offset.
|
||||
offset: 500,
|
||||
|
||||
// Default zoom level when showing a single circle on a Map. Should
|
||||
// be small enough so the whole circle fits in.
|
||||
defaultZoomLevel: 13,
|
||||
|
||||
// Color of the circle on the Map component.
|
||||
circleColor: '#c0392b',
|
||||
},
|
||||
|
||||
// Custom marker image to use in the Map component.
|
||||
//
|
||||
// NOTE: Not used if fuzzy locations are enabled.
|
||||
customMarker: {
|
||||
enabled: false,
|
||||
|
||||
// Publicly accessible URL for the custom marker image.
|
||||
//
|
||||
// The easiest place is /public/static/icons/ folder, but then the
|
||||
// marker image is not available while developing through
|
||||
// localhost.
|
||||
url: encodeURI(`${canonicalRootURL}/static/icons/map-marker-32x32.png`),
|
||||
|
||||
// Dimensions of the marker image.
|
||||
width: 32,
|
||||
height: 32,
|
||||
|
||||
// Position to anchor the image in relation to the coordinates,
|
||||
// ignored when using Mapbox.
|
||||
anchorX: 16,
|
||||
anchorY: 32,
|
||||
},
|
||||
};
|
||||
|
||||
// NOTE: only expose configuration that should be visible in the
|
||||
|
|
@ -350,8 +368,7 @@ const config = {
|
|||
facebookAppId,
|
||||
sentryDsn,
|
||||
usingSSL,
|
||||
googleMapsAPIKey,
|
||||
coordinates,
|
||||
maps,
|
||||
custom,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class SectionMapMaybe extends Component {
|
|||
const address = publicData.location ? publicData.location.address : '';
|
||||
const classes = classNames(rootClassName || css.sectionMap, className);
|
||||
|
||||
const mapProps = config.coordinates.fuzzy
|
||||
const mapProps = config.maps.fuzzy.enabled
|
||||
? { obfuscatedCenter: obfuscatedCoordinates(geolocation, listingId ? listingId.uuid : null) }
|
||||
: { address, center: geolocation };
|
||||
const map = <Map {...mapProps} useStaticMap={this.state.isStatic} />;
|
||||
|
|
|
|||
51
src/default-location-searches.js
Normal file
51
src/default-location-searches.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { types as sdkTypes } from './util/sdkLoader';
|
||||
|
||||
const { LatLng, LatLngBounds } = sdkTypes;
|
||||
|
||||
// An array of locations to show in the LocationAutocompleteInput when
|
||||
// the input is in focus but the user hasn't typed in any search yet.
|
||||
//
|
||||
// Each item in the array should be an object with a unique `id` (String) and a
|
||||
// `predictionPlace` (util.types.place) properties.
|
||||
export default [
|
||||
{
|
||||
id: 'default-helsinki',
|
||||
predictionPlace: {
|
||||
address: 'Helsinki, Finland',
|
||||
origin: new LatLng(60.16985, 24.93837),
|
||||
bounds: new LatLngBounds(new LatLng(60.29783, 25.25448), new LatLng(59.92248, 24.78287)),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'default-turku',
|
||||
predictionPlace: {
|
||||
address: 'Turku, Finland',
|
||||
origin: new LatLng(60.45181, 22.26663),
|
||||
bounds: new LatLngBounds(new LatLng(60.53045, 22.38197), new LatLng(60.33361, 22.06644)),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'default-tampere',
|
||||
predictionPlace: {
|
||||
address: 'Tampere, Finland',
|
||||
origin: new LatLng(61.49775, 23.76095),
|
||||
bounds: new LatLngBounds(new LatLng(61.83657, 24.11838), new LatLng(61.42728, 23.5422)),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'default-oulu',
|
||||
predictionPlace: {
|
||||
address: 'Oulu, Finland',
|
||||
origin: new LatLng(65.01208, 25.46507),
|
||||
bounds: new LatLngBounds(new LatLng(65.56434, 26.77069), new LatLng(64.8443, 24.11494)),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'default-ruka',
|
||||
predictionPlace: {
|
||||
address: 'Ruka, Finland',
|
||||
origin: new LatLng(66.16546, 29.15172),
|
||||
bounds: new LatLngBounds(new LatLng(66.16997, 29.16773), new LatLng(66.16095, 29.13572)),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -12,10 +12,9 @@ const { LatLng } = sdkTypes;
|
|||
*/
|
||||
const obfuscatedCoordinatesImpl = (latlng, cacheKey) => {
|
||||
const { lat, lng } = latlng;
|
||||
const offset = config.coordinates.coordinateOffset;
|
||||
|
||||
// https://gis.stackexchange.com/questions/25877/generating-random-locations-nearby
|
||||
const r = offset / 111300;
|
||||
const r = config.maps.fuzzy.offset / 111300;
|
||||
const y0 = lat;
|
||||
const x0 = lng;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue