Skip to content

Conversation

@arxitpln
Copy link

@arxitpln arxitpln commented May 20, 2025

Description

Displays the legend of the ArcGIS & WMS layers visible in the current extent of the map

440788441-9596eab8-5042-48cb-8737-cb850a74ac27

Please check if the PR fulfills these requirements

What kind of change does this PR introduce? (check one with "x", remove the others)

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

Issue

What is the current behavior?
No floating legend
#11075

What is the new behavior?
Displays in a modal the legend of the ArcGIS & WMS layers visible in the current extent of the map and so automatically adapts its content on zoom in/out, pan or layers visibility toggle on/off
Displays the legends in the same hierarchy as the Layer List

Breaking change

Does this PR introduce a breaking change? (check one with "x", remove the other)

  • Yes, and I documented them in migration notes
  • No

Other useful information

@tdipisa tdipisa requested a review from allyoucanmap May 29, 2025 07:50
@tdipisa tdipisa added this to the 2025.02.00 milestone May 29, 2025
@tdipisa tdipisa added the New Feature used for new functionalities label May 29, 2025
@tdipisa tdipisa linked an issue May 29, 2025 that may be closed by this pull request
@tdipisa
Copy link
Member

tdipisa commented May 29, 2025

@arxitpln thank you so much for your contribution. PR state updated as needed. We will review it soon.

Copy link
Contributor

@allyoucanmap allyoucanmap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arxitpln I created this branch https://github.com/allyoucanmap/MapStore2/tree/arxit-floating-dynamic-legend on my fork with the initial review changes to apply, this is the commit allyoucanmap@a11b673 you can cherry pick on your branch to apply the provided changes.

In addition and after applying the above changes we need also to improve the following:

  • The default layout for this type of plugin is a side panel, we should allow to make it configurable using a boolean cfg.floating by default it should be false. When true it will render the floating modal when false the side panel similar to other plugins (eg: GeoProcessing)
  • When the legend is completely empty there is no feedback to the user. We should at least add a message explaining that the legend is empty because there are not visible layer on the current visible map
  • Missing unit tests for components and utils
  • Missing jsDoc for the plugin configuration
  • We should have the options to visualize the legend as a flat list of layers without groups. We could include a configuration boolean cfg.flatLegend so when a user configure it set a true only the list of layers is rendered, see in the image above TOC has group but legend only the list of layers. We could try to use groups prop to extract layers as const layers = flattenArrayOfObjects(groups)?.filter(node => !node?.nodes);

image

I'm adding inline comment to explain changes included here allyoucanmap@a11b673

Comment on lines 147 to 151
"dependencies": [
"Toolbar",
"BurgerMenu",
"SidebarMenu"
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In allyoucanmap@a11b673 only the SidebarMenu is included as dependency because is the current preferred container for all side plugins

],
"desktop": [
"Details",
"Details","DynamicLegend",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In allyoucanmap@a11b673 this has been excluded because the default localConfig.json should not contain the plugin. This plugin will be configured only via context in the default product application

Comment on lines 79 to 81
{
"name": "DynamicLegend"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed

Comment on lines 38 to 40
options: {
disablePluginIf: "{state('router') && (state('router').endsWith('new') || state('router').includes('newgeostory') || state('router').endsWith('dashboard'))}"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In In allyoucanmap@a11b673 removed because not needed

Comment on lines 37 to 40
const dynamicLegendIsEmpty = data.layers.every(layer => layer.legend.length === 0);
if ((node.dynamicLegendIsEmpty ?? null) !== dynamicLegendIsEmpty) {
onUpdateNode({ dynamicLegendIsEmpty });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In allyoucanmap@a11b673 the property as been renamed to legendEmpty to make it generic because it could be empty in other cases. Also the onUpdateNode has been changed to onChange to make it consistent with the parent component

Comment on lines 142 to 144
if ((this.props.layer.dynamicLegendIsEmpty ?? null) !== imgError) {
this.props.onUpdateNode({ dynamicLegendIsEmpty: imgError });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In allyoucanmap@a11b673 same as previous comment

Comment on lines 109 to 112
const dynamicLegendIsEmpty = data.length === 0 || data[0].rules.length === 0;
if ((this.props.layer.dynamicLegendIsEmpty ?? null) !== dynamicLegendIsEmpty) {
this.props.onUpdateNode({ dynamicLegendIsEmpty });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In allyoucanmap@a11b673 same as previous comment

Comment on lines 51 to 67
const customGroupNodeComponent = props => (
<div style={getVisibilityStyle(props.node?.isVisible ?? true)}>
<DefaultGroup {...props} />
</div>
);
const customLayerNodeComponent = props => {
const layer = layerDict[props.node.id];
if (!layer) {
return null;
}

return (
<div style={getVisibilityStyle(props.node?.isVisible ?? true)}>
<DefaultLayer {...props} node={layer} />
</div>
);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In allyoucanmap@a11b673 this component has been changed to avoid too many re-render inside the custom nodes, changes:

  • moved customGroupNodeComponent and customLayerNodeComponent outside the render function to avoid re-render on each prop update of DynamicLegend component
  • reviewed the hiding logic of node by exposing and using the getNodeStyle prop in ControlledTOC

@@ -0,0 +1,14 @@
const isLayer = node => node.nodeType === "layers";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In allyoucanmap@a11b673 this file has been renamed to DynamicLegendUtils because it does not contain selectors but utils. Some of the utils has been changed to support the new hiding logic.

To better isolate the plugin all files have been moved under the plugins/DynamicLegend folder:

plugins/DynamicLegend/
    |__assets/
    |__components/
    |__utils/
    |__index.js

Note DynamicLegend is uppercase as the name file so the import resolver will look for the index.js file inside

@arxitpln
Copy link
Author

@allyoucanmap, we asked for a review but there is still a pending issue. Please see above our comment (4 Nov)
Note that this is also a prerequisite for us to writ unit test

@allyoucanmap
Copy link
Contributor

@arxitpln in this other branch https://github.com/allyoucanmap/MapStore2/commits/issue_11075_layout on my fork you can find two commits:

Please double check both commits before applying them on your branch, thanks

Copy link
Contributor

@allyoucanmap allyoucanmap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see this comment #11118 (comment)

github-actions bot and others added 17 commits December 1, 2025 11:06
…) (geosolutions-it#11736)

(cherry picked from commit c0b9487)

Co-authored-by: Lorenzo Natali <lorenzo.natali@geosolutionsgroup.com>
…chrone plugin (geosolutions-it#11737) (geosolutions-it#11741)

(cherry picked from commit 7974015)

Co-authored-by: Lorenzo Natali <lorenzo.natali@geosolutionsgroup.com>
…#11727) (geosolutions-it#11743)

(cherry picked from commit 1fffbef)

Co-authored-by: Suren <dsuren1@gmail.com>
…eosolutions-it#11756) (geosolutions-it#11757)

(cherry picked from commit e6ad159)

Co-authored-by: ElenaGallo <56537133+ElenaGallo@users.noreply.github.com>
…Unadvertised Contexts (geosolutions-it#11752) (geosolutions-it#11755)

(cherry picked from commit 1b6d336)

Co-authored-by: RowHeat <40065760+rowheat02@users.noreply.github.com>
…eosolutions-it#11759)

* add_11684

* add_review_11684

(cherry picked from commit c27477c)

Co-authored-by: ElenaGallo <56537133+ElenaGallo@users.noreply.github.com>
…tions-it#11761) (geosolutions-it#11763)

(cherry picked from commit 23b1527)

Co-authored-by: Lorenzo Natali <lorenzo.natali@geosolutionsgroup.com>
…Chart Widget (geosolutions-it#11764) (geosolutions-it#11765)

(cherry picked from commit b02c773)

Co-authored-by: ElenaGallo <56537133+ElenaGallo@users.noreply.github.com>
…eosolutions-it#11767)

* add_11662

* Update docs/user-guide/filtering-layers.md

* Update docs/user-guide/filtering-layers.md

---------


(cherry picked from commit 9a8083e)

Co-authored-by: ElenaGallo <56537133+ElenaGallo@users.noreply.github.com>
Co-authored-by: Tobia Di Pisa <tobia.dipisa@geosolutionsgroup.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Floating Dynamic Legend Plugin for ArcGIS & WMS layers