@masterportal/masterportalapi 2.14.0 → 2.15.1

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.
@@ -0,0 +1,250 @@
1
+ import WebGLPointsLayer from "ol/layer/WebGLPoints";
2
+ import WebGLVectorLayerRenderer from "ol/renderer/webgl/VectorLayer";
3
+ import VectorLayer from "ol/layer/Layer";
4
+ import {packColor} from "ol/renderer/webgl/shaders";
5
+ import styleList from "../vectorStyle/styleList";
6
+ import {getRulesForFeature} from "../vectorStyle/lib/getRuleForIndex";
7
+
8
+ /**
9
+ * The default style for OpenLayers WebGLPoints class
10
+ * @see https://openlayers.org/en/latest/examples/webgl-points-layer.html
11
+ * @private
12
+ */
13
+ const defaultStyle = {
14
+ symbol: {
15
+ symbolType: "circle",
16
+ size: 20,
17
+ color: "#006688",
18
+ rotateWithView: false,
19
+ offset: [0, 0],
20
+ opacity: 0.6
21
+ }
22
+ };
23
+
24
+ /**
25
+ * parses the styling rules for the renderer
26
+ * @static
27
+ * @private
28
+ * @returns {Object} the style options object with conditional functions
29
+ */
30
+ export function getRenderFunctions () {
31
+ return {
32
+ /**
33
+ * Used for polygon fills
34
+ * Reads the relevant properties from the Masterportal style object
35
+ * @see https://bitbucket.org/geowerkstatt-hamburg/masterportal/src/dev/doc/style.json.md
36
+ */
37
+ fill: {
38
+ attributes: {
39
+ color: (feature) => {
40
+ return packColor(feature.styleRule?.style.polygonFillColor || "#006688");
41
+ },
42
+ opacity: (feature) => {
43
+ return typeof feature.styleRule?.style.polygonFillColor?.[3] === "number" ?
44
+ feature.styleRule.style.polygonFillColor[3] : 1;
45
+ }
46
+ }
47
+ },
48
+ stroke: {
49
+ /**
50
+ * Used for polygon edges and lineStrings
51
+ * Reads the relevant properties from the Masterportal style object
52
+ * @see https://bitbucket.org/geowerkstatt-hamburg/masterportal/src/dev/doc/style.json.md
53
+ */
54
+ attributes: {
55
+ color: (feature) => {
56
+ return packColor(feature.styleRule?.style.polygonStrokeColor || "#006688");
57
+ },
58
+ width: (feature) => {
59
+ return feature.styleRule?.style.polygonStrokeWidth || 1;
60
+ },
61
+ opacity: (feature) => {
62
+ return typeof feature.styleRule?.style.polygonStrokeColor?.[3] === "number" ?
63
+ feature.styleRule.style.polygonStrokeColor[3] : 1;
64
+ }
65
+ }
66
+ },
67
+ point: {
68
+ /**
69
+ * As of now, the generic VectorLayerRenderer only supports points rendered as quads
70
+ * available attributes: color, size, opacity
71
+ * Due to that, we use WebGLPoints Layer Class for point geom types
72
+ * Reads the relevant properties from the Masterportal style object
73
+ * @see https://bitbucket.org/geowerkstatt-hamburg/masterportal/src/dev/doc/style.json.md
74
+ */
75
+ attributes: {
76
+ color: (feature) => {
77
+ return packColor(feature.styleRule?.style.circleFillColor || "#006688");
78
+ },
79
+ size: (feature) => {
80
+ return feature.styleRule?.style.circleRadius || 20;
81
+ },
82
+ opacity: (feature) => {
83
+ return typeof feature.styleRule?.style.circleFillColor?.[3] === "number" ?
84
+ feature.styleRule.style.circleFillColor[3] : 1;
85
+ }
86
+ }
87
+ }
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Creates a layer object to extend from.
93
+ * @augments VectorLayer
94
+ * @private
95
+ * @implements {WebGLVectorLayerRenderer}
96
+ * @param {Object} attrs attributes of the layer
97
+ * @returns {module:ol/layer/Layer} the LocalWebGLLayer with a custom renderer for WebGL styling
98
+ */
99
+ export function createVectorLayerRenderer () {
100
+ /**
101
+ * @class LocalWebGLLayer
102
+ * @see https://openlayers.org/en/latest/examples/webgl-vector-layer.html
103
+ * @description the temporary class with a custom renderer to render the vector data with WebGL
104
+ */
105
+ class LocalWebGLLayer extends VectorLayer {
106
+ /**
107
+ * Creates a new renderer that takes the defined style of the new layer as an input
108
+ * @returns {module:ol/renderer/webgl/WebGLVectorLayerRenderer} the custom renderer
109
+ * @experimental
110
+ */
111
+ createRenderer () {
112
+ return new WebGLVectorLayerRenderer(this, getRenderFunctions());
113
+ }
114
+ }
115
+
116
+ return LocalWebGLLayer;
117
+ }
118
+
119
+ /**
120
+ * Parses the vectorStyle from style.json to the feature
121
+ * to reduce processing on runtime
122
+ * @private
123
+ * @param {module:ol/Feature} feature - the feature to check
124
+ * @param {module:Backbone/Model} [styleObject] - (optional) the style model from StyleList
125
+ * @returns {void}
126
+ */
127
+ export function formatFeatureStyles (feature, styleObject) {
128
+ if (!styleObject) {
129
+ return;
130
+ }
131
+
132
+ // extract first matching rule only
133
+ const rule = getRulesForFeature(styleObject, feature)[0];
134
+
135
+ // don't set on properties to avoid GFI issues
136
+ // undefined if no match
137
+ feature.styleRule = rule;
138
+ }
139
+
140
+ /**
141
+ * Layouts the geometry coordinates, removes the Z component
142
+ * @deprecated Will be probably removed in release version
143
+ * @private
144
+ * @param {module:ol/Feature} feature - the feature to format
145
+ * @returns {void}
146
+ */
147
+ export function formatFeatureGeometry (feature) {
148
+ feature.getGeometry()?.setCoordinates?.(feature.getGeometry().getCoordinates(), "XY");
149
+ }
150
+
151
+ /**
152
+ * Cleans the data by automatically parsing data provided as strings to the accurate data type
153
+ * @todo Extend to Date types
154
+ * @private
155
+ * @param {module:ol/Feature} feature - the feature to format
156
+ * @param {String[]} [excludeTypes=["boolean"]] - types that should not be parsed from strings
157
+ * @returns {void}
158
+ */
159
+ export function formatFeatureData (feature, excludeTypes = ["boolean"]) {
160
+ for (const key in feature.getProperties()) {
161
+ const
162
+ valueAsNumber = parseFloat(feature.get(key)),
163
+ valueIsTrue = typeof feature.get(key) === "string" && feature.get(key).toLowerCase() === "true" ? true : undefined,
164
+ valueIsFalse = typeof feature.get(key) === "string" && feature.get(key).toLowerCase() === "false" ? false : undefined;
165
+
166
+ if (!isNaN(parseFloat(feature.get(key))) && !excludeTypes.includes("number")) {
167
+ feature.set(key, valueAsNumber);
168
+ }
169
+ if (valueIsTrue === true && !excludeTypes.includes("boolean")) {
170
+ feature.set(key, valueIsTrue);
171
+ }
172
+ if (valueIsFalse === false && !excludeTypes.includes("boolean")) {
173
+ feature.set(key, valueIsFalse);
174
+ }
175
+ }
176
+ }
177
+
178
+ /**
179
+ * feature transformations called after loading
180
+ * called by the layer source loader, binds the instance of the layer model
181
+ * should be called on each source refresh
182
+ * @param {module:ol/Feature[]} features - the features loaded by the layer
183
+ * @param {String} styleId - The layer's styleId
184
+ * @param {String[]} excludeTypesFromParsing - types that should not be parsed from strings, only necessary for webgl
185
+ * @returns {void}
186
+ */
187
+ export function afterLoading (features, styleId, excludeTypesFromParsing) {
188
+ const styleObject = styleList.returnStyleObject(styleId); // load styleModel to extract rules per feature
189
+
190
+ if (Array.isArray(features)) {
191
+ features.forEach(feature => {
192
+ formatFeatureGeometry(feature); /** @deprecated will propbably not be necessary anymore in release version */
193
+ formatFeatureStyles(feature, styleObject); /** @todo needs refactoring in release version */
194
+ formatFeatureData(feature, excludeTypesFromParsing); /** Necessary since the WebGLPoints Style Syntax depends on data types (i.e. numbers not as strings) */
195
+ });
196
+ }
197
+ }
198
+
199
+
200
+ /**
201
+ * Creates the OL Layer instance, used to rebuild the layer when shown again after layer has been disposed
202
+ * @param {Object} attrs - the attributes of the layer
203
+ * @public
204
+ * @returns {VectorLayer | WebGLPointsLayer} returns the layer instance
205
+ */
206
+ export function createLayer (attrs) {
207
+ let LayerConstructor = WebGLPointsLayer;
208
+ const options = {
209
+ id: attrs.id,
210
+ source: attrs.source,
211
+ disableHitDetection: false,
212
+ name: attrs.name,
213
+ typ: attrs.typ,
214
+ gfiAttributes: attrs.gfiAttributes,
215
+ gfiTheme: attrs.gfiTheme,
216
+ hitTolerance: attrs.hitTolerance || 10,
217
+ opacity: attrs.transparency ? (100 - attrs.transparency) / 100 : attrs.opacity,
218
+ renderer: "webgl",
219
+ styleId: attrs.styleId,
220
+ excludeTypesFromParsing: attrs.excludeTypesFromParsing
221
+ };
222
+
223
+ /**
224
+ * If the layer consists only of points, use WebGLPointsLayer
225
+ * For advanced styling options
226
+ * @see https://openlayers.org/en/latest/examples/webgl-points-layer.html
227
+ */
228
+ if (attrs.isPointLayer) {
229
+ /**
230
+ * @deprecated
231
+ * @todo will be replaced in the next OL release and incorporated in the WebGLVectorLayerRenderer
232
+ */
233
+ return new LayerConstructor({
234
+ style: attrs.style || defaultStyle,
235
+ disableHitDetection: false,
236
+ ...options,
237
+ isPointLayer: true
238
+ });
239
+ }
240
+
241
+ /**
242
+ * use ol/renderer/webgl/WebGLVectorLayerRenderer if not point layer
243
+ * Point styling as quads only
244
+ */
245
+ LayerConstructor = createVectorLayerRenderer(attrs);
246
+ return new LayerConstructor({
247
+ ...options,
248
+ isPointLayer: false
249
+ });
250
+ }
@@ -278,4 +278,4 @@ export default {
278
278
  initializeStyleList,
279
279
  addToStyleList,
280
280
  returnStyleObject
281
- };
281
+ };
@@ -46,8 +46,12 @@ class PointStyle extends StyleClass {
46
46
  * @returns {ol/style} - The created style.
47
47
  */
48
48
  getStyle () {
49
- const type = this.attributes.type.toLowerCase(),
50
- isClustered = this.isClustered;
49
+ const isClustered = this.isClustered;
50
+ let type = this.attributes.type.toLowerCase();
51
+
52
+ if (isClustered && this.feature.get("features")?.length > 1) {
53
+ type = this.attributes.clusterType.toLowerCase();
54
+ }
51
55
 
52
56
  if (type === "icon") {
53
57
  return createIconStyle(this.attributes, this.feature, isClustered);
@@ -38,7 +38,7 @@ class TextStyle extends StyleClass {
38
38
  getStyle () {
39
39
  const isClustered = this.isClustered,
40
40
  feature = this.feature,
41
- labelField = this.labelField;
41
+ labelField = this.attributes.labelField;
42
42
 
43
43
  if (isClustered && feature.get("features")?.length > 1 && this.attributes.clusterTextType !== "none") {
44
44
  return this.createClusteredTextStyle();
@@ -3,9 +3,17 @@ import VectorSource from "ol/source/Vector.js";
3
3
  import Feature from "ol/Feature";
4
4
  import {Style, Icon} from "ol/style.js";
5
5
  import {geojson} from "../../../src";
6
+ import * as webgl from "../../../src/renderer/webgl.js";
6
7
 
7
8
  const features = [new Feature(), new Feature()];
8
9
 
10
+ jest.mock("../../../src/renderer/webgl.js", () => {
11
+ const original = jest.requireActual("../../../src/renderer/webgl.js");
12
+
13
+ original.afterLoading = jest.fn();
14
+ return original;
15
+ });
16
+
9
17
  describe("geojson/index", function () {
10
18
  describe("createLayer", function () {
11
19
  it("creates an ol/layer/Vector", function () {
@@ -70,6 +78,12 @@ describe("geojson/index", function () {
70
78
  expect(layer.get("name")).toEqual("name");
71
79
  expect(layer.get("layers")).toEqual("layer1, layer2");
72
80
  });
81
+ it("creates a WebGLLayer, with param renderer \"webgl\"", function () {
82
+ const layer = geojson.createLayer({}, {layerParams: {renderer: "webgl"}});
83
+
84
+ expect(layer.constructor.name).toEqual("LocalWebGLLayer");
85
+ expect(layer.getSource()).toBeInstanceOf(VectorSource);
86
+ });
73
87
  });
74
88
 
75
89
  describe("createLayerSource", function () {
@@ -79,6 +93,15 @@ describe("geojson/index", function () {
79
93
  expect(source.getFormat()).toBeDefined();
80
94
  expect(source.getUrl()).toBeDefined();
81
95
  });
96
+ it("creates a vectorSource with an additional listener, when renderer is \"webgl\"", () => {
97
+ const
98
+ rawLayer = {url: "example.com/geo.json"},
99
+ source = geojson.createLayerSource({...rawLayer, renderer: "webgl"}, {});
100
+
101
+ expect(source.getListeners("featuresloadend")).toHaveLength(2);
102
+ source.getListeners("featuresloadend")[1]({features: []});
103
+ expect(webgl.afterLoading).toHaveBeenCalled();
104
+ });
82
105
 
83
106
  });
84
107
 
@@ -7,6 +7,7 @@ import defaults from "../../src/defaults";
7
7
  import GeoJSON from "ol/format/GeoJSON.js";
8
8
  import * as oaf from "../../src/layer/oaf";
9
9
  import {featureCollection} from "./resources/oafFeatures";
10
+ import * as webgl from "../../src/renderer/webgl.js";
10
11
 
11
12
  jest.mock("../../src/rawLayerList.js", () => {
12
13
  const original = jest.requireActual("../../src/rawLayerList.js");
@@ -15,6 +16,13 @@ jest.mock("../../src/rawLayerList.js", () => {
15
16
  return original;
16
17
  });
17
18
 
19
+ jest.mock("../../src/renderer/webgl.js", () => {
20
+ const original = jest.requireActual("../../src/renderer/webgl.js");
21
+
22
+ original.afterLoading = jest.fn();
23
+ return original;
24
+ });
25
+
18
26
 
19
27
  describe("oaf.js", function () {
20
28
  describe("createLayer", function () {
@@ -107,6 +115,12 @@ describe("oaf.js", function () {
107
115
  expect(layer.get("name")).toEqual("name");
108
116
  expect(layer.get("layers")).toEqual("layer1, layer2");
109
117
  });
118
+ it("creates a WebGLLayer, with param renderer \"webgl\"", function () {
119
+ const layer = oaf.createLayer({id: "id"}, {layerParams: {renderer: "webgl"}});
120
+
121
+ expect(layer.constructor.name).toEqual("LocalWebGLLayer");
122
+ expect(layer.getSource()).toBeInstanceOf(VectorSource);
123
+ });
110
124
  });
111
125
  describe("createLayerSource", function () {
112
126
  const consoleError = console.error;
@@ -241,5 +255,21 @@ describe("oaf.js", function () {
241
255
  expect(afterLoadingMock.mock.calls.length).toBe(1);
242
256
  });
243
257
  });
258
+ it("creates a vectorSource with an additional listener, when renderer is \"webgl\"", () => {
259
+ const
260
+ url = "https://url.de",
261
+ rawLayer = {
262
+ id: "id",
263
+ url: url,
264
+ featureNS: "http://www.deegree.org/app",
265
+ featureType: "krankenhaeuser_hh",
266
+ version: "1.0.0"
267
+ },
268
+ source = oaf.createLayerSource({...rawLayer, renderer: "webgl"});
269
+
270
+ expect(source.getListeners("featuresloadend")).toHaveLength(1);
271
+ source.getListeners("featuresloadend")[0]({features: []});
272
+ expect(webgl.afterLoading).toHaveBeenCalled();
273
+ });
244
274
  });
245
275
  });
@@ -4,6 +4,14 @@ import Polygon from "ol/geom/Polygon";
4
4
  import VectorLayer from "ol/layer/Vector";
5
5
  import VectorSource from "ol/source/Vector.js";
6
6
  import * as vectorBase from "../../src/layer/vectorBase";
7
+ import * as webgl from "../../src/renderer/webgl.js";
8
+
9
+ jest.mock("../../src/renderer/webgl.js", () => {
10
+ const original = jest.requireActual("../../src/renderer/webgl.js");
11
+
12
+ original.afterLoading = jest.fn();
13
+ return original;
14
+ });
7
15
 
8
16
  describe("vectorBase.js", function () {
9
17
 
@@ -25,23 +33,35 @@ describe("vectorBase.js", function () {
25
33
 
26
34
  expect(source).toBeInstanceOf(VectorSource);
27
35
  });
36
+ it("creates a vectorSource with an additional listener, when renderer is \"webgl\"", () => {
37
+ vectorBase.createLayerSource({renderer: "webgl"});
38
+
39
+ expect(webgl.afterLoading).toHaveBeenCalled();
40
+ });
28
41
  });
29
42
 
30
43
  describe("createLayer", function () {
44
+ const attr = {
45
+ name: "Albus Percival Wulfric Brian Dumbledore",
46
+ typ: "VectorBase",
47
+ gfiAttributes: "ignore",
48
+ id: "Rawenclaw_01"
49
+ };
50
+
31
51
  it("creates a vector Base Layer", function () {
32
- const attr = {
33
- name: "Albus Percival Wulfric Brian Dumbledore",
34
- typ: "VectorBase",
35
- gfiAttributes: "ignore",
36
- id: "Rawenclaw_01"
37
- },
38
- layer = vectorBase.createLayer(attr);
52
+ const layer = vectorBase.createLayer(attr);
39
53
 
40
54
  expect(layer).toBeInstanceOf(VectorLayer);
41
55
  expect(layer.get("name")).toEqual("Albus Percival Wulfric Brian Dumbledore");
42
56
  expect(layer.get("typ")).toEqual("VectorBase");
43
57
  expect(layer.get("id")).toEqual("Rawenclaw_01");
44
58
  });
59
+ it("creates a WebGLLayer, with param renderer \"webgl\"", function () {
60
+ const layer = vectorBase.createLayer({...attr, renderer: "webgl"});
61
+
62
+ expect(layer.constructor.name).toEqual("LocalWebGLLayer");
63
+ expect(layer.getSource()).toBeInstanceOf(VectorSource);
64
+ });
45
65
  });
46
66
 
47
67
  describe("updateSource", function () {
@@ -8,6 +8,7 @@ import {WFS} from "ol/format.js";
8
8
  import * as wfs from "../../src/layer/wfs";
9
9
  import {featureCollection} from "./resources/wfsFeatures";
10
10
  import {wfsFilterQuery} from "./resources/wfsFilter";
11
+ import * as webgl from "../../src/renderer/webgl.js";
11
12
 
12
13
  jest.mock("../../src/rawLayerList.js", () => {
13
14
  const original = jest.requireActual("../../src/rawLayerList.js");
@@ -16,6 +17,13 @@ jest.mock("../../src/rawLayerList.js", () => {
16
17
  return original;
17
18
  });
18
19
 
20
+ jest.mock("../../src/renderer/webgl.js", () => {
21
+ const original = jest.requireActual("../../src/renderer/webgl.js");
22
+
23
+ original.afterLoading = jest.fn();
24
+ return original;
25
+ });
26
+
19
27
 
20
28
  describe("wfs.js", function () {
21
29
  describe("createLayer", function () {
@@ -107,6 +115,12 @@ describe("wfs.js", function () {
107
115
  expect(layer.get("name")).toEqual("name");
108
116
  expect(layer.get("layers")).toEqual("layer1, layer2");
109
117
  });
118
+ it("creates a WebGLLayer, with param renderer \"webgl\"", function () {
119
+ const layer = wfs.createLayer({version: "1.1.0"}, {layerParams: {renderer: "webgl"}});
120
+
121
+ expect(layer.constructor.name).toEqual("LocalWebGLLayer");
122
+ expect(layer.getSource()).toBeInstanceOf(VectorSource);
123
+ });
110
124
  });
111
125
  describe("createLayerSource", function () {
112
126
  const consoleError = console.error;
@@ -383,6 +397,22 @@ describe("wfs.js", function () {
383
397
  expect(afterLoadingMock.mock.calls.length).toBe(1);
384
398
  });
385
399
  });
400
+ it("creates a vectorSource with an additional listener, when renderer is \"webgl\"", () => {
401
+ const
402
+ url = "https://url.de",
403
+ rawLayer = {
404
+ id: "id",
405
+ url: url,
406
+ featureNS: "http://www.deegree.org/app",
407
+ featureType: "krankenhaeuser_hh",
408
+ version: "1.0.0"
409
+ },
410
+ source = wfs.createLayerSource({...rawLayer, renderer: "webgl"});
411
+
412
+ expect(source.getListeners("featuresloadend")).toHaveLength(1);
413
+ source.getListeners("featuresloadend")[0]({features: []});
414
+ expect(webgl.afterLoading).toHaveBeenCalled();
415
+ });
386
416
  });
387
417
  });
388
418
 
@@ -0,0 +1,161 @@
1
+ import VectorSource from "ol/source/Vector.js";
2
+ import Feature from "ol/Feature";
3
+ import Polygon from "ol/geom/Polygon";
4
+ import * as webgl from "../../src/renderer/webgl";
5
+ import WebGLPointsLayer from "ol/layer/WebGLPoints";
6
+ import Layer from "ol/layer/Layer";
7
+ import {packColor} from "ol/renderer/webgl/shaders";
8
+ import styleList from "../../src/vectorStyle/styleList";
9
+
10
+ describe("webgl.js", () => {
11
+ let layerParams, rawLayer, styleRule, styleObject;
12
+
13
+ beforeEach(() => {
14
+ layerParams = {
15
+ name: "webglTestLayer",
16
+ id: "123",
17
+ typ: "WFS",
18
+ renderer: "webgl",
19
+ styleId: "123"
20
+ };
21
+ rawLayer = {
22
+ url: "https://url.de",
23
+ name: "wfsSourceLayer",
24
+ id: "123",
25
+ typ: "WFS",
26
+ version: "2.0.0",
27
+ featureNS: "http://www.deegree.org/app",
28
+ featureType: "krankenhaeuser_hh",
29
+ outputFormat: "XML"
30
+ };
31
+ styleRule = {style: {
32
+ polygonFillColor: [255, 0, 0, 0.5],
33
+ polygonStrokeColor: [0, 255, 0, 0.5],
34
+ polygonStrokeWidth: 2,
35
+ circleFillColor: [0, 0, 255, 0.5],
36
+ circleRadius: 6
37
+ }};
38
+ styleObject = {
39
+ rules: [styleRule]
40
+ };
41
+
42
+ jest.spyOn(styleList, "returnStyleObject").mockImplementation(() => styleObject);
43
+ });
44
+
45
+ afterEach(() => {
46
+ jest.restoreAllMocks();
47
+ });
48
+
49
+ describe("createLayer", () => {
50
+ const source = new VectorSource();
51
+
52
+ it("should return a WebGLPointsLayer", () => {
53
+ layerParams.isPointLayer = true;
54
+ const webglLayer = webgl.createLayer({...rawLayer, ...layerParams, source});
55
+
56
+ expect(webglLayer).toBeInstanceOf(WebGLPointsLayer);
57
+ expect(webglLayer.get("isPointLayer")).toBeTruthy();
58
+ });
59
+ it("should return a custom Layer", () => {
60
+ layerParams.isPointLayer = false;
61
+ const webglLayer = webgl.createLayer({...rawLayer, ...layerParams, source});
62
+
63
+ expect(webglLayer).toBeInstanceOf(Layer);
64
+ expect(webglLayer).not.toBeInstanceOf(WebGLPointsLayer);
65
+ expect(webglLayer.get("isPointLayer")).toBeFalsy();
66
+ });
67
+ });
68
+ describe("private format and style functions", () => {
69
+ const
70
+ feature = new Feature({
71
+ geometry: new Polygon([
72
+ [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 0, 0]]
73
+ ], "XYZ"),
74
+ apple: "42",
75
+ pear: "true",
76
+ pumpkin: "false"
77
+ });
78
+ let $feature;
79
+
80
+ describe("formatFeatureGeometry", () => {
81
+ it("should remove any Z components from the geometry", () => {
82
+ $feature = feature.clone();
83
+ webgl.formatFeatureGeometry($feature);
84
+ /* eslint-disable-next-line max-nested-callbacks */
85
+ expect($feature.getGeometry().getCoordinates()[0].every(coord => coord.length === 2)).toBeTruthy();
86
+ });
87
+ });
88
+ describe("formatFeatureData", () => {
89
+ it("should not format excluded formats 'number' and 'boolean", () => {
90
+ $feature = feature.clone();
91
+ webgl.formatFeatureData($feature, ["number", "boolean"]);
92
+ expect(typeof $feature.get("apple")).toEqual("string");
93
+ expect(typeof $feature.get("pear")).toEqual("string");
94
+ expect(typeof $feature.get("pumpkin")).toEqual("string");
95
+ });
96
+ it("should format numbers and booleans", () => {
97
+ $feature = feature.clone();
98
+ webgl.formatFeatureData($feature, []);
99
+ expect(typeof $feature.get("apple")).toEqual("number");
100
+ expect(typeof $feature.get("pear")).toEqual("boolean");
101
+ expect(typeof $feature.get("pumpkin")).toEqual("boolean");
102
+ });
103
+ });
104
+ describe("formatFeatureStyles", () => {
105
+ it("bind the styling rule from the styleObject to each feature", () => {
106
+ $feature = feature.clone();
107
+ webgl.formatFeatureStyles($feature, styleObject);
108
+ expect($feature.styleRule).toEqual(styleRule);
109
+ });
110
+ });
111
+ describe("getRenderFunctions", () => {
112
+ it("should read the style from styleRule and pack them to single float", () => {
113
+ const renderFunctions = webgl.getRenderFunctions();
114
+
115
+ $feature = feature.clone();
116
+ webgl.formatFeatureStyles($feature, styleObject);
117
+ expect(renderFunctions.fill.attributes.color($feature)).toEqual(packColor(styleRule.style.polygonFillColor));
118
+ expect(renderFunctions.fill.attributes.opacity($feature)).toEqual(styleRule.style.polygonFillColor[3]);
119
+ expect(renderFunctions.stroke.attributes.color($feature)).toEqual(packColor(styleRule.style.polygonStrokeColor));
120
+ expect(renderFunctions.stroke.attributes.width($feature)).toEqual(styleRule.style.polygonStrokeWidth);
121
+ expect(renderFunctions.stroke.attributes.opacity($feature)).toEqual(styleRule.style.polygonStrokeColor[3]);
122
+ expect(renderFunctions.point.attributes.color($feature)).toEqual(packColor(styleRule.style.circleFillColor));
123
+ expect(renderFunctions.point.attributes.size($feature)).toEqual(styleRule.style.circleRadius);
124
+ expect(renderFunctions.point.attributes.opacity($feature)).toEqual(styleRule.style.circleFillColor[3]);
125
+ });
126
+ it("should return default values if style is empty, i.e. \"default\" style", () => {
127
+ const renderFunctions = webgl.getRenderFunctions();
128
+
129
+ styleObject = {
130
+ rules: [{
131
+ style: {}
132
+ }]
133
+ };
134
+ $feature = feature.clone();
135
+ webgl.formatFeatureStyles($feature, styleObject);
136
+ expect(typeof renderFunctions.fill.attributes.color($feature)).toEqual("number");
137
+ expect(typeof renderFunctions.fill.attributes.opacity($feature)).toEqual("number");
138
+ expect(typeof renderFunctions.stroke.attributes.color($feature)).toEqual("number");
139
+ expect(typeof renderFunctions.stroke.attributes.width($feature)).toEqual("number");
140
+ expect(typeof renderFunctions.stroke.attributes.opacity($feature)).toEqual("number");
141
+ expect(typeof renderFunctions.point.attributes.color($feature)).toEqual("number");
142
+ expect(typeof renderFunctions.point.attributes.size($feature)).toEqual("number");
143
+ expect(typeof renderFunctions.point.attributes.opacity($feature)).toEqual("number");
144
+ });
145
+ it("should return default values if no style rule is found", () => {
146
+ const renderFunctions = webgl.getRenderFunctions();
147
+
148
+ $feature = feature.clone();
149
+ expect(feature.styleRule).toBeUndefined();
150
+ expect(typeof renderFunctions.fill.attributes.color($feature)).toEqual("number");
151
+ expect(typeof renderFunctions.fill.attributes.opacity($feature)).toEqual("number");
152
+ expect(typeof renderFunctions.stroke.attributes.color($feature)).toEqual("number");
153
+ expect(typeof renderFunctions.stroke.attributes.width($feature)).toEqual("number");
154
+ expect(typeof renderFunctions.stroke.attributes.opacity($feature)).toEqual("number");
155
+ expect(typeof renderFunctions.point.attributes.color($feature)).toEqual("number");
156
+ expect(typeof renderFunctions.point.attributes.size($feature)).toEqual("number");
157
+ expect(typeof renderFunctions.point.attributes.opacity($feature)).toEqual("number");
158
+ });
159
+ });
160
+ });
161
+ });