@masterportal/masterportalapi 2.48.0 → 2.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,56 @@
3
3
 
4
4
  The [Semantic Versioning](https://semver.org/spec/v2.0.0.html) is used.
5
5
 
6
+ ## Unreleased - in development
7
+ ### __Breaking Changes__
8
+
9
+ ### Added
10
+
11
+ ### Changed
12
+
13
+ ### Deprecated
14
+
15
+ ### Removed
16
+
17
+ ### Fixed
18
+
19
+ ---
20
+
21
+ ## 2.50.0 - 2025-08-214
22
+
23
+ ### Added
24
+ - vectorStyle: added function `initStyleAndAddToList` to styleList. Adds a style contained in style.json to list of styles.
25
+ - A new parameter "doNotLoadInitially" for OAF layer so that the layer can be loaded without features, which is necessary for external filtering.
26
+
27
+ ### Changed
28
+ - The following packages have been updated:
29
+ - dependencies:
30
+ - ol: 10.4.1 to 10.6.0
31
+
32
+ ### Fixed
33
+ - WMTS-Layer: Fixed layers without capabilities.
34
+ - WFTS-Layer: Ensured zIndex is applied correctly to layers using webgl renderer.
35
+
36
+ ---
37
+
38
+ ## 2.49.0 - 2025-04-29
39
+
40
+ ### Added
41
+ - Add new parameters polygonStrokeDash, polygonStrokeDashOffset in styleObject of drawInteraction.
42
+ - webgl: extended default style for points.
43
+
44
+ ### Changed
45
+ - The following packages have been updated:
46
+ - dependencies:
47
+ - ol-mapbox-style: 12.4.0 to 12.5.0
48
+
49
+ ### Fixed
50
+ - wms: Fix passing layerParams from layerBuilder.
51
+ - wms-time: layers that are updated daily don't run into errors due to late promise-resolving anymore.
52
+ - Issue #1386: handle label creation if values are empty.
53
+
54
+ ---
55
+
6
56
  ## 2.48.0 - 2025-04-01
7
57
 
8
58
  ### Fixed
package/babel.config.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "presets": [],
2
+ "presets": [],
3
3
  "plugins": [
4
4
  "@babel/plugin-transform-modules-commonjs"
5
5
  ]
@@ -0,0 +1,43 @@
1
+ image: node:20.12.2
2
+
3
+ clone:
4
+ depth: 5000 # include the last five hundred commits
5
+
6
+ pipelines:
7
+ # Start pipeline with tag to build examples zips and copy them to the Bitbucket download folder
8
+ tags:
9
+ 'v2.*.*':
10
+ - step:
11
+ name: deploy on openCode
12
+ script:
13
+ - echo 'deploy to opencode:'$BITBUCKET_TAG
14
+ - git fetch --all --tags
15
+ - git checkout tags/$BITBUCKET_TAG
16
+ - git push https://$OpenCode_User:$OpenCode_Password@gitlab.opencode.de/geowerkstatt-hamburg/masterportalapi.git $BITBUCKET_TAG
17
+ - git clone --single-branch --branch master https://geowerkstatt@bitbucket.org/geowerkstatt-hamburg/masterportalapi.git
18
+ - cd masterportalapi
19
+ - git push https://$OpenCode_User:$OpenCode_Password@gitlab.opencode.de/geowerkstatt-hamburg/masterportalapi.git -f
20
+ custom: # Pipelines that are triggered manually
21
+ npm audit:
22
+ - step:
23
+ name: npm audit (security)
24
+ caches:
25
+ - node
26
+ script:
27
+ - npm install
28
+ - npm audit --json
29
+ deploy last tag on openCode:
30
+ - variables:
31
+ - name: BITBUCKET_TAG
32
+ description: tag to publish docs for
33
+ - step:
34
+ name: deploy last tag on openCode
35
+ script:
36
+ - apt-get update && apt-get install -y curl wput jq
37
+ - git fetch --all --tags
38
+ - echo 'deply to opencode:'$BITBUCKET_TAG
39
+ - git checkout tags/$BITBUCKET_TAG
40
+ - git push https://$OpenCode_User:$OpenCode_Password@gitlab.opencode.de/geowerkstatt-hamburg/masterportalapi.git $BITBUCKET_TAG
41
+ - git clone --single-branch --branch master https://geowerkstatt@bitbucket.org/geowerkstatt-hamburg/masterportalapi.git
42
+ - cd masterportalapi
43
+ - git push https://$OpenCode_User:$OpenCode_Password@gitlab.opencode.de/geowerkstatt-hamburg/masterportalapi.git -f
package/jest.config.js CHANGED
@@ -6,7 +6,7 @@ module.exports = {
6
6
  /** ol prints errors without HTMLCanvasElement being available in test environment */
7
7
  "setupFiles": ["jest-canvas-mock"],
8
8
  /** node_modules are usually ignored by babel-jest, but ol is published in ES6 */
9
- "transformIgnorePatterns": ["/node_modules/(?!(ol|olcs|ol-mapbox-style|geotiff|quick-lru|color-space|color-rgba|color-parse|color-name|rbush|quickselect|earcut|pbf)/).*/"],
9
+ "transformIgnorePatterns": ["/node_modules/(?!(ol|olcs|ol-mapbox-style|mapbox-to-css-font|geotiff|quick-lru|color-space|color-rgba|color-parse|color-name|rbush|quickselect|earcut|pbf)/).*/"],
10
10
  /** only consider files in src/ for coverage */
11
11
  "collectCoverageFrom": ["src/**/*.js"],
12
12
  /** coverage reporters */
@@ -14,7 +14,8 @@ module.exports = {
14
14
  /** mapping svg to string representation since jest can't handle svg and mapping olcs paths*/
15
15
  "moduleNameMapper": {
16
16
  "marker.svg": "<rootDir>/public/stringMarker.js",
17
- "olcs/lib/olcs/(.*)$": "<rootDir>/node_modules/olcs/lib/olcs/$1"
17
+ "olcs/lib/olcs/(.*)$": "<rootDir>/node_modules/olcs/lib/olcs/$1",
18
+ "ol-mapbox-style$": "<rootDir>/node_modules/ol-mapbox-style/src/$1"
18
19
  },
19
20
  "testEnvironment": "jsdom",
20
21
  "setupFilesAfterEnv": ["./jest.setup.js"],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@masterportal/masterportalapi",
3
3
  "author": "Implementierungspartnerschaft Masterportal <info@masterportal.org> (https://www.masterportal.org)",
4
- "version": "2.48.0",
4
+ "version": "2.50.0",
5
5
  "license": "MIT",
6
6
  "description": "Basic functions of the Masterportal as api",
7
7
  "repository": {
@@ -21,8 +21,8 @@
21
21
  "dependencies": {
22
22
  "core-js": "^3.33.1",
23
23
  "dayjs": "^1.11.10",
24
- "ol": "^10.4.0",
25
- "ol-mapbox-style": "12.4.0",
24
+ "ol": "^10.6.0",
25
+ "ol-mapbox-style": "12.5.0",
26
26
  "olcs": "^2.22.1",
27
27
  "proj4": "^2.10.0",
28
28
  "xml2js": "^0.6.2"
@@ -64,6 +64,7 @@
64
64
  },
65
65
  "homepage": "https://bitbucket.org/geowerkstatt-hamburg/masterportalapi#readme",
66
66
  "directories": {
67
+ "doc": "docs",
67
68
  "example": "example",
68
69
  "test": "test"
69
70
  },
package/publiccode.yml ADDED
@@ -0,0 +1,88 @@
1
+ # This repository adheres to the publiccode.yml standard by including this
2
+ # metadata file that makes public software easily discoverable.
3
+ # More info at https://github.com/italia/publiccode.yml
4
+
5
+ publiccodeYmlVersion: '0.3'
6
+ categories:
7
+ - geographic-information-systems, api
8
+ description:
9
+ de:
10
+ apiDocumentation: 'https://bitbucket.org/geowerkstatt-hamburg/masterportalapi/src/master/README.md'
11
+ documentation: 'https://www.masterportal.org/dokumentation'
12
+ features:
13
+ - OGC-konform
14
+ - Konfigurierbar
15
+ - OpenSource
16
+ - Adminfreundlich
17
+ - Modular
18
+ genericName: 'MasterportalAPI'
19
+ localisedName: MasterportalAPI
20
+ longDescription: |2
21
+ Die MasterportalAPI ist eine API zum Einbinden und Anzeigen von Karteninhalten auf Ihrer Webseite. Sie basiert auf OpenLayers und wurde um Funktionen erweitert, die die einfache Nutzung von Konfigurations- und Infrastrukturdateien des Masterportals, einer funktionsreichen Mapping-App der Geowerkstatt Hamburg, ermöglichen. Sie ermöglicht außerdem die Erstellung einer 3D-Karte mithilfe von OLCS und Cäsium. Weitere Informationen finden Sie auf masterportal.org. Die MasterportalAPI ist Open-Source-Software. Es ist unter der [++MIT-Lizenz++](https://bitbucket.org/geowerkstatt-hamburg/masterportalapi/src/master/License.txt) veröffentlicht.
22
+ shortDescription: 'Die MasterportalAPI ist eine auf OpenLayers basierende API zum Einbinden und Anzeigen von Karteninhalten auf Ihrer Webseite'
23
+ developmentStatus: stable
24
+ intendedAudience:
25
+ countries:
26
+ - de
27
+ - en
28
+ - es
29
+ - it
30
+ - pt
31
+ - ru
32
+ - tr
33
+ - ua
34
+ - nl
35
+ scope:
36
+ - welfare
37
+ - agriculture
38
+ - culture
39
+ - defence
40
+ - education
41
+ - emergency-services
42
+ - employment
43
+ - energy
44
+ - environment
45
+ - finance-and-economic-development
46
+ - foreign-affairs
47
+ - government
48
+ - healthcare
49
+ - infrastructures
50
+ - local-authorities
51
+ - manufacturing
52
+ - research
53
+ - justice
54
+ - science-and-technology
55
+ - security
56
+ - society
57
+ - sport
58
+ - tourism
59
+ - transportation
60
+ landingURL: 'https://www.masterportal.org'
61
+ legal:
62
+ license: MIT
63
+ mainCopyrightOwner: 'Freie und Hansestadt Hamburg, Landesbetrieb Geoinformation und Vermessung'
64
+ repoOwner: 'Freie und Hansestadt Hamburg, Landesbetrieb Geoinformation und Vermessung'
65
+ localisation:
66
+ availableLanguages:
67
+ - de
68
+ - en
69
+ localisationReady: true
70
+ logo: |-
71
+ https://www.masterportal.org/fileadmin/_processed_/7/d/csm_news_masterportal_ce24f3cc3d.jpg
72
+ maintenance:
73
+ contacts:
74
+ - name: Betrieb Webanwendungen
75
+ affiliation: Freie und Hansestadt Hamburg, Landesbetrieb Geoinformation und Vermessung
76
+ contractors:
77
+ - name: Landesbetrieb Geoinformation und Vermessung
78
+ until: '2025-12-01'
79
+ website: 'https://www.hamburg.de/bsw/landesbetrieb-geoinformation-und-vermessung/'
80
+ type: community
81
+ name: Masterportal
82
+ platforms:
83
+ - web
84
+ releaseDate: '2025-04-29'
85
+ roadmap: 'https://bitbucket.org/geowerkstatt-hamburg/masterportalapi/src/master/'
86
+ softwareType: api
87
+ softwareVersion: 2.49.0
88
+ url: 'https://bitbucket.org/geowerkstatt-hamburg/masterportalapi.git'
package/src/layer/oaf.js CHANGED
@@ -23,6 +23,7 @@ import * as webgl from "../renderer/webgl";
23
23
  * @property {function} beforeLoading - function called before loading
24
24
  * @property {function} afterLoading - function called after loading, gets parameter features
25
25
  * @property {function} featuresFilter - function called after loading to filter features, gets parameter features
26
+ * @property {function} doNotLoadInitially - default false, if set to true the layer will be initialized without network call, an empty array of features is promoted - this is useful to add features later on (e.g. by filtering) to a full functional but initially empty layer
26
27
  * @property {function} clusterGeometryFunction - used in cluster source. Returns the geometry of the cluster, gets parameter feature
27
28
  * @property {function} style - style function to style the layer
28
29
  * @property {object} loadingParams - added as params to url
@@ -173,6 +174,10 @@ function getLayerSource (rawLayer, options) {
173
174
  let source = null;
174
175
 
175
176
  function loader (extent, _, __, success, failure) {
177
+ if (options.doNotLoadInitially) {
178
+ onLoad(source, [], onError, success, failure, options);
179
+ return;
180
+ }
176
181
  const bboxParam = options.loadingStrategy === bbox ? extent : options.loadingParams.bbox,
177
182
  url = createUrl(rawLayer, {
178
183
  ...options.loadingParams,
@@ -4,11 +4,11 @@ import VectorTileSource from "ol/source/VectorTile";
4
4
  import OpenLayersTileGrid from "ol/tilegrid/TileGrid";
5
5
  import {extentFromProjection} from "ol/tilegrid";
6
6
  import * as webgl from "../renderer/webgl";
7
-
8
- import {stylefunction, apply} from "ol-mapbox-style";
7
+ import {apply, stylefunction} from "ol-mapbox-style";
9
8
 
10
9
  import defaults from "../defaults";
11
10
 
11
+
12
12
  const OL_DEFAULT_VECTOR_TILE_GRID_CRS = "EPSG:3857";
13
13
 
14
14
  /**
package/src/layer/wms.js CHANGED
@@ -112,6 +112,14 @@ export function createLayerSource (rawLayer, options) {
112
112
  projection = rawLayer.crs ? getProjection(rawLayer.crs) : undefined;
113
113
  let tileGrid = null;
114
114
 
115
+
116
+ // Fix for daily updated WMS-Time Layer, which use 'current' as the default value of the time-Extent in their getCapabilities
117
+ // The promise isn't resolved quickly enough for the continued work with the layer.
118
+ // Its resolved value would be the current date, so it is hardcoded here.
119
+ if (rawLayer.TIME && rawLayer.TIME.toString() === "[object Promise]") {
120
+ params.TIME = new Date().toISOString();
121
+ }
122
+
115
123
  if (rawLayer.singleTile) {
116
124
  return new ImageWMS({
117
125
  url: rawLayer.url,
@@ -154,13 +162,15 @@ export function createLayerSource (rawLayer, options) {
154
162
  * @param {function} [rawLayer.olAttribution] - optional function that takes a module:ol/Map~FrameState and returns a string or an array of strings representing source attributions
155
163
  * @param {string|number} [rawLayer.tilesize] - optional needed to create the tileGrid
156
164
  * @param {string|"anonymous"} [rawLayer.crossOrigin] - optional needed for CORS requests of image data, to enable canvas export
157
- * @param {object} layerParams - additional layer params
165
+ * @param {object} [optionalParams] - optional params
166
+ * @param {object} [optionalParams.layerParams] - additional layer params
167
+ * @param {options} [optionalParams.options] - additional options
158
168
  * @param {object} options - optional resolutions and origin to create the TileGrid
159
169
  * @param {Array} [options.resolutions] - optional resolutions to create the TileGrid, must be in descending order
160
170
  * @param {Array} [options.origin] - optional origin to create the TileGrid
161
171
  * @returns {ol.Layer} Layer that can be added to map.
162
172
  */
163
- export function createLayer (rawLayer, layerParams = {}, options) {
173
+ export function createLayer (rawLayer = {}, {layerParams = {}, options = {}} = {}) {
164
174
  const source = createLayerSource(rawLayer, options),
165
175
  Layer = rawLayer.singleTile ? ImageLayer : TileLayer;
166
176
 
package/src/layer/wmts.js CHANGED
@@ -186,7 +186,7 @@ function createLayer (rawLayer, layerParams = {}) {
186
186
  infoFormat: rawLayer.infoFormat
187
187
  }, layerParams));
188
188
 
189
- if (rawLayer.optionsFromCapabilities === undefined || rawLayer.capabilitiesUrl === undefined) {
189
+ if (!rawLayer.optionsFromCapabilities || !rawLayer.capabilitiesUrl) {
190
190
  createLayerSourceByDefinitions(rawLayer, tileLayer);
191
191
  }
192
192
  else {
@@ -169,6 +169,8 @@ function setStyleObject (currentLayout, outerCircle = false) {
169
169
  lineStrokeWidth: currentLayout.strokeWidth,
170
170
  polygonFillColor: fillColorRgba,
171
171
  polygonStrokeColor: currentLayout.strokeColor,
172
+ polygonStrokeDash: currentLayout.polygonDash,
173
+ polygonStrokeDashOffset: currentLayout.polygonStrokeDashOffset,
172
174
  polygonStrokeWidth: currentLayout.strokeWidth
173
175
  }
174
176
  }
@@ -1,27 +1,38 @@
1
- import WebGLPointsLayer from "ol/layer/WebGLVector";
2
1
  import WebGLVectorLayerRenderer from "ol/renderer/webgl/VectorLayer";
3
2
  import WebGLVectorTileLayerRenderer from "ol/renderer/webgl/VectorTileLayer.js";
4
3
  import VectorTile from "ol/layer/VectorTile.js";
5
4
  import VectorLayer from "ol/layer/Layer";
5
+ import WebGLVectorLayer from "ol/layer/WebGLVector.js";
6
6
  import styleList from "../vectorStyle/styleList";
7
7
  import {getRulesForFeature} from "../vectorStyle/lib/getRuleForIndex";
8
8
  import {returnColor} from "../vectorStyle/lib/colorConvertions";
9
- import {asArray} from "ol/color.js";
10
- import {packColor, parseLiteralStyle} from "ol/webgl/styleparser.js";
11
9
 
12
10
  /**
13
11
  * The default style for OpenLayers WebGLPoints class
14
12
  * @see https://openlayers.org/en/latest/examples/webgl-points-layer.html
15
13
  * @private
16
14
  */
17
- const defaultPointStyle = {
18
- "circle-radius": 10,
19
- "circle-fill-color": "#006688",
20
- "circle-rotate-with-view": false,
21
- "circle-displacement": [0, 0],
22
- "circle-opacity": 0.6
23
- },
24
-
15
+ const defaultPointStyle = [
16
+ {
17
+ style: {
18
+ "circle-fill-color": ["match", ["get", "selected"], 1, "#0c2026", "#006688"],
19
+ "circle-radius": [
20
+ "interpolate",
21
+ ["exponential", 1.5],
22
+ ["zoom"],
23
+ 3, 6,
24
+ 6, 10,
25
+ 9, 20,
26
+ 12, 35,
27
+ 15, 60,
28
+ 18, 110
29
+ ],
30
+ "circle-rotate-with-view": false,
31
+ "circle-displacement": [0, 0],
32
+ "circle-opacity": 0.6
33
+ }
34
+ }
35
+ ],
25
36
  defaultPolygonStyle = {
26
37
  fillColor: "#006688",
27
38
  strokeColor: "#006688",
@@ -52,6 +63,11 @@ export function createVectorLayerRenderer () {
52
63
  * @description the temporary class with a custom renderer to render the vector data with WebGL
53
64
  */
54
65
  class LocalWebGLLayer extends VectorLayer {
66
+ constructor (options) {
67
+ super(options);
68
+ // Initialize with any default style variables
69
+ this.styleVariables = options.styleVariables || {};
70
+ }
55
71
  /**
56
72
  * Creates a new renderer that takes the defined style of the new layer as an input.
57
73
  * @returns {module:ol/renderer/webgl/WebGLVectorLayerRenderer} the custom renderer
@@ -62,6 +78,13 @@ export function createVectorLayerRenderer () {
62
78
  style
63
79
  });
64
80
  }
81
+ /**
82
+ * Get the current style variables.
83
+ * @returns {Object} - The current style variables.
84
+ */
85
+ getStyleVariables () {
86
+ return this.styleVariables;
87
+ }
65
88
  }
66
89
 
67
90
  return LocalWebGLLayer;
@@ -72,9 +95,10 @@ export function createVectorLayerRenderer () {
72
95
  * @augments VectorTile
73
96
  * @private
74
97
  * @implements {WebGLVectorTileLayerRenderer}
98
+ * @param {Object} attrs - the attributes of the layer
75
99
  * @returns {module:ol/layer/VectorTile} the LocalWebGLLayer with a custom renderer for WebGL styling of vectorTile layers.
76
100
  */
77
- export function createVectorTileLayerRenderer () {
101
+ export function createVectorTileLayerRenderer (attrs) {
78
102
  /**
79
103
  * @class LocalWebGLLayer
80
104
  * @see https://openlayers.org/en/latest/examples/webgl-vector-tiles.html
@@ -88,70 +112,8 @@ export function createVectorTileLayerRenderer () {
88
112
  * @experimental
89
113
  */
90
114
  createRenderer () {
91
- const result = parseLiteralStyle(style),
92
- invisible = [255, 255, 255, 0],
93
- grey = [119, 119, 119, 1];
94
-
95
-
96
115
  return new WebGLVectorTileLayerRenderer(this, {
97
- style: {
98
- fill: {
99
- fragment: result.builder.getFillFragmentShader(),
100
- vertex: result.builder.getFillVertexShader()
101
- },
102
- stroke: {
103
- fragment: result.builder.getStrokeFragmentShader(),
104
- vertex: result.builder.getStrokeVertexShader()
105
- },
106
- symbol: {
107
- fragment: result.builder.getSymbolFragmentShader(),
108
- vertex: result.builder.getSymbolVertexShader()
109
- },
110
- builder: result.builder,
111
- attributes: {
112
- fillColor: {
113
- size: 2,
114
- callback: (feature) => {
115
- const featureStyle = this.getStyle()(feature, 1);
116
-
117
- if (featureStyle && featureStyle[0]) {
118
- const color = featureStyle[0]?.getFill()?.getColor();
119
-
120
- return packColor(color && typeof color === "string" ? asArray(color) : invisible);
121
- }
122
- return packColor(grey);
123
- }
124
- },
125
- strokeColor: {
126
- size: 2,
127
- callback: (feature) => {
128
- const featureStyle = this.getStyle()(feature, 1);
129
-
130
- if (featureStyle && featureStyle[0]) {
131
- const color = featureStyle[0]?.getStroke()?.getColor();
132
-
133
- return packColor(color ? asArray(color) : invisible);
134
- }
135
- return packColor(grey);
136
- }
137
- },
138
- strokeWidth: {
139
- size: 1,
140
- callback: (feature) => {
141
- const featureStyle = this.getStyle()(feature, 1);
142
-
143
- if (featureStyle && featureStyle[0]) {
144
- const width = featureStyle[0]?.getStroke()?.getWidth();
145
-
146
- if (width !== undefined) {
147
- return width > 10 ? width / 10 : 1;/** @todo needs refactoring in later versions */
148
- }
149
- }
150
- return 1;
151
- }
152
- }
153
- }
154
- }
116
+ style: attrs.style ? attrs.style : style
155
117
  });
156
118
  }
157
119
  }
@@ -275,10 +237,10 @@ export function afterLoading (features, styleId, excludeTypesFromParsing, isPoin
275
237
  * Creates the OL Layer instance, used to rebuild the layer when shown again after layer has been disposed
276
238
  * @param {Object} attrs - the attributes of the layer
277
239
  * @public
278
- * @returns {VectorLayer | WebGLPointsLayer} returns the layer instance
240
+ * @returns {VectorLayer | WebGLVectorLayer} returns the layer instance
279
241
  */
280
242
  export function createLayer (attrs) {
281
- let LayerConstructor = WebGLPointsLayer;
243
+ let LayerConstructor = WebGLVectorLayer;
282
244
  const options = {
283
245
  id: attrs.id,
284
246
  source: attrs.source,
@@ -292,7 +254,8 @@ export function createLayer (attrs) {
292
254
  renderer: "webgl",
293
255
  styleId: attrs.styleId,
294
256
  excludeTypesFromParsing: attrs.excludeTypesFromParsing,
295
- extent: attrs.extent
257
+ extent: attrs.extent,
258
+ zIndex: attrs.zIndex
296
259
  };
297
260
 
298
261
  /**
@@ -274,6 +274,30 @@ function addToStyleList (jsonStyles) {
274
274
  });
275
275
  }
276
276
 
277
+ /**
278
+ * Fetches the style.json file and adds the style for the styleId to the style list, if contained in style.json.
279
+ * @param {object} [Config] - the Config.js object
280
+ * @param {string} [styleId] - the styleId to add
281
+ * @returns {object} the style object for the styleId
282
+ */
283
+ async function initStyleAndAddToList (Config, styleId) {
284
+ let style;
285
+
286
+ await fetch(Config.styleConf)
287
+ .then(response => response.json())
288
+ .then(data => {
289
+ style = data.find(aStyle => aStyle.styleId === styleId);
290
+
291
+ if (style) {
292
+ styleList.push(style);
293
+ }
294
+ })
295
+ .catch(error => {
296
+ console.error(error);
297
+ });
298
+ return style;
299
+ }
300
+
277
301
  /**
278
302
  * Returns style object by styleId or by layerId
279
303
  * @param {string} layerId layerId
@@ -285,6 +309,7 @@ function returnStyleObject (layerId) {
285
309
 
286
310
  export default {
287
311
  initializeStyleList,
312
+ initStyleAndAddToList,
288
313
  addToStyleList,
289
314
  returnStyleObject
290
315
  };
@@ -120,7 +120,7 @@ class TextStyle extends StyleClass {
120
120
  const feature = this.feature,
121
121
  featureProperties = feature.getProperties(),
122
122
  textSuffix = this.attributes.textSuffix;
123
- let text = mapAttributes(featureProperties, this.attributes.labelField, false);
123
+ let text = mapAttributes(featureProperties, this.attributes.labelField, false) ?? "";
124
124
 
125
125
  if (textSuffix !== "") {
126
126
  text = text + " " + textSuffix;
@@ -52,6 +52,16 @@ describe("oaf.js", function () {
52
52
  expect(layer.get("id")).toEqual("id");
53
53
  expect(layer.getSource()).toBeInstanceOf(VectorSource);
54
54
  });
55
+ it("creates empty layer if doNotLoadInitially is true", function () {
56
+ const options = {
57
+ doNotLoadInitially: true
58
+ },
59
+ layer = oaf.createLayer({id: "id"}, {options});
60
+
61
+ expect(layer).toBeInstanceOf(VectorLayer);
62
+ expect(layer.getSource()).toBeInstanceOf(VectorSource);
63
+ expect(layer.getSource().getFeatures().length).toEqual(0);
64
+ });
55
65
  it("creates a VectorLayer with style in rawLayer", function () {
56
66
  function styleFunction () {
57
67
  const icon = new Style({
@@ -250,7 +250,7 @@ describe("wms.js", function () {
250
250
  name: "name",
251
251
  layers: "layer1, layer2"
252
252
  },
253
- layer = wms.createLayer({singleTile: false, tilesize: "10", extent: [10, 20, 11, 22]}, layerParams, options);
253
+ layer = wms.createLayer({singleTile: false, tilesize: "10", extent: [10, 20, 11, 22]}, {layerParams, options});
254
254
 
255
255
  expect(layer).toBeInstanceOf(TileLayer);
256
256
  expect(layer.get("name")).toEqual("name");
@@ -266,7 +266,7 @@ describe("wms.js", function () {
266
266
  name: "name",
267
267
  layers: "layer1, layer2"
268
268
  },
269
- layer = wms.createLayer({singleTile: true}, layerParams);
269
+ layer = wms.createLayer({singleTile: true}, {layerParams});
270
270
 
271
271
  expect(layer).toBeInstanceOf(ImageLayer);
272
272
  expect(layer.get("name")).toEqual("name");
@@ -86,7 +86,8 @@ describe("src/maps/interactions/drawInteraction.js", () => {
86
86
  fillColor: [55, 126, 184],
87
87
  fillTransparency: 0,
88
88
  strokeColor: [0, 0, 0],
89
- strokeWidth: 1
89
+ strokeWidth: 1,
90
+ polygonDash: [4]
90
91
  };
91
92
 
92
93
  drawInteractions.setStyleObject(currentLayout);
@@ -124,6 +125,8 @@ describe("src/maps/interactions/drawInteraction.js", () => {
124
125
  0,
125
126
  0
126
127
  ],
128
+ polygonStrokeDash: [4],
129
+ polygonStrokeDashOffset: undefined,
127
130
  polygonStrokeWidth: 1
128
131
  }
129
132
  }
@@ -5,7 +5,7 @@ import Feature from "ol/Feature";
5
5
  import Polygon from "ol/geom/Polygon";
6
6
  import MultiPoint from "ol/geom/MultiPoint";
7
7
  import * as webgl from "../../src/renderer/webgl";
8
- import WebGLPointsLayer from "ol/layer/WebGLVector";
8
+ import WebGLVectorLayer from "ol/layer/WebGLVector.js";
9
9
  import Layer from "ol/layer/Layer";
10
10
  import {returnColor} from "../../src/vectorStyle/lib/colorConvertions";
11
11
 
@@ -18,7 +18,7 @@ jest.mock("../../src/vectorStyle/styleList.js", () => {
18
18
  });
19
19
 
20
20
  describe("webgl.js", () => {
21
- let layerParams, layerParamsVectorTile, rawLayer, rawLayerVectorTile, styleRule, styleObject, defaultStyle;
21
+ let layerParams, layerParamsVectorTile, rawLayer, rawLayerVectorTile, styleRule, styleObject, defaultPointStyle;
22
22
 
23
23
  beforeEach(() => {
24
24
  layerParams = {
@@ -68,23 +68,30 @@ describe("webgl.js", () => {
68
68
  styleObject = {
69
69
  rules: [styleRule]
70
70
  };
71
- defaultStyle = {
71
+ defaultPointStyle = {
72
72
  fillColor: "#006688",
73
73
  strokeColor: "#006688",
74
74
  strokeWidth: 1,
75
75
  opacity: 1,
76
- size: 20
76
+ zoom: [
77
+ 3, 6,
78
+ 6, 10,
79
+ 9, 20,
80
+ 12, 35,
81
+ 15, 60,
82
+ 18, 110
83
+ ]
77
84
  };
78
85
  });
79
86
 
80
87
  describe("createLayer", () => {
81
88
  let source = new VectorSource();
82
89
 
83
- it("should return a WebGLPointsLayer", () => {
90
+ it("should return a WebGLVectorLayer", () => {
84
91
  layerParams.isPointLayer = true;
85
92
  const webglLayer = webgl.createLayer({...rawLayer, ...layerParams, source});
86
93
 
87
- expect(webglLayer).toBeInstanceOf(WebGLPointsLayer);
94
+ expect(webglLayer).toBeInstanceOf(WebGLVectorLayer);
88
95
  expect(webglLayer.get("isPointLayer")).toBeTruthy();
89
96
  });
90
97
  it("should return a custom Layer", () => {
@@ -92,7 +99,7 @@ describe("webgl.js", () => {
92
99
  const webglLayer = webgl.createLayer({...rawLayer, ...layerParams, source});
93
100
 
94
101
  expect(webglLayer).toBeInstanceOf(Layer);
95
- expect(webglLayer).not.toBeInstanceOf(WebGLPointsLayer);
102
+ expect(webglLayer).not.toBeInstanceOf(WebGLVectorLayer);
96
103
  expect(webglLayer.get("isPointLayer")).toBeFalsy();
97
104
  });
98
105
  it("vectorTile: should return a VectorTile layer", () => {
@@ -102,7 +109,7 @@ describe("webgl.js", () => {
102
109
 
103
110
  expect(webglLayer).toBeInstanceOf(Layer);
104
111
  expect(webglLayer).toBeInstanceOf(VectorTile);
105
- expect(webglLayer).not.toBeInstanceOf(WebGLPointsLayer);
112
+ expect(webglLayer).not.toBeInstanceOf(WebGLVectorLayer);
106
113
  expect(webglLayer.get("isPointLayer")).toBeFalsy();
107
114
  });
108
115
  });
@@ -187,12 +194,46 @@ describe("webgl.js", () => {
187
194
  rules: [styleRule]
188
195
  };
189
196
  webgl.formatFeatureStyles($feature, styleObject);
190
- expect($feature.get("fillColor")).toEqual(defaultStyle.fillColor);
191
- expect($feature.get("strokeColor")).toEqual(defaultStyle.strokeColor);
192
- expect($feature.get("strokeWidth")).toEqual(defaultStyle.strokeWidth);
193
- expect($feature.get("opacity")).toEqual(defaultStyle.opacity);
194
- expect($feature.get("circleSize")).toEqual(defaultStyle.size);
197
+ expect($feature.get("fillColor")).toEqual(defaultPointStyle.fillColor);
198
+ expect($feature.get("strokeColor")).toEqual(defaultPointStyle.strokeColor);
199
+ expect($feature.get("strokeWidth")).toEqual(defaultPointStyle.strokeWidth);
200
+ expect($feature.get("opacity")).toEqual(defaultPointStyle.opacity);
195
201
  });
202
+
203
+ it("should calculate circle-radius based on zoom level", () => {
204
+ const zoomLevels = [3, 6, 9, 12, 15, 18],
205
+ expectedRadii = [6, 10, 20, 35, 60, 110];
206
+
207
+ // eslint-disable-next-line no-use-before-define, max-nested-callbacks
208
+ zoomLevels.forEach((zoom, index) => testZoomLevel(zoom, index, expectedRadii));
209
+ });
210
+
211
+ function interpolateCircleRadius (zoom, zoomArray) {
212
+ for (let i = 0; i < zoomArray.length; i += 2) {
213
+ const z = zoomArray[i],
214
+ r = zoomArray[i + 1];
215
+
216
+ if (zoom <= z) {
217
+ if (i === 0) {
218
+ return r;
219
+ }
220
+ const zPrev = zoomArray[i - 2],
221
+ rPrev = zoomArray[i - 1],
222
+ t = (zoom - zPrev) / (z - zPrev);
223
+
224
+ return rPrev + (t * (r - rPrev));
225
+ }
226
+ }
227
+ return zoomArray[zoomArray.length - 1];
228
+ }
229
+
230
+ function testZoomLevel (zoom, index, expectedRadii) {
231
+ const expectedRadius = expectedRadii[index],
232
+ actualRadius = interpolateCircleRadius(zoom, defaultPointStyle.zoom);
233
+
234
+ expect(actualRadius).toEqual(expectedRadius);
235
+ }
236
+
196
237
  });
197
238
  });
198
239
  });