Skip to content

Commit

Permalink
Merge pull request #166 from Dataport/feature/geolocation-outside-ext…
Browse files Browse the repository at this point in the history
…ent-or-boundary

Feature/geolocation outside extent or boundary
  • Loading branch information
jedi-of-the-sea authored Sep 27, 2024
2 parents f070459 + 56c8be9 commit 0bcbe9a
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 30 deletions.
1 change: 1 addition & 0 deletions packages/plugins/GeoLocation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## unpublished

- Feature: Position is now tracked when user is outside of the boundary layer but inside the map extent.
- Fix: Adjust documentation to properly describe optionality of configuration parameters.
- Fix: Add missing peerDependency `ol@^9.2.4`.

Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/GeoLocation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ either `true` or `false`. When a users denies the location tracking, the button

| fieldName | type | description |
| - | - | - |
| boundaryLayerId | string? | Id of a vector layer to restrict geolocation markers and zooms to. When geolocation outside of its features occurs, an information will be shown once and the feature is stopped. The map will wait at most 10s for the layer to load; should it not happen, the geolocation feature is turned off. |
| boundaryLayerId | string? | Id of a vector layer to restrict geolocation markers and zooms to. When geolocation outside of its features occurs, a single information will be shown. When loading the boundary layer, the map will wait at most 10s; should it not happen, the geolocation feature is turned off. |
| boundaryOnError | ('strict' \| 'permissive')? | If the boundary layer check does not work due to loading or configuration errors, style `'strict'` will disable the geolocation feature, and style `'permissive'` will act as if no boundaryLayerId was set. Defaults to `'permissive'`. |
| checkLocationInitially | boolean? | If `true` the location gets checked on page load. When `false` this can be triggered with a button. Defaults to `false`. |
| keepCentered | boolean? | If `true`, the map will re-center on the user on any position change. If `false`, only the first position will be centered on. Defaults to `false`. |
Expand Down
63 changes: 35 additions & 28 deletions packages/plugins/GeoLocation/src/store/actions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable max-lines-per-function */
import { PolarActionTree } from '@polar/lib-custom-types'
import { passesBoundaryCheck } from '@polar/lib-passes-boundary-check'
import VectorLayer from 'ol/layer/Vector'
import Point from 'ol/geom/Point'
import { Vector } from 'ol/source'
Expand All @@ -11,8 +11,12 @@ import Geolocation from 'ol/Geolocation.js'
import { transform as transformCoordinates } from 'ol/proj'
import Overlay from 'ol/Overlay'
import { getTooltip } from '@polar/lib-tooltip'
import { passesBoundaryCheck } from '@polar/lib-passes-boundary-check'
import { GeoLocationState, GeoLocationGetters } from '../types'
import geoLocationMarker from '../assets/geoLocationMarker'
import positionChanged from '../utils/positionChanged'

let boundaryCheckChanged = true

const actions: PolarActionTree<GeoLocationState, GeoLocationGetters> = {
setupModule({ getters, commit, dispatch }): void {
Expand Down Expand Up @@ -118,11 +122,12 @@ const actions: PolarActionTree<GeoLocationState, GeoLocationGetters> = {
async positioning({
rootGetters: { map, configuration },
getters: {
boundaryLayerId,
boundaryOnError,
boundaryLayerId,
geolocation,
configuredEpsg,
position,
boundaryCheck,
},
commit,
dispatch,
Expand All @@ -132,38 +137,36 @@ const actions: PolarActionTree<GeoLocationState, GeoLocationGetters> = {
Proj.get('EPSG:4326') as Proj.Projection,
configuredEpsg
)

const boundaryCheckPassed =
typeof boundaryLayerId === 'string'
? await passesBoundaryCheck(map, boundaryLayerId, transformedCoords)
: containsCoordinate(
// NOTE: The fallback is the default value set by @masterportal/masterportalapi
configuration?.extent || [510000.0, 5850000.0, 625000.4, 6000000.0],
transformedCoords
)
const boundaryErrorOccurred = typeof boundaryCheckPassed === 'symbol'

if (
boundaryCheckPassed === false ||
(boundaryErrorOccurred && boundaryOnError !== 'permissive')
) {
dispatch('printPositioningFailed', boundaryErrorOccurred)
// if check initially breaks or user leaves boundary, turn off tracking
const coordinateInExtent = containsCoordinate(
// NOTE: The fallback is the default value set by @masterportal/masterportalApi
configuration?.extent || [510000.0, 5850000.0, 625000.4, 6000000.0],
transformedCoords
)
const boundaryCheckPassed = await passesBoundaryCheck(
map,
boundaryLayerId,
transformedCoords
)
boundaryCheckChanged = boundaryCheck !== boundaryCheckPassed
commit('setBoundaryCheck', boundaryCheckPassed)
const showBoundaryLayerError =
typeof boundaryCheckPassed === 'symbol' && boundaryOnError === 'strict'
if (!coordinateInExtent || showBoundaryLayerError) {
dispatch('printPositioningFailed', showBoundaryLayerError)
dispatch('untrack')
return
}

if (
position[0] !== transformedCoords[0] ||
position[1] !== transformedCoords[1]
) {
if (positionChanged(position, transformedCoords)) {
commit('setPosition', transformedCoords)
dispatch('addMarker', transformedCoords)
if (boundaryCheckChanged && !boundaryCheckPassed) {
dispatch('printPositioningFailed', false)
}
}
},
printPositioningFailed(
{ dispatch, getters: { toastAction } },
boundaryErrorOccurred: string
boundaryErrorOccurred: boolean
) {
if (toastAction) {
const toast = boundaryErrorOccurred
Expand Down Expand Up @@ -194,7 +197,12 @@ const actions: PolarActionTree<GeoLocationState, GeoLocationGetters> = {
*/
addMarker(
{
getters: { geoLocationMarkerLayer, markerFeature, keepCentered },
getters: {
geoLocationMarkerLayer,
markerFeature,
keepCentered,
boundaryCheck,
},
dispatch,
},
coordinates
Expand All @@ -213,8 +221,7 @@ const actions: PolarActionTree<GeoLocationState, GeoLocationGetters> = {
}),
})
)

if (keepCentered || !hadPosition) {
if ((keepCentered || !hadPosition) && boundaryCheck) {
dispatch('zoomAndCenter')
}
},
Expand Down
1 change: 1 addition & 0 deletions packages/plugins/GeoLocation/src/store/getInitialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const getInitialState = (): GeoLocationState => ({
position: [],
tracking: false,
isGeolocationDenied: false,
boundaryCheck: null,
})

export default getInitialState
2 changes: 1 addition & 1 deletion packages/plugins/GeoLocation/src/store/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const getters: PolarGetterTree<GeoLocationState, GeoLocationGetters> = {
return rootGetters.configuration?.geoLocation?.toastAction
},
zoomLevel: (_, __, ___, rootGetters): number => {
return rootGetters.configuration?.geoLocation?.zoomLevel || 7
return rootGetters.configuration?.geoLocation?.zoomLevel ?? 7
},
geoLocationMarkerLayer(_, __, ___, rootGetters) {
return rootGetters?.map
Expand Down
1 change: 1 addition & 0 deletions packages/plugins/GeoLocation/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface GeoLocationState {
position: number[]
tracking: boolean
isGeolocationDenied: boolean
boundaryCheck: boolean | symbol | null
}

export interface GeoLocationGetters extends GeoLocationState {
Expand Down
6 changes: 6 additions & 0 deletions packages/plugins/GeoLocation/src/utils/positionChanged.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default function positionChanged(
oldPosition: number[],
newPosition: number[]
): boolean {
return oldPosition[0] !== newPosition[0] || oldPosition[1] !== newPosition[1]
}

0 comments on commit 0bcbe9a

Please sign in to comment.