From d5f3197d7d68dc13b8b2262202d09c5d7e3b1a11 Mon Sep 17 00:00:00 2001 From: dleadbetter <> Date: Mon, 13 Nov 2023 07:07:39 -0500 Subject: [PATCH] CDC #35 - Updating point bounding box calculation --- packages/geospatial/src/components/MapDraw.js | 52 +++++++++++++++++-- .../src/geospatial/MapDraw.stories.js | 17 ++++++ 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/packages/geospatial/src/components/MapDraw.js b/packages/geospatial/src/components/MapDraw.js index de44d010..b2c9134e 100644 --- a/packages/geospatial/src/components/MapDraw.js +++ b/packages/geospatial/src/components/MapDraw.js @@ -3,7 +3,11 @@ import MapboxDraw from '@mapbox/mapbox-gl-draw'; import { bbox, + destination, feature, + featureCollection, + getCoord, + point, type FeatureCollection, type GeometryCollection } from '@turf/turf'; @@ -13,12 +17,18 @@ import React, { useEffect, useMemo, useRef, + useState } from 'react'; import Map, { MapRef } from 'react-map-gl'; import _ from 'underscore'; import DrawControl from './DrawControl'; import './MapDraw.css'; +const BEARING_SW = 225; +const BEARING_NE = 45; + +const POINT_DISTANCE = 10; + type Props = { /** * GeoJSON structured data to be displayed on the map. @@ -43,14 +53,45 @@ type Props = { style?: any }; +const GeometryTypes = { + geometryCollection: 'GeometryCollection', + point: 'Point' +}; + /** * This component renders a map with controls for drawing one or more geometries. Geometries can be a point (lat/long), * a line, or a polygon. */ const MapDraw = (props: Props) => { + const [loaded, setLoaded] = useState(false); + const drawRef = useRef(); const mapRef = useRef(); + /** + * Returns the bounding box for the current data set. Points are handled differently so that the bounding box + * does not zoom too much and shows relevant information close to the point. + * + * @type {function(): *} + */ + const getBoundingBox = useCallback(() => { + let boundingBox; + + if (props.data.type === GeometryTypes.point) { + const coordinates = getCoord(props.data); + const p = point(coordinates); + + const sw = destination(p, POINT_DISTANCE, BEARING_SW); + const ne = destination(p, POINT_DISTANCE, BEARING_NE); + + boundingBox = bbox(featureCollection([sw, ne])); + } else { + boundingBox = bbox(props.data); + } + + return boundingBox; + }, [props.data]); + /** * Calls the onChange prop with all of the geometries in the current drawer. * @@ -71,9 +112,9 @@ const MapDraw = (props: Props) => { * Updates the map bounding box and drawer when the geometry is changed. */ useEffect(() => { - if (props.data) { + if (loaded && props.data) { // Sets the bounding box for the current geometry. - const boundingBox = bbox(props.data); + const boundingBox = getBoundingBox(); if (_.every(boundingBox, _.isFinite)) { const [minLng, minLat, maxLng, maxLat] = boundingBox; @@ -82,8 +123,8 @@ const MapDraw = (props: Props) => { mapRef.current.fitBounds(bounds, { padding: 40, duration: 1000 }); } - // Handle special case for geometry collection (not supported by mabox-gl-draw) - if (props.data.type === 'GeometryCollection') { + // Handle special cases for geometry collection (not supported by mabox-gl-draw) and point + if (props.data.type === GeometryTypes.geometryCollection) { _.each(props.data.geometries, (geometry) => { drawRef.current.add(feature(geometry)); }); @@ -91,11 +132,12 @@ const MapDraw = (props: Props) => { drawRef.current.add(props.data); } } - }, [props.data]); + }, [loaded, props.data]); return ( setLoaded(true)} mapLib={maplibregl} ref={mapRef} style={style} diff --git a/packages/storybook/src/geospatial/MapDraw.stories.js b/packages/storybook/src/geospatial/MapDraw.stories.js index 73fcc253..98b62523 100644 --- a/packages/storybook/src/geospatial/MapDraw.stories.js +++ b/packages/storybook/src/geospatial/MapDraw.stories.js @@ -18,3 +18,20 @@ export const Default = () => ( }} /> ); + +export const Point = () => ( + +);