Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced Customization for Highlight Styles in Feature Selection #10537

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion web/client/components/data/identify/IdentifyContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import React, { useEffect } from 'react';

import {Row} from 'react-bootstrap';
import { get } from 'lodash';
Expand Down Expand Up @@ -76,6 +76,11 @@ export default props => {
onInitPlugin = () => {},
pluginCfg
} = props;

useEffect(() => {
pluginCfg?.highlightStyle && onInitPlugin({ highlightStyle: pluginCfg.highlightStyle });
}, []);

const latlng = point && point.latlng || null;

// Layer selector allows only selection of valid response's index, so target response will always be valid.
Expand Down
1 change: 1 addition & 0 deletions web/client/plugins/Identify.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ const identifyDefaultProps = defaultProps({
* @prop cfg.draggable {boolean} draggable info window, when modal
* @prop cfg.showHighlightFeatureButton {boolean} show the highlight feature button if the interrogation returned valid features (openlayers only)
* @prop cfg.highlightEnabledFromTheStart {boolean} the highlight feature button will be activated by default if true
* @prop cfg.highlightSytle {object} custom highlight style will be merged to default if value exist
* @prop cfg.viewerOptions.container {expression} the container of the viewer, expression from the context
* @prop cfg.viewerOptions.header {expression} the header of the viewer, expression from the context{expression}
* @prop cfg.disableCenterToMarker {bool} disable zoom to marker action
Expand Down
6 changes: 4 additions & 2 deletions web/client/plugins/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ import {getHighlightLayerOptions} from "../utils/HighlightUtils";
* @class Map
* @prop {array} additionalLayers static layers available in addition to those loaded from the configuration
* @prop {object} mapOptions map options grouped by map type
* @prop {object} highlightStyle custom highlight Style
* @prop {boolean} mapOptions.cesium.navigationTools enable cesium navigation tool (default false)
* @prop {boolean} mapOptions.cesium.showSkyAtmosphere enable sky atmosphere of the globe (default true)
* @prop {boolean} mapOptions.cesium.showGroundAtmosphere enable ground atmosphere of the globe (default false)
Expand Down Expand Up @@ -209,7 +210,8 @@ class MapPlugin extends React.Component {
items: PropTypes.array,
onLoadingMapPlugins: PropTypes.func,
onMapTypeLoaded: PropTypes.func,
pluginsCreator: PropTypes.func
pluginsCreator: PropTypes.func,
highlightStyle: PropTypes.object
};

static defaultProps = {
Expand Down Expand Up @@ -271,7 +273,7 @@ class MapPlugin extends React.Component {

getHighlightLayer = (projection, index, env) => {
const plugins = this.state.plugins;
const {features, ...options} = getHighlightLayerOptions({features: this.props.features});
const {features, ...options} = getHighlightLayerOptions({features: this.props.features}, this.props?.highlightStyle);
return (<plugins.Layer type="vector"
srs={projection}
position={index}
Expand Down
12 changes: 8 additions & 4 deletions web/client/selectors/__tests__/mapInfo-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,20 +285,24 @@ describe('Test mapinfo selectors', () => {
const TEST = {
color: 'test'
};
// check default
expect(highlightStyleSelector({})).toEqual({
const defaultStyle = {
color: '#3388ff',
weight: 4,
radius: 4,
dashArray: '',
fillColor: '#3388ff',
fillOpacity: 0.2
});
};
// check default
expect(highlightStyleSelector({})).toEqual(defaultStyle);
expect(highlightStyleSelector({
mapInfo: {
highlightStyle: TEST
}
})).toBe(TEST);
})).toEqual({
...defaultStyle,
...TEST
});
});
it('test clickPointSelector', () => {
expect(clickPointSelector(RESPONSE_STATE)).toBe(RESPONSE_STATE.mapInfo.clickPoint);
Expand Down
11 changes: 9 additions & 2 deletions web/client/selectors/mapInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,21 @@ export const applyMapInfoStyle = style => f => ({
* @param {object} state the application state
* @returns {object} style object
*/
export const highlightStyleSelector = state => get(state, 'mapInfo.highlightStyle', {
const defaultHighlightStyle = {
color: '#3388ff',
weight: 4,
radius: 4,
dashArray: '',
fillColor: '#3388ff',
fillOpacity: 0.2
});
};
// merge and replace default highlight style with custom values
export const highlightStyleSelector = state => {
return {
...defaultHighlightStyle,
...get(state, 'mapInfo.highlightStyle', {})
};
};

export const clickedPointWithFeaturesSelector = createSelector(
clickPointSelector,
Expand Down
124 changes: 67 additions & 57 deletions web/client/utils/HighlightUtils.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,82 @@
export const GEOMETRY_PROPERTY = '__geometry__type__';
export function createHighlightStyle(highlightStyle = {}) {
const defaultStyle = {
color: '#f2f2f2',
lineColor: '#3075e9',
fillOpacity: 0.3,
opacity: 1,
width: 2,
radius: 10
};

// Merge custom styles with default values
const style = { ...defaultStyle, ...highlightStyle };

export const GEOMETRY_PROPERTY = '__geometry__type__';
export const HIGH_LIGHT_STYLE = {
format: 'geostyler',
body: {
name: "highlight",
rules: [{
name: 'Default Polygon Style',
ruleId: "defaultPolygon",
filter: ['||',
['==', GEOMETRY_PROPERTY, 'Polygon'],
['==', GEOMETRY_PROPERTY, 'MultiPolygon']
],
symbolizers: [
{
return {
format: 'geostyler',
body: {
name: "highlight",
rules: [{
name: 'Default Polygon Style',
ruleId: "defaultPolygon",
filter: ['||',
['==', GEOMETRY_PROPERTY, 'Polygon'],
['==', GEOMETRY_PROPERTY, 'MultiPolygon']
],
symbolizers: [{
kind: 'Fill',
color: '#f2f2f2',
fillOpacity: 0.3,
outlineColor: '#3075e9',
outlineOpacity: 1,
outlineWidth: 2
}
]
}, {
name: 'Default Line Style',
ruleId: "defaultLine",
filter: ['||',
['==', GEOMETRY_PROPERTY, 'LineString'],
['==', GEOMETRY_PROPERTY, 'MultiLineString']
],
symbolizers: [
{
color: style.color,
fillOpacity: style.fillOpacity,
outlineColor: style.lineColor,
outlineOpacity: style.opacity,
outlineWidth: style.width
}]
}, {
name: 'Default Line Style',
ruleId: "defaultLine",
filter: ['||',
['==', GEOMETRY_PROPERTY, 'LineString'],
['==', GEOMETRY_PROPERTY, 'MultiLineString']
],
symbolizers: [{
kind: 'Line',
color: '#3075e9',
opacity: 1,
width: 2
}
]
}, {
name: 'Default Point Style',
ruleId: "defaultPoint",
filter: ['||',
['==', GEOMETRY_PROPERTY, 'Point'],
['==', GEOMETRY_PROPERTY, 'MultiPoint']
],
symbolizers: [{
kind: 'Mark',
color: '#f2f2f2',
fillOpacity: 0.3,
strokeColor: '#3075e9',
strokeOpacity: 1,
strokeWidth: 2,
radius: 10,
wellKnownName: 'Circle',
msBringToFront: true
color: style.lineColor,
opacity: style.opacity,
width: style.width
}]
}, {
name: 'Default Point Style',
ruleId: "defaultPoint",
filter: ['||',
['==', GEOMETRY_PROPERTY, 'Point'],
['==', GEOMETRY_PROPERTY, 'MultiPoint']
],
symbolizers: [{
kind: 'Mark',
color: style.color,
fillOpacity: style.fillOpacity,
strokeColor: style.lineColor,
strokeOpacity: style.opacity,
strokeWidth: style.width,
radius: style.radius,
wellKnownName: 'Circle',
msBringToFront: true
}]
}]
}]
}
};
}
};
}

/**
* Add the the proper options to the highlight layer:
* - `visibility`: `true`
* - `features`: the features to highlight should be enhanced with the geometry type in properties, to allow the default style to work
* - `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
* @param {options} base options
* @param highlightStyle
* @returns the new options with the highlight layer
*/
export const getHighlightLayerOptions = ({features, ...options}) => {
export const getHighlightLayerOptions = ({ features, ...options }, highlightStyle = {}) => {
return {
...options,
visibility: true, // required by cesium
Expand All @@ -78,6 +88,6 @@ export const getHighlightLayerOptions = ({features, ...options}) => {
}

})),
style: HIGH_LIGHT_STYLE
style: createHighlightStyle(highlightStyle)
};
};
39 changes: 37 additions & 2 deletions web/client/utils/__tests__/HighlightUtils-test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import expect from 'expect';
import {getHighlightLayerOptions, GEOMETRY_PROPERTY, HIGH_LIGHT_STYLE} from '../HighlightUtils';
import {getHighlightLayerOptions, GEOMETRY_PROPERTY, createHighlightStyle} from '../HighlightUtils';

describe('HighlightUtils', () => {
it('getHighlightLayerOptions', () => {
Expand Down Expand Up @@ -29,7 +29,42 @@ describe('HighlightUtils', () => {
coordinates: [0, 0]
}
}],
style: HIGH_LIGHT_STYLE
style: createHighlightStyle()
});
});

it('getHighlightLayerOptions with custom highlight style', () => {
const costumHighlightStyle = {
color: '#33eeff',
width: 4
};
// adds standard options
const options = getHighlightLayerOptions({
features: [{
type: 'Feature',
properties: {
id: '1'
},
geometry: {
type: 'Point',
coordinates: [0, 0]
}
}]
}, costumHighlightStyle);
expect(options).toEqual({
visibility: true, // required by cesium
features: [{
type: 'Feature',
properties: {
id: '1',
[GEOMETRY_PROPERTY]: 'Point' // required by default style
},
geometry: {
type: 'Point',
coordinates: [0, 0]
}
}],
style: createHighlightStyle(costumHighlightStyle)
});
});
});
Loading