diff --git a/package-lock.json b/package-lock.json
index 18b279f..6f9f892 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48,6 +48,7 @@
"react-input-range": "^1.3.0",
"react-leaflet": "^2.7.0",
"react-leaflet-draw": "0.19.0",
+ "react-leaflet-semicircle": "^2.0.12",
"react-modal": "^3.16.1",
"react-select": "^5.7.7",
"react-virtualized-auto-sizer": "^1.0.20",
@@ -29646,6 +29647,11 @@
"resolved": "https://registry.npmjs.org/leaflet-editable/-/leaflet-editable-1.2.0.tgz",
"integrity": "sha512-wG11JwpL8zqIbypTop6xCRGagMuWw68ihYu4uqrqc5Ep0wnEJeyob7NB2Rt5t74Oih4rwJ3OfwaGbzdowOGfYQ=="
},
+ "node_modules/leaflet-semicircle": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/leaflet-semicircle/-/leaflet-semicircle-2.0.4.tgz",
+ "integrity": "sha512-7FV9kGBMSQ1CNZYPxoPCEVpDpiIoh/owZV91BWUKYFik5WuaYij0zGEWOE0elTUlRyTHFJHW4rNfQJ2fqreqnA=="
+ },
"node_modules/legacy-swc-helpers": {
"name": "@swc/helpers",
"version": "0.4.14",
@@ -36659,6 +36665,20 @@
"react-leaflet": "^2.0.0"
}
},
+ "node_modules/react-leaflet-semicircle": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/react-leaflet-semicircle/-/react-leaflet-semicircle-2.0.12.tgz",
+ "integrity": "sha512-zE4thWNJ17CLiNs4wgGkr3nogNo3N6ETHT78O2nIqPrkNd+rT0FrdGrk9PEkT1tfjnmspX4hw0tV6nCot43QZw==",
+ "dependencies": {
+ "leaflet-semicircle": "^2.0.4"
+ },
+ "peerDependencies": {
+ "leaflet": "^1.0.0",
+ "react": "^15.0.0 || ^16.0.0 || ^17.0.0",
+ "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0",
+ "react-leaflet": "^2.0.0"
+ }
+ },
"node_modules/react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
@@ -66486,6 +66506,11 @@
"resolved": "https://registry.npmjs.org/leaflet-editable/-/leaflet-editable-1.2.0.tgz",
"integrity": "sha512-wG11JwpL8zqIbypTop6xCRGagMuWw68ihYu4uqrqc5Ep0wnEJeyob7NB2Rt5t74Oih4rwJ3OfwaGbzdowOGfYQ=="
},
+ "leaflet-semicircle": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/leaflet-semicircle/-/leaflet-semicircle-2.0.4.tgz",
+ "integrity": "sha512-7FV9kGBMSQ1CNZYPxoPCEVpDpiIoh/owZV91BWUKYFik5WuaYij0zGEWOE0elTUlRyTHFJHW4rNfQJ2fqreqnA=="
+ },
"legacy-swc-helpers": {
"version": "npm:@swc/helpers@0.4.14",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz",
@@ -71809,6 +71834,14 @@
"lodash-es": "^4.17.10"
}
},
+ "react-leaflet-semicircle": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/react-leaflet-semicircle/-/react-leaflet-semicircle-2.0.12.tgz",
+ "integrity": "sha512-zE4thWNJ17CLiNs4wgGkr3nogNo3N6ETHT78O2nIqPrkNd+rT0FrdGrk9PEkT1tfjnmspX4hw0tV6nCot43QZw==",
+ "requires": {
+ "leaflet-semicircle": "^2.0.4"
+ }
+ },
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
diff --git a/package.json b/package.json
index f301ffa..2c8fbd2 100644
--- a/package.json
+++ b/package.json
@@ -46,6 +46,7 @@
"react-input-range": "^1.3.0",
"react-leaflet": "^2.7.0",
"react-leaflet-draw": "0.19.0",
+ "react-leaflet-semicircle": "^2.0.12",
"react-modal": "^3.16.1",
"react-select": "^5.7.7",
"react-virtualized-auto-sizer": "^1.0.20",
diff --git a/src/components/MapPreview/MapPreview.js b/src/components/MapPreview/MapPreview.js
index 804ecc5..953a302 100644
--- a/src/components/MapPreview/MapPreview.js
+++ b/src/components/MapPreview/MapPreview.js
@@ -1,6 +1,7 @@
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
-import { Polygon } from 'react-leaflet';
+import { Polygon, Circle, Polyline } from 'react-leaflet';
+import { SemiCircle } from 'react-leaflet-semicircle';
import { useLayers } from '../../hooks';
import { LayersContext } from '../../context';
@@ -46,6 +47,7 @@ const MapPreview = ({
onDrawEdited,
featureRef = useRef(),
emptyMap = false,
+ azimuthDisplay
}) => {
const layers = useLayers(availableLayers, fetchLayerData);
@@ -176,6 +178,120 @@ const MapPreview = ({
}
}
+ let featuresArray = [];
+
+ if (!emptyMap) {
+ featuresArray = features.map((feature) => {
+ const { geometry, properties } = feature;
+
+ const {
+ shapeOptions = {},
+ onClick,
+ onMouseover,
+ onMouseout
+ } = properties;
+
+ const { style = {} } = shapeOptions;
+
+ const featureProps = {
+ ...style,
+ onClick,
+ onMouseover,
+ onMouseout
+ };
+
+ if (geometry.type === 'Point') {
+ const latLngs = latLngFromGeoJson(feature);
+
+ return latLngs.map(({ lat, lng }, index) => {
+ return (
+
+ );
+ });
+ }
+
+ if (geometry.type === 'Polygon') {
+ const coordinates = coordinatesFromGeoJson({
+ type: 'FeatureCollection',
+ features: [feature]
+ });
+
+ return coordinates.map((set) => {
+ return set.map((position, index) => {
+ const fixedPosition = position.map((coordinates) => [
+ coordinates[1],
+ coordinates[0]
+ ]);
+ return (
+
+ );
+ });
+ });
+ }
+
+ return null;
+ });
+ }
+
+ if (azimuthDisplay) {
+ const { center, start, stop } = azimuthDisplay;
+
+ featuresArray.push(
+
+ );
+
+ if (start === stop) {
+ const angleRadians = start * Math.PI / 180;
+ const earthRadius = 6371000; // meters
+ const [centerLat, centerLon] = center;
+
+ const endLat = centerLat
+ + (1500 / earthRadius)
+ * Math.cos(angleRadians)
+ * (180 / Math.PI);
+
+ const endLon = centerLon
+ + (1500 / earthRadius)
+ * Math.sin(angleRadians)
+ * (180 / Math.PI)
+ / Math.cos(centerLat * Math.PI / 180);
+
+ featuresArray.push(
+
+ );
+ } else if (!((start === 0 && stop === 360) || (start === 360 && stop === 0))) {
+ featuresArray.push(
+
+ );
+ }
+ }
+
return (
@@ -189,65 +305,7 @@ const MapPreview = ({
controlOptions={drawControlOptions}
shapeOptions={shapeOptions}
>
- {!emptyMap && features.map((feature) => {
- const { geometry, properties } = feature;
-
- const {
- shapeOptions = {},
- onClick,
- onMouseover,
- onMouseout
- } = properties;
-
- const { style = {} } = shapeOptions;
-
- const featureProps = {
- ...style,
- onClick,
- onMouseover,
- onMouseout
- };
-
- if (geometry.type === 'Point') {
- const latLngs = latLngFromGeoJson(feature);
-
- return latLngs.map(({ lat, lng }, index) => {
- return (
-
- );
- });
- }
-
- if (geometry.type === 'Polygon') {
- const coordinates = coordinatesFromGeoJson({
- type: 'FeatureCollection',
- features: [feature]
- });
-
- return coordinates.map((set) => {
- return set.map((position, index) => {
- const fixedPosition = position.map((coordinates) => [
- coordinates[1],
- coordinates[0]
- ]);
- return (
-
- );
- });
- });
- }
-
- return null;
- })}
+ {featuresArray}
@@ -320,7 +378,8 @@ MapPreview.propTypes = {
onDrawCreated: PropTypes.func,
onDrawEdited: PropTypes.func,
featureRef: PropTypes.object,
- emptyMap: PropTypes.bool
+ emptyMap: PropTypes.bool,
+ azimuthDisplay: PropTypes.object
};
export default MapPreview;
diff --git a/src/components/MapPreview/MapPreview.test.js b/src/components/MapPreview/MapPreview.test.js
index 7b32683..6409e38 100644
--- a/src/components/MapPreview/MapPreview.test.js
+++ b/src/components/MapPreview/MapPreview.test.js
@@ -1,4 +1,6 @@
import React from 'react';
+import { Circle, Polyline } from 'react-leaflet';
+import { SemiCircle } from 'react-leaflet-semicircle';
import { shallow } from 'enzyme';
import MapPreview from './';
@@ -70,4 +72,110 @@ describe('MapPreview', () => {
);
});
});
+
+ describe('Azimuth Display', () => {
+ const baseAzimuthParams = {
+ center: ALEXANDRIA_COORDINATES
+ };
+
+ it('should render only a circle if start=0 and stop=360', () => {
+ const mapPreview = shallow(
+
+ );
+ const mapPreviewCircle = mapPreview.find(Circle);
+ const mapPreviewSemicircle = mapPreview.find(SemiCircle);
+ const mapPreviewPolyline = mapPreview.find(Polyline);
+
+ expect(mapPreviewCircle).toHaveLength(1);
+ expect(mapPreviewSemicircle).toHaveLength(0);
+ expect(mapPreviewPolyline).toHaveLength(0);
+ });
+
+ it('should render only a circle if start=360 and stop=0', () => {
+ const mapPreview = shallow(
+
+ );
+ const mapPreviewCircle = mapPreview.find(Circle);
+ const mapPreviewSemicircle = mapPreview.find(SemiCircle);
+ const mapPreviewPolyline = mapPreview.find(Polyline);
+
+ expect(mapPreviewCircle).toHaveLength(1);
+ expect(mapPreviewSemicircle).toHaveLength(0);
+ expect(mapPreviewPolyline).toHaveLength(0);
+ });
+
+ it('should render a circle and polyline if start=stop', () => {
+ const mapPreview = shallow(
+
+ );
+ const mapPreviewCircle = mapPreview.find(Circle);
+ const mapPreviewSemicircle = mapPreview.find(SemiCircle);
+ const mapPreviewPolyline = mapPreview.find(Polyline);
+
+ expect(mapPreviewCircle).toHaveLength(1);
+ expect(mapPreviewSemicircle).toHaveLength(0);
+ expect(mapPreviewPolyline).toHaveLength(1);
+ });
+
+ it('should render a circle and semicircle if start > stop', () => {
+ const mapPreview = shallow(
+
+ );
+ const mapPreviewCircle = mapPreview.find(Circle);
+ const mapPreviewSemicircle = mapPreview.find(SemiCircle);
+ const mapPreviewPolyline = mapPreview.find(Polyline);
+
+ expect(mapPreviewCircle).toHaveLength(1);
+ expect(mapPreviewSemicircle).toHaveLength(1);
+ expect(mapPreviewPolyline).toHaveLength(0);
+ });
+
+ it('should render a circle and semicircle if start < stop', () => {
+ const mapPreview = shallow(
+
+ );
+ const mapPreviewCircle = mapPreview.find(Circle);
+ const mapPreviewSemicircle = mapPreview.find(SemiCircle);
+ const mapPreviewPolyline = mapPreview.find(Polyline);
+
+ expect(mapPreviewCircle).toHaveLength(1);
+ expect(mapPreviewSemicircle).toHaveLength(1);
+ expect(mapPreviewPolyline).toHaveLength(0);
+ });
+ });
});
diff --git a/src/hooks/useInput.js b/src/hooks/useInput.js
index 6176cfc..38cf58b 100644
--- a/src/hooks/useInput.js
+++ b/src/hooks/useInput.js
@@ -43,7 +43,9 @@ const INPUT_PROPS_WHITELIST = [
'isMulti',
'inputProps',
'ref',
- 'selectionStart'
+ 'selectionStart',
+ 'min',
+ 'max'
];
const INPUT_LIST_TYPES = ['radio', 'checkbox'];