@masterportal/masterportalapi 2.13.0 → 2.15.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/.eslintrc +2 -1
- package/CHANGELOG.md +16 -7
- package/example/config/localGeoJSONPoints.js +2106 -0
- package/example/config/portal.json +47 -1
- package/example/config/services.json +20 -0
- package/example/index.js +50 -7
- package/jest.config.js +1 -1
- package/jest.setup.js +9 -1
- package/package.json +64 -62
- package/src/index.js +3 -1
- package/src/layer/geojson/index.js +55 -4
- package/src/layer/oaf.js +35 -5
- package/src/layer/vectorBase.js +20 -1
- package/src/layer/wfs.js +38 -7
- package/src/lib/attributeMapper.js +231 -0
- package/src/lib/getValueFromObjectByPath.js +73 -0
- package/src/lib/thousandsSeparator.js +23 -0
- package/src/maps/ol/olMap.js +4 -3
- package/src/renderer/webgl.js +250 -0
- package/src/vectorStyle/createStyle.js +259 -0
- package/src/vectorStyle/lib/colorConvertions.js +97 -0
- package/src/vectorStyle/lib/createLegendInfo.js +28 -0
- package/src/vectorStyle/lib/getGeometryTypeFromService.js +153 -0
- package/src/vectorStyle/lib/getRuleForIndex.js +62 -0
- package/src/vectorStyle/lib/valueOperations.js +172 -0
- package/src/vectorStyle/styleList.js +281 -0
- package/src/vectorStyle/styles/defaultStyles.js +177 -0
- package/src/vectorStyle/styles/point/stylePoint.js +108 -0
- package/src/vectorStyle/styles/point/stylePointCircle.js +29 -0
- package/src/vectorStyle/styles/point/stylePointIcon.js +79 -0
- package/src/vectorStyle/styles/point/stylePointInterval.js +124 -0
- package/src/vectorStyle/styles/point/stylePointNominal.js +232 -0
- package/src/vectorStyle/styles/point/stylePointRegularShape.js +39 -0
- package/src/vectorStyle/styles/polygon/polygonStyleHatch.js +160 -0
- package/src/vectorStyle/styles/polygon/stylePolygon.js +125 -0
- package/src/vectorStyle/styles/style.js +161 -0
- package/src/vectorStyle/styles/styleCesium.js +106 -0
- package/src/vectorStyle/styles/styleLine.js +51 -0
- package/src/vectorStyle/styles/styleText.js +143 -0
- package/test/layer/geojson/index.test.js +23 -0
- package/test/layer/oaf.test.js +30 -0
- package/test/layer/vectorBase.test.js +27 -7
- package/test/layer/wfs.test.js +30 -0
- package/test/lib/attributeMapper.test.js +290 -0
- package/test/lib/getValueFromObjectByPath.test.js +61 -0
- package/test/lib/thousandsSeparator.test.js +58 -0
- package/test/renderer/webgl.test.js +161 -0
- package/test/vectorStyle/createStyle.test.js +335 -0
- package/test/vectorStyle/lib/colorConvertions.test.js +42 -0
- package/test/vectorStyle/lib/getRuleForIndex.test.js +132 -0
- package/test/vectorStyle/lib/valueOperations.test.js +191 -0
- package/test/vectorStyle/styles/point/stylePoint.test.js +28 -0
- package/test/vectorStyle/styles/point/stylePointCircle.test.js +30 -0
- package/test/vectorStyle/styles/point/stylePointIcon.test.js +83 -0
- package/test/vectorStyle/styles/point/stylePointInterval.test.js +57 -0
- package/test/vectorStyle/styles/point/stylePointNominal.test.js +84 -0
- package/test/vectorStyle/styles/point/stylePointRegularShape.test.js +24 -0
- package/test/vectorStyle/styles/polygon/polygonStyleHatch.test.js +95 -0
- package/test/vectorStyle/styles/polygon/stylePolygon.test.js +61 -0
- package/test/vectorStyle/styles/styleLine.test.js +29 -0
- 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
|
+
}
|