Skip to content

Commit

Permalink
Refactor and fix measurement layer
Browse files Browse the repository at this point in the history
  • Loading branch information
louptheron committed Sep 25, 2024
1 parent dff9138 commit a2ce0b1
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 123 deletions.
191 changes: 68 additions & 123 deletions frontend/src/features/Measurement/layers/MeasurementLayer.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { getNauticalMilesOfLine, getNauticalMilesRadiusOfCircle } from '@features/Measurement/layers/utils'
import { addCustomCircleMeasurement } from '@features/Measurement/useCases/addCustomCircleMeasurement'
import { useMainAppDispatch } from '@hooks/useMainAppDispatch'
import { useMainAppSelector } from '@hooks/useMainAppSelector'
import { getCenter } from 'ol/extent'
import Feature from 'ol/Feature'
import GeoJSON from 'ol/format/GeoJSON'
import Circle from 'ol/geom/Circle'
import LineString from 'ol/geom/LineString'
import { circular } from 'ol/geom/Polygon'
import Draw from 'ol/interaction/Draw'
import VectorLayer from 'ol/layer/Vector'
import { unByKey } from 'ol/Observable'
import { transform } from 'ol/proj'
import { METERS_PER_UNIT } from 'ol/proj/Units'
import VectorSource from 'ol/source/Vector'
import React, { useCallback, useEffect, useRef, useState } from 'react'

Expand All @@ -25,9 +23,8 @@ import { saveMeasurement } from '../useCases/saveMeasurement'

import type { VectorLayerWithName } from '../../../domain/types/layer'
import type { MeasurementInProgress } from '@features/Measurement/types'
import type { Coordinate } from 'ol/coordinate'
import type Geometry from 'ol/geom/Geometry'
import type { Type } from 'ol/geom/Geometry'
import type Geometry from 'ol/geom/Geometry'
import type { MutableRefObject } from 'react'

const DRAW_START_EVENT = 'drawstart'
Expand All @@ -46,7 +43,7 @@ function UnmemoizedMeasurementLayer() {
measurementInProgressRef.current = value
_setMeasurementInProgress(value)
}
const [drawObject, setDrawObject] = useState<Draw | undefined>(undefined)
const currentInteraction = useRef<Draw | undefined>(undefined)

const vectorSourceRef = useRef() as MutableRefObject<VectorSource<Feature<Geometry>>>
const getVectorSource = useCallback(() => {
Expand Down Expand Up @@ -91,14 +88,16 @@ function UnmemoizedMeasurementLayer() {

useEffect(() => {
function drawExistingFeaturesOnMap() {
measurementsDrawed.forEach(measurement => {
const features = measurementsDrawed.map(measurement => {
const feature = new GeoJSON({
featureProjection: OPENLAYERS_PROJECTION
}).readFeature(measurement.geometry)

feature.setId(measurement.id)

getVectorSource().addFeature(feature)
return feature
})
getVectorSource().addFeatures(features)
}

getVectorSource().clear(true)
Expand All @@ -117,25 +116,76 @@ function UnmemoizedMeasurementLayer() {
})
}

function startDrawing(event) {
setMeasurementInProgress({
center: getCenter(event.feature.getGeometry().getExtent()),
coordinates: event.feature.getGeometry().getLastCoordinate(),
measurement: ''
})

return event.feature.getGeometry().on('change', changeEvent => {
function updateMeasurementOnNewPoint(geom) {
if (geom instanceof LineString) {
const nextMeasurementOutput = getNauticalMilesOfLine(geom)

setMeasurementInProgress({
coordinates: geom.getLastCoordinate(),
measurement: nextMeasurementOutput
})
} else if (geom instanceof Circle) {
const nextMeasurementOutput = getNauticalMilesRadiusOfCircle(geom)

setMeasurementInProgress({
center: getCenter(geom.getExtent()),
coordinates: geom.getLastCoordinate(),
measurement: nextMeasurementOutput
})
}
}

updateMeasurementOnNewPoint(changeEvent.target)
})
}

function drawNewFeatureOnMap() {
const draw = new Draw({
source: getVectorSource(),
style: [measurementStyle, measurementStyleWithCenter],
type: measurementTypeToAdd as Type
})
let listener

draw.on(DRAW_START_EVENT, event => {
listener = startDrawing(event)
})

draw.on(DRAW_ABORT_EVENT, () => {
unByKey(listener)
dispatch(resetMeasurementTypeToAdd())
setMeasurementInProgress(undefined)
})

draw.on(DRAW_END_EVENT, event => {
if (measurementInProgressRef.current?.measurement) {
dispatch(saveMeasurement(event.feature, measurementInProgressRef.current.measurement))
}

unByKey(listener)
dispatch(resetMeasurementTypeToAdd())
setMeasurementInProgress(undefined)
})

monitorfishMap.addInteraction(draw)
setDrawObject(draw)
currentInteraction.current = draw
}

addEmptyNextMeasurement()
drawNewFeatureOnMap()
}, [getVectorSource, measurementTypeToAdd])
}, [dispatch, getVectorSource, measurementTypeToAdd])

useEffect(() => {
function removeInteraction() {
if (!measurementTypeToAdd && drawObject) {
setDrawObject(undefined)
if (!measurementTypeToAdd) {
setMeasurementInProgress(undefined)

waitForUnwantedZoomAndQuitInteraction()
Expand All @@ -144,93 +194,19 @@ function UnmemoizedMeasurementLayer() {

function waitForUnwantedZoomAndQuitInteraction() {
setTimeout(() => {
if (drawObject) {
monitorfishMap.removeInteraction(drawObject)
if (currentInteraction.current) {
monitorfishMap.removeInteraction(currentInteraction.current)
currentInteraction.current = undefined
}
}, 300)
}

removeInteraction()
}, [measurementTypeToAdd, drawObject])

useEffect(() => {
function addCustomCircleMeasurement() {
const metersForOneNauticalMile = 1852
const longitude = 1
const latitude = 0
const numberOfVertices = 64

if (
!circleMeasurementHasCoordinatesAndRadiusFromForm() &&
!circleMeasurementHasRadiusFromFormAndCoordinatesFromDraw()
) {
return
}

function circleMeasurementHasCoordinatesAndRadiusFromForm() {
return circleMeasurementToAdd?.circleCoordinatesToAdd?.length === 2 && circleMeasurementToAdd?.circleRadiusToAdd
}

function circleMeasurementHasRadiusFromFormAndCoordinatesFromDraw() {
return circleMeasurementToAdd?.circleRadiusToAdd && measurementInProgress?.center?.length === 2
}

const radiusInMeters =
METERS_PER_UNIT.m * ((circleMeasurementToAdd?.circleRadiusToAdd ?? 0) as number) * metersForOneNauticalMile
let coordinates: Coordinate = []
if (circleMeasurementHasCoordinatesAndRadiusFromForm()) {
coordinates = [
circleMeasurementToAdd!.circleCoordinatesToAdd![longitude]!,
circleMeasurementToAdd!.circleCoordinatesToAdd![latitude]!
]
} else if (circleMeasurementHasRadiusFromFormAndCoordinatesFromDraw()) {
coordinates = transform(measurementInProgress!.center!, OPENLAYERS_PROJECTION, WSG84_PROJECTION)
}

const circleFeature = new Feature({
geometry: circular(coordinates, radiusInMeters, numberOfVertices).transform(
WSG84_PROJECTION,
OPENLAYERS_PROJECTION
),
style: [measurementStyle, measurementStyleWithCenter]
})
dispatch(saveMeasurement(circleFeature, `r = ${circleMeasurementToAdd?.circleRadiusToAdd} nm`))
}

addCustomCircleMeasurement()
}, [dispatch, circleMeasurementToAdd, measurementInProgress])
}, [measurementTypeToAdd])

useEffect(() => {
function handleDrawEvents() {
if (drawObject) {
let listener

drawObject.on(DRAW_START_EVENT, event => {
listener = startDrawing(event)
})

drawObject.on(DRAW_ABORT_EVENT, () => {
unByKey(listener)
dispatch(resetMeasurementTypeToAdd())
setMeasurementInProgress(undefined)
})

drawObject.on(DRAW_END_EVENT, event => {
if (measurementInProgressRef.current?.measurement) {
dispatch(saveMeasurement(event.feature, measurementInProgressRef.current.measurement))
}

unByKey(listener)
dispatch(resetMeasurementTypeToAdd())
setMeasurementInProgress(undefined)
})
}
}

handleDrawEvents()
// TODO startDrawing is re-created at each render, memoize it and add it to deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch, drawObject])
dispatch(addCustomCircleMeasurement(measurementInProgressRef.current))
}, [dispatch, circleMeasurementToAdd])

useEffect(() => {
if (measurementInProgress?.center || measurementInProgress?.measurement) {
Expand All @@ -252,37 +228,6 @@ function UnmemoizedMeasurementLayer() {
}
}

function startDrawing(event) {
setMeasurementInProgress({
center: getCenter(event.feature.getGeometry().getExtent()),
coordinates: event.feature.getGeometry().getLastCoordinate(),
measurement: ''
})

return event.feature.getGeometry().on('change', changeEvent => {
function updateMeasurementOnNewPoint(geom) {
if (geom instanceof LineString) {
const nextMeasurementOutput = getNauticalMilesOfLine(geom)

setMeasurementInProgress({
coordinates: geom.getLastCoordinate(),
measurement: nextMeasurementOutput
})
} else if (geom instanceof Circle) {
const nextMeasurementOutput = getNauticalMilesRadiusOfCircle(geom)

setMeasurementInProgress({
center: getCenter(geom.getExtent()),
coordinates: geom.getLastCoordinate(),
measurement: nextMeasurementOutput
})
}
}

updateMeasurementOnNewPoint(changeEvent.target)
})
}

return (
<>
{measurementsDrawed.map(measurement => (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { measurementStyle, measurementStyleWithCenter } from '@features/Measurement/layers/measurement.style'
import { saveMeasurement } from '@features/Measurement/useCases/saveMeasurement'
import Feature from 'ol/Feature'
import { circular } from 'ol/geom/Polygon'
import { METERS_PER_UNIT, transform } from 'ol/proj'

import { OPENLAYERS_PROJECTION, WSG84_PROJECTION } from '../../../domain/entities/map/constants'

import type { MeasurementInProgress } from '@features/Measurement/types'
import type { Coordinate } from 'ol/coordinate'

export const addCustomCircleMeasurement =
(measurementInProgress: MeasurementInProgress | undefined) => (dispatch, getState) => {
const { circleMeasurementToAdd } = getState().measurement
const metersForOneNauticalMile = 1852
const longitude = 1
const latitude = 0
const numberOfVertices = 64

if (
!circleMeasurementHasCoordinatesAndRadiusFromForm() &&
!circleMeasurementHasRadiusFromFormAndCoordinatesFromDraw()
) {
return
}

const radiusInMeters =
METERS_PER_UNIT.m * ((circleMeasurementToAdd?.circleRadiusToAdd ?? 0) as number) * metersForOneNauticalMile

let coordinates: Coordinate = []
if (circleMeasurementHasCoordinatesAndRadiusFromForm()) {
coordinates = [
circleMeasurementToAdd!.circleCoordinatesToAdd![longitude]!,
circleMeasurementToAdd!.circleCoordinatesToAdd![latitude]!
]
} else if (circleMeasurementHasRadiusFromFormAndCoordinatesFromDraw()) {
coordinates = transform(measurementInProgress!.center!, OPENLAYERS_PROJECTION, WSG84_PROJECTION)
}

const circleFeature = new Feature({
geometry: circular(coordinates, radiusInMeters, numberOfVertices).transform(
WSG84_PROJECTION,
OPENLAYERS_PROJECTION
),
style: [measurementStyle, measurementStyleWithCenter]
})

dispatch(saveMeasurement(circleFeature, `r = ${circleMeasurementToAdd?.circleRadiusToAdd} nm`))

function circleMeasurementHasCoordinatesAndRadiusFromForm() {
return circleMeasurementToAdd?.circleCoordinatesToAdd?.length === 2 && circleMeasurementToAdd?.circleRadiusToAdd
}

function circleMeasurementHasRadiusFromFormAndCoordinatesFromDraw() {
return circleMeasurementToAdd?.circleRadiusToAdd && measurementInProgress?.center?.length === 2
}
}

0 comments on commit a2ce0b1

Please sign in to comment.