Skip to content

Commit

Permalink
Merge pull request #2 from Dataport/feature/extend_and_clear_pins_con…
Browse files Browse the repository at this point in the history
…figuration

Feature: Add configuration to add an initial pin which can be centered on
  • Loading branch information
dopenguin authored Nov 14, 2023
2 parents c9f30da + a993639 commit 6e0b842
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 41 deletions.
13 changes: 12 additions & 1 deletion packages/clients/meldemichel/example/single.immovable.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,18 @@
meldemichelMapClient.createMap({
containerId: 'polarstern',
mode: 'SINGLE',
// TODO incomplete API
configOverride: {
pins: {
initial: {
centerOn: true,
coordinates: [569028, 5932885],
},
movable: 'none',
style: {
fill: '#ff0019',
},
},
},
})
</script>
</body>
Expand Down
13 changes: 12 additions & 1 deletion packages/clients/meldemichel/example/single.movable.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,18 @@
meldemichelMapClient.createMap({
containerId: 'polarstern',
mode: 'SINGLE',
// TODO incomplete API
configOverride: {
pins: {
initial: {
centerOn: true,
coordinates: [569028, 5932885],
},
movable: 'drag',
style: {
fill: '#0392cf'
},
},
},
})
</script>
</body>
Expand Down
16 changes: 16 additions & 0 deletions packages/clients/meldemichel/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
// // // // // // // // // // // // // // // //
const mode = 'COMPLETE' // COMPLETE, REPORT, SINGLE
const stage = true // true, false
const movablePin = 'drag' // 'drag', 'none'
const coordinates = [569028, 5932885] // anything in HH in EPSG:25832

// TODO API incomplete
const mapInstance = await client.createMap({
Expand All @@ -34,6 +36,20 @@
stage ? 'stage.' : ''
}afm.hamburg.de/intelliform/forms/mml_melde_michel/standard/mml_melde_michel/index`,
reportServiceId: stage ? '6061' : '6059',
/*
configOverride: {
pins: {
initial: {
centerOn: true,
coordinates,
},
movable: movablePin,
style: {
fill: movablePin === 'drag' ? '#0392cf' : '#ff0019',
},
},
},
*/
})

// added to window for testing
Expand Down
3 changes: 0 additions & 3 deletions packages/clients/meldemichel/src/mapConfigurations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// TODO Seemingly this is how movable pins for Sachbearbeiter came in prior
// pinCoordinate: [565699.2, 5933923.69],

import {
AddressSearchConfiguration,
Attribution,
Expand Down
6 changes: 6 additions & 0 deletions packages/plugins/Pins/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

## unpublished

- Deprecated: Using `movable` with a `boolean` has been deprecated. Please use the parameter with a string. For more information, see the documentation of the package.
- Feature: Add new configuration parameter `initial` to be able to add a pin initially to the map.
- Feature: If `movable` is set to `none` or `false`, the style of the cursor is set to `not-allowed` when hovering the pin.

## 1.0.0

Initial release.
35 changes: 22 additions & 13 deletions packages/plugins/Pins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,31 @@ The usage of `displayComponent` has no influence on the creation of Pins on the

### pins

| fieldName | type | description |
| ---------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| toZoomLevel | number | Zoom level to use on outside input by e.g. address search. |
| movable | boolean | Whether user may drag pin with mouse. |
| appearOnClick | appearOnClick | Pin restrictions. See object description below. |
| coordinateSource | string | The pins plugin may react to changes in other plugins. This specifies the path to such store positions. The position must, when subscribed to, return a GeoJSON feature. |
| style | style? | Display style configuration. |
| boundaryLayerId | string? | Id of a vector layer to restrict pins to. When pins are moved or created outside of the boundary, an information will be shown and the pin is reset to its previous state. The map will wait at most 10s for the layer to load; should it not happen, the geolocation feature is turned off. |
| toastAction | string? | If `boundaryLayerId` is set, and the pin is moved or created outside the boundary, this string will be used as action to send a toast information to the user. If no toast information is desired, leave this field undefined; for testing purposes, you can still find information in the console. |
| fieldName | type | description |
|------------------|-----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| toZoomLevel | number | Zoom level to use on outside input by e.g. address search. |
| appearOnClick | appearOnClick? | Pin restrictions. If not set, a pin can be set on all zoom levels and will be visible. |
| boundaryLayerId | string? | Id of a vector layer to restrict pins to. When pins are moved or created outside of the boundary, an information will be shown and the pin is reset to its previous state. The map will wait at most 10s for the layer to load; should it not happen, the geolocation feature is turned off. |
| coordinateSource | string? | The pins plugin may react to changes in other plugins. This specifies the path to such store positions. The position must, when subscribed to, return a GeoJSON feature. |
| initial | number[]? | Configuration options for setting an initial pin. |
| movable | boolean? \| 'drag' \| 'click' \| 'none' | Whether a user may drag and re-click the pin (`drag` or `true`), only re-click it (`click`) or may only be placed programmatically (`none` or `false`). Defaults to 'none'. **Using a boolean for this configuration has been deprecated and will be removed in the next major release.** |
| style | style? | Display style configuration. |
| toastAction | string? | If `boundaryLayerId` is set, and the pin is moved or created outside the boundary, this string will be used as action to send a toast information to the user. If no toast information is desired, leave this field undefined; for testing purposes, you can still find information in the console. |

#### pins.appearOnClick

| fieldName | type | description |
| ----------- | -------- | ---------------------------------------- |
| show | boolean? | Display marker. |
| atZoomLevel | number? | Minimum zoom level for sensible marking. |
| fieldName | type | description |
|-------------|---------|------------------------------------------|
| show | boolean | Display marker. |
| atZoomLevel | number? | Minimum zoom level for sensible marking. |

#### pins.initial

| fieldName | type | description |
|-------------|----------|---------------------------------------------------------------------------------------------------------------------------------------|
| coordinates | number[] | Coordinate pair for the pin. |
| centerOn | boolean? | If set to true, center on and zoom to the given coordinates on start. Defaults to false. |
| epsg | string? | Coordinate reference system in which the given coordinates are encoded. Defaults to the `epsg` value defined in the mapConfiguration. |

#### pins.style

Expand Down
81 changes: 66 additions & 15 deletions packages/plugins/Pins/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import VectorLayer from 'ol/layer/Vector'
import Point from 'ol/geom/Point'
import { Vector } from 'ol/source'
import Feature from 'ol/Feature'
import { Translate, Draw } from 'ol/interaction'
import { Draw, Select, Translate } from 'ol/interaction'
import { PolarModule } from '@polar/lib-custom-types'
import { toLonLat } from 'ol/proj'
import { toLonLat, transform } from 'ol/proj'
import { pointerMove } from 'ol/events/condition'
import { Geometry } from 'ol/geom'
import { Coordinate } from 'ol/coordinate'
import { PinsState } from '../types'
Expand All @@ -28,6 +29,12 @@ const getInitialState = (): PinsState => ({

let pinsLayer: VectorLayer<Vector<Geometry>>

const move = new Select({
layers: (l) => l === pinsLayer,
style: null,
condition: pointerMove,
})

const storeModule: PolarModule<PinsState, PinsState> = {
namespaced: true,
state: getInitialState(),
Expand All @@ -37,22 +44,35 @@ const storeModule: PolarModule<PinsState, PinsState> = {
* calls removeMarker and showMarker if the store for addressSearch changes
* its value for the chosenAddress.
*/
setupModule({ rootGetters, dispatch, commit }): void {
const { coordinateSource, appearOnClick } =
setupModule({ getters, rootGetters, dispatch, commit }): void {
const { appearOnClick, coordinateSource, initial, movable, toZoomLevel } =
rootGetters.configuration.pins || {}
const interactions = rootGetters.map.getInteractions()
commit('setToZoomLevel', rootGetters.configuration.pins?.toZoomLevel)
commit('setAtZoomLevel', appearOnClick?.atZoomLevel)
if (toZoomLevel) {
commit('setToZoomLevel', toZoomLevel)
}
if (appearOnClick?.atZoomLevel) {
commit('setAtZoomLevel', appearOnClick.atZoomLevel)
}
const showPin = appearOnClick === undefined ? true : appearOnClick.show
if (typeof movable === 'boolean') {
console.warn(
"Pins: Using a boolean for the configuration parameter 'movable' has been deprecated and will be removed in the next major release."
)
}
rootGetters.map.on('singleclick', async ({ coordinate }) => {
const isDrawing = interactions
.getArray()
.some((interaction) => interaction instanceof Draw)

if (
appearOnClick?.show &&
((typeof movable === 'boolean' && movable) ||
movable === 'drag' ||
movable === 'click') &&
showPin &&
// NOTE: It is assumed that getZoom actually returns the currentZoomLevel, thus the view has a constraint in the resolution.
(rootGetters.map.getView().getZoom() as number) >=
appearOnClick.atZoomLevel &&
getters.atZoomLevel &&
!isDrawing &&
(await dispatch('isCoordinateInBoundaryLayer', coordinate))
) {
Expand Down Expand Up @@ -85,27 +105,55 @@ const storeModule: PolarModule<PinsState, PinsState> = {
{ deep: true }
)
}
if (!movable || movable === 'none') {
rootGetters.map.addInteraction(move)
move.on(
'select',
({ selected }) =>
(document.body.style.cursor = selected.length ? 'not-allowed' : '')
)
}
if (initial) {
const { coordinates, centerOn, epsg } = initial
const transformedCoordinates =
typeof epsg === 'string'
? transform(coordinates, epsg, rootGetters.configuration.epsg)
: coordinates

dispatch('removeMarker')
dispatch('showMarker', {
coordinates: transformedCoordinates,
clicked: true,
})
commit('setCoordinatesAfterDrag', transformedCoordinates)
dispatch('updateCoordinates', transformedCoordinates)
if (centerOn) {
rootGetters.map.getView().setCenter(getters.transformedCoordinate)
rootGetters.map.getView().setZoom(getters.toZoomLevel)
}
}
},
/**
* Builds a vectorLayer which contains the mapMarker as
* a vectorFeature and adds it to the map.
* @param payload - an object with a boolean that shows if the coordinate
* was submitted via click and the corresponding coordinates.
*/
showMarker({ rootGetters, getters, commit, dispatch }, payload): void {
showMarker({ getters, rootGetters, commit, dispatch }, payload): void {
if (getters.isActive === false) {
const { configuration, map } = rootGetters
if (payload.clicked === false) {
dispatch(
'updateCoordinates',
getPointCoordinate(
payload.epsg,
rootGetters.configuration.epsg,
configuration.epsg,
payload.type,
payload.coordinates
)
)
rootGetters.map.getView().setCenter(getters.transformedCoordinate)
rootGetters.map.getView().setZoom(getters.toZoomLevel)
map.getView().setCenter(getters.transformedCoordinate)
map.getView().setZoom(getters.toZoomLevel)
}
const coordinatesForIcon =
payload.clicked === true
Expand All @@ -122,13 +170,16 @@ const storeModule: PolarModule<PinsState, PinsState> = {
}),
],
}),
style: getPinStyle(rootGetters?.configuration?.pins?.style || {}),
style: getPinStyle(configuration?.pins?.style || {}),
})
pinsLayer.set('polarInternalId', 'mapMarkerVectorLayer')
rootGetters.map.addLayer(pinsLayer)
map.addLayer(pinsLayer)
pinsLayer.setZIndex(100)
commit('setIsActive', true)
if (rootGetters.configuration.pins?.movable) {
const movable = configuration.pins?.movable
if (typeof movable === 'boolean' && movable) {
dispatch('makeMarkerDraggable')
} else if (movable === 'drag') {
dispatch('makeMarkerDraggable')
}
}
Expand Down
5 changes: 5 additions & 0 deletions packages/types/custom/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## unpublished

- Feature: Add new optional parameter `initial` to `PinsConfiguration` including related interface `InitialPin`.
- Feature: Added new configuration variation for `movable` in `PinsConfiguration`.

## 1.0.0

Initial release.
25 changes: 17 additions & 8 deletions packages/types/custom/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,35 +322,44 @@ export interface AppearOnClick {
/** Whether the pin should be set with a click on a map. */
show: boolean
/** At which zoomLevel it should be possible to have a pin set (if show is set to true). */
atZoomLevel: number
atZoomLevel?: number
}

interface InitialPin {
coordinates: [number, number]
centerOn?: boolean
epsg?: string
}

type MovablePin = 'drag' | 'click' | 'none'

interface PinStyle {
fill?: string
stroke?: string
}

export interface PinsConfiguration extends PluginOptions {
appearOnClick: AppearOnClick
/** Path in store from where coordinates can be retrieved from. */
coordinateSource: string
/** The zoom level to zoom to when a pin is added to the map. */
toZoomLevel: number
appearOnClick?: AppearOnClick
/**
* If set, Pins will only be set within the layer's features.
* The layer must contain vectors. This is useful for restricted maps to avoid
* selecting unfit coordinates.
*/
boundaryLayerId?: string
/** Path in store from where coordinates can be retrieved from. */
coordinateSource?: string
initial?: InitialPin
/** If the pin should be movable; defaults to false. */
movable?: boolean | MovablePin
/** Pin styling */
style?: PinStyle
/**
* Used if boundaryLayer does not contain the user's pin to inform
* the user that the pin could not be set/updated.
*/
toastAction?: string
/** If the pin should be movable; defaults to false. */
movable?: boolean
/** Pin styling */
style?: PinStyle
}

export interface ReverseGeocoderConfiguration {
Expand Down

0 comments on commit 6e0b842

Please sign in to comment.