Skip to content

Commit 521a46c

Browse files
authored
Merge pull request #237 from Dataport/feature/add-snapTo-mode-to-draw
Feature/add snap to mode to draw
2 parents ea6f796 + c84fd1e commit 521a46c

File tree

17 files changed

+199
-53
lines changed

17 files changed

+199
-53
lines changed

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/clients/diplan/example/config.js

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// service id map to avoid typos, ease renames
22
const basemap = 'basemapde_farbe'
3-
const xplanwms = '1111'
4-
const xplanwfs = '1112'
3+
const xplanwms = 'xplanwms'
4+
const xplanwfs = 'xplanwfs'
5+
const flurstuecke = 'flurstuecke'
56

67
export default {
78
startResolution: 264.583190458,
@@ -18,11 +19,13 @@ export default {
1819
[basemap]: 'BasemapDE',
1920
[xplanwms]: 'XPlanWMS',
2021
[xplanwfs]: 'XPlanSynWFS',
22+
[flurstuecke]: 'Flurstücke',
2123
},
2224
attributions: {
2325
[basemap]: `$t(diplan.layers.${basemap}) © GeoBasis-DE / BKG <YEAR> CC BY 4.0`,
2426
[xplanwms]: `$t(diplan.layers.${xplanwms}) © ???`,
2527
[xplanwfs]: `$t(diplan.layers.${xplanwfs}) © ???`,
28+
[flurstuecke]: `$t(diplan.layers.${flurstuecke}) © ???`,
2629
},
2730
},
2831
},
@@ -60,10 +63,18 @@ export default {
6063
},
6164
{
6265
id: xplanwfs,
63-
visibility: true,
66+
visibility: false,
6467
type: 'mask',
6568
name: `diplan.layers.${xplanwfs}`,
6669
},
70+
{
71+
id: flurstuecke,
72+
visibility: false,
73+
// TODO available from 7, but only starts loading from 8 - bug or skill issue?
74+
minZoom: 7,
75+
type: 'mask',
76+
name: `diplan.layers.${flurstuecke}`,
77+
},
6778
],
6879
attributions: {
6980
layerAttributions: [
@@ -79,8 +90,39 @@ export default {
7990
id: xplanwfs,
8091
title: `diplan.attributions.${xplanwfs}`,
8192
},
93+
{
94+
id: flurstuecke,
95+
title: `diplan.attributions.${flurstuecke}`,
96+
},
8297
],
8398
},
99+
draw: {
100+
enableOptions: true,
101+
measureOptions: {
102+
metres: true,
103+
kilometres: true,
104+
hectares: true,
105+
},
106+
selectableDrawModes: ['Point', 'LineString', 'Circle', 'Text', 'Polygon'],
107+
snapTo: [xplanwfs, flurstuecke],
108+
textStyle: {
109+
font: {
110+
size: [10, 20, 30],
111+
family: 'Arial',
112+
},
113+
},
114+
style: {
115+
fill: { color: 'rgb(51 117 212 / 50%)' },
116+
stroke: {
117+
color: '#3375d4',
118+
width: 2,
119+
},
120+
circle: {
121+
radius: 7,
122+
fillColor: 'rgb(51 117 212 / 50%)',
123+
},
124+
},
125+
},
84126
export: {
85127
displayComponent: true,
86128
showJpg: false,

packages/clients/diplan/example/services.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
export default [
77
{
88
visibility: true,
9-
id: '1111',
9+
id: 'xplanwms',
1010
name: 'XPlanWMS',
1111
url: 'https://hh-qs.xplanungsplattform.de/xplan-wms/services/wms',
1212
typ: 'WMS',
@@ -137,7 +137,7 @@ export default [
137137
},
138138
{
139139
visibility: false,
140-
id: '1112',
140+
id: 'xplanwfs',
141141
name: 'XPlanSynWFS',
142142
url: 'https://hh-qs.xplanungsplattform.de/xplansyn-wfs/services/xplansynwfs',
143143
typ: 'WFS',
@@ -442,4 +442,13 @@ export default [
442442
legend: true,
443443
featureCount: 1,
444444
},
445+
{
446+
id: 'flurstuecke',
447+
typ: 'OAF',
448+
name: 'Flurstueck',
449+
url: 'https://api.hamburg.de/datasets/v1/alkis_vereinfacht',
450+
collection: 'Flurstueck',
451+
crs: 'http://www.opengis.net/def/crs/EPSG/0/25832',
452+
bboxCrs: 'http://www.opengis.net/def/crs/EPSG/0/25832',
453+
},
445454
]

packages/clients/diplan/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@polar/plugin-attributions": "^1.4.0",
4040
"@polar/plugin-draw": "^3.0.0",
4141
"@polar/plugin-export": "^1.2.2",
42+
"@polar/plugin-fullscreen": "^1.2.3",
4243
"@polar/plugin-gfi": "^3.0.0",
4344
"@polar/plugin-icon-menu": "^1.3.1",
4445
"@polar/plugin-layer-chooser": "^2.0.0",

packages/clients/diplan/src/polar-client.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import AddressSearch from '@polar/plugin-address-search'
33
import Attributions from '@polar/plugin-attributions'
44
import Draw from '@polar/plugin-draw'
55
import Export from '@polar/plugin-export'
6+
import Fullscreen from '@polar/plugin-fullscreen'
67
import Gfi from '@polar/plugin-gfi'
78
import IconMenu from '@polar/plugin-icon-menu'
89
import LayerChooser from '@polar/plugin-layer-chooser'
@@ -45,6 +46,11 @@ polarCore.addPlugins([
4546
icon: '$vuetify.icons.ruler',
4647
id: 'draw',
4748
},
49+
{
50+
plugin: Fullscreen({ renderType: 'iconMenu' }),
51+
// TODO icon: '$vuetify.icons.fullscreen',
52+
id: 'fullscreen',
53+
},
4854
{
4955
plugin: Zoom({
5056
renderType: 'iconMenu',

packages/core/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ Whitelisted and confirmed parameters include:
342342
- WMS: id, name, url, typ, format, version, transparent, layers, STYLES
343343
- WFS: id, name, url, typ, outputFormat, version, featureType
344344
- WMTS: id, name, urls, typ, capabilitiesUrl, optionsFromCapabilities, tileMatrixSet, layers, legendURL, format, coordinateSystem, origin, transparent, tileSize, minScale, maxScale, requestEncoding, resLength
345+
- OAF: id, name, url, typ, collection, crs, bboxCrs
345346
- GeoJSON: id, name, url, typ, version, minScale, maxScale, legendURL
346347

347348
###### Example services register
@@ -396,6 +397,16 @@ Whitelisted and confirmed parameters include:
396397
"layers": "layer-name",
397398
"legendURL": "my-legend-url"
398399
},
400+
{
401+
"id": "oaf",
402+
"typ": "OAF",
403+
"name": "My OAF",
404+
"url": "https://api.hamburg.de/datasets/v1/stadtgruen",
405+
"collection": "poi",
406+
"crs": "http://www.opengis.net/def/crs/EPSG/0/25832",
407+
"bboxCrs": "http://www.opengis.net/def/crs/EPSG/0/25832",
408+
"gfiTheme": "default",
409+
},
399410
{
400411
"id": "my-geojson",
401412
"name": "My GeoJSON data",

packages/plugins/Draw/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## unpublished
44

5-
- Feature: Add a "Translate" mode that allows moving drawn features as they are.
5+
- Feature: Add a `"translate"` mode that allows moving drawn features as they are.
6+
- Feature: Add a `"snapTo"` key to the configuration that allows defining vector layers to snap to while drawing, editing, and translating.
67

78
## 3.0.0
89

packages/plugins/Draw/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ The styling of the drawn features can be configured to overwrite the default ol-
3636
| enableOptions | boolean? | If `true`, draw options are displayed, like choosing and changing stroke color. Not available for texts features. Defaults to `false`. |
3737
| measureOptions | measureOptions? | If set, an additional radio is being shown to the user to be able to let the (then) drawn features display their length and / or area. See [draw.measureOptions](#drawmeasureoptions) for further information. Not shown by default. |
3838
| selectableDrawModes | string[]? | List 'Point', 'LineString', 'Circle', 'Text' and/or 'Polygon' as desired. All besides 'Text' are selectable by default. |
39+
| snapTo | string[]? | Accepts an array of layer IDs. If these layers are active, they are used as snapping material for geometry manipulation. The Draw layer will also always snap to its own features regardless. Please mind that used layers must provide vector data. The layers referred to must be configured in `mapConfiguration.layers`. |
3940
| style | style? | Please see example below for styling options. Defaults to standard OpenLayers styling. |
4041
| textStyle | textStyle? | Use this object with properties 'font' and 'textColor' to style text feature. |
4142

packages/plugins/Draw/src/store/actions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import { createTextStyle } from '../utils/createTextStyle'
99
import createDrawStyle from '../utils/createDrawStyle'
1010
import createInteractions from './createInteractions'
1111
import createModifyInteractions from './createInteractions/createModifyInteractions'
12+
import createTextInteractions from './createInteractions/createTextInteractions'
1213
import createTranslateInteractions from './createInteractions/createTranslateInteractions'
1314
import modifyDrawStyle from './createInteractions/modifyDrawStyle'
1415
import modifyTextStyle from './createInteractions/modifyTextStyle'
16+
import createDrawInteractions from './createInteractions/createDrawInteractions'
1517

1618
// OK for module action set creation
1719
// eslint-disable-next-line max-lines-per-function
@@ -22,8 +24,10 @@ export const makeActions = () => {
2224

2325
const actions: PolarActionTree<DrawState, DrawGetters> = {
2426
createInteractions,
27+
createDrawInteractions,
2528
createModifyInteractions,
2629
createTranslateInteractions,
30+
createTextInteractions,
2731
modifyDrawStyle,
2832
modifyTextStyle,
2933
setupModule({
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Draw, Snap } from 'ol/interaction'
2+
import Interaction from 'ol/interaction/Interaction'
3+
import { PolarActionContext } from '@polar/lib-custom-types'
4+
import { CreateInteractionsPayload, DrawGetters, DrawState } from '../../types'
5+
import createDrawStyle from '../../utils/createDrawStyle'
6+
import { getSchnaps } from './getSnaps'
7+
8+
export default function (
9+
{
10+
dispatch,
11+
rootGetters,
12+
getters: {
13+
configuration,
14+
drawMode,
15+
measureMode,
16+
selectedStrokeColor,
17+
textInput,
18+
textSize,
19+
},
20+
}: PolarActionContext<DrawState, DrawGetters>,
21+
{ drawSource }: CreateInteractionsPayload
22+
): Promise<Interaction[]> | Interaction[] {
23+
if (drawMode === 'Text') {
24+
return dispatch('createTextInteractions', {
25+
textInput,
26+
textSize,
27+
drawSource,
28+
configuration,
29+
})
30+
}
31+
const style = createDrawStyle(
32+
drawMode,
33+
selectedStrokeColor,
34+
measureMode,
35+
rootGetters.map.getView().getProjection(),
36+
configuration?.style
37+
)
38+
const draw = new Draw({
39+
source: drawSource,
40+
type: drawMode,
41+
style,
42+
})
43+
// @ts-expect-error | internal hack to detect it in @polar/plugin-pins and @polar/plugin-gfi
44+
draw._isDrawPlugin = true
45+
draw.on('drawend', (e) => e.feature.setStyle(style))
46+
return [
47+
draw,
48+
...getSchnaps(
49+
rootGetters.map,
50+
rootGetters.configuration?.draw?.snapTo || []
51+
),
52+
new Snap({ source: drawSource }),
53+
]
54+
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { PolarActionContext } from '@polar/lib-custom-types'
44
import { Collection, Feature, Map } from 'ol'
55
import { CreateInteractionsPayload, DrawGetters, DrawState } from '../../types'
66
import { makeLocalSelector } from './localSelector'
7+
import { getSchnaps } from './getSnaps'
78

89
const createModify = (
910
map: Map,
@@ -72,9 +73,12 @@ export default function (
7273
}
7374
}
7475
})
75-
7676
return [
7777
createModify(rootGetters.map, drawLayer),
78+
...getSchnaps(
79+
rootGetters.map,
80+
rootGetters.configuration?.draw?.snapTo || []
81+
),
7882
new Snap({ source: drawSource }),
7983
select,
8084
]

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
import { Draw, Snap } from 'ol/interaction'
22
import Interaction from 'ol/interaction/Interaction'
33
import VectorSource from 'ol/source/Vector'
4-
import { DrawConfiguration } from '@polar/lib-custom-types'
4+
import { DrawConfiguration, PolarActionContext } from '@polar/lib-custom-types'
55
import { DrawGetters, DrawState } from '../../types'
66
import { createTextStyle } from '../../utils/createTextStyle'
7+
import { getSchnaps } from './getSnaps'
78

8-
export default function (
9-
textInput: DrawState['textInput'],
10-
textSize: DrawGetters['textSize'],
11-
drawSource: VectorSource,
9+
interface CreateTextInteractionsPayload {
10+
textInput: DrawState['textInput']
11+
textSize: DrawGetters['textSize']
12+
drawSource: VectorSource
1213
drawConfiguration?: DrawConfiguration
14+
}
15+
16+
export default function (
17+
{ rootGetters }: PolarActionContext<DrawState, DrawGetters>,
18+
{
19+
textInput,
20+
textSize,
21+
drawSource,
22+
drawConfiguration,
23+
}: CreateTextInteractionsPayload
1324
): Interaction[] {
1425
if (!textInput) {
1526
// nothing to draw yet
@@ -37,5 +48,12 @@ export default function (
3748
drawSource.removeFeature(event.feature)
3849
}
3950
})
40-
return [draw, new Snap({ source: drawSource })]
51+
return [
52+
draw,
53+
...getSchnaps(
54+
rootGetters.map,
55+
rootGetters.configuration?.draw?.snapTo || []
56+
),
57+
new Snap({ source: drawSource }),
58+
]
4159
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { PolarActionContext } from '@polar/lib-custom-types'
44
import { Collection, Feature, Map } from 'ol'
55
import { CreateInteractionsPayload, DrawGetters, DrawState } from '../../types'
66
import { makeLocalSelector } from './localSelector'
7+
import { getSchnaps } from './getSnaps'
78

89
const createTranslate = (
910
map: Map,
@@ -38,6 +39,10 @@ export default function (
3839
): Interaction[] {
3940
return [
4041
createTranslate(rootGetters.map, drawLayer),
42+
...getSchnaps(
43+
rootGetters.map,
44+
rootGetters.configuration?.draw?.snapTo || []
45+
),
4146
new Snap({ source: drawSource }),
4247
]
4348
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Map } from 'ol'
2+
import { Snap } from 'ol/interaction'
3+
import VectorLayer from 'ol/layer/Vector'
4+
import VectorSource from 'ol/source/Vector'
5+
6+
export const getSchnaps = (map: Map, snapIds: string[]): Snap[] =>
7+
snapIds.reduce((accumulator, layerId) => {
8+
const source = (
9+
map
10+
.getLayers()
11+
.getArray()
12+
.find((layer) => layer.get('id') === layerId) as VectorLayer
13+
)?.getSource?.()
14+
if (source instanceof VectorSource) {
15+
accumulator.push(new Snap({ source }))
16+
} else {
17+
console.warn(
18+
`@polar/plugin-draw: Layer with ID "${layerId}" configured for 'snapTo', but it has no source to snap to. The layer does probably not hold any vector data.`
19+
)
20+
}
21+
return accumulator
22+
}, [] as Snap[])

0 commit comments

Comments
 (0)