Skip to content

Commit

Permalink
geosolutions-it#10026: Interactive legend for TOC layers [Vector laye…
Browse files Browse the repository at this point in the history
…r part]

- Adding interactive legend for vector layers
- Add checkbox for enable the interactive legend for wfs and vector into layer settings and for the catalog as well [just for wfs]
- handle the logic of filter by legend for vector layer in case of 2d openlayer map and 3d cesium map
- write unit tests based on code changes
  • Loading branch information
mahmoudadel54 committed Apr 11, 2024
1 parent 6b4d662 commit 8a1b4c3
Show file tree
Hide file tree
Showing 30 changed files with 1,024 additions and 68 deletions.
18 changes: 17 additions & 1 deletion web/client/actions/__tests__/layerFilter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import {
DISCARD_CURRENT_FILTER,
discardCurrentFilter,
applyFilter,
APPLY_FILTER
APPLY_FILTER,
LAYER_FILTER_BY_LEGEND,
layerFilterByLegend,
RESET_LAYER_FILTER_BY_LEGEND,
resetLegendFilter
} from '../layerFilter';


Expand Down Expand Up @@ -64,4 +68,16 @@ describe('Test correctness of the layerFilter actions', () => {
expect(retval.type).toBe(APPLY_FILTER);
});

it('layerFilterByLegend', () => {
var retval = layerFilterByLegend();
expect(retval).toBeTruthy();
expect(retval.type).toBe(LAYER_FILTER_BY_LEGEND);
});

it('resetLegendFilter', () => {
var retval = resetLegendFilter();
expect(retval).toBeTruthy();
expect(retval.type).toBe(RESET_LAYER_FILTER_BY_LEGEND);
});

});
20 changes: 20 additions & 0 deletions web/client/actions/layerFilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export const APPLY_FILTER = 'LAYER_FILTER:APPLY_FILTER';
*/
export const OPEN_QUERY_BUILDER = 'LAYER_FILTER:OPEN_QUERY_BUILDER';

export const LAYER_FILTER_BY_LEGEND = 'LAYER_FILTER:LAYER_FILTER_BY_LEGEND';

export const RESET_LAYER_FILTER_BY_LEGEND = 'LAYER_FILTER:RESET_LAYER_FILTER_BY_LEGEND';

export function storeCurrentFilter() {
return {
Expand Down Expand Up @@ -62,3 +65,20 @@ export function initLayerFilter(filter) {
};
}

export function layerFilterByLegend(layerId, nodeType, legendCQLFilter, filterArr) {
return {
type: LAYER_FILTER_BY_LEGEND,
legendCQLFilter,
nodeType,
layerId,
filterArr
};
}

export function resetLegendFilter(reason, value) {
return {
type: RESET_LAYER_FILTER_BY_LEGEND,
reason, // here the reason for reset is change 'style' or change the enable/disable interactive legend config 'disableEnableInteractiveLegend'
value
};
}
11 changes: 9 additions & 2 deletions web/client/api/catalog/WFS.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,13 @@ const searchAndPaginate = (json = {}, startPosition, maxRecords, text) => {
};
};

const recordToLayer = (record) => {
const recordToLayer = (record, {
service
}) => {
// this is for getting the configration of interactive legend
const {
layerOptions
} = service || {};
return {
type: record.type || "wfs",
search: {
Expand All @@ -90,7 +96,8 @@ const recordToLayer = (record) => {
description: record.description || "",
bbox: record.boundingBox,
links: getRecordLinks(record),
...record.layerOptions
...record.layerOptions,
...layerOptions
};
};

Expand Down
31 changes: 28 additions & 3 deletions web/client/components/TOC/fragments/settings/Display.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { getSupportedFormat } from '../../../../api/WMS';
import WMSCacheOptions from './WMSCacheOptions';
import ThreeDTilesSettings from './ThreeDTilesSettings';
import ModelTransformation from './ModelTransformation';

export default class extends React.Component {
static propTypes = {
opacityText: PropTypes.node,
Expand All @@ -36,12 +37,14 @@ export default class extends React.Component {
isCesiumActive: PropTypes.bool,
projection: PropTypes.string,
resolutions: PropTypes.array,
zoom: PropTypes.number
zoom: PropTypes.number,
resetLegendFilter: PropTypes.func
};

static defaultProps = {
onChange: () => {},
opacityText: <Message msgId="opacity"/>
opacityText: <Message msgId="opacity"/>,
resetLegendFilter: () => {}
};

constructor(props) {
Expand Down Expand Up @@ -216,7 +219,29 @@ export default class extends React.Component {
layer={this.props.element}
onChange={this.props.onChange}
/>

{['wfs', 'vector'].includes(this.props.element.type) &&
<Row>
<div className={"legend-options"}>
<Col xs={12} className={"legend-label"}>
<label key="legend-options-title" className="control-label"><Message msgId="layerProperties.legendOptions.title" /></label>
</Col>
<Col xs={12}>
<Checkbox
data-qa="display-interactive-legend-option"
value="enableInteractiveLegend"
key="enableInteractiveLegend"
onChange={(e) => {
if (!e.target.checked) this.props.resetLegendFilter('disableEnableInteractiveLegend');
this.props.onChange("enableInteractiveLegend", e.target.checked);
}}
checked={this.props.element.enableInteractiveLegend} >
<Message msgId="layerProperties.enableInteractiveLegendInfo.label"/>
&nbsp;{this.props.element.type === 'wfs' && <InfoPopover text={<Message msgId="layerProperties.enableInteractiveLegendInfo.tooltip" />} />}
</Checkbox>
</Col>
</div>
</Row>
}
{this.props.element.type === "wms" &&
<Row>
<Col xs={12}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ describe('test Layer Properties Display module component', () => {
// wrap in a stateful component, stateless components render return null
// see: https://facebook.github.io/react/docs/top-level-api.html#reactdom.render
const comp = ReactDOM.render(<Display element={l} settings={settings} />, document.getElementById("container"));
expect(comp).toExist();
expect(comp).toBeTruthy();
const inputs = ReactTestUtils.scryRenderedDOMComponentsWithTag( comp, "input" );
expect(inputs).toExist();
expect(inputs).toBeTruthy();
expect(inputs.length).toBe(5);
ReactTestUtils.Simulate.focus(inputs[0]);
expect(inputs[0].value).toBe('100');
Expand All @@ -71,9 +71,9 @@ describe('test Layer Properties Display module component', () => {
// wrap in a stateful component, stateless components render return null
// see: https://facebook.github.io/react/docs/top-level-api.html#reactdom.render
const comp = ReactDOM.render(<Display element={l} settings={settings} onChange={handlers.onChange}/>, document.getElementById("container"));
expect(comp).toExist();
expect(comp).toBeTruthy();
const inputs = ReactTestUtils.scryRenderedDOMComponentsWithTag( comp, "input" );
expect(inputs).toExist();
expect(inputs).toBeTruthy();
expect(inputs.length).toBe(13);
ReactTestUtils.Simulate.focus(inputs[2]);
expect(inputs[2].value).toBe('70');
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('test Layer Properties Display module component', () => {
};

const comp = ReactDOM.render(<Display element={l} settings={settings} onChange={handlers.onChange}/>, document.getElementById("container"));
expect(comp).toExist();
expect(comp).toBeTruthy();
const formatRefresh = ReactTestUtils.scryRenderedDOMComponentsWithClass( comp, "format-refresh" );
ReactTestUtils.Simulate.click(formatRefresh[0]);
});
Expand Down Expand Up @@ -165,7 +165,7 @@ describe('test Layer Properties Display module component', () => {
};
ReactDOM.render(<Display isLocalizedLayerStylesEnabled element={l} settings={settings}/>, document.getElementById("container"));
const isLocalizedLayerStylesOption = document.querySelector('[data-qa="display-lacalized-layer-styles-option"]');
expect(isLocalizedLayerStylesOption).toExist();
expect(isLocalizedLayerStylesOption).toBeTruthy();
});

it('tests Display component for wms with force proxy option displayed', () => {
Expand Down Expand Up @@ -243,7 +243,7 @@ describe('test Layer Properties Display module component', () => {
onChange() {}
};
const comp = ReactDOM.render(<Display element={l} settings={settings} onChange={handlers.onChange}/>, document.getElementById("container"));
expect(comp).toExist();
expect(comp).toBeTruthy();
const labels = ReactTestUtils.scryRenderedDOMComponentsWithClass( comp, "control-label" );
const inputs = ReactTestUtils.scryRenderedDOMComponentsWithTag( comp, "input" );
const legendWidth = inputs[11];
Expand Down Expand Up @@ -281,11 +281,11 @@ describe('test Layer Properties Display module component', () => {
};
let spy = expect.spyOn(handlers, "onChange");
const comp = ReactDOM.render(<Display element={l} settings={settings} onChange={handlers.onChange}/>, document.getElementById("container"));
expect(comp).toExist();
expect(comp).toBeTruthy();
const inputs = ReactTestUtils.scryRenderedDOMComponentsWithTag( comp, "input" );
const legendPreview = ReactTestUtils.scryRenderedDOMComponentsWithClass( comp, "legend-preview" );
expect(legendPreview).toExist();
expect(inputs).toExist();
expect(legendPreview).toBeTruthy();
expect(inputs).toBeTruthy();
expect(inputs.length).toBe(13);
let legendWidth = inputs[11];
let legendHeight = inputs[12];
Expand Down Expand Up @@ -350,9 +350,9 @@ describe('test Layer Properties Display module component', () => {
}
};
const comp = ReactDOM.render(<Display element={l} settings={settings}/>, document.getElementById("container"));
expect(comp).toExist();
expect(comp).toBeTruthy();
const inputs = ReactTestUtils.scryRenderedDOMComponentsWithTag( comp, "input" );
expect(inputs).toExist();
expect(inputs).toBeTruthy();
expect(inputs.length).toBe(13);
expect(inputs[11].value).toBe("20");
expect(inputs[12].value).toBe("40");
Expand Down
19 changes: 15 additions & 4 deletions web/client/components/map/cesium/plugins/VectorLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '../../../../utils/VectorStyleUtils';
import { applyDefaultStyleToVectorLayer } from '../../../../utils/StyleUtils';
import GeoJSONStyledFeatures from '../../../../utils/cesium/GeoJSONStyledFeatures';
import { geoStylerStyleFilter as filterVectorLayerFeatures } from '../../../../utils/styleparser/StyleParserUtils';

const createLayer = (options, map) => {

Expand All @@ -26,8 +27,11 @@ const createLayer = (options, map) => {
};
}

const features = flattenFeatures(options?.features || [], ({ style, ...feature }) => feature);

let features = flattenFeatures(options?.features || [], ({ style, ...feature }) => feature);
const hasLegendFilter = options?.geoStylerFilter;
if (hasLegendFilter) {
features = features.filter(feat => filterVectorLayerFeatures(feat, hasLegendFilter));
}
let styledFeatures = new GeoJSONStyledFeatures({
features,
id: options?.id,
Expand Down Expand Up @@ -59,11 +63,18 @@ const createLayer = (options, map) => {
Layers.registerType('vector', {
create: createLayer,
update: (layer, newOptions, oldOptions, map) => {
if (!isEqual(newOptions.features, oldOptions.features)) {
const isStyleChanged = !isEqual(oldOptions.style, newOptions.style);
const areFeaturesChanged = !isEqual(oldOptions.features, newOptions.features);

const oldLegendFilter = oldOptions?.layerFilter?.filters?.find(f=>f.id === 'interactiveLegend');
const newLegendFilter = newOptions?.layerFilter?.filters?.find(f=>f.id === 'interactiveLegend');
const isLegendFilterChanged = !isEqual(oldLegendFilter, newLegendFilter);

if (areFeaturesChanged || isLegendFilterChanged) {
return createLayer(newOptions, map);
}

if (layer?.styledFeatures && !isEqual(newOptions.style, oldOptions.style)) {
if ((layer?.styledFeatures && isStyleChanged)) {
layerToGeoStylerStyle(newOptions)
.then((style) => {
getStyle(applyDefaultStyleToVectorLayer({ ...newOptions, style }), 'cesium')
Expand Down
Loading

0 comments on commit 8a1b4c3

Please sign in to comment.