WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Conversation

@anup39
Copy link
Member

@anup39 anup39 commented Sep 25, 2025

Description

This PR add new plugin called CameraPosition. In 3D mode it shows the camera position along with the height . The camera position plugin is now rendered in MapFooter. The following changes are made :

  1. This plugin is available only for 3D
  2. Refactor of the MousePosition components.
  3. This new plugin have a structure similar to the MousePosition plugin.
  4. Logic to manage the geoid model is implemented using @math.gl/geoid.
  5. The geoid EGM96 is used to compute height above the mean sea level MSL

Please check if the PR fulfills these requirements

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

  • Feature
  • Refactoring (no functional changes, no api changes)

Issue

What is the current behavior?

#11455

What is the new behavior?

Screenshot 2025-09-25 at 20 28 51

Breaking change

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

  • No

Other useful information

This plugin style needs to be further revised again after MapFooter refactor PR is merged . #11492

@anup39 anup39 added this to the 2025.02.00 milestone Sep 25, 2025
@anup39 anup39 self-assigned this Sep 25, 2025
@anup39 anup39 added the New Feature used for new functionalities label Sep 25, 2025
@anup39 anup39 linked an issue Sep 25, 2025 that may be closed by this pull request
5 tasks
@anup39 anup39 requested a review from allyoucanmap September 25, 2025 15:07
@allyoucanmap allyoucanmap assigned allyoucanmap and unassigned anup39 Oct 13, 2025
@tdipisa tdipisa added BackportNeeded Commits provided for an issue need to be backported to the milestone's stable branch and removed BackportNeeded Commits provided for an issue need to be backported to the milestone's stable branch labels Nov 4, 2025
@tdipisa tdipisa modified the milestones: 2025.02.00, 2026.01.00 Nov 4, 2025
Comment on lines +213 to +221
export default {
CameraPositionPlugin: Object.assign(CameraPositionPlugin, {
disablePluginIf: "{state('mapType') !== 'cesium'}"
},
{
MapFooter: { name: 'cameraPosition', position: 3, target: 'right-footer',
priority: 1}
})
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use the createPlugin function

Comment on lines +92 to +104
export function changeCameraPositionCrs(crs) {
return {
type: CHANGE_CAMERA_POSITION_CRS,
crs
};
}

export function changeCameraPositionHeightType(heightType) {
return {
type: CHANGE_CAMERA_POSITION_HEIGHT_TYPE,
heightType
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be part of a new cameraposition state and not included inside the Map, this is valid for actions, reducers and selectors

height: cameraPosition.height
height: cameraPosition.height,
crs: this.props.viewerOptions?.cameraPosition?.crs || "EPSG:4326",
heightType: this.props.viewerOptions?.cameraPosition?.heightType || 'Ellipsoidal'
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove all this change this should not be part of the Map state

Comment on lines +91 to +100
<ControlLabel style={{ margin: 0, fontWeight: 'normal', minWidth: 'max-content' }}>
{label}
</ControlLabel>
<FormControl
componentClass="select"
id={id}
value={crs}
onChange={launchNewCRSAction}
bsSize="small"
style={{ borderRadius: 4 }}
Copy link
Contributor

Choose a reason for hiding this comment

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

please move all the inline styles inside the less theme. Also let's reduce the width of this selector to 90px
image

Comment on lines +39 to +46
const availableHeightTypes = [
{ value: "Ellipsoidal", label: "Ellipsoidal" },
{ value: "MSL", label: "MSL" }
];

const filteredHeightTypes = filterAllowedHeight && filterAllowedHeight.length > 0
? availableHeightTypes.filter((height) => filterAllowedHeight.includes(height.value))
: availableHeightTypes;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the filterAllowed... props are not clear so at least for the new configuration introduced in this PR we should avoid them. Please remove filterAllowedHeight
In this case it would be enough to override the full list with the availableHeightTypes as prop

"cfg": {
    "availableHeightTypes": [
            { "value": "Ellipsoidal", label: "Ellipsoidal" },
            { "value": "MSL", label: "MSL" }
    ]
}

Comment on lines +129 to +211
/**
* CameraPosition Plugin is a plugin that shows the coordinate of the camera position in a selected crs along with the height above ellipsoid or mean sea level.
* it gets displayed into the mapFooter plugin
* @name CameraPosition
* @memberof plugins
* @class
* @prop {string} cfg.editCRS if true shows a combobox to select the crs of the camera position.
* @prop {string} cfg.showLabels if true shows the labels of the coordinates.
* @prop {string} cfg.showToggle if true shows a toggle button to enable/disable the plugin.
* @prop {boolean} cfg.showElevation shows elevation in Ellipsoidal or MSL in 3D map.
* @prop {function} cfg.elevationTemplate custom template to show the elevation if showElevation is true (default template shows the elevation number with no formatting)
* @prop {object[]} projectionDefs list of additional project definitions
* @prop {string[]} cfg.filterAllowedCRS list of allowed crs in the combobox list to used as filter for the one of retrieved proj4.defs()
* @prop {string[]} cfg.filterAllowedHeight list of allowed height type in the combobox list. Accepted values are "Ellipsoidal" and "MSL"
* @prop {object} cfg.additionalCRS additional crs added to the list. The label param is used after in the combobox.
* @example
* // If you want to add some crs you need to provide a definition and adding it in the additionalCRS property
* // Put the following lines at the first level of the localconfig
* {
* "projectionDefs": [{
* "code": "EPSG:3003",
* "def": "+proj=tmerc +lat_0=0 +lon_0=9 +k=0.9996 +x_0=1500000 +y_0=0 +ellps=intl+towgs84=-104.1,-49.1,-9.9,0.971,-2.917,0.714,-11.68 +units=m +no_defs",
* "extent": [1241482.0019, 973563.1609, 1830078.9331, 5215189.0853],
* "worldExtent": [6.6500, 8.8000, 12.0000, 47.0500]
* }]
* }
* @example
* // And configure the mouse position plugin as below:
* {
* "cfg": {
* "additionalCRS": {
* "EPSG:3003": { "label": "EPSG:3003" }
* },
* "filterAllowedCRS": ["EPSG:4326", "EPSG:3857"]
* }
* }
* @example
* // to show elevation and (optionally) use a custom template configure the plugin this way:
* {
* "cfg": {
* ...
* "showElevation": true,
* "elevationTemplate": "{(function(elevation) {return 'myelev: ' + (elevation || 0);})}",
* ...
* }
* }
* @example
* // to filter the height type list configure the plugin this way:
* {
* "cfg": {
* ...
* "filterAllowedHeight": ["Ellipsoidal", "MSL"],
* ...
* }
* }
* @example
* // to show the crs and height type labels configure the plugin this way:
* {
* "cfg": {
* ...
* "showLabels": true,
* ...
* }
* }
* @example
* // to show the toggle button configure the plugin this way:
* {
* "cfg": {
* ...
* "showToggle": true,
* ...
* }
* }
* @example
* // to show the crs selector configure the plugin this way:
* {
* "cfg": {
* ...
* "editCRS": true,
* ...
* }
* }
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Please review the documentation based on requested changes

MediaEditorPlugin: toModulePlugin('MediaEditor', () => import(/* webpackChunkName: 'plugins/mediaEditor' */ '../plugins/MediaEditor')),
MetadataExplorerPlugin: toModulePlugin('MetadataExplorer', () => import(/* webpackChunkName: 'plugins/metadataExplorer' */ '../plugins/MetadataExplorer')),
MousePositionPlugin: toModulePlugin('MousePosition', () => import(/* webpackChunkName: 'plugins/mousePosition' */ '../plugins/MousePosition')),
CameraPositionPlugin: toModulePlugin('CameraPosition', () => import(/* webpackChunkName: 'plugins/cameraPosition' */ '../plugins/CameraPosition')),
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's import this plugin without toModulePlugin

Comment on lines +191 to +212
case CHANGE_CAMERA_POSITION_CRS:
return {
...state,
viewerOptions: {
...state.viewerOptions,
cameraPosition: {
...state?.viewerOptions?.cameraPosition,
crs: action.crs
}
}
};
case CHANGE_CAMERA_POSITION_HEIGHT_TYPE:
return {
...state,
viewerOptions: {
...state.viewerOptions,
cameraPosition: {
...state?.viewerOptions?.cameraPosition,
heightType: action.heightType
}
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

as mentioned in previous comment this should be moved in a specific reducers

Comment on lines +154 to +155
export const cameraPositionCrsSelector = (state) => state.map?.present?.viewerOptions?.cameraPosition.crs || 'EPSG:4326';
export const cameraPositionHeightTypeSelector = (state) => state.map?.present?.viewerOptions?.cameraPosition.heightType || 'Ellipsoidal';
Copy link
Contributor

Choose a reason for hiding this comment

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

as mentioned in previous comment this should be moved in a specific selector

Comment on lines +146 to +152
export const mouseLeftDragListenerSelector = (state) => get(mapSelector(state), 'eventListeners.leftdrag', []);

export const isMouseMoveActiveSelector = (state) => !!mouseMoveListenerSelector(state).length;
export const isMouseLeftDragActiveSelector = (state) => !!mouseLeftDragListenerSelector(state).length;

export const isMouseMoveCoordinatesActiveSelector = (state) => mouseMoveListenerSelector(state).includes('mouseposition');
export const isMouseLeftDragCoordinatesActiveSelector = (state) => mouseLeftDragListenerSelector(state).includes('cameraposition');
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the usage of these new selectors?

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.

In addition to previous review:

  • remove the geoid file
  • merge master on this branch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

New Feature used for new functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CameraPosition plugin

3 participants