@masterportal/masterportalapi 2.12.0 → 2.14.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.
Files changed (50) hide show
  1. package/.eslintrc +2 -1
  2. package/CHANGELOG.md +19 -1
  3. package/example/config/portal.json +8 -1
  4. package/example/config/services.json +10 -0
  5. package/example/index.js +34 -2
  6. package/jest.config.js +1 -1
  7. package/jest.setup.js +9 -1
  8. package/package.json +63 -63
  9. package/src/layer/geojson/index.js +3 -3
  10. package/src/lib/attributeMapper.js +231 -0
  11. package/src/lib/getValueFromObjectByPath.js +73 -0
  12. package/src/lib/thousandsSeparator.js +23 -0
  13. package/src/maps/olcs/3dUtils/wmsRasterSynchronizer.js +3 -0
  14. package/src/vectorStyle/createStyle.js +259 -0
  15. package/src/vectorStyle/lib/colorConvertions.js +97 -0
  16. package/src/vectorStyle/lib/createLegendInfo.js +28 -0
  17. package/src/vectorStyle/lib/getGeometryTypeFromService.js +153 -0
  18. package/src/vectorStyle/lib/getRuleForIndex.js +62 -0
  19. package/src/vectorStyle/lib/valueOperations.js +172 -0
  20. package/src/vectorStyle/styleList.js +281 -0
  21. package/src/vectorStyle/styles/defaultStyles.js +177 -0
  22. package/src/vectorStyle/styles/point/stylePoint.js +108 -0
  23. package/src/vectorStyle/styles/point/stylePointCircle.js +29 -0
  24. package/src/vectorStyle/styles/point/stylePointIcon.js +79 -0
  25. package/src/vectorStyle/styles/point/stylePointInterval.js +124 -0
  26. package/src/vectorStyle/styles/point/stylePointNominal.js +232 -0
  27. package/src/vectorStyle/styles/point/stylePointRegularShape.js +39 -0
  28. package/src/vectorStyle/styles/polygon/polygonStyleHatch.js +160 -0
  29. package/src/vectorStyle/styles/polygon/stylePolygon.js +125 -0
  30. package/src/vectorStyle/styles/style.js +161 -0
  31. package/src/vectorStyle/styles/styleCesium.js +106 -0
  32. package/src/vectorStyle/styles/styleLine.js +51 -0
  33. package/src/vectorStyle/styles/styleText.js +143 -0
  34. package/test/lib/attributeMapper.test.js +290 -0
  35. package/test/lib/getValueFromObjectByPath.test.js +61 -0
  36. package/test/lib/thousandsSeparator.test.js +58 -0
  37. package/test/vectorStyle/createStyle.test.js +335 -0
  38. package/test/vectorStyle/lib/colorConvertions.test.js +42 -0
  39. package/test/vectorStyle/lib/getRuleForIndex.test.js +132 -0
  40. package/test/vectorStyle/lib/valueOperations.test.js +191 -0
  41. package/test/vectorStyle/styles/point/stylePoint.test.js +28 -0
  42. package/test/vectorStyle/styles/point/stylePointCircle.test.js +30 -0
  43. package/test/vectorStyle/styles/point/stylePointIcon.test.js +83 -0
  44. package/test/vectorStyle/styles/point/stylePointInterval.test.js +57 -0
  45. package/test/vectorStyle/styles/point/stylePointNominal.test.js +84 -0
  46. package/test/vectorStyle/styles/point/stylePointRegularShape.test.js +24 -0
  47. package/test/vectorStyle/styles/polygon/polygonStyleHatch.test.js +95 -0
  48. package/test/vectorStyle/styles/polygon/stylePolygon.test.js +61 -0
  49. package/test/vectorStyle/styles/styleLine.test.js +29 -0
  50. package/test/vectorStyle/styles/styleText.test.js +49 -0
@@ -0,0 +1,259 @@
1
+ import {Style} from "ol/style.js";
2
+ import PointStyle from "./styles/point/stylePoint";
3
+ import TextStyle from "./styles/styleText";
4
+ import PolygonStyle from "./styles/polygon/stylePolygon";
5
+ import LineStringStyle from "./styles/styleLine";
6
+ import CesiumStyle from "./styles/styleCesium";
7
+ import {getRuleForIndex, getRulesForFeature} from "./lib/getRuleForIndex";
8
+
9
+ const legendsOfAllStyles = [],
10
+ uniqueStyles = [];
11
+ let legendInformationLength = 0;
12
+
13
+ /**
14
+ * Returns true if feature contains some kind of MultiGeometry
15
+ * @param {string} geometryType the geometry type to check
16
+ * @returns {Boolean} is geometrytype a multiGeometry
17
+ */
18
+ function isMultiGeometry (geometryType) {
19
+ return geometryType === "MultiPoint" || geometryType === "MultiLineString" || geometryType === "MultiPolygon" || geometryType === "GeometryCollection" || geometryType === "Cesium";
20
+ }
21
+
22
+ /**
23
+ * Returns the style for simple (non-multi) geometry types
24
+ * @param {string} geometryType GeometryType
25
+ * @param {ol/feature} feature the ol/feature to style
26
+ * @param {object} rule styling rules to check.
27
+ * @param {Boolean} isClustered Flag to show if feature is clustered.
28
+ * @param {String} wfsImgPathFromConfig path to wfsImg from Config
29
+ * @returns {ol/style/Style} style is always returned
30
+ */
31
+ function getSimpleGeometryStyle (geometryType, feature, rule, isClustered, wfsImgPathFromConfig) {
32
+ const style = rule?.style,
33
+ legendValue = style ? style.legendValue : null,
34
+ alreadyExisitingStyle = uniqueStyles.find(element => element.featureStyle === style && element.geometryType === geometryType);
35
+ let styleObject;
36
+
37
+ feature.legendValue = legendValue ? legendValue : null;
38
+
39
+ if (alreadyExisitingStyle) {
40
+ styleObject = alreadyExisitingStyle.featureStyleObject;
41
+ }
42
+ else if (geometryType === "Point") {
43
+ styleObject = new PointStyle(feature, style, isClustered);
44
+ }
45
+ else if (geometryType === "LineString") {
46
+ styleObject = new LineStringStyle(feature, style, isClustered);
47
+ }
48
+ else if (geometryType === "Polygon") {
49
+ styleObject = new PolygonStyle(feature, style, isClustered);
50
+ }
51
+ else if (geometryType === "Cesium") {
52
+ styleObject = new CesiumStyle(rule);
53
+ styleObject.initialize(rule);
54
+ styleObject.addLegendInfo("Cesium", styleObject, rule);
55
+ styleObject.legendValue = legendValue;
56
+ return styleObject;
57
+ }
58
+ else if (geometryType === "LinearRing" || geometryType === "Circle") {
59
+ console.warn("Geometry type not implemented: " + geometryType + " default style ist used for feature " + feature);
60
+ return new Style();
61
+ }
62
+ else {
63
+ console.warn("Geometry type not implemented: " + geometryType + " default style ist used for feature " + feature);
64
+ return new Style();
65
+ }
66
+ uniqueStyles.push({featureStyle: style, featureStyleObject: styleObject, geometryType});
67
+ styleObject.initialize(feature, style, isClustered, wfsImgPathFromConfig);
68
+ styleObject.addLegendInfo(geometryType, styleObject, rule);
69
+ styleObject.legendValue = legendValue;
70
+ return styleObject;
71
+ }
72
+
73
+ /**
74
+ * Returns an array of simple geometry styles.
75
+ * @param {string} geometryType GeometryType
76
+ * @param {ol/feature} feature the ol/feature to style
77
+ * @param {object[]} rules styling rules to check.
78
+ * @param {Boolean} isClustered Flag to show if feature is clustered.
79
+ * @param {String} wfsImgPathFromConfig path to wfsImg from Config
80
+ * @returns {ol/style/Style[]} style array of simple geometry styles is always returned
81
+ */
82
+ function getMultiGeometryStyle (geometryType, feature, rules, isClustered, wfsImgPathFromConfig) {
83
+ const olStyle = [];
84
+ let geometries = [];
85
+
86
+ if (typeof feature === "object") {
87
+ if (geometryType === "MultiPoint") {
88
+ geometries = feature.getGeometry().getPoints();
89
+ }
90
+ else if (geometryType === "MultiLineString") {
91
+ geometries = feature.getGeometry().getLineStrings();
92
+ }
93
+ else if (geometryType === "MultiPolygon") {
94
+ geometries = feature.getGeometry().getPolygons();
95
+ }
96
+ else if (geometryType === "GeometryCollection") {
97
+ geometries = feature.getGeometry().getGeometries();
98
+ }
99
+
100
+ geometries.forEach((geometry, index) => {
101
+ const geometryTypeSimpleGeom = geometry.getType(),
102
+ rule = rules ? getRuleForIndex(rules, index) : undefined,
103
+ simpleStyle = getSimpleGeometryStyle(geometryTypeSimpleGeom, feature, rule, isClustered, wfsImgPathFromConfig);
104
+
105
+ // For simplicity reasons we do not support multi encasulated multi geometries but ignore them.
106
+ if (isMultiGeometry(geometryTypeSimpleGeom)) {
107
+ console.warn("Multi encapsulated multiGeometries are not supported.");
108
+ }
109
+ else if (!simpleStyle.styleMultiGeomOnlyWithRule || rule) {
110
+ olStyle.push(simpleStyle);
111
+ }
112
+ });
113
+ }
114
+ else if (geometryType === "Cesium") {
115
+ rules.forEach(rule => {
116
+ const simpleStyle = getSimpleGeometryStyle(geometryType, feature, rule, isClustered, wfsImgPathFromConfig);
117
+
118
+ olStyle.push(simpleStyle);
119
+ });
120
+ }
121
+ else {
122
+ const simpleStyle = getSimpleGeometryStyle(geometryType, feature, rules, isClustered, wfsImgPathFromConfig);
123
+
124
+ simpleStyle.getStyle().setGeometry(geometryType);
125
+ olStyle.push(simpleStyle);
126
+ }
127
+ return olStyle;
128
+ }
129
+
130
+ /**
131
+ * Returns the style for the geometry object
132
+ * @param {ol/feature} feature the ol/feature to style
133
+ * @param {object[]} rules styling rules to check. Array can be empty.
134
+ * @param {Boolean} isClustered Flag to show if feature is clustered.
135
+ * @param {String} wfsImgPathFromConfig path to wfsImg from Config
136
+ * @returns {ol/style/Style} style is always returned
137
+ */
138
+ function getGeometryStyle (feature, rules, isClustered, wfsImgPathFromConfig) {
139
+ const geometryType = feature ? feature.getGeometry().getType() : "Cesium";
140
+
141
+ // For simple geometries the first styling rule is used.
142
+ // That algorithm implements an OR statement between multiple valid conditions giving precedence to its order in the style.json.
143
+ if (!isMultiGeometry(geometryType) && Object.prototype.hasOwnProperty.call(rules, 0) && Object.prototype.hasOwnProperty.call(rules[0], "style")) {
144
+ return getSimpleGeometryStyle(geometryType, feature, rules[0], isClustered, wfsImgPathFromConfig);
145
+ }
146
+ // MultiGeometries must be checked against all rules because there might be a "sequence" in the condition.
147
+ else if (isMultiGeometry(geometryType) && rules.length > 0 && rules.every(element => element?.style)) {
148
+ return getMultiGeometryStyle(geometryType, feature, rules, isClustered, wfsImgPathFromConfig);
149
+ }
150
+
151
+ // fall back to default styles as configured in geomType specific styles, if no rule is matched
152
+ console.warn("No valid styling rule found. Falling back to defaults");
153
+ return isMultiGeometry(geometryType)
154
+ ? getMultiGeometryStyle(geometryType, feature, undefined, isClustered, wfsImgPathFromConfig)
155
+ : getSimpleGeometryStyle(geometryType, feature, undefined, isClustered, wfsImgPathFromConfig);
156
+ }
157
+
158
+ /**
159
+ * Returns the style to label the object
160
+ * @param {ol/feature} feature the ol/feature to style
161
+ * @param {object} style styling rule from style.json
162
+ * @param {Boolean} isClustered Flag to show if feature is clustered.
163
+ * @returns {ol/style/Text} style is always returned
164
+ */
165
+ function getLabelStyle (feature, style, isClustered) {
166
+ const styleObject = new TextStyle(feature, style, isClustered);
167
+
168
+ styleObject.initialize(feature, style, isClustered);
169
+ return styleObject.getStyle();
170
+ }
171
+
172
+ /**
173
+ * Captures the legend from a feature and pushes it to an array of all legends.
174
+ * @param {string} styleId styleId from a given feature
175
+ * @param {object} legendInformation legendInformation from a given feature
176
+ * @returns {void}
177
+ */
178
+ function captureLegendFromFeature (styleId, legendInformation) {
179
+ let legend = legendsOfAllStyles.find(element => element.id === styleId);
180
+
181
+ if (!legend) {
182
+ legend = {id: styleId, legendInformation: []};
183
+ legendsOfAllStyles.push(legend);
184
+ }
185
+ else if (styleId === "default" && legend.legendInformation !== legendInformation) {
186
+ legend.legendInformation = legendInformation;
187
+ legendInformationLength = legendInformation.length;
188
+ }
189
+ else if (!legend.legendInformation.find(element => element.label === legendInformation[0].label)) {
190
+ legend.legendInformation.push(legendInformation[0]);
191
+
192
+ const event = new CustomEvent("legendCaptured");
193
+
194
+ event.id = legend.id;
195
+ if (this) {
196
+ this.dispatchEvent(event);
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Function is called from layer models for each feature.
203
+ * @param {String} styleObject id of the style
204
+ * @param {ol/feature} feature the feature to style
205
+ * @param {Boolean} isClustered is feature clustered
206
+ * @param {String} wfsImgPathFromConfig path to wfsImg from Config
207
+ * @returns {ol/style/Style} style used in layer model
208
+ */
209
+ function createStyle (styleObject, feature, isClustered, wfsImgPathFromConfig) {
210
+ const rules = getRulesForFeature(styleObject, feature),
211
+ // Takes first rule in array for labeling so that is giving precedence to the order in the style.json
212
+ style = Array.isArray(rules) && rules.length > 0 ? rules[0].style : null,
213
+ hasLabelField = style?.labelField,
214
+ geometryStyle = getGeometryStyle(feature, rules, isClustered, wfsImgPathFromConfig),
215
+ legendInformation = Array.isArray(geometryStyle) ? geometryStyle[0].legendInfos : geometryStyle.legendInfos,
216
+ styleObjectGeometry = Array.isArray(geometryStyle) ? geometryStyle[0].getStyle() : geometryStyle.getStyle();
217
+
218
+ captureLegendFromFeature(styleObject.styleId, legendInformation);
219
+
220
+ // label style is optional and depends on some fields
221
+ if (isClustered || hasLabelField) {
222
+ if (Array.isArray(styleObjectGeometry)) {
223
+ styleObjectGeometry[0].setText(getLabelStyle(feature, style, isClustered));
224
+ }
225
+ else {
226
+ styleObjectGeometry.setText(getLabelStyle(feature, style, isClustered));
227
+ }
228
+ }
229
+ return styleObjectGeometry;
230
+ }
231
+
232
+ async function returnLegendByStyleId (styleId) {
233
+ return new Promise(function (resolve) {
234
+ const legend = legendsOfAllStyles.find(element => element.id === styleId);
235
+
236
+ if (legend && (styleId.id !== "default" || legend.legendInformation.length === legendInformationLength)) {
237
+ resolve(legend);
238
+ }
239
+
240
+ this.addEventListener("legendCaptured", event => {
241
+ if (event.id === styleId && event.id !== "default") {
242
+ resolve(legendsOfAllStyles.find(element => element.id === event.id));
243
+ }
244
+ else if (legend && legend.legendInformation.length === legendInformationLength) {
245
+ resolve(legendsOfAllStyles.find(element => element.id === event.id));
246
+ }
247
+ }, false);
248
+ });
249
+ }
250
+
251
+ export default {
252
+ isMultiGeometry,
253
+ getSimpleGeometryStyle,
254
+ getMultiGeometryStyle,
255
+ getGeometryStyle,
256
+ getLabelStyle,
257
+ createStyle,
258
+ returnLegendByStyleId
259
+ };
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Makes sure that one rgb color always consists of four values
3
+ * @param {Number[]} newColor Color in rgb
4
+ * @return {Number[]} normColor
5
+ */
6
+ export function normalizeRgbColor (newColor) {
7
+ const defaultArray = [1, 1, 1, 1];
8
+
9
+ return newColor.concat(defaultArray).slice(0, 4);
10
+ }
11
+
12
+ /**
13
+ * Converts hex value to rgbarray.
14
+ * @param {String} hex Color as hex string.
15
+ * @returns {Number[]} - Color als rgb array.
16
+ */
17
+ export function hexToRgb (hex) {
18
+ // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
19
+ const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
20
+ hexReplace = hex.replace(shorthandRegex, function (m, r, g, b) {
21
+ return r + r + g + g + b + b;
22
+ });
23
+ let result;
24
+
25
+ result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
26
+ result = result.exec(hexReplace);
27
+
28
+ return result
29
+ ? [
30
+ parseFloat(result[1], 16),
31
+ parseFloat(result[2], 16),
32
+ parseFloat(result[3], 16)
33
+ ]
34
+ : null;
35
+ }
36
+
37
+ /**
38
+ * Converts number to hex string.
39
+ * @param {Number} c Color value as number.
40
+ * @returns {String} - Converted color number as hex string.
41
+ */
42
+ export function componentToHex (c) {
43
+ const hex = Number(c).toString(16);
44
+
45
+ return hex.length === 1 ? "0" + hex : hex;
46
+ }
47
+ /**
48
+ * Converts rgb to hex.
49
+ * @param {Number} r Red value.
50
+ * @param {Number} g Green Value.
51
+ * @param {Number} b Blue value.
52
+ * @returns {String} - Hex color string.
53
+ */
54
+ export function rgbToHex (r, g, b) {
55
+ return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
56
+ }
57
+ /**
58
+ * Returns input color to destinated color.
59
+ * possible values for dest are "rgb" and "hex".
60
+ * color has to come as hex (e.g. "#ffffff" || "#fff") or as array (e.g [255,255,255,0]) or as String ("[255,255,255,0]")
61
+ * @param {Number[]|String} color The color to return.
62
+ * @param {String} dest Destination color type.
63
+ * @returns {String|Number[]} - The converted color.
64
+ */
65
+ export function returnColor (color, dest) {
66
+ let src,
67
+ newColor = color,
68
+ pArray = [];
69
+
70
+ if (Array.isArray(newColor)) {
71
+ src = "rgb";
72
+ }
73
+ else if (typeof newColor === "string" && newColor.indexOf("#") === 0) {
74
+ src = "hex";
75
+ }
76
+ else if (typeof newColor === "string" && newColor.indexOf("#") === -1) {
77
+ src = "rgb";
78
+
79
+ pArray = newColor
80
+ .replace("[", "")
81
+ .replace("]", "")
82
+ .replace(/ /g, "")
83
+ .split(",");
84
+ newColor = [pArray[0], pArray[1], pArray[2], pArray[3]];
85
+ }
86
+
87
+ if (src === "hex" && dest === "rgb") {
88
+ newColor = hexToRgb(newColor);
89
+ }
90
+ else if (src === "rgb" && dest === "hex") {
91
+ newColor = rgbToHex(newColor[0], newColor[1], newColor[2]);
92
+ }
93
+
94
+ newColor = dest === "rgb" ? normalizeRgbColor(newColor) : newColor;
95
+
96
+ return newColor;
97
+ }
@@ -0,0 +1,28 @@
1
+ import {getSimpleGeometryStyle, getMultiGeometryStyle} from "../createStyle";
2
+ /**
3
+ * Creates the style objects for the layer
4
+ * @param {object[]} rules styling rules from the styleObject
5
+ * @param {string[]} geometryType Array of geometry types
6
+ * @returns {void}
7
+ */
8
+ export function createLegendInfo (rules, geometryType) {
9
+ let styleObject,
10
+ simpleGeom;
11
+
12
+ geometryType.forEach(geom => rules.forEach(rule => {
13
+ if (geom === "MultiSurface") {
14
+ simpleGeom = "Polygon";
15
+ styleObject = getSimpleGeometryStyle(simpleGeom, "", rule, false);
16
+ return styleObject;
17
+ }
18
+ else if (geom.includes("Multi")) {
19
+ simpleGeom = geom.replace("Multi", "");
20
+ styleObject = getMultiGeometryStyle(simpleGeom, "", rule, false);
21
+ return styleObject;
22
+ }
23
+
24
+ simpleGeom = geom;
25
+ styleObject = getSimpleGeometryStyle(simpleGeom, "", rule, false);
26
+ return styleObject;
27
+ }));
28
+ }
@@ -0,0 +1,153 @@
1
+ import {createLegendInfo} from "./createLegendInfo";
2
+
3
+ /**
4
+ * Parses the xml with another structure to get the subelements from the layer
5
+ * @param {string} xml response xml
6
+ * @param {string} featureType wfs feature type from layer without namespace
7
+ * @returns {object[]} subElements of the xml element
8
+ */
9
+ function getSubelementsFromXMLOtherStructure (xml, featureType) {
10
+ const elements = xml ? Array.from(xml.getElementsByTagName("element")) : [];
11
+ let subElements = [];
12
+
13
+ elements.forEach(element => {
14
+ if (element.getAttribute("name") === featureType) {
15
+ const sibling = element.nextElementSibling;
16
+
17
+ if (sibling && sibling.tagName === "complexType" && sibling.hasAttribute("name")) {
18
+ subElements = Array.from(sibling.getElementsByTagName("element"));
19
+ }
20
+ }
21
+ });
22
+ return subElements;
23
+ }
24
+
25
+ /**
26
+ * Parses the xml to get the subelements from the layer
27
+ * @param {string} xml response xml
28
+ * @param {string} featureType wfs feature type from layer. Namespace is taken into account.
29
+ * @returns {object[]} subElements of the xml element
30
+ */
31
+ function getSubelementsFromXML (xml, featureType) {
32
+ const elements = xml ? Array.from(xml.getElementsByTagName("element")) : [];
33
+ let subElements = [],
34
+ featureTypeWithoutNamespace = featureType;
35
+
36
+ if (featureType && featureType.indexOf(":") > -1) {
37
+ featureTypeWithoutNamespace = featureType.substr(featureType.indexOf(":") + 1, featureType.length);
38
+ }
39
+
40
+ elements.forEach(element => {
41
+ if (element.getAttribute("name") === featureTypeWithoutNamespace) {
42
+ subElements = Array.from(element.getElementsByTagName("element"));
43
+ }
44
+ });
45
+ if (subElements.length === 0) {
46
+ subElements = getSubelementsFromXMLOtherStructure(xml, featureTypeWithoutNamespace);
47
+ }
48
+ return subElements;
49
+ }
50
+
51
+ /**
52
+ * Parses the geometry types from the subelements
53
+ * @param {Object[]} [subElements=[]] xml subelements
54
+ * @param {String[] | String} [styleGeometryType=null] The configured geometry type of the layer
55
+ * @returns {String[]} geometry types of the layer
56
+ */
57
+ function getTypeAttributesFromSubelements (subElements = [], styleGeometryType = null) {
58
+ const geometryType = [];
59
+
60
+ subElements.forEach(elements => {
61
+ const typeAttribute = elements.getAttribute("type");
62
+ let geomType = styleGeometryType;
63
+
64
+ if (typeAttribute && typeAttribute.includes("gml")) {
65
+ geomType = styleGeometryType || typeAttribute.split("gml:")[1].replace("PropertyType", "");
66
+ if (geomType === "Geometry") {
67
+ geometryType.push("Point");
68
+ geometryType.push("Polygon");
69
+ geometryType.push("LineString");
70
+ }
71
+ else if (Array.isArray(geomType)) {
72
+ geomType.forEach(singleGeomType => geometryType.push(singleGeomType));
73
+ }
74
+ else {
75
+ geometryType.push(geomType);
76
+ }
77
+ }
78
+ });
79
+ return geometryType;
80
+ }
81
+ /**
82
+ * Requests the DescribeFeatureType of the wfs layer and starts the function to parse the xml and creates the legend info
83
+ * @param {object[]} rules styling rules from the styleObject
84
+ * @param {string} wfsURL url from layer
85
+ * @param {string} version wfs version from layer
86
+ * @param {string} featureType wfs feature type from layer
87
+ * @param {string[] | string} styleGeometryType The configured geometry type of the layer
88
+ * @param {boolean} isSecured true if wfs is secured
89
+ * @param {function} [callback] - called with services after loaded; called with false and error on error
90
+ * @returns {void}
91
+ */
92
+ // eslint-disable-next-line max-params
93
+ function getGeometryTypeFromWFS (rules, wfsURL, version, featureType, styleGeometryType, isSecured, callback) {
94
+ const params = {
95
+ "SERVICE": "WFS",
96
+ "VERSION": version,
97
+ "REQUEST": "DescribeFeatureType"
98
+ };
99
+ let url = wfsURL + "?";
100
+
101
+ Object.keys(params).forEach(key => {
102
+ url += key + "=" + params[key] + "&";
103
+ });
104
+ url = url.slice(0, -1);
105
+
106
+
107
+ fetch(url, {
108
+ method: "get",
109
+ withCredentials: isSecured,
110
+ responseType: "text"
111
+ }).then(response => response.text())
112
+ .then(responseAsString => new window.DOMParser().parseFromString(responseAsString, "text/xml"))
113
+ .then(responseXML => {
114
+ const subElements = getSubelementsFromXML(responseXML, featureType),
115
+ geometryTypes = getTypeAttributesFromSubelements(subElements, styleGeometryType);
116
+
117
+ createLegendInfo(rules, geometryTypes);
118
+ }).catch(error => {
119
+ return callback(error);
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Requests the geometry type of the OAF collection and creates the legend info
125
+ * @param {object[]} rules styling rules from the styleObject
126
+ * @param {string} oafURL url from layer
127
+ * @param {String} collection the collection name to fetch geometry type for
128
+ * @param {function} [callback] - called with services after loaded; called with false and error on error
129
+ * @returns {void}
130
+ */
131
+ function getGeometryTypeFromOAF (rules, oafURL, collection, callback) {
132
+ const url = oafURL + "/collections/" + collection + "/items?limit=1";
133
+
134
+ fetch(url, {
135
+ method: "get",
136
+ headers: {
137
+ accept: "application/geo+json"
138
+ }
139
+ }).then(response => {
140
+ const geometryType = response.data?.features[0]?.geometry?.type;
141
+
142
+ if (geometryType) {
143
+ createLegendInfo(rules, [geometryType]);
144
+ }
145
+ }).catch(error => {
146
+ return callback(error);
147
+ });
148
+ }
149
+
150
+ export default {
151
+ getGeometryTypeFromWFS,
152
+ getGeometryTypeFromOAF
153
+ };
@@ -0,0 +1,62 @@
1
+ import {checkProperties} from "../lib/valueOperations";
2
+ /**
3
+ * Returning all rules that fit to the feature. Array could be empty.
4
+ * @param {object} styleObject the styleObject with style information
5
+ * @param {ol/feature} feature the feature to check
6
+ * @returns {object[]} return all rules that fit to the feature
7
+ */
8
+ export function getRulesForFeature (styleObject, feature) {
9
+ styleObject.rules.forEach(rule => {
10
+ if (typeof feature.get("rotation") !== "undefined") {
11
+ rule.style.rotation = feature.get("rotation");
12
+ }
13
+ });
14
+ return styleObject.rules.filter(rule => checkProperties(feature, rule));
15
+ }
16
+ /**
17
+ * Returns the first rule that satisfies the index of the multi geometry.
18
+ * The "sequence" must be an integer with defined min and max values representing the index range.
19
+ * @param {object[]} rules all rules the satisfy conditions.properties.
20
+ * @param {integer} index the simple geometries index
21
+ * @returns {object|undefined} the proper rule
22
+ */
23
+ export function getIndexedRule (rules, index) {
24
+ return rules.find(rule => {
25
+ const sequence = rule.conditions?.sequence ? rule.conditions.sequence : null,
26
+ isSequenceValid = sequence && Array.isArray(sequence) && sequence.every(element => typeof element === "number") && sequence.length === 2 && sequence[1] >= sequence[0],
27
+ minValue = isSequenceValid ? sequence[0] : -1,
28
+ maxValue = isSequenceValid ? sequence[1] : -1;
29
+
30
+ return index >= minValue && index <= maxValue;
31
+ });
32
+ }
33
+
34
+ /**
35
+ * Returns the best rule for the indexed feature giving precedence to the index position.
36
+ * Otherwhile returns the rule with conditions but without a sequence definition.
37
+ * Fallback is a rule without conditions.
38
+ * That means also: A rule with fitting properties but without fitting sequence is never used for any multi geometry.
39
+ * @param {object[]} rules the rules to check
40
+ * @param {integer} index the index position of geometry in the multi geometry
41
+ * @returns {object|null} the rule or null if no rule match the conditions
42
+ */
43
+ export function getRuleForIndex (rules, index) {
44
+ const indexedRule = getIndexedRule(rules, index),
45
+ propertiesRule = rules.find(rule => {
46
+ return rule?.conditions && !Object.prototype.hasOwnProperty.call(rule.conditions, "sequence");
47
+ }),
48
+ fallbackRule = rules.find(rule => {
49
+ return !rule?.conditions;
50
+ });
51
+
52
+ if (indexedRule) {
53
+ return indexedRule;
54
+ }
55
+ else if (propertiesRule) {
56
+ return propertiesRule;
57
+ }
58
+ else if (fallbackRule) {
59
+ return fallbackRule;
60
+ }
61
+ return null;
62
+ }