Skip to content

Commit e5ba9ba

Browse files
committed
refactor lasso, centralize service requests
1 parent 5bc9014 commit e5ba9ba

File tree

7 files changed

+175
-149
lines changed

7 files changed

+175
-149
lines changed

packages/lib/getFeatures/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG
22

3+
## unpublished
4+
5+
- Feature: Add new methods `getVectorFeaturesByBboxRequest` and `getVectorFeaturesByFeatureRequest` that support both WFS and OAF layers.
6+
37
## 3.0.0
48

59
- Breaking: Upgrade peerDependency `ol` from `^9.2.4` to `^10.3.1`.

packages/lib/getFeatures/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
export * from './types'
22
export { getWfsFeatures } from './wfs'
3+
export {
4+
getVectorFeaturesByBboxRequest,
5+
getVectorFeaturesByFeatureRequest,
6+
} from './vector'
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { rawLayerList } from '@masterportal/masterportalapi'
2+
import { Feature } from 'ol'
3+
4+
const supportedFormats = ['OAF', 'WFS']
5+
6+
export const getVectorFeaturesByBboxRequest = ({
7+
bbox,
8+
fetchLayerId,
9+
projectionCode,
10+
}: {
11+
bbox: number[]
12+
fetchLayerId: string
13+
projectionCode: string
14+
}) => {
15+
const serviceDefinition = rawLayerList.getLayerWhere({ id: fetchLayerId })
16+
if (!supportedFormats.includes(serviceDefinition.typ)) {
17+
throw new Error(
18+
`@polar/lib-get-features#getVectorFeaturesByBboxRequest: Layer with ID "${fetchLayerId}" of type "${serviceDefinition.typ}" used to retrieve vector data, but is not within the range of supported types [${supportedFormats}].`
19+
)
20+
}
21+
22+
const [codeName, codeNumber] = projectionCode.split(':')
23+
24+
const url =
25+
serviceDefinition.typ === 'OAF'
26+
? [
27+
serviceDefinition.url,
28+
'collections',
29+
serviceDefinition.collection,
30+
`items?f=json&limit=100&bbox=${bbox}&bbox-crs=http://www.opengis.net/def/crs/${codeName}/0/${codeNumber}&crs=http://www.opengis.net/def/crs/${codeName}/0/${codeNumber}`,
31+
].join('/')
32+
: `${serviceDefinition.url}${[
33+
`?service=${serviceDefinition.typ}`,
34+
`version=${serviceDefinition.version}`,
35+
`request=GetFeature`,
36+
`srsName=${projectionCode}`,
37+
`typeName=${serviceDefinition.featureType}`,
38+
`bbox=${bbox},${projectionCode}`,
39+
].join('&')}`
40+
41+
return fetch(url)
42+
}
43+
44+
export const getVectorFeaturesByFeatureRequest = ({
45+
feature,
46+
fetchLayerId,
47+
projectionCode,
48+
}: {
49+
feature: Feature
50+
fetchLayerId: string
51+
projectionCode: string
52+
}) => {
53+
const bbox = feature.getGeometry()?.getExtent?.()
54+
55+
if (typeof bbox === 'undefined') {
56+
throw new Error(
57+
'@polar/lib-get-features#getVectorFeaturesByFeatureRequest: Given feature had no extent.'
58+
)
59+
}
60+
61+
return getVectorFeaturesByBboxRequest({
62+
bbox,
63+
fetchLayerId,
64+
projectionCode,
65+
})
66+
}

packages/plugins/Draw/src/locales.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ export const resourcesDe = {
4444
lasso: {
4545
layerRejected:
4646
'Die Antwort des Layers "{{id}}" konnte nicht gelesen werden. Es wurden keine Geometrien aus diesem Layer bezogen.',
47-
notInZoomRange:
48-
'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.',
49-
fatalError:
47+
internalError:
5048
'Ein unerwarteter Fehler ist in der Verarbeitung der Lasso-Daten aufgetreten.',
5149
},
5250
},
@@ -97,9 +95,7 @@ export const resourcesEn = {
9795
lasso: {
9896
layerRejected:
9997
'The response of layer "{{id}}" could not be read. No geometries were fetched from that layer.',
100-
notInZoomRange:
101-
'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.',
102-
fatalError:
98+
internalError:
10399
'An unexpected error occured in the processing of lasso data.',
104100
},
105101
},

packages/plugins/Draw/src/store/createInteractions/createLassoInteractions.ts

Lines changed: 77 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import Draw from 'ol/interaction/Draw'
2-
import Interaction from 'ol/interaction/Interaction'
32
import i18next from 'i18next'
43
import { GeoJSON } from 'ol/format'
54
import { booleanContains } from '@turf/boolean-contains'
@@ -9,186 +8,121 @@ import { Feature } from 'ol'
98
import { Polygon } from 'ol/geom'
109
import { parseWfsResponse } from '@polar/lib-get-features/wfs/parse'
1110
import { FeatureCollection, Feature as GeoJsonFeature } from 'geojson'
12-
import VectorLayer from 'ol/layer/Vector'
13-
import VectorSource from 'ol/source/Vector'
11+
import { getVectorFeaturesByFeatureRequest } from '@polar/lib-get-features'
1412
import { DrawGetters, DrawState } from '../../types'
1513

16-
const loaderKey = 'drawLasso'
17-
const supportedFormats = ['OAF', 'WFS']
14+
let loaderKeyCounter = 0
15+
const loaderKeyBase = 'draw-lasso-load'
1816

19-
// TODO un – refactor after done (actions/getters are mixed here)
20-
/* eslint-disable max-lines-per-function */
17+
const requestError = `@polar/plugin-draw: An error occurred on creating the lasso request: `
18+
const rejectedError =
19+
'@polar/plugin-draw: The response to a lasso request indicated an error.'
20+
const parseError =
21+
'@polar/plugin-draw: Client failure in reading responses in lasso action.'
22+
const internalError = () => ({
23+
type: 'error',
24+
text: i18next.t('plugins.draw.lasso.internalError'),
25+
})
2126

27+
const buildAddFeaturesPayload = (
28+
featureCollections: FeatureCollection[],
29+
drawnLasso: Feature
30+
) => ({
31+
geoJSON: {
32+
type: 'FeatureCollection',
33+
features: featureCollections
34+
.reduce(
35+
(accumulator, { features }) => accumulator.concat(features),
36+
[] as GeoJsonFeature[]
37+
)
38+
.filter((feature) =>
39+
booleanContains(
40+
JSON.parse(new GeoJSON().writeFeature(drawnLasso)),
41+
feature
42+
)
43+
),
44+
},
45+
})
46+
47+
// should be fine, surrounding method is only unpacking/packing, also see below
48+
// eslint-disable-next-line max-lines-per-function
2249
export default function ({
2350
rootGetters,
51+
getters,
2452
commit,
2553
dispatch,
26-
}: PolarActionContext<DrawState, DrawGetters>): Interaction[] {
27-
const draw = new Draw({
28-
type: 'Polygon',
29-
freehand: true,
30-
})
31-
const { addLoading, removeLoading } = rootGetters.configuration?.draw || {}
32-
const toastAction = rootGetters.configuration.draw?.toastAction || ''
54+
}: PolarActionContext<DrawState, DrawGetters>) {
55+
const draw = new Draw({ type: 'Polygon', freehand: true })
56+
57+
// should be fine, line bloat is from error handling (only logging/toasting)
58+
// eslint-disable-next-line max-lines-per-function
3359
draw.on('drawend', (e) => {
3460
dispatch('setMode', 'none')
3561

62+
const toast = (toastObject) =>
63+
getters.toastAction &&
64+
dispatch(getters.toastAction, toastObject, { root: true })
3665
const drawnLasso = e.feature as Feature<Polygon> // due to Draw 'type' param
37-
const drawnLassoAsGeoJson = JSON.parse(
38-
new GeoJSON().writeFeature(drawnLasso)
39-
)
40-
const lassoIds = (rootGetters.configuration.draw?.lassos || []).reduce(
41-
(accumulator, { id, minZoom = true }) => {
42-
const layerConfig = rootGetters.configuration.layers?.find(
43-
(layer) => id === layer.id
44-
)
45-
if (
46-
minZoom &&
47-
layerConfig &&
48-
typeof layerConfig.minZoom !== 'undefined' &&
49-
rootGetters.zoomLevel < layerConfig.minZoom
50-
) {
51-
if (toastAction) {
52-
dispatch(
53-
toastAction,
54-
{
55-
type: 'info',
56-
text: i18next.t('plugins.draw.lasso.notInZoomRange', {
57-
serviceName: layerConfig.name || id,
58-
}),
59-
timeout: 10000,
60-
},
61-
{ root: true }
62-
)
63-
} else {
64-
console.warn(
65-
`Lasso not used with layer with id "${id}". (minZoom not reached)`
66-
)
67-
}
68-
return accumulator
69-
}
70-
accumulator.push(id)
71-
return accumulator
72-
},
73-
[] as string[]
74-
)
75-
const requests = lassoIds.reduce((accumulator, id) => {
76-
const serviceDefinition = rawLayerList.getLayerWhere({ id })
77-
if (!supportedFormats.includes(serviceDefinition.typ)) {
78-
console.warn(
79-
`@polar/plugin-draw: Layer with ID "${id} configured for 'lasso, but it's not a supported format. Layer is of type "${serviceDefinition.typ}", but only [${supportedFormats}] are supported.`
80-
)
81-
return accumulator
82-
}
83-
84-
const source = (
85-
rootGetters.map
86-
.getLayers()
87-
.getArray()
88-
.find((layer) => layer.get('id') === id) as VectorLayer
89-
)?.getSource?.()
90-
if (!(source instanceof VectorSource)) {
91-
console.warn(
92-
`@polar/plugin-draw: Layer with ID "${id}" configured for 'lasso', but it has no vector source. The layer does probably not hold any vector data and is skipped.`
93-
)
94-
return accumulator
66+
const requests = getters.activeLassoIds.reduce((accumulator, id) => {
67+
try {
68+
const request = getVectorFeaturesByFeatureRequest({
69+
feature: drawnLasso,
70+
fetchLayerId: id,
71+
projectionCode: rootGetters.map.getView().getProjection().getCode(),
72+
})
73+
accumulator.push(request)
74+
} catch (e) {
75+
console.error(requestError, e)
76+
toast(internalError())
9577
}
96-
97-
const code = rootGetters.map.getView().getProjection().getCode()
98-
const [codeName, codeNumber] = code.split(':')
99-
100-
const url =
101-
serviceDefinition.typ === 'OAF'
102-
? [
103-
serviceDefinition.url,
104-
'collections',
105-
serviceDefinition.collection,
106-
`items?f=json&limit=100&bbox=${drawnLasso
107-
.getGeometry()
108-
?.getExtent()}&bbox-crs=http://www.opengis.net/def/crs/${codeName}/0/${codeNumber}&crs=http://www.opengis.net/def/crs/${codeName}/0/${codeNumber}`,
109-
].join('/')
110-
: `${serviceDefinition.url}${[
111-
`?service=${serviceDefinition.typ}`,
112-
`version=${serviceDefinition.version}`,
113-
`request=GetFeature`,
114-
`srsName=${code}`,
115-
`typeName=${serviceDefinition.featureType}`,
116-
`bbox=${drawnLasso.getGeometry()?.getExtent()},${code}`,
117-
].join('&')}`
118-
119-
accumulator.push(fetch(url))
12078
return accumulator
12179
}, [] as Promise<Response>[])
12280

123-
if (addLoading) {
124-
commit(addLoading, loaderKey, { root: true })
81+
let loaderKey
82+
if (getters.configuration.addLoading) {
83+
loaderKey = `${loaderKeyBase}-${loaderKeyCounter++}`
84+
commit(getters.configuration.addLoading, loaderKey, { root: true })
12585
}
86+
12687
Promise.allSettled(requests)
12788
.then((settledRequests) =>
12889
Promise.all(
12990
(
13091
settledRequests.filter((promiseSettledResult, index) => {
13192
if (promiseSettledResult.status === 'rejected') {
132-
console.error(
133-
'@polar/plugin-draw: Error during reading lasso response from layer.',
134-
promiseSettledResult.reason
135-
)
136-
if (toastAction) {
137-
dispatch(
138-
toastAction,
139-
{
140-
type: 'error',
141-
text: i18next.t('plugins.draw.lasso.layerRejected', {
142-
id: lassoIds[index],
143-
}),
144-
},
145-
{ root: true }
146-
)
147-
}
93+
console.error(rejectedError, promiseSettledResult.reason)
94+
toast({
95+
type: 'error',
96+
text: i18next.t('plugins.draw.lasso.layerRejected', {
97+
id: getters.activeLassoIds[index],
98+
}),
99+
})
148100
return false
149101
}
150102
return true
151103
}) as PromiseFulfilledResult<Response>[]
152104
).map(async (resolution, index) =>
153-
rawLayerList.getLayerWhere({ id: lassoIds[index] }).typ === 'WFS'
105+
rawLayerList.getLayerWhere({ id: getters.activeLassoIds[index] })
106+
.typ === 'WFS'
154107
? await parseWfsResponse(resolution.value, undefined, false)
155108
: ((await resolution.value.json()) as FeatureCollection)
156109
)
157110
)
158111
)
159112
.then((featureCollections) =>
160-
dispatch('addFeatures', {
161-
geoJSON: {
162-
type: 'FeatureCollection',
163-
features: featureCollections
164-
.reduce(
165-
(accumulator, { features }) => accumulator.concat(features),
166-
[] as GeoJsonFeature[]
167-
)
168-
.filter((feature) =>
169-
booleanContains(drawnLassoAsGeoJson, feature)
170-
),
171-
},
172-
})
113+
dispatch(
114+
'addFeatures',
115+
buildAddFeaturesPayload(featureCollections, drawnLasso)
116+
)
173117
)
174118
.catch((error) => {
175-
console.error(
176-
'@polar/plugin-draw: Client failure in reading responses in lasso action.',
177-
error
178-
)
179-
if (toastAction) {
180-
dispatch(
181-
toastAction,
182-
{
183-
type: 'error',
184-
text: i18next.t('plugins.draw.lasso.fatalError'),
185-
},
186-
{ root: true }
187-
)
188-
}
119+
console.error(parseError, error)
120+
toast(internalError())
189121
})
190122
.finally(
191-
() => removeLoading && commit(removeLoading, loaderKey, { root: true })
123+
() =>
124+
getters.configuration.removeLoading &&
125+
commit(getters.configuration.removeLoading, loaderKey, { root: true })
192126
)
193127
})
194128

0 commit comments

Comments
 (0)