Skip to content

Commit

Permalink
[Tech] Refactoring des composants OpenLayers (#2694)
Browse files Browse the repository at this point in the history
## Linked issues

- Suppression de la props `map`

----

- [ ] Tests E2E (Cypress)
  • Loading branch information
louptheron authored Nov 10, 2023
2 parents 4111dca + b771070 commit 9e12cfe
Show file tree
Hide file tree
Showing 31 changed files with 345 additions and 366 deletions.
6 changes: 3 additions & 3 deletions frontend/src/domain/shared_slices/Map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const hideVesselsAtPortLocalStorageKey = 'hideVesselsAtPort'

export type MapState = {
/** End of vessels map properties */
animateToCoordinates: null
animateToCoordinates: [number, number] | undefined
animateToExtent: boolean
animateToRegulatoryLayer: { center?: [number, number]; extent?: [number, number] } | undefined
coordinatesFormat: CoordinatesFormat
Expand All @@ -46,7 +46,7 @@ export type MapState = {
}
}
const INITIAL_STATE: MapState = {
animateToCoordinates: null,
animateToCoordinates: undefined,
animateToExtent: false,
animateToRegulatoryLayer: undefined,
coordinatesFormat: getLocalStorageState(CoordinatesFormat.DEGREES_MINUTES_SECONDS, coordinatesFormatLocalStorageKey),
Expand Down Expand Up @@ -110,7 +110,7 @@ const mapSlice = createSlice({
state.fitToExtent = action.payload
},
resetAnimateToCoordinates(state) {
state.animateToCoordinates = null
state.animateToCoordinates = undefined
},
resetAnimateToExtent(state) {
state.animateToExtent = false
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/features/MainWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import styled from 'styled-components'
import { ErrorToastNotification } from './commonComponents/ErrorToastNotification'
import { HealthcheckHeadband } from './Healthcheck/components/HealthcheckHeadband'
import { DrawLayerModal } from './map/draw/DrawModal'
import Map from './map/Map'
import { Map } from './map/Map'
import { MapButtons } from './MapButtons'
import { LayersSidebar } from './MapButtons/LayersSidebar'
import { RightMenuOnHoverArea } from './MapButtons/shared/RightMenuOnHoverArea'
Expand Down
13 changes: 2 additions & 11 deletions frontend/src/features/map/BaseMap.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { platformModifierKeyOnly } from 'ol/events/condition'
import OpenLayerMap from 'ol/Map'
import { Children, cloneElement, useCallback, useEffect, useRef, useState } from 'react'
import { Children, useCallback, useEffect, useRef, useState } from 'react'
import styled from 'styled-components'

import MapAttributionsBox from './controls/MapAttributionsBox'
Expand Down Expand Up @@ -230,16 +230,7 @@ export function BaseMap({
/>
{showCoordinates && <MapCoordinatesBox coordinates={cursorCoordinates} />}
{showAttributions && <MapAttributionsBox />}
{Children.map(children, child => {
if (!child) {
return null
}

const props = { map: monitorfishMap }

// @ts-ignore
return cloneElement(child, props)
})}
{Children.map(children, child => child)}
</MapWrapper>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,52 @@
import React, { useState } from 'react'
import { Feature } from 'ol'
import { useState } from 'react'

import { BaseMap } from './BaseMap'
import { LayerDetailsBox } from './controls/LayerDetailsBox'
import { VesselsTracksLayerMemoized } from './layers/Vessel/VesselsTracksLayer'
import { VesselsLayer } from './layers/Vessel/VesselsLayer'
import FilterLayer from './layers/FilterLayer'
import { RegulatoryLayerSearch } from './layers/RegulatoryLayerSearch'
import { DrawLayer } from './layers/DrawLayer'
import { AdministrativeLayers } from './layers/AdministrativeLayers'
import { BaseLayer } from './layers/BaseLayer'
import { DrawLayer } from './layers/DrawLayer'
import FilterLayer from './layers/FilterLayer'
import InterestPointLayer from './layers/InterestPointLayer'
import MeasurementLayer from './layers/MeasurementLayer'
import { MissionHoveredLayer } from './layers/Mission/HoveredMissionLayer'
import { MissionLayer } from './layers/Mission/MissionLayer'
import { MissionsLabelsLayer } from './layers/Mission/MissionsLabelsLayer/MissionsLabelsLayer'
import { SelectedMissionActionsLayer } from './layers/Mission/SelectedMissionActionsLayer'
import { SelectedMissionLayer } from './layers/Mission/SelectedMissionLayer'
import { RegulatoryLayers } from './layers/RegulatoryLayers'
import { AdministrativeLayers } from './layers/AdministrativeLayers'
import { RegulatoryLayerSearch } from './layers/RegulatoryLayerSearch'
import { RegulatoryPreviewLayer } from './layers/RegulatoryPreviewLayer'
import MeasurementLayer from './layers/MeasurementLayer'
import MapHistory from './MapHistory'
import { VesselCardOverlay } from './overlays/VesselCardOverlay'
import VesselTrackOverlay from './overlays/VesselTrackOverlay'
import { TrackTypeOverlay } from './overlays/TrackTypeOverlay'
import { MapVesselClickAndAnimationHandler } from './MapVesselClickAndAnimationHandler'
import VesselEstimatedPositionLayer from './layers/Vessel/VesselEstimatedPositionLayer'
import VesselSelectedLayer from './layers/Vessel/VesselSelectedLayer'
import VesselEstimatedPositionOverlay from './overlays/VesselEstimatedPositionOverlay'
import { VesselsLabelsLayer } from './layers/Vessel/VesselsLabelsLayer'
import InterestPointLayer from './layers/InterestPointLayer'
import MapMenu from './MapMenu'
import VesselAlertAndBeaconMalfunctionLayer from './layers/Vessel/VesselAlertAndBeaconMalfunctionLayer'
import VesselAlertLayer from './layers/Vessel/VesselAlertLayer'
import VesselBeaconMalfunctionLayer from './layers/Vessel/VesselBeaconMalfunctionLayer'
import VesselAlertAndBeaconMalfunctionLayer from './layers/Vessel/VesselAlertAndBeaconMalfunctionLayer'
import VesselEstimatedPositionLayer from './layers/Vessel/VesselEstimatedPositionLayer'
import VesselInfractionSuspicionLayer from './layers/Vessel/VesselInfractionSuspicionLayer'
import { MissionLayer } from './layers/Mission/MissionLayer'
import { SelectedMissionLayer } from './layers/Mission/SelectedMissionLayer'
import { MissionsLabelsLayer } from './layers/Mission/MissionsLabelsLayer/MissionsLabelsLayer'
import { MissionOverlay } from './overlays/MissionOverlay'
import { SelectedMissionOverlay } from './overlays/SelectedMissionOverlay'
import { MissionHoveredLayer } from './layers/Mission/HoveredMissionLayer'
import { SelectedMissionActionsLayer } from './layers/Mission/SelectedMissionActionsLayer'
import VesselSelectedLayer from './layers/Vessel/VesselSelectedLayer'
import { VesselsLabelsLayer } from './layers/Vessel/VesselsLabelsLayer'
import { VesselsLayer } from './layers/Vessel/VesselsLayer'
import { VesselsTracksLayerMemoized } from './layers/Vessel/VesselsTracksLayer'
import MapHistory from './MapHistory'
import { MapMenu } from './MapMenu'
import { MapVesselClickAndAnimationHandler } from './MapVesselClickAndAnimationHandler'
import { ControlOverlay } from './overlays/ControlOverlay'
import { MissionOverlay } from './overlays/MissionOverlay'
import { SelectedControlOverlay } from './overlays/SelectedControlOverlay'
import { useSelector } from 'react-redux'
import { SelectedMissionOverlay } from './overlays/SelectedMissionOverlay'
import { TrackTypeOverlay } from './overlays/TrackTypeOverlay'
import { VesselCardOverlay } from './overlays/VesselCardOverlay'
import VesselEstimatedPositionOverlay from './overlays/VesselEstimatedPositionOverlay'
import VesselTrackOverlay from './overlays/VesselTrackOverlay'
import { useIsSuperUser } from '../../hooks/authorization/useIsSuperUser'
import { useMainAppSelector } from '../../hooks/useMainAppSelector'

const Map = () => {
export function Map() {
const isSuperUser = useIsSuperUser()
const { areVesselsDisplayed, isMissionsLayerDisplayed } = useSelector(state => state.displayedComponent)
const { areVesselsDisplayed, isMissionsLayerDisplayed } = useMainAppSelector(state => state.displayedComponent)
const [shouldUpdateView, setShouldUpdateView] = useState(true)
const [historyMoveTrigger, setHistoryMoveTrigger] = useState({})
const [currentFeature, setCurrentFeature] = useState(null)
const [mapMovingAndZoomEvent, setMapMovingAndZoomEvent] = useState(null)
const [currentFeature, setCurrentFeature] = useState<Feature>()
const [mapMovingAndZoomEvent, setMapMovingAndZoomEvent] = useState<Object>({})
const [handlePointerMoveEventPixel, setHandlePointerMoveEventPixel] = useState(null)

const handleMovingAndZoom = () => {
Expand All @@ -56,7 +57,7 @@ const Map = () => {
setMapMovingAndZoomEvent({ dummyUpdate: true })
}

const handlePointerMove = (event) => {
const handlePointerMove = event => {
if (event) {
setHandlePointerMoveEventPixel(event.pixel)
}
Expand All @@ -67,54 +68,52 @@ const Map = () => {
// BaseMap forwards map as props to children
handleMovingAndZoom={handleMovingAndZoom}
handlePointerMove={handlePointerMove}
setCurrentFeature={setCurrentFeature}
showCoordinates={true}
showAttributions={true}
isMainApp
setCurrentFeature={setCurrentFeature}
showAttributions
showCoordinates
>
<BaseLayer />
<RegulatoryLayers mapMovingAndZoomEvent={mapMovingAndZoomEvent}/>
<RegulatoryLayers mapMovingAndZoomEvent={mapMovingAndZoomEvent} />
<AdministrativeLayers />
<MapVesselClickAndAnimationHandler/>
<MapVesselClickAndAnimationHandler />
<MapHistory
shouldUpdateView={shouldUpdateView}
setShouldUpdateView={setShouldUpdateView}
historyMoveTrigger={historyMoveTrigger}
setShouldUpdateView={setShouldUpdateView}
shouldUpdateView={shouldUpdateView}
/>
<MapMenu/>
<MeasurementLayer/>
<FilterLayer/>
{/** <></> can't be used to group condition as BaseMap needs the layers to be direct children **/}
{isSuperUser && isMissionsLayerDisplayed && <MissionLayer/>}
{isSuperUser && <MissionsLabelsLayer mapMovingAndZoomEvent={mapMovingAndZoomEvent}/>}
{isSuperUser && <SelectedMissionLayer feature={currentFeature}/>}
{isSuperUser && <MissionHoveredLayer feature={currentFeature}/>}
{isSuperUser && <MissionOverlay feature={currentFeature}/>}
{isSuperUser && <SelectedMissionOverlay/>}
{isSuperUser && <SelectedMissionActionsLayer/>}
{isSuperUser && <ControlOverlay feature={currentFeature}/>}
{isSuperUser && <SelectedControlOverlay/>}
<DrawLayer/>
<RegulatoryLayerSearch/>
<VesselsLabelsLayer mapMovingAndZoomEvent={mapMovingAndZoomEvent}/>
{/** <></> can't be used to group condition as BaseMap needs the layers to be direct children **/}
{<VesselsLayer/>}
{areVesselsDisplayed && <VesselEstimatedPositionLayer/>}
{areVesselsDisplayed && <VesselSelectedLayer/>}
{areVesselsDisplayed && <VesselAlertLayer/>}
{areVesselsDisplayed && <VesselBeaconMalfunctionLayer/>}
{areVesselsDisplayed && <VesselAlertAndBeaconMalfunctionLayer/>}
{areVesselsDisplayed && <VesselInfractionSuspicionLayer/>}
{<VesselsTracksLayerMemoized/>}
<VesselCardOverlay feature={currentFeature}/>
<TrackTypeOverlay pointerMoveEventPixel={handlePointerMoveEventPixel} feature={currentFeature}/>
<VesselEstimatedPositionOverlay pointerMoveEventPixel={handlePointerMoveEventPixel} feature={currentFeature}/>
<VesselTrackOverlay feature={currentFeature}/>
{currentFeature && <LayerDetailsBox feature={currentFeature}/>}
<InterestPointLayer mapMovingAndZoomEvent={mapMovingAndZoomEvent}/>
<MapMenu />
<MeasurementLayer />
<FilterLayer />
{/** <></> can't be used to group condition as BaseMap needs the layers to be direct children * */}
{isSuperUser && isMissionsLayerDisplayed && <MissionLayer />}
{isSuperUser && <MissionsLabelsLayer mapMovingAndZoomEvent={mapMovingAndZoomEvent} />}
{isSuperUser && <SelectedMissionLayer />}
{isSuperUser && <MissionHoveredLayer feature={currentFeature} />}
{isSuperUser && <MissionOverlay feature={currentFeature} />}
{isSuperUser && <SelectedMissionOverlay />}
{isSuperUser && <SelectedMissionActionsLayer />}
{isSuperUser && <ControlOverlay feature={currentFeature} />}
{isSuperUser && <SelectedControlOverlay />}
<DrawLayer />
<RegulatoryLayerSearch />
<VesselsLabelsLayer mapMovingAndZoomEvent={mapMovingAndZoomEvent} />
{/** <></> can't be used to group condition as BaseMap needs the layers to be direct children * */}
<VesselsLayer />
{areVesselsDisplayed && <VesselEstimatedPositionLayer />}
{areVesselsDisplayed && <VesselSelectedLayer />}
{areVesselsDisplayed && <VesselAlertLayer />}
{areVesselsDisplayed && <VesselBeaconMalfunctionLayer />}
{areVesselsDisplayed && <VesselAlertAndBeaconMalfunctionLayer />}
{areVesselsDisplayed && <VesselInfractionSuspicionLayer />}
<VesselsTracksLayerMemoized />
<VesselCardOverlay feature={currentFeature} />
<TrackTypeOverlay feature={currentFeature} pointerMoveEventPixel={handlePointerMoveEventPixel} />
<VesselEstimatedPositionOverlay feature={currentFeature} pointerMoveEventPixel={handlePointerMoveEventPixel} />
<VesselTrackOverlay feature={currentFeature} />
{currentFeature && <LayerDetailsBox feature={currentFeature} />}
<InterestPointLayer mapMovingAndZoomEvent={mapMovingAndZoomEvent} />
<RegulatoryPreviewLayer />
</BaseMap>
)
}

export default Map
49 changes: 23 additions & 26 deletions frontend/src/features/map/MapHistory.jsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import { useEffect } from 'react'
import { getLocalStorageState } from '../../utils'
import { isNumeric } from '../../utils/isNumeric'
import { monitorfishMap } from './monitorfishMap'

const savedMapExtentLocalStorageKey = 'mapExtent'
const savedMapViewLocalStorageKey = 'mapView'
/**
* Handle browser and LocalStorage history on map URL - Note that the map parameter is given from
* the BaseMap component, event if it's not seen in the props passed to MapHistory
* Handle browser and LocalStorage history on map URL
*/
const MapHistory = ({ map, setShouldUpdateView, shouldUpdateView, historyMoveTrigger }) => {
const MapHistory = ({ setShouldUpdateView, shouldUpdateView, historyMoveTrigger }) => {
useEffect(() => {
// restore view on browser history navigation
window.addEventListener('popstate', event => {
if (event.state === null) {
return
}

if (map) {
map.getView().setCenter(event.state.center)
map.getView().setZoom(event.state.zoom)
setShouldUpdateView(false)
}
monitorfishMap.getView().setCenter(event.state.center)
monitorfishMap.getView().setZoom(event.state.zoom)
setShouldUpdateView(false)
})
}, [map, setShouldUpdateView])
}, [setShouldUpdateView])

useEffect(() => {
const mapState = {
Expand All @@ -33,29 +31,28 @@ const MapHistory = ({ map, setShouldUpdateView, shouldUpdateView, historyMoveTri
extent: getLocalStorageState(null, savedMapExtentLocalStorageKey)
}
function initMapView () {
if (map) {
if (window.location.hash !== '') {
const hash = window.location.hash.replace('@', '').replace('#', '')
const viewParts = hash.split(',')
if (viewParts.length === 3 && isNumeric(viewParts[0]) && isNumeric(viewParts[1]) && isNumeric(viewParts[2])) {
map.getView().setCenter([parseFloat(viewParts[0]), parseFloat(viewParts[1])])
map.getView().setZoom(parseFloat(viewParts[2]))
}
} else if (mapState) {
if (mapState.view && mapState.view.center && mapState.view.center[0] && mapState.view.center[1] && mapState.view.zoom) {
map.getView().setCenter(mapState.view.center)
map.getView().setZoom(mapState.view.zoom)
}
if (window.location.hash !== '') {
const hash = window.location.hash.replace('@', '').replace('#', '')
const viewParts = hash.split(',')
if (viewParts.length === 3 && isNumeric(viewParts[0]) && isNumeric(viewParts[1]) && isNumeric(viewParts[2])) {
monitorfishMap.getView().setCenter([parseFloat(viewParts[0]), parseFloat(viewParts[1])])
monitorfishMap.getView().setZoom(parseFloat(viewParts[2]))
}
} else if (mapState) {
if (mapState.view && mapState.view.center && mapState.view.center[0] && mapState.view.center[1] && mapState.view.zoom) {
monitorfishMap.getView().setCenter(mapState.view.center)
monitorfishMap.getView().setZoom(mapState.view.zoom)
}
}
}

initMapView()
}, [map])
}, [])

useEffect(() => {
function saveMapView () {
if (map && shouldUpdateView) {
const currentView = map.getView()
if (shouldUpdateView) {
const currentView = monitorfishMap.getView()
const center = currentView.getCenter()
const view = {
zoom: currentView.getZoom().toFixed(2),
Expand All @@ -70,7 +67,7 @@ const MapHistory = ({ map, setShouldUpdateView, shouldUpdateView, historyMoveTri
}
}
saveMapView()
}, [map, shouldUpdateView, historyMoveTrigger])
}, [shouldUpdateView, historyMoveTrigger])

return null
}
Expand Down
57 changes: 0 additions & 57 deletions frontend/src/features/map/MapMenu.jsx

This file was deleted.

Loading

0 comments on commit 9e12cfe

Please sign in to comment.