mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
Add StaticMap sub component for Map
This commit is contained in:
parent
01c5d0570a
commit
17e87a8501
3 changed files with 199 additions and 1 deletions
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
177
src/components/Map/StaticMap.js
Normal file
177
src/components/Map/StaticMap.js
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
import React, { Component } from 'react';
|
||||
import { number, object, shape, string } from 'prop-types';
|
||||
import pick from 'lodash/pick';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import polyline from '@mapbox/polyline';
|
||||
import { encodeLatLng, stringify } from '../../util/urlHelpers';
|
||||
import { lazyLoadWithDimensions } from '../../util/contextHelpers';
|
||||
import config from '../../config';
|
||||
|
||||
const DEFAULT_COLOR = 'FF0000';
|
||||
const DEFAULT_STROKE_OPACITY = 0.3;
|
||||
const DEFAULT_FILL_OPACITY = 0.2;
|
||||
|
||||
// Return polyline encoded list of points forming a circle
|
||||
// This algorithm is based on
|
||||
// https://stackoverflow.com/questions/7316963/drawing-a-circle-google-static-maps
|
||||
const getEncodedGMapCirclePoints = (lat, lng, rad, detail = 8) => {
|
||||
const R = 6371;
|
||||
const pi = Math.PI;
|
||||
|
||||
const _lat = lat * pi / 180;
|
||||
const _lng = lng * pi / 180;
|
||||
const d = rad / 1000 / R;
|
||||
|
||||
let points = [];
|
||||
for (let i = 0; i <= 360; i += detail) {
|
||||
const brng = i * pi / 180;
|
||||
|
||||
let pLat = Math.asin(
|
||||
Math.sin(_lat) * Math.cos(d) + Math.cos(_lat) * Math.sin(d) * Math.cos(brng)
|
||||
);
|
||||
const pLng =
|
||||
(_lng +
|
||||
Math.atan2(
|
||||
Math.sin(brng) * Math.sin(d) * Math.cos(_lat),
|
||||
Math.cos(d) - Math.sin(_lat) * Math.sin(pLat)
|
||||
)) *
|
||||
180 /
|
||||
pi;
|
||||
pLat = pLat * 180 / pi;
|
||||
|
||||
points.push([pLat.toFixed(6), pLng.toFixed(6)]);
|
||||
}
|
||||
|
||||
return polyline.encode(points);
|
||||
};
|
||||
|
||||
// Extract color from string. Given value should be either with '#' (e.g. #FFFFFF') or without it.
|
||||
const formatColorFromString = color => {
|
||||
if (typeof color === 'string' && /^#[0-9A-F]{6}$/i.test(color)) {
|
||||
return color.substring(1).toUpperCase();
|
||||
} else if (typeof color === 'string' && /^[0-9A-F]{6}$/i) {
|
||||
return color.toUpperCase();
|
||||
} else {
|
||||
return DEFAULT_COLOR;
|
||||
}
|
||||
};
|
||||
|
||||
// Convert opacity from floating point value (0.0 -> 1.0) to a hexadecimal format
|
||||
const convertOpacity = opacity => {
|
||||
if (typeof opacity === 'number' && !isNaN(opacity) && opacity >= 0 && opacity <= 1) {
|
||||
// 0.2 => 20
|
||||
return Math.floor(opacity * 255)
|
||||
.toString(16)
|
||||
.toUpperCase();
|
||||
}
|
||||
};
|
||||
|
||||
// Draw a circle polyline for fuzzy location.
|
||||
const drawFuzzyCircle = (coordinatesConfig, center) => {
|
||||
if (
|
||||
!(
|
||||
coordinatesConfig &&
|
||||
typeof coordinatesConfig === 'object' &&
|
||||
center &&
|
||||
typeof center === 'object'
|
||||
)
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const { fillColor, fillOpacity, strokeColor, strokeWeight } = coordinatesConfig.circleOptions;
|
||||
const { lat, lng } = center;
|
||||
|
||||
const circleRadius = coordinatesConfig.coordinateOffset || 500;
|
||||
const circleStrokeWeight = strokeWeight || 1;
|
||||
const circleStrokeColor = formatColorFromString(strokeColor);
|
||||
const circleStrokeOpacity = convertOpacity(DEFAULT_STROKE_OPACITY);
|
||||
const circleFill = formatColorFromString(fillColor);
|
||||
const circleFillOpacity = convertOpacity(fillOpacity || DEFAULT_FILL_OPACITY);
|
||||
|
||||
//Encoded polyline string
|
||||
const encodedPolyline = getEncodedGMapCirclePoints(lat, lng, circleRadius, 8);
|
||||
|
||||
const polylineGraphicTokens = [
|
||||
`color:0x${circleStrokeColor}${circleStrokeOpacity}`,
|
||||
`fillcolor:0x${circleFill}${circleFillOpacity}`,
|
||||
`weight:${circleStrokeWeight}`,
|
||||
`enc:${encodedPolyline}`,
|
||||
];
|
||||
|
||||
return polylineGraphicTokens.join('|');
|
||||
};
|
||||
|
||||
// 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('|');
|
||||
};
|
||||
|
||||
class StaticMap extends Component {
|
||||
shouldComponentUpdate(nextProps, prevState) {
|
||||
// Do not draw the map unless center, zoom or dimensions change
|
||||
// We want to prevent unnecessary calls to Google Maps APIs due
|
||||
const currentData = pick(this.props, ['center', 'zoom', 'dimensions']);
|
||||
const nextData = pick(nextProps, ['center', 'zoom', 'dimensions']);
|
||||
return !isEqual(currentData, nextData);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { center, zoom, address, coordinatesConfig, dimensions } = this.props;
|
||||
const { lat, lng } = center || {};
|
||||
const { width, height } = dimensions;
|
||||
|
||||
// Extra graphics for the static map image
|
||||
// 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) }
|
||||
: { markers: `${lat},${lng}` };
|
||||
|
||||
const srcParams = stringify({
|
||||
center: encodeLatLng(center),
|
||||
zoom,
|
||||
size: `${width}x${height}`,
|
||||
maptype: 'roadmap',
|
||||
key: config.googleMapsAPIKey,
|
||||
...targetMaybe,
|
||||
});
|
||||
|
||||
return (
|
||||
<img src={`https://maps.googleapis.com/maps/api/staticmap?${srcParams}`} alt={address} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StaticMap.defaultProps = {
|
||||
className: null,
|
||||
rootClassName: null,
|
||||
address: '',
|
||||
center: null,
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
};
|
||||
|
||||
StaticMap.propTypes = {
|
||||
className: string,
|
||||
rootClassName: string,
|
||||
address: string,
|
||||
center: shape({
|
||||
lat: number.isRequired,
|
||||
lng: number.isRequired,
|
||||
}).isRequired,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
|
||||
// from withDimensions
|
||||
dimensions: shape({
|
||||
width: number.isRequired,
|
||||
height: number.isRequired,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
export default lazyLoadWithDimensions(StaticMap, { maxWidth: '640px' });
|
||||
|
|
@ -252,6 +252,9 @@ 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 coordinates = {
|
||||
// If true, obfuscate the coordinates of the listings that are shown
|
||||
// on a map.
|
||||
|
|
@ -280,9 +283,26 @@ const coordinates = {
|
|||
fillColor: '#c0392b',
|
||||
fillOpacity: 0.2,
|
||||
strokeColor: '#c0392b',
|
||||
strokeWeight: 0.5,
|
||||
strokeOpacity: 0.5,
|
||||
strokeWeight: 1,
|
||||
clickable: false,
|
||||
},
|
||||
|
||||
// An option to use custom marker on static maps. Uncomment to enable it.
|
||||
// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers
|
||||
//
|
||||
// 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.
|
||||
|
||||
// customMarker: {
|
||||
// markerURI: encodeURI(`${canonicalRootURL}/static/icons/map-marker-32x32.png`),
|
||||
// anchorX: 16,
|
||||
// anchorY: 32,
|
||||
// width: 32,
|
||||
// height: 32,
|
||||
// },
|
||||
};
|
||||
|
||||
// NOTE: only expose configuration that should be visible in the
|
||||
|
|
@ -318,6 +338,7 @@ const config = {
|
|||
facebookAppId,
|
||||
sentryDsn,
|
||||
usingSSL,
|
||||
googleMapsAPIKey,
|
||||
coordinates,
|
||||
custom,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue