From 75e9b0c7bebd19e967b7164a55e3f43832c65bd5 Mon Sep 17 00:00:00 2001 From: Lorenzo Natali Date: Fri, 23 Oct 2026 17:34:29 +0200 Subject: [PATCH] Fix Cesium point zoom with map padding --- web/client/components/map/cesium/Map.jsx | 7 +- .../map/cesium/__tests__/Map-test.jsx | 73 +++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/web/client/components/map/cesium/Map.jsx b/web/client/components/map/cesium/Map.jsx index 25dcd20dfa2..2be59b4ddbd 100644 --- a/web/client/components/map/cesium/Map.jsx +++ b/web/client/components/map/cesium/Map.jsx @@ -629,6 +629,9 @@ class CesiumMap extends React.Component { let deltaY = north - south; if (deltaX === 0 && deltaY === 0) { + if (!Number.isFinite(maxZoom)) { + return bounds; + } const centerLat = (south + north) / 2; const fallbackHeight = getHeightFromZoom(maxZoom); const metersPerDegreeLat = 111320; @@ -667,11 +670,12 @@ class CesiumMap extends React.Component { return; } const ellipsoid = this.map.scene.globe.ellipsoid; + const maxZoomValue = Number.isFinite(maxZoom) ? maxZoom : this.props.mapOptions?.zoomToExtentSettings?.maxZoom; const [west, south, east, north] = this.applyPaddingToBounds( bounds, padding, { width: this.map.canvas?.clientWidth, height: this.map.canvas?.clientHeight }, - maxZoom, + maxZoomValue, this.getHeightFromZoom ); const height = options?.height ?? options?.altitude ?? 0; @@ -695,7 +699,6 @@ class CesiumMap extends React.Component { if (this.map.camera.flyToBoundingSphere) { const fitFactor = this.props.mapOptions?.zoomToExtentSettings?.fitFactor || 2.0; - const maxZoomValue = Number.isFinite(maxZoom) ? maxZoom : this.props.mapOptions?.zoomToExtentSettings?.maxZoom; const idealRange = fitFactor * radius; const minRangeFromMaxZoom = Number.isFinite(maxZoomValue) ? this.getHeightFromZoom(maxZoomValue) : 0; const range = Number.isFinite(maxZoomValue) && idealRange < minRangeFromMaxZoom diff --git a/web/client/components/map/cesium/__tests__/Map-test.jsx b/web/client/components/map/cesium/__tests__/Map-test.jsx index 4f2c422265f..143cf62e553 100644 --- a/web/client/components/map/cesium/__tests__/Map-test.jsx +++ b/web/client/components/map/cesium/__tests__/Map-test.jsx @@ -551,6 +551,79 @@ describe('CesiumMap', () => { // unregister hook registerHook(ZOOM_TO_EXTENT_HOOK); }); + it('pads a point extent using the configured maxZoom when the action omits it', () => { + const hookRegister = createRegisterHooks(); + let ref; + act(() => { + ReactDOM.render( { ref = value; }} + center={{ y: 20, x: 10 }} + zoom={11} + hookRegister={hookRegister} + mapOptions={{ zoomToExtentSettings: { maxZoom: 20 } }} + />, document.getElementById('container')); + }); + Object.defineProperties(ref.map.canvas, { + clientWidth: { configurable: true, value: 400 }, + clientHeight: { configurable: true, value: 200 } + }); + let flight; + ref.map.camera.flyToBoundingSphere = (boundingSphere, options) => { + flight = { boundingSphere, options }; + }; + + const hook = hookRegister.getHook(ZOOM_TO_EXTENT_HOOK); + expect(typeof hook).toBe('function'); + hook([10, 20, 10, 20], { crs: 'EPSG:4326', duration: 0, padding: { left: 100 } }); + + expect(flight).toExist(); + const position = Cesium.Cartographic.fromCartesian(flight.boundingSphere.center); + const longitude = Cesium.Math.toDegrees(position.longitude); + const latitude = Cesium.Math.toDegrees(position.latitude); + expect(Number.isFinite(longitude)).toBe(true); + expect(Number.isFinite(latitude)).toBe(true); + expect(Number.isFinite(flight.boundingSphere.radius)).toBe(true); + expect(Math.round(longitude * 1000000)).toBe(9999757); + expect(Math.round(latitude * 1000000)).toBe(20000000); + expect(Math.round(flight.boundingSphere.radius)).toBe(25); + expect(Math.round(flight.options.offset.range)).toBe(153); + }); + it('uses the point radius when padding has no configured maxZoom', () => { + const hookRegister = createRegisterHooks(); + let ref; + act(() => { + ReactDOM.render( { ref = value; }} + center={{ y: 20, x: 10 }} + zoom={11} + hookRegister={hookRegister} + />, document.getElementById('container')); + }); + Object.defineProperties(ref.map.canvas, { + clientWidth: { configurable: true, value: 400 }, + clientHeight: { configurable: true, value: 200 } + }); + let flight; + ref.map.camera.flyToBoundingSphere = (boundingSphere, options) => { + flight = { boundingSphere, options }; + }; + + const hook = hookRegister.getHook(ZOOM_TO_EXTENT_HOOK); + expect(typeof hook).toBe('function'); + hook([10, 20, 10, 20], { crs: 'EPSG:4326', duration: 0, padding: { left: 100 } }); + + expect(flight).toExist(); + const position = Cesium.Cartographic.fromCartesian(flight.boundingSphere.center); + const longitude = Cesium.Math.toDegrees(position.longitude); + const latitude = Cesium.Math.toDegrees(position.latitude); + expect(Number.isFinite(longitude)).toBe(true); + expect(Number.isFinite(latitude)).toBe(true); + expect(Number.isFinite(flight.boundingSphere.radius)).toBe(true); + expect(Math.round(longitude * 1000000)).toBe(10000000); + expect(Math.round(latitude * 1000000)).toBe(20000000); + expect(flight.boundingSphere.radius).toBe(10); + expect(flight.options.offset.range).toBe(20); + }); it('should reorder the layer correctly even if the position property of layer exceed the imageryLayers length', (done) => { let ref;