From 4251cf9a310a88d1e02a9432e89a73eda8354a03 Mon Sep 17 00:00:00 2001 From: ray Date: Mon, 1 Apr 2024 17:09:35 -0700 Subject: [PATCH] DBC22-1935: added advisory layer on map --- src/frontend/src/Components/Map.js | 34 ++++++++++++- .../advisories/AdvisoriesOnMap.scss | 2 +- .../data/featureStyleDefinitions.js | 15 +++++- .../Components/map/layers/advisoriesLayer.js | 50 +++++++++++++++++++ src/frontend/src/pages/AdvisoryDetailsPage.js | 7 ++- 5 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 src/frontend/src/Components/map/layers/advisoriesLayer.js diff --git a/src/frontend/src/Components/Map.js b/src/frontend/src/Components/Map.js index 8606916b..d7e1b6b5 100644 --- a/src/frontend/src/Components/Map.js +++ b/src/frontend/src/Components/Map.js @@ -33,7 +33,6 @@ import { // Components and functions import CamPopup from './map/camPopup.js'; -import { getCamerasLayer } from './map/layers/camerasLayer.js'; import { getEventPopup, getFerryPopup, @@ -44,6 +43,8 @@ import { import { getEvents } from './data/events.js'; import { getWeather, getRegional } from './data/weather.js'; import { getRestStops } from './data/restStops.js'; +import { getAdvisoriesLayer } from './map/layers/advisoriesLayer.js'; +import { getCamerasLayer } from './map/layers/camerasLayer.js'; import { getRestStopsLayer } from './map/layers/restStopsLayer.js'; import { loadEventsLayers } from './map/layers/eventsLayer.js'; import { loadWeatherLayers } from './map/layers/weatherLayer.js'; @@ -103,8 +104,9 @@ export default function MapWrapper({ camTimeStamp, // Cameras events, eventTimeStamp, // Events + advisories, // CMS ferries, - ferriesTimeStamp, // CMS + ferriesTimeStamp, // Ferries weather, weatherTimeStamp, // Current Weather regional, @@ -125,6 +127,8 @@ export default function MapWrapper({ events: state.feeds.events.list, eventTimeStamp: state.feeds.events.routeTimeStamp, // CMS + advisories: state.cms.advisories.list, + // Ferries ferries: state.feeds.ferries.list, ferriesTimeStamp: state.feeds.ferries.routeTimeStamp, // Current Weather @@ -631,6 +635,7 @@ export default function MapWrapper({ } }, [searchLocationFrom]); + // Route layer useEffect(() => { if (isInitialMountRoute.current) { // Do nothing on first load @@ -646,6 +651,7 @@ export default function MapWrapper({ loadData(false); }, [selectedRoute]); + // Camera layer useEffect(() => { // Remove layer if it already exists if (mapLayers.current['highwayCams']) { @@ -687,6 +693,7 @@ export default function MapWrapper({ } }; + // Event layers useEffect(() => { loadEventsLayers(events, mapContext, mapLayers, mapRef); }, [events]); @@ -706,6 +713,7 @@ export default function MapWrapper({ } }; + // Ferries and rest stops layers useEffect(() => { // Remove layer if it already exists if (mapLayers.current['inlandFerries']) { @@ -767,6 +775,7 @@ export default function MapWrapper({ } }; + // Weather layers useEffect(() => { if (mapLayers.current['weather']) { mapRef.current.removeLayer(mapLayers.current['weather']); @@ -797,6 +806,27 @@ export default function MapWrapper({ } }; + // Advisories layer + useEffect(() => { + // Remove layer if it already exists + if (mapLayers.current['advisoriesLayer']) { + mapRef.current.removeLayer(mapLayers.current['advisoriesLayer']); + } + + // Add layer if array exists + if (advisories) { + // Generate and add layer + mapLayers.current['advisoriesLayer'] = getAdvisoriesLayer( + advisories, + mapRef.current.getView().getProjection().getCode(), + mapContext, + ); + + mapRef.current.addLayer(mapLayers.current['advisoriesLayer']); + mapLayers.current['advisoriesLayer'].setZIndex(55); + } + }, [advisories]); + useEffect(() => { if (mapLayers.current['regional']) { mapRef.current.removeLayer(mapLayers.current['regional']); diff --git a/src/frontend/src/Components/advisories/AdvisoriesOnMap.scss b/src/frontend/src/Components/advisories/AdvisoriesOnMap.scss index 2f466dfd..b6c7ac81 100644 --- a/src/frontend/src/Components/advisories/AdvisoriesOnMap.scss +++ b/src/frontend/src/Components/advisories/AdvisoriesOnMap.scss @@ -2,7 +2,7 @@ .advisories-on-map { position: relative; - top: 1rem; + top: 6rem; left: 1rem; width: fit-content; diff --git a/src/frontend/src/Components/data/featureStyleDefinitions.js b/src/frontend/src/Components/data/featureStyleDefinitions.js index ab985dcc..067828bc 100644 --- a/src/frontend/src/Components/data/featureStyleDefinitions.js +++ b/src/frontend/src/Components/data/featureStyleDefinitions.js @@ -1,4 +1,4 @@ -import { Icon, Stroke, Style } from 'ol/style.js'; +import { Fill, Icon, Stroke, Style } from 'ol/style.js'; // Static assets // Cameras @@ -75,6 +75,19 @@ import genericDelaysActiveIcon from '../../images/mapIcons/incident-minor-active import genericDelaysHoverIcon from '../../images/mapIcons/incident-minor-hover.png'; import genericDelaysStaticIcon from '../../images/mapIcons/incident-minor-static.png'; +// Map advisory styles +export const advisoryStyles = { + polygon: new Style({ + stroke: new Stroke({ + color: 'rgb(255, 90, 0)', + width: 2, + }), + fill: new Fill({ + color: 'rgba(255, 217, 105, 0.4)', + }), + }) +}; + // Camera icon styles export const cameraStyles = { static: new Style({ diff --git a/src/frontend/src/Components/map/layers/advisoriesLayer.js b/src/frontend/src/Components/map/layers/advisoriesLayer.js new file mode 100644 index 00000000..2b93b5d4 --- /dev/null +++ b/src/frontend/src/Components/map/layers/advisoriesLayer.js @@ -0,0 +1,50 @@ +// Components and functions +import { transformFeature } from '../helper.js'; + +// OpenLayers +import { Polygon } from 'ol/geom'; +import * as ol from 'ol'; +import GeoJSON from 'ol/format/GeoJSON.js'; +import VectorLayer from 'ol/layer/Vector'; +import VectorSource from 'ol/source/Vector'; + +// Styling +import { advisoryStyles } from '../../data/featureStyleDefinitions.js'; + +export function getAdvisoriesLayer( + advisories, + projectionCode, + mapContext, +) { + return new VectorLayer({ + classname: 'advisories', + visible: true, + source: new VectorSource({ + format: new GeoJSON(), + loader: function (extent, resolution, projection) { + const vectorSource = this; + vectorSource.clear(); + + advisories.forEach(advisory => { + // Build a new OpenLayers feature + const olGeometry = new Polygon(advisory.geometry.coordinates); + const olFeature = new ol.Feature({ geometry: olGeometry }); + + // Transform the projection + const olFeatureForMap = transformFeature( + olFeature, + 'EPSG:4326', + projectionCode, + ); + + // feature ID to advisory ID for retrieval + olFeatureForMap.setId(advisory.id); + + vectorSource.addFeature(olFeatureForMap); + }); + }, + }), + + style: () => advisoryStyles.polygon, + }); +} diff --git a/src/frontend/src/pages/AdvisoryDetailsPage.js b/src/frontend/src/pages/AdvisoryDetailsPage.js index 50e75294..52ab6816 100644 --- a/src/frontend/src/pages/AdvisoryDetailsPage.js +++ b/src/frontend/src/pages/AdvisoryDetailsPage.js @@ -54,12 +54,11 @@ function getMap(advisoryData) { }), 'Polygon': new Style({ stroke: new Stroke({ - color: 'blue', - lineDash: [4], - width: 3, + color: 'rgb(255, 90, 0)', + width: 2, }), fill: new Fill({ - color: 'rgba(0, 0, 255, 0.1)', + color: 'rgba(255, 217, 105, 0.4)', }), }) };