-
Notifications
You must be signed in to change notification settings - Fork 22
/
FeatureUtil.ts
153 lines (136 loc) · 5.84 KB
/
FeatureUtil.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import StringUtil from '@terrestris/base-util/dist/StringUtil/StringUtil';
import _isArray from 'lodash/isArray';
import _isNil from 'lodash/isNil';
import _isString from 'lodash/isString';
import OlFeature from 'ol/Feature';
import OlGeometry from 'ol/geom/Geometry';
/**
* Helper class for working with OpenLayers features.
*
* @class FeatureUtil
*/
class FeatureUtil {
/**
* Returns the featureType name out of a given feature. It assumes that
* the feature has an ID in the following structure FEATURETYPE.FEATUREID.
*
* @param {import("ol/Feature").default} feature The feature to obtain the featureType
* name from.
* @return {string|undefined} The (unqualified) name of the featureType or undefined if
* the name could not be picked.
*/
static getFeatureTypeName(feature: OlFeature<OlGeometry>): string | undefined {
const featureId = feature.getId();
const featureIdParts = _isString(featureId) ? featureId.split('.') : featureId;
return _isArray(featureIdParts) ? featureIdParts[0] : undefined;
}
/**
* Extracts the featureType name from given GetFeatureInfo URL.
* This method is mostly useful for raster layers which features could have
* no ID set.
*
* @param {string} url GetFeatureInfo URL possibly containing featureType name.
* @param {boolean} qualified Whether the qualified featureType name should be
* returned or not. Default is true.
*
* @return {string|undefined} Obtained featureType name as string.
*/
static getFeatureTypeNameFromGetFeatureInfoUrl(url: string, qualified: boolean = true): string | undefined {
const regex = /query_layers=(.*?)(&|$)/i;
const match = url.match(regex);
let featureTypeName;
if (match && match[1]) {
featureTypeName = decodeURIComponent(match[1]);
if (!qualified && featureTypeName.indexOf(':') > 0) {
featureTypeName = featureTypeName.split(':')[1];
}
}
return featureTypeName;
}
/**
* Resolves the given template string with the given feature attributes, e.g.
* the template "Size of area is {{AREA_SIZE}} km²" would be to resolved
* to "Size of area is 1909 km²" (assuming the feature's attribute AREA_SIZE
* really exists).
*
* @param {import("ol/Feature").default} feature The feature to get the attributes from.
* @param {string} template The template string to resolve.
* @param {string} [noValueFoundText] The text to apply, if the templated value
* could not be found, default is to 'n.v.'.
* @param {(key: string, val: string) => string} [valueAdjust] A method that will be called with each
* key/value match, we'll use what this function returns for the actual
* replacement. Optional, defaults to a function which will return the raw
* value it received. This can be used for last minute adjustments before
* replacing happens, e.g. to filter out falsy values or to do number
* formatting and such.
* @param {boolean} leaveAsUrl If set to true, template won't be wrapped into
* <a>-tag and will be returned as URL. Default is false.
* @return {string} The resolved template string.
*/
static resolveAttributeTemplate(
feature: OlFeature<OlGeometry>,
template: string,
noValueFoundText: string = 'n.v.',
valueAdjust = (key: string, val: any) => val,
leaveAsUrl = false
) {
let attributeTemplatePrefix = '\\{\\{';
let attributeTemplateSuffix = '\\}\\}';
let resolved;
// Find any character between two braces (including the braces in the result)
let regExp = new RegExp(attributeTemplatePrefix + '(.*?)' + attributeTemplateSuffix, 'g');
let regExpRes = _isString(template) ? template.match(regExp) : null;
// If we have a regex result, it means we found a placeholder in the
// template and have to replace the placeholder with its appropriate value.
if (regExpRes) {
// Iterate over all regex match results and find the proper attribute
// for the given placeholder, finally set the desired value to the hover.
// field text
regExpRes.forEach((res) => {
// We count every candidate that is not matching. If this count is equal to
// the object array length, we assume that there is no match at all and
// set the output value to the value of "noValueFoundText".
let noMatchCnt = 0;
for (let [key, value] of Object.entries(feature.getProperties())) {
// Remove the suffixes and find the matching attribute column.
let attributeName = res.slice(2, res.length - 2);
if (attributeName.toLowerCase() === key.toLowerCase()) {
template = template.replace(res, valueAdjust(key, value));
break;
} else {
noMatchCnt++;
}
}
// No key match found for this feature (e.g. if key not
// present or value is null).
if (noMatchCnt === Object.keys(feature.getProperties()).length) {
template = template.replace(res, noValueFoundText);
}
});
}
resolved = template;
// Fallback if no feature attribute is found.
if (!resolved) {
resolved = `${feature.getId()}`;
}
if (!leaveAsUrl) {
// Replace any HTTP url with an <a> element.
resolved = StringUtil.urlify(resolved);
// Replace all newline breaks with a html <br> tag.
resolved = resolved.replace(/\n/g, '<br>');
}
return resolved;
}
/**
* Maps an array of features to an array of geometries.
*
* @param {import("ol/Feature").default[]} features
* @return {import("ol/Geometry").default[]} The geometries of the features
*/
static mapFeaturesToGeometries(features: OlFeature<OlGeometry>[]): OlGeometry[] {
return features
.filter(feature => !_isNil(feature.getGeometry()))
.map(f => f.getGeometry() as OlGeometry);
}
}
export default FeatureUtil;