Skip to content

Commit

Permalink
Merge pull request #202 from Dataport/feature/conditional-vector-styling
Browse files Browse the repository at this point in the history
Feature/conditional vector styling
  • Loading branch information
dopenguin authored Nov 18, 2024
2 parents 3e37965 + 644041b commit bd75e90
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 13 deletions.
8 changes: 5 additions & 3 deletions packages/clients/snowbox/src/mapConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ const ausgleichsflaechen = '1454'
const hamburgBorder = '6074'

const isAusgleichsflaecheActive = (feature: GeoJsonFeature) =>
new Date(
Date.parse(feature.properties?.vorhaben_zulassung_am.split('.')[2])
).getFullYear() >= 2000
['08.07.1997', '02.05.1991', '21.02.2003', '08.12.1989'].includes(
feature.properties?.vorhaben_zulassung_am
)

// arbitrary condition for testing
const isEvenId = (mmlid: string) => Number(mmlid.slice(-1)) % 2 === 0
Expand Down Expand Up @@ -62,6 +62,7 @@ export const mapConfiguration = {
},
},
},
featureStyles: './style.json',
extendedMasterportalapiMarkers: {
layers: [reports],
defaultStyle: {
Expand Down Expand Up @@ -239,6 +240,7 @@ export const mapConfiguration = {
id: ausgleichsflaechen,
type: 'mask',
name: 'snowbox.layers.ausgleichsflaechen',
styleId: 'panda',
},
{
id: hamburgBorder,
Expand Down
73 changes: 73 additions & 0 deletions packages/clients/snowbox/src/style.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[
{
"styleId": "panda",
"rules": [
{
"conditions": {
"properties": [
{
"attrName": "vorhaben_zulassung_am",
"type": "date",
"value": "08.07.1997"
}
]
},
"style": {
"polygonStrokeColor": [3, 255, 1, 1],
"polygonFillColor": [3, 255, 1, 0.25]
}
},
{
"conditions": {
"properties": [
{
"attrName": "vorhaben_zulassung_am",
"type": "date",
"value": "02.05.1991"
}
]
},
"style": {
"polygonStrokeColor": [3, 255, 1, 1],
"polygonFillColor": [3, 255, 1, 0.25]
}
},
{
"conditions": {
"properties": [
{
"attrName": "vorhaben_zulassung_am",
"type": "date",
"value": "21.02.2003"
}
]
},
"style": {
"polygonStrokeColor": [3, 255, 1, 1],
"polygonFillColor": [3, 255, 1, 0.25]
}
},
{
"conditions": {
"properties": [
{
"attrName": "vorhaben_zulassung_am",
"type": "date",
"value": "08.12.1989"
}
]
},
"style": {
"polygonStrokeColor": [3, 255, 1, 1],
"polygonFillColor": [3, 255, 1, 0.25]
}
},
{
"style": {
"polygonStrokeColor": [128, 128, 128, 1],
"polygonFillColor": [128, 128, 128, 0.5]
}
}
]
}
]
2 changes: 2 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- Feature: Add clearer documentation regarding `@masterportal/masterportalapi` related configuration parameters including examples.
- Feature: Officially add support for WMTS layers.
- Feature: Add reasonable default values for configuration parameters `epsg`, `options`, `namedProjections` and `startResolution`.
- Feature: Add new configuration parameter `featureStyles` in conjunction with the parameter `styleId` on layer configurations to be able to style vector features.
- Feature: Officially add support for GeoJSON layers.
- Fix: Document `rawLayerList.initializeLayerList` as an essential step when creating a client.
- Fix: Move basic documentation of `layers` from `@polar/plugin-layer-chooser` to `@polar/core`.
- Fix: Adjust documentation to properly describe optionality of configuration parameters.
Expand Down
59 changes: 55 additions & 4 deletions packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ If the storeModule features a `setupModule` action, it will be executed automati
Layers intended to be used in the map have to be initialized by calling `initializeLayerList` with a service register.
This register may either be a link to a predefined service register like [the Hamburg service register](https://geodienste.hamburg.de/services-internet.json), or the custom service register that is also used in [mapConfiguration.layerConf](#mapconfigurationlayerconf).

``js
```js
core.rawLayerList.initializeLayerList(services: mapConfiguration.layerConf | string, callback?: Function)
``
```

[createMap](#createmap) is usually called inside the callback or directly after this function call.

Expand Down Expand Up @@ -83,6 +83,7 @@ The mapConfiguration allows controlling many client instance details.
| <...masterportalapi.fields> | various | Multiple different parameters are required by the masterportalapi to be able to create the map. Also, some fields are optional but relevant and thus described here as well. For all additional options, refer to the documentation of the masterportalapi itself. |
| checkServiceAvailability | boolean? | If set to `true`, all services' availability will be checked with head requests. |
| extendedMasterportalapiMarkers | extendedMasterportalapiMarkers? | Optional. If set, all configured visible vector layers' features can be hovered and selected by mouseover and click respectively. They are available as features in the store. Layers with `clusterDistance` will be clustered to a multi-marker that supports the same features. Please mind that this only works properly if you configure nothing but point marker vector layers styled by the masterportalapi. |
| featureStyles | string? | Optional path to define styles for vector features. See `mapConfiguration.featureStyles` for more information. May be a url or a path on the local file system. |
| language | enum["de", "en"]? | Initial language. |
| locales | LanguageOption[]? | All locales in POLAR's plugins can be overridden to fit your needs.|
| <plugin.fields> | various? | Fields for configuring plugins added with `addPlugins`. Refer to each plugin's documentation for specific fields and options. Global plugin parameters are described [below](#global-plugin-parameters). |
Expand Down Expand Up @@ -236,6 +237,43 @@ A full documentation of the masterportalapiPolygonFillHatch is available at the
>|patternColor|no|Number[]|`[255, 255, 255, 1]`|Fill color of pattern drawn on polygon.|
>|size|no|Number|`30`|Edge length of a singular repeated pattern element.|
##### mapConfiguration.featureStyles

Vector Layers (GeoJSON and WFS) can also be styled on the client side.
Configuration and implementation is based on [style.json](https://bitbucket.org/geowerkstatt-hamburg/masterportal/src/dev_vue/docs/User/Global-Config/style.json.md) of `@masterportal/masterportalapi`.
For the full documentation, including all rules that are applied when parsing the configuration, see the above linked documentation.

Example styling some points of a layer gray that have the value `food` in the property `not bamboo`.
All Other features will use the provided default green styling.
A Layer needs to use the property `styleId` in its `mapConfiguration.layers` entry and set it to `panda` to use this styling.

```json
[
{
"styleId": "panda",
"rules": [
{
"conditions": {
"properties": {
"food": "bamboo"
}
},
"style": {
"circleStrokeColor": [3, 255, 1, 1],
"circleFillColor": [3, 255, 1, 1]
}
},
{
"style": {
"circleStrokeColor": [128, 128, 128, 1],
"circleFillColor": [128, 128, 128, 1]
}
}
]
}
]
```

##### <...masterportalapi.fields>

The `<...masterportalapi.fields>` means that any masterportalapi field may also be used here _directly_ in the mapConfiguration. The fields described here are fields that are interesting for the usage of POLAR.
Expand Down Expand Up @@ -286,15 +324,16 @@ Fields that are not set as required have default values.

##### mapConfiguration.layerConf

The layer configuration (or: service register) is read by the masterportalapi. The full definition can be read [here](https://bitbucket.org/geowerkstatt-hamburg/masterportal/src/dev/doc/services.json.md).
The layer configuration (or: service register) is read by the `@masterportal/masterportalapi`. The full definition can be read [here](https://bitbucket.org/geowerkstatt-hamburg/masterportal/src/dev/doc/services.json.md).

However, not all listed services have been implemented in the masterportalapi yet, and no documentation regarding implemented properties exists there yet.
However, not all listed services have been implemented in the `@masterportal/masterportalapi` yet, and no documentation regarding implemented properties exists there yet.

Whitelisted and confirmed parameters include:

- WMS: id, name, url, typ, format, version, transparent, layers, STYLES
- WFS: id, name, url, typ, outputFormat, version, featureType
- WMTS: id, name, urls, typ, capabilitiesUrl, optionsFromCapabilities, tileMatrixSet, layers, legendURL, format, coordinateSystem, origin, transparent, tileSize, minScale, maxScale, requestEncoding, resLength
- GeoJSON: id, name, url, typ, format, version, minScale, maxScale, legendURL

###### Example services register

Expand Down Expand Up @@ -347,6 +386,17 @@ Whitelisted and confirmed parameters include:
"typ": "WMTS",
"layers": "layer-name",
"legendURL": "my-legend-url"
},
{
"id": "my-geojson",
"name": "My GeoJSON data",
"url": "Service url",
"typ": "GeoJSON",
"format": "XML",
"version": "1.0",
"minScale": "0",
"maxScale": "2500000",
"legendURL": ""
}
]
```
Expand All @@ -367,6 +417,7 @@ Since this is the base for many functions, the service id set in this is used to
| - | - | - |
| id | string | Service register id in `mapConfiguration.layerConf`. |
| name | string | Display name in UI. |
| styleId | string? | Id of the used style. May lead to unexpected results if the layer is also configured to be used with `mapConfiguration.extendedMasterportalapiMarkers`. Only applicable for vector-type layers. For more information and an example see `mapConfiguration.featureStyles`. Defaults and fallbacks to OpenLayers default styling. |

<details>
<summary>Example configuration</summary>
Expand Down
13 changes: 9 additions & 4 deletions packages/core/src/components/MapContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,21 @@
</template>

<script lang="ts">
import Vue from 'vue'
import Vue, { PropType } from 'vue'
import { mapActions, mapGetters, mapMutations } from 'vuex'
import api from '@masterportal/masterportalapi/src/maps/api'
import { MoveHandle } from '@polar/components'
import Hammer from 'hammerjs'
import i18next from 'i18next'
import { defaults } from 'ol/interaction'
import { LanguageOption, MoveHandleProperties } from '@polar/lib-custom-types'
import {
LanguageOption,
MapConfig,
MoveHandleProperties,
} from '@polar/lib-custom-types'
import { SMALL_DISPLAY_HEIGHT, SMALL_DISPLAY_WIDTH } from '../utils/constants'
import { addClusterStyle } from '../utils/addClusterStyle'
import { setupStyling } from '../utils/setupStyling'
import MapUi from './MapUi.vue'
// NOTE: OpenLayers styles need to be imported as the map resides in the shadow DOM
import 'ol/ol.css'
Expand All @@ -67,7 +72,7 @@ export default Vue.extend({
},
props: {
mapConfiguration: {
type: Object,
type: Object as PropType<MapConfig>,
required: true,
},
},
Expand Down Expand Up @@ -143,7 +148,7 @@ export default Vue.extend({
},
}
)
setupStyling(this.mapConfiguration, map)
this.setMap(map)
this.updateDragAndZoomInteractions()
if (this.mapConfiguration.extendedMasterportalapiMarkers) {
Expand Down
52 changes: 52 additions & 0 deletions packages/core/src/utils/setupStyling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { MapConfig } from '@polar/lib-custom-types'
import noop from '@repositoryname/noop'
import styleList from '@masterportal/masterportalapi/src/vectorStyle/styleList'
import createStyle from '@masterportal/masterportalapi/src/vectorStyle/createStyle'
import VectorLayer from 'ol/layer/Vector'
import { Feature, Map } from 'ol'
import { FeatureLike } from 'ol/Feature'

export async function setupStyling(mapConfiguration: MapConfig, map: Map) {
if (mapConfiguration.featureStyles) {
await styleList.initializeStyleList(
// Masterportal specific field not required by POLAR
{},
{ styleConf: mapConfiguration.featureStyles },
mapConfiguration.layers.map((layer) => {
const layerConfig = mapConfiguration.layerConf.find(
(l) => l.id === layer.id
)
if (layerConfig) {
return {
...layer,
// Required by @masterportal/masterportalapi
typ: layerConfig.typ,
}
}
return layer
}),
// Masterportal specific field not required by POLAR
[],
// Callback currently yields no relevant benefit
noop
)
map.getLayers().forEach((layer) => {
if (!layer.get('styleId')) {
return
}
const styleObject = styleList.returnStyleObject(layer.get('styleId'))
if (styleObject) {
;(layer as VectorLayer<Feature>).setStyle(
(feature: Feature | FeatureLike) =>
createStyle.createStyle(
styleObject,
feature,
feature.get('features') !== undefined,
// NOTE: This field may be implemented in the future to be able to style points with graphics
''
)
)
}
})
}
}
2 changes: 2 additions & 0 deletions packages/types/custom/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
- Feature: Add new type `MasterportalApiConfig`.
- Feature: Change `MapConfig` to allow for partial configuration as some parameters have default values and have it be extended from `MasterportalApiConfig`.
- Feature: Add new configuration parameter `directSelect` and `boxSelect` to `GfiConfiguration`.
- Feature: Add new configuration parameter `featureStyles` to `MapConfig`.
- Feature: Add new configuration parameter `styleId` to `LayerConfiguration`.
- Fix: Document missing return type to `afterLoadFunction`, which may also return a Promise.
- Fix: Add `string` as option for `SearchType` since arbitrary strings can be registered.
- Fix: Remove unused parameters `proxyUrl` and `loadingStrategy` from `LayerConfigurationOptions`.
Expand Down
6 changes: 4 additions & 2 deletions packages/types/custom/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ export interface LayerConfiguration {
name: string
/** Whether the layer is a background layer or a feature layer with specific information */
type: LayerType
/** layers may have their own gfiMode */
gfiMode?: 'bboxDot' | 'intersects'
/** Whether the mask-layer should be hidden from the LayerChooser selection menu */
hideInMenu?: boolean
/** The minimum zoom level the layer will be rendered in; defaults to 0 */
Expand All @@ -544,10 +546,9 @@ export interface LayerConfiguration {
maxZoom?: number
/** Enables a configuration feature for the layer in its selection. */
options?: LayerConfigurationOptions
styleId?: string
/** Whether the layer should be rendered; defaults to false */
visibility?: boolean
/** layers may have their own gfiMode */
gfiMode?: 'bboxDot' | 'intersects'
}

export interface PolarMapOptions {
Expand Down Expand Up @@ -618,6 +619,7 @@ export interface MapConfig extends MasterportalApiConfig {
/** if true, all services' availability will be checked with head requests */
checkServiceAvailability?: boolean
extendedMasterportalapiMarkers?: ExtendedMasterportalapiMarkers
featureStyles?: string
language?: InitialLanguage
locales?: LanguageOption[]
renderFaToLightDom?: boolean
Expand Down

0 comments on commit bd75e90

Please sign in to comment.