Skip to content

Commit 66cbd65

Browse files
committed
Enhanced Customization for Highlight Styles in Feature Selection - Enabled defining `highlightStyle` objects under `Map` and `Identify` sections in localConfig.json to allow customization of highlight styles. - Updated and added relevant tests to reflect these changes. On behalf of DB Systel GmbH
1 parent 1affe02 commit 66cbd65

7 files changed

Lines changed: 132 additions & 68 deletions

File tree

web/client/components/data/identify/IdentifyContainer.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
import React from 'react';
9+
import React, { useEffect } from 'react';
1010

1111
import {Row} from 'react-bootstrap';
1212
import { get } from 'lodash';
@@ -76,6 +76,11 @@ export default props => {
7676
onInitPlugin = () => {},
7777
pluginCfg
7878
} = props;
79+
80+
useEffect(() => {
81+
pluginCfg?.highlightStyle && onInitPlugin({ highlightStyle: pluginCfg.highlightStyle });
82+
}, []);
83+
7984
const latlng = point && point.latlng || null;
8085

8186
// Layer selector allows only selection of valid response's index, so target response will always be valid.

web/client/plugins/Identify.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ const identifyDefaultProps = defaultProps({
197197
* @prop cfg.draggable {boolean} draggable info window, when modal
198198
* @prop cfg.showHighlightFeatureButton {boolean} show the highlight feature button if the interrogation returned valid features (openlayers only)
199199
* @prop cfg.highlightEnabledFromTheStart {boolean} the highlight feature button will be activated by default if true
200+
* @prop cfg.highlightSytle {object} custom highlight style will be merged to default if value exist
200201
* @prop cfg.viewerOptions.container {expression} the container of the viewer, expression from the context
201202
* @prop cfg.viewerOptions.header {expression} the header of the viewer, expression from the context{expression}
202203
* @prop cfg.disableCenterToMarker {bool} disable zoom to marker action

web/client/plugins/Map.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ import {getHighlightLayerOptions} from "../utils/HighlightUtils";
155155
* @class Map
156156
* @prop {array} additionalLayers static layers available in addition to those loaded from the configuration
157157
* @prop {object} mapOptions map options grouped by map type
158+
* @prop {object} highlightStyle custom highlight Style
158159
* @prop {boolean} mapOptions.cesium.navigationTools enable cesium navigation tool (default false)
159160
* @prop {boolean} mapOptions.cesium.showSkyAtmosphere enable sky atmosphere of the globe (default true)
160161
* @prop {boolean} mapOptions.cesium.showGroundAtmosphere enable ground atmosphere of the globe (default false)
@@ -209,7 +210,8 @@ class MapPlugin extends React.Component {
209210
items: PropTypes.array,
210211
onLoadingMapPlugins: PropTypes.func,
211212
onMapTypeLoaded: PropTypes.func,
212-
pluginsCreator: PropTypes.func
213+
pluginsCreator: PropTypes.func,
214+
highlightStyle: PropTypes.object
213215
};
214216

215217
static defaultProps = {
@@ -271,7 +273,7 @@ class MapPlugin extends React.Component {
271273

272274
getHighlightLayer = (projection, index, env) => {
273275
const plugins = this.state.plugins;
274-
const {features, ...options} = getHighlightLayerOptions({features: this.props.features});
276+
const {features, ...options} = getHighlightLayerOptions({features: this.props.features}, this.props?.highlightStyle);
275277
return (<plugins.Layer type="vector"
276278
srs={projection}
277279
position={index}

web/client/selectors/__tests__/mapInfo-test.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,20 +285,24 @@ describe('Test mapinfo selectors', () => {
285285
const TEST = {
286286
color: 'test'
287287
};
288-
// check default
289-
expect(highlightStyleSelector({})).toEqual({
288+
const defaultStyle = {
290289
color: '#3388ff',
291290
weight: 4,
292291
radius: 4,
293292
dashArray: '',
294293
fillColor: '#3388ff',
295294
fillOpacity: 0.2
296-
});
295+
};
296+
// check default
297+
expect(highlightStyleSelector({})).toEqual(defaultStyle);
297298
expect(highlightStyleSelector({
298299
mapInfo: {
299300
highlightStyle: TEST
300301
}
301-
})).toBe(TEST);
302+
})).toEqual({
303+
...defaultStyle,
304+
...TEST
305+
});
302306
});
303307
it('test clickPointSelector', () => {
304308
expect(clickPointSelector(RESPONSE_STATE)).toBe(RESPONSE_STATE.mapInfo.clickPoint);

web/client/selectors/mapInfo.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,21 @@ export const applyMapInfoStyle = style => f => ({
162162
* @param {object} state the application state
163163
* @returns {object} style object
164164
*/
165-
export const highlightStyleSelector = state => get(state, 'mapInfo.highlightStyle', {
165+
const defaultHighlightStyle = {
166166
color: '#3388ff',
167167
weight: 4,
168168
radius: 4,
169169
dashArray: '',
170170
fillColor: '#3388ff',
171171
fillOpacity: 0.2
172-
});
172+
};
173+
// merge and replace default highlight style with custom values
174+
export const highlightStyleSelector = state => {
175+
return {
176+
...defaultHighlightStyle,
177+
...get(state, 'mapInfo.highlightStyle', {})
178+
};
179+
};
173180

174181
export const clickedPointWithFeaturesSelector = createSelector(
175182
clickPointSelector,

web/client/utils/HighlightUtils.js

Lines changed: 67 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,82 @@
1+
export const GEOMETRY_PROPERTY = '__geometry__type__';
2+
export function createHighlightStyle(highlightStyle = {}) {
3+
const defaultStyle = {
4+
color: '#f2f2f2',
5+
lineColor: '#3075e9',
6+
fillOpacity: 0.3,
7+
opacity: 1,
8+
width: 2,
9+
radius: 10
10+
};
11+
12+
// Merge custom styles with default values
13+
const style = { ...defaultStyle, ...highlightStyle };
114

2-
export const GEOMETRY_PROPERTY = '__geometry__type__';
3-
export const HIGH_LIGHT_STYLE = {
4-
format: 'geostyler',
5-
body: {
6-
name: "highlight",
7-
rules: [{
8-
name: 'Default Polygon Style',
9-
ruleId: "defaultPolygon",
10-
filter: ['||',
11-
['==', GEOMETRY_PROPERTY, 'Polygon'],
12-
['==', GEOMETRY_PROPERTY, 'MultiPolygon']
13-
],
14-
symbolizers: [
15-
{
15+
return {
16+
format: 'geostyler',
17+
body: {
18+
name: "highlight",
19+
rules: [{
20+
name: 'Default Polygon Style',
21+
ruleId: "defaultPolygon",
22+
filter: ['||',
23+
['==', GEOMETRY_PROPERTY, 'Polygon'],
24+
['==', GEOMETRY_PROPERTY, 'MultiPolygon']
25+
],
26+
symbolizers: [{
1627
kind: 'Fill',
17-
color: '#f2f2f2',
18-
fillOpacity: 0.3,
19-
outlineColor: '#3075e9',
20-
outlineOpacity: 1,
21-
outlineWidth: 2
22-
}
23-
]
24-
}, {
25-
name: 'Default Line Style',
26-
ruleId: "defaultLine",
27-
filter: ['||',
28-
['==', GEOMETRY_PROPERTY, 'LineString'],
29-
['==', GEOMETRY_PROPERTY, 'MultiLineString']
30-
],
31-
symbolizers: [
32-
{
28+
color: style.color,
29+
fillOpacity: style.fillOpacity,
30+
outlineColor: style.lineColor,
31+
outlineOpacity: style.opacity,
32+
outlineWidth: style.width
33+
}]
34+
}, {
35+
name: 'Default Line Style',
36+
ruleId: "defaultLine",
37+
filter: ['||',
38+
['==', GEOMETRY_PROPERTY, 'LineString'],
39+
['==', GEOMETRY_PROPERTY, 'MultiLineString']
40+
],
41+
symbolizers: [{
3342
kind: 'Line',
34-
color: '#3075e9',
35-
opacity: 1,
36-
width: 2
37-
}
38-
]
39-
}, {
40-
name: 'Default Point Style',
41-
ruleId: "defaultPoint",
42-
filter: ['||',
43-
['==', GEOMETRY_PROPERTY, 'Point'],
44-
['==', GEOMETRY_PROPERTY, 'MultiPoint']
45-
],
46-
symbolizers: [{
47-
kind: 'Mark',
48-
color: '#f2f2f2',
49-
fillOpacity: 0.3,
50-
strokeColor: '#3075e9',
51-
strokeOpacity: 1,
52-
strokeWidth: 2,
53-
radius: 10,
54-
wellKnownName: 'Circle',
55-
msBringToFront: true
43+
color: style.lineColor,
44+
opacity: style.opacity,
45+
width: style.width
46+
}]
47+
}, {
48+
name: 'Default Point Style',
49+
ruleId: "defaultPoint",
50+
filter: ['||',
51+
['==', GEOMETRY_PROPERTY, 'Point'],
52+
['==', GEOMETRY_PROPERTY, 'MultiPoint']
53+
],
54+
symbolizers: [{
55+
kind: 'Mark',
56+
color: style.color,
57+
fillOpacity: style.fillOpacity,
58+
strokeColor: style.lineColor,
59+
strokeOpacity: style.opacity,
60+
strokeWidth: style.width,
61+
radius: style.radius,
62+
wellKnownName: 'Circle',
63+
msBringToFront: true
64+
}]
5665
}]
57-
}]
58-
}
59-
};
66+
}
67+
};
68+
}
6069

6170
/**
6271
* Add the the proper options to the highlight layer:
6372
* - `visibility`: `true`
6473
* - `features`: the features to highlight should be enhanced with the geometry type in properties, to allow the default style to work
6574
* - `style`: the default style applies a different style for each geometry type. The geometry type is extracted from the geometry type and added to the feature properties
6675
* @param {options} base options
76+
* @param highlightStyle
6777
* @returns the new options with the highlight layer
6878
*/
69-
export const getHighlightLayerOptions = ({features, ...options}) => {
79+
export const getHighlightLayerOptions = ({ features, ...options }, highlightStyle = {}) => {
7080
return {
7181
...options,
7282
visibility: true, // required by cesium
@@ -78,6 +88,6 @@ export const getHighlightLayerOptions = ({features, ...options}) => {
7888
}
7989

8090
})),
81-
style: HIGH_LIGHT_STYLE
91+
style: createHighlightStyle(highlightStyle)
8292
};
8393
};

web/client/utils/__tests__/HighlightUtils-test.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import expect from 'expect';
2-
import {getHighlightLayerOptions, GEOMETRY_PROPERTY, HIGH_LIGHT_STYLE} from '../HighlightUtils';
2+
import {getHighlightLayerOptions, GEOMETRY_PROPERTY, createHighlightStyle} from '../HighlightUtils';
33

44
describe('HighlightUtils', () => {
55
it('getHighlightLayerOptions', () => {
@@ -29,7 +29,42 @@ describe('HighlightUtils', () => {
2929
coordinates: [0, 0]
3030
}
3131
}],
32-
style: HIGH_LIGHT_STYLE
32+
style: createHighlightStyle()
33+
});
34+
});
35+
36+
it('getHighlightLayerOptions with custom highlight style', () => {
37+
const costumHighlightStyle = {
38+
color: '#33eeff',
39+
width: 4
40+
};
41+
// adds standard options
42+
const options = getHighlightLayerOptions({
43+
features: [{
44+
type: 'Feature',
45+
properties: {
46+
id: '1'
47+
},
48+
geometry: {
49+
type: 'Point',
50+
coordinates: [0, 0]
51+
}
52+
}]
53+
}, costumHighlightStyle);
54+
expect(options).toEqual({
55+
visibility: true, // required by cesium
56+
features: [{
57+
type: 'Feature',
58+
properties: {
59+
id: '1',
60+
[GEOMETRY_PROPERTY]: 'Point' // required by default style
61+
},
62+
geometry: {
63+
type: 'Point',
64+
coordinates: [0, 0]
65+
}
66+
}],
67+
style: createHighlightStyle(costumHighlightStyle)
3368
});
3469
});
3570
});

0 commit comments

Comments
 (0)