Skip to content

Commit

Permalink
hardcode lasso solution for OAF layers (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
warm-coolguy committed Feb 18, 2025
1 parent 69fa0a4 commit 501ef82
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 66 deletions.
1 change: 1 addition & 0 deletions packages/plugins/Draw/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Feature: Add a `"translate"` mode that allows moving drawn features as they are.
- Feature: Add a `"snapTo"` key to the configuration that allows defining vector layers to snap to while drawing, editing, and translating.
- Feature: Add a lasso mode that allows copying up features from a vector layer that are contained within the user's hand drawn polygon. This feature is currently without UI and needs to be started from the outside, see docs.

## 3.0.0

Expand Down
2 changes: 2 additions & 0 deletions packages/plugins/Draw/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ draw: {

#### draw.lasso

This feature currently has no UI and can only be started with a programmatic `mapInstance.$store.dispatch('plugin/draw/setMode', 'lasso')` call.

| fieldName | type | description |
| - | - | - |
| id | string | The layer id of a vector layer to copy up vector features from. |
Expand Down
3 changes: 2 additions & 1 deletion packages/plugins/Draw/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"CHANGELOG.md"
],
"dependencies": {
"@turf/center-of-mass": "^7.2.0"
"@turf/center-of-mass": "^7.2.0",
"@polar/lib-get-features": "^3.0.0"
},
"peerDependencies": {
"@masterportal/masterportalapi": "2.45.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/Draw/src/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const resourcesDe = {
},
lasso: {
notInZoomRange:
'Der Layer "$t({{serviceName}})" wurde nicht für die Lasso-Funktion genutzt, da er auf der derzeitigen Zoomstufe nicht aktivierbar ist. Bitte zoomen Sie weiter rein.',
'Der Layer "$t({{serviceName}})" wurde nicht für die Lasso-Funktion genutzt, da er auf der derzeitigen Zoomstufe nicht aktivierbar ist. Bitte passen Sie die Zoomstufe an, um die Lasso-Funktion zu nutzen.',
},
},
},
Expand Down Expand Up @@ -90,7 +90,7 @@ export const resourcesEn = {
},
lasso: {
notInZoomRange:
'The layer "$t({{serviceName}})" was not used for the lasso as it is not activatable on the current zoom level. Please zoom in further.',
'The layer "$t({{serviceName}})" was not used for the lasso as it is not activatable on the current zoom level. Please change the zoom level to use the lasso.',
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,89 @@ import Draw from 'ol/interaction/Draw'
import Interaction from 'ol/interaction/Interaction'
import i18next from 'i18next'
import { rawLayerList } from '@masterportal/masterportalapi'
import { PolarActionContext } from '@polar/lib-custom-types'
import { MapConfig, PolarActionContext } from '@polar/lib-custom-types'
import { Dispatch } from 'vuex'
import { Feature, Map } from 'ol'
import { Polygon } from 'ol/geom'
import { getWfsFeatures } from '@polar/lib-get-features'

Check failure on line 9 in packages/plugins/Draw/src/store/createInteractions/createLassoInteractions.ts

View workflow job for this annotation

GitHub Actions / lint

'getWfsFeatures' is defined but never used

Check warning on line 9 in packages/plugins/Draw/src/store/createInteractions/createLassoInteractions.ts

View workflow job for this annotation

GitHub Actions / lint

'getWfsFeatures' is defined but never used
import { FeatureCollection, Feature as GeoJsonFeature } from 'geojson'
import { DrawGetters, DrawState } from '../../types'

const loaderKey = 'drawLasso'

// TODO un – refactor after done (actions/getters are mixed here)
/* eslint-disable max-lines-per-function */

const getLassoIdsInZoomRange = (
configuration: MapConfig,
zoomLevel: number,
dispatch: Dispatch
) =>
(configuration.draw?.lassos || []).reduce(
(accumulator, { id, minZoom = true }) => {
const layerConfig = configuration.layers?.find((layer) => id === layer.id)
const toastAction = configuration.draw?.toastAction || ''
if (
minZoom &&
layerConfig &&
typeof layerConfig.minZoom !== 'undefined' &&
zoomLevel < layerConfig.minZoom
) {
if (toastAction) {
dispatch(
toastAction,
{
type: 'info',
text: i18next.t('plugins.draw.lasso.notInZoomRange', {
serviceName: layerConfig.name || id,
}),
timeout: 10000,
},
{ root: true }
)
} else {
console.warn(
`Lasso not used with layer with id "${id}". (minZoom not reached)`
)
}
return accumulator
}
accumulator.push(id)
return accumulator
},
[] as string[]
)

const getLassoRequests = (
lassoIds: string[],
lasso: Feature<Polygon>,
map: Map
) =>
lassoIds.reduce((accumulator, id) => {
const serviceDefinition = rawLayerList.getLayerWhere({ id })

// TODO add WFS support
// getWfsFeatures(null, serviceDefinition.url, ) FILTER-ONLY atm

const [codeName, codeNumber] = map
.getView()
.getProjection()
.getCode()
.split(':')

const url = [
serviceDefinition.url,
'collections',
serviceDefinition.collection,
`items?f=json&limit=100&bbox=${lasso
.getGeometry()
?.getExtent()}&bbox-crs=http://www.opengis.net/def/crs/${codeName}/0/${codeNumber}&crs=http://www.opengis.net/def/crs/${codeName}/0/${codeNumber}`,
].join('/')

accumulator.push(fetch(url))
return accumulator
}, [] as Promise<Response>[])

/*
TODO use snippet to confirm the layer type worked on
const source = (
Expand All @@ -24,8 +102,40 @@ TODO use snippet to confirm the layer type worked on
}
*/

// TODO un – refactor after done
// eslint-disable-next-line max-lines-per-function
const handleSettledRequests = (
resolutions: PromiseSettledResult<Response>[],
dispatch: Dispatch

Check warning on line 107 in packages/plugins/Draw/src/store/createInteractions/createLassoInteractions.ts

View workflow job for this annotation

GitHub Actions / lint

'dispatch' is defined but never used
) =>
Promise.all(
(
resolutions.filter((promiseSettledResult) => {
if (promiseSettledResult.status === 'rejected') {
console.error(promiseSettledResult.reason)
// TODO toast
return false
}
return true
}) as PromiseFulfilledResult<Response>[]
).map(
async (resolution) => (await resolution.value.json()) as FeatureCollection
)
)

const handleFulfilledRequests = (
featureCollections: FeatureCollection[],
dispatch: Dispatch
) =>
dispatch('addFeatures', {
geoJSON: {
type: 'FeatureCollection',
features: featureCollections.reduce(
(accumulator, { features }) => accumulator.concat(features),
[] as GeoJsonFeature[]
),
},
// TODO filter with drawnLasso
})

export default function ({
rootGetters,
commit,
Expand All @@ -36,65 +146,29 @@ export default function ({
freehand: true,
})
const { addLoading, removeLoading } = rootGetters.configuration?.draw || {}
// TODO un
// eslint-disable-next-line max-lines-per-function
draw.on('drawend', (e) => {
dispatch('setMode', 'none')

const drawnLasso = e.feature
const lassos = rootGetters.configuration.draw?.lassos || []
const toastAction = rootGetters.configuration.draw?.toastAction || ''
const promises = lassos.reduce((accumulator, { id, minZoom = true }) => {
const layerConfig = rootGetters.configuration.layers?.find(
(layer) => id === layer.id
)
if (
minZoom &&
layerConfig &&
typeof layerConfig.minZoom !== 'undefined' &&
rootGetters.zoomLevel < layerConfig.minZoom
) {
if (toastAction) {
dispatch(toastAction, {
type: 'info',
text: i18next.t('plugins.draw.lasso.notInZoomRange', {
serviceName: layerConfig.name || id,
}),
timeout: 10000,
})
} else {
console.warn(
`Lasso not used with layer with id "${id}". (minZoom not reached)`
)
}
return accumulator
}
const serviceDefinition = rawLayerList.getLayerWhere({ id })

// TODO implement for OAF, use existing getFeatures for WFS
// https://api.hamburg.de/datasets/v1/alkis_vereinfacht/collections/Flurstueck/items?f=json&limit=10&bbox=10.0872,53.5357,10.0883,53.5362

accumulator.push(new Promise(() => ({})))
return accumulator
}, [] as Promise<object>[])

Promise.all(promises)
.then((resolutions) => {
if (addLoading) {
commit(addLoading, loaderKey, { root: true })
}

// TODO parse resolutions
// TODO filter with drawnLasso (we're probably just loading by bbox?)
// TODO add as geoJSON to draw

console.warn(resolutions)
const drawnLasso = e.feature as Feature<Polygon> // due to Draw 'type' param
const lassoIds = getLassoIdsInZoomRange(
rootGetters.configuration,
rootGetters.zoomLevel,
dispatch
)
const requests = getLassoRequests(lassoIds, drawnLasso, rootGetters.map)

dispatch('addFeatures', { geoJSON: {} })
})
.catch(() => {
/* TODO at least toast something */
})
if (addLoading) {
commit(addLoading, loaderKey, { root: true })
}
Promise.allSettled(requests)
.then((settledRequests) =>
handleSettledRequests(settledRequests, dispatch)
)
.then((fulfilledRequests) =>
handleFulfilledRequests(fulfilledRequests, dispatch)
)
// TODO add toast, unexpected catastrophic error
.catch(console.error)
.finally(
() => removeLoading && commit(removeLoading, loaderKey, { root: true })
)
Expand Down
2 changes: 1 addition & 1 deletion packages/types/custom/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## unpublished

- Feature: Add `snapTo` to `DrawConfiguration` for specification of layers to snap to.
- Feature: Add `lassos` to `DrawConfiguration`. With this, `addLoading`, `removeLoading`, and `toastAction` have also been introduced to allow the feature to use other plugins via API calls.
- Feature: Add `lassos` to `DrawConfiguration`. With this, `addLoading`, `removeLoading`, and `toastAction` have also been introduced to allow the feature to use other plugins via API calls, and `Lasso` itself has been introduced.

## 2.0.0

Expand Down
10 changes: 6 additions & 4 deletions packages/types/custom/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,15 @@ export interface MeasureOptions {
initialOption?: MeasureMode
}

export interface Lasso {
id: string
minZoom: boolean
}

export interface DrawConfiguration extends Partial<PluginOptions> {
addLoading?: string
enableOptions?: boolean
lassos?: {
id: string
minZoom: boolean
}[]
lassos?: Lasso[]
measureOptions?: MeasureOptions
removeLoading?: string
selectableDrawModes?: DrawMode[]
Expand Down

0 comments on commit 501ef82

Please sign in to comment.