@masterportal/masterportalapi 2.49.0 → 2.51.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
@@ -4,7 +4,6 @@
4
4
  The [Semantic Versioning](https://semver.org/spec/v2.0.0.html) is used.
5
5
 
6
6
  ## Unreleased - in development
7
-
8
7
  ### __Breaking Changes__
9
8
 
10
9
  ### Added
@@ -19,10 +18,49 @@
19
18
 
20
19
  ---
21
20
 
22
- ## 2.49.0 - 2025-04-294
21
+ ## 2.51.0 - 2025-09-18
22
+
23
+ ### __Breaking Changes__
24
+ - Dropped support for **Node.js 18.x**, **20.x** and **npm 9**. Minimum required is now **Node.js 22.19.0 (LTS)** with **npm 10.x**.
25
+
26
+ ### Changed
27
+ - cesium/engine updated to current Version 20.0.1
28
+ - The following packages have been updated:
29
+ - devDependencies:
30
+ - @parcel: ^2.13.0 to ^2.15.4
31
+ - @swc/jest: ^0.2.29 to ^0.2.39
32
+ - canvas: ^2.11.2 to ^3.1.2
33
+ - jest: ^29.7.0 to ^30.0.5
34
+ - jest-environment-jsdom: ^29.7.0 to ^30.0.5
35
+ - transformer-sass: ^2.13.0 to ^2.15.4
36
+ - the following package has been added:
37
+ - devDependencies:
38
+ - @parcel/config-default": "^2.15.4"
39
+
40
+ ---
41
+
42
+ ## 2.50.0 - 2025-08-214
43
+
44
+ ### Added
45
+ - vectorStyle: added function `initStyleAndAddToList` to styleList. Adds a style contained in style.json to list of styles.
46
+ - A new parameter "doNotLoadInitially" for OAF layer so that the layer can be loaded without features, which is necessary for external filtering.
47
+
48
+ ### Changed
49
+ - The following packages have been updated:
50
+ - dependencies:
51
+ - ol: 10.4.1 to 10.6.0
52
+
53
+ ### Fixed
54
+ - WMTS-Layer: Fixed layers without capabilities.
55
+ - WFTS-Layer: Ensured zIndex is applied correctly to layers using webgl renderer.
56
+
57
+ ---
58
+
59
+ ## 2.49.0 - 2025-04-29
23
60
 
24
61
  ### Added
25
62
  - Add new parameters polygonStrokeDash, polygonStrokeDashOffset in styleObject of drawInteraction.
63
+ - webgl: extended default style for points.
26
64
 
27
65
  ### Changed
28
66
  - The following packages have been updated:
@@ -0,0 +1,43 @@
1
+ image: node:22.19.0
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/package.json CHANGED
@@ -1,14 +1,25 @@
1
1
  {
2
2
  "name": "@masterportal/masterportalapi",
3
3
  "author": "Implementierungspartnerschaft Masterportal <info@masterportal.org> (https://www.masterportal.org)",
4
- "version": "2.49.0",
4
+ "version": "2.51.0",
5
5
  "license": "MIT",
6
6
  "description": "Basic functions of the Masterportal as api",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://bitbucket.org/geowerkstatt-hamburg/masterportalapi.git"
10
10
  },
11
+ "source": "src/index.js",
11
12
  "main": "src/index.js",
13
+ "exports": {
14
+ ".": "./src/index.js"
15
+ },
16
+ "targets": {
17
+ "library": {
18
+ "source": "src/index.js",
19
+ "distDir": "dist",
20
+ "outputFormat": "commonjs"
21
+ }
22
+ },
12
23
  "scripts": {
13
24
  "test": "jest .test.js --config ./jest.config.js --collectCoverage",
14
25
  "test:trace": "node --trace-warnings node_modules/jest/bin/jest.js .test.js --config ./jest.config.js",
@@ -21,33 +32,34 @@
21
32
  "dependencies": {
22
33
  "core-js": "^3.33.1",
23
34
  "dayjs": "^1.11.10",
24
- "ol": "^10.4.0",
35
+ "ol": "^10.6.0",
25
36
  "ol-mapbox-style": "12.5.0",
26
37
  "olcs": "^2.22.1",
27
38
  "proj4": "^2.10.0",
28
39
  "xml2js": "^0.6.2"
29
40
  },
30
41
  "devDependencies": {
31
- "@babel/core": "^7.23.2",
42
+ "@babel/core": "7.26.0",
32
43
  "@babel/plugin-transform-modules-commonjs": "^7.23.0",
33
- "@parcel/transformer-sass": "^2.10.0",
34
- "@swc/jest": "^0.2.29",
44
+ "@parcel/config-default": "^2.15.4",
45
+ "@parcel/transformer-sass": "^2.15.4",
46
+ "@swc/jest": "^0.2.39",
35
47
  "assert": "^2.1.0",
36
48
  "browserify-zlib": "^0.2.0",
37
49
  "buffer": "^6.0.3",
38
- "canvas": "^2.11.2",
39
- "eslint": "^8.52.0",
50
+ "canvas": "3.2.0",
51
+ "eslint": "8.57.1",
40
52
  "events": "^3.3.0",
41
53
  "https-browserify": "^1.0.0",
42
- "husky": "^8.0.3",
43
- "jest": "^29.7.0",
44
- "jest-canvas-mock": "^2.5.2",
45
- "jest-environment-jsdom": "^29.7.0",
54
+ "husky": "8.0.3",
55
+ "jest": "30.1.3",
56
+ "jest-canvas-mock": "2.5.2",
57
+ "jest-environment-jsdom": "30.1.2",
46
58
  "jest-fetch-mock": "^3.0.3",
47
- "jsdoc": "^4.0.2",
48
- "parcel": "^2.10.0",
59
+ "jsdoc": "4.0.2",
60
+ "parcel": "^2.15.4",
49
61
  "process": "^0.11.10",
50
- "sass": "^1.69.4",
62
+ "sass": "1.69.4",
51
63
  "stream-browserify": "^3.0.0",
52
64
  "stream-http": "^3.2.0",
53
65
  "timers-browserify": "^2.0.12",
@@ -56,11 +68,11 @@
56
68
  "util": "^0.12.5"
57
69
  },
58
70
  "peerDependencies": {
59
- "@cesium/engine": "^15.0.0"
71
+ "@cesium/engine": "^20.0.1"
60
72
  },
61
73
  "engines": {
62
- "node": "^16.13.2 || ^18.12.0 || ^20.12.2",
63
- "npm": "^8.1.2 || ^9.3.1 || ^10.5.0"
74
+ "node": "^22.19.0",
75
+ "npm": "^10.5.0"
64
76
  },
65
77
  "homepage": "https://bitbucket.org/geowerkstatt-hamburg/masterportalapi#readme",
66
78
  "directories": {
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,
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 {
@@ -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",
@@ -29,7 +40,14 @@ const defaultPointStyle = {
29
40
  opacity: 1
30
41
  },
31
42
 
32
- /** @type {import('ol/style/literal.js').LiteralStyle} */
43
+ /**
44
+ * @typedef {Object} LiteralStyle
45
+ * @property {string} [stroke-color]
46
+ * @property {number} [stroke-width]
47
+ * @property {string} [fill-color]
48
+ * @property {number} [opacity]
49
+ * @property {number} [size]
50
+ */
33
51
  style = Object.assign({
34
52
  "stroke-color": ["get", "strokeColor"],
35
53
  "stroke-width": ["get", "strokeWidth", "number"],
@@ -52,6 +70,11 @@ export function createVectorLayerRenderer () {
52
70
  * @description the temporary class with a custom renderer to render the vector data with WebGL
53
71
  */
54
72
  class LocalWebGLLayer extends VectorLayer {
73
+ constructor (options) {
74
+ super(options);
75
+ // Initialize with any default style variables
76
+ this.styleVariables = options.styleVariables || {};
77
+ }
55
78
  /**
56
79
  * Creates a new renderer that takes the defined style of the new layer as an input.
57
80
  * @returns {module:ol/renderer/webgl/WebGLVectorLayerRenderer} the custom renderer
@@ -62,6 +85,13 @@ export function createVectorLayerRenderer () {
62
85
  style
63
86
  });
64
87
  }
88
+ /**
89
+ * Get the current style variables.
90
+ * @returns {Object} - The current style variables.
91
+ */
92
+ getStyleVariables () {
93
+ return this.styleVariables;
94
+ }
65
95
  }
66
96
 
67
97
  return LocalWebGLLayer;
@@ -72,9 +102,10 @@ export function createVectorLayerRenderer () {
72
102
  * @augments VectorTile
73
103
  * @private
74
104
  * @implements {WebGLVectorTileLayerRenderer}
105
+ * @param {Object} attrs - the attributes of the layer
75
106
  * @returns {module:ol/layer/VectorTile} the LocalWebGLLayer with a custom renderer for WebGL styling of vectorTile layers.
76
107
  */
77
- export function createVectorTileLayerRenderer () {
108
+ export function createVectorTileLayerRenderer (attrs) {
78
109
  /**
79
110
  * @class LocalWebGLLayer
80
111
  * @see https://openlayers.org/en/latest/examples/webgl-vector-tiles.html
@@ -88,70 +119,8 @@ export function createVectorTileLayerRenderer () {
88
119
  * @experimental
89
120
  */
90
121
  createRenderer () {
91
- const result = parseLiteralStyle(style),
92
- invisible = [255, 255, 255, 0],
93
- grey = [119, 119, 119, 1];
94
-
95
-
96
122
  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
- }
123
+ style: attrs.style ? attrs.style : style
155
124
  });
156
125
  }
157
126
  }
@@ -275,10 +244,10 @@ export function afterLoading (features, styleId, excludeTypesFromParsing, isPoin
275
244
  * Creates the OL Layer instance, used to rebuild the layer when shown again after layer has been disposed
276
245
  * @param {Object} attrs - the attributes of the layer
277
246
  * @public
278
- * @returns {VectorLayer | WebGLPointsLayer} returns the layer instance
247
+ * @returns {VectorLayer | WebGLVectorLayer} returns the layer instance
279
248
  */
280
249
  export function createLayer (attrs) {
281
- let LayerConstructor = WebGLPointsLayer;
250
+ let LayerConstructor = WebGLVectorLayer;
282
251
  const options = {
283
252
  id: attrs.id,
284
253
  source: attrs.source,
@@ -292,7 +261,8 @@ export function createLayer (attrs) {
292
261
  renderer: "webgl",
293
262
  styleId: attrs.styleId,
294
263
  excludeTypesFromParsing: attrs.excludeTypesFromParsing,
295
- extent: attrs.extent
264
+ extent: attrs.extent,
265
+ zIndex: attrs.zIndex
296
266
  };
297
267
 
298
268
  /**
@@ -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
  };
@@ -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({
@@ -34,11 +34,12 @@ describe("setBackgroundImage.js", function () {
34
34
  });
35
35
 
36
36
  it("preserves empty string as input to set explicitly no background image", function () {
37
- const backgroundImage = "";
37
+ const backgroundImage = "",
38
+ got = document.getElementById("map").style.backgroundImage;
38
39
 
39
40
  setBackgroundImage({backgroundImage});
40
41
 
41
- expect(document.getElementById("map").style.backgroundImage).toBe("url()");
42
+ expect(["", "url()", "url(\"\")"]).toContain(got);
42
43
  });
43
44
 
44
45
  it("sets the default background image if none was given", function () {
@@ -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
  });