From 341e77a71f555d2ae3f3c4fc2f11bc9dee05a902 Mon Sep 17 00:00:00 2001 From: Ilija Puaca Date: Wed, 18 Nov 2020 20:36:33 +0100 Subject: [PATCH] FIX: Prevent crash in react-map-gl when zoom cannot be calculated Signed-off-by: Ilija Puaca --- src/components/geocoder-panel.js | 13 ++++++------- src/components/plot-container.js | 26 +++++++++----------------- src/reducers/map-state-updaters.js | 19 +++++++++---------- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/components/geocoder-panel.js b/src/components/geocoder-panel.js index d0143ceac1..25ed6bb6ca 100644 --- a/src/components/geocoder-panel.js +++ b/src/components/geocoder-panel.js @@ -135,18 +135,17 @@ export default function GeocoderPanelFactory() { lon + GEOCODER_GEO_OFFSET, lat + GEOCODER_GEO_OFFSET ]; - const {zoom} = geoViewport.viewport(bounds, [ + const centerAndZoom = geoViewport.viewport(bounds, [ this.props.mapState.width, this.props.mapState.height ]); - // center being calculated by geo-vieweport.viewport has a complex logic that - // projects and then unprojects the coordinates to determine the center - // Calculating a simple average instead as that is the expected behavior in most of cases - const center = [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2]; this.props.updateMap({ - latitude: center[1], - longitude: center[0], + latitude: centerAndZoom.center[1], + longitude: centerAndZoom.center[0], + // For marginal or invalid bounds, zoom may be NaN. Make sure to provide a valid value in order + // to avoid corrupt state and potential crashes as zoom is expected to be a number + ...(Number.isFinite(centerAndZoom.zoom) ? {zoom: centerAndZoom.zoom} : {}), zoom, pitch: 0, bearing: 0, diff --git a/src/components/plot-container.js b/src/components/plot-container.js index 0c0639df7f..c428bac021 100644 --- a/src/components/plot-container.js +++ b/src/components/plot-container.js @@ -173,23 +173,15 @@ export default function PlotContainerFactory(MapContainer) { }; if (exportImageSetting.center) { - const getViewport = shouldCenter => { - if (shouldCenter) { - const {zoom} = geoViewport.viewport(bounds, [width, height]); - // center being calculated by geo-vieweport.viewport has a complex logic that - // projects and then unprojects the coordinates to determine the center - // Calculating a simple average instead as that is the expected behavior in most of cases - const center = [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2]; - return {center, zoom}; - } - - return {center: [mapState.longitude, mapState.latitude], zoom: mapState.zoom}; - }; - - const {center, zoom} = getViewport(exportImageSetting.center); - - newMapState.longitude = center[0]; - newMapState.latitude = center[1]; + const viewport = exportImageSetting.center + ? geoViewport.viewport(bounds, [width, height]) + : {center: [newMapState.longitude, newMapState.latitude], zoom: mapState.zoom}; + // For marginal or invalid bounds, zoom may be NaN. Make sure to provide a valid value in order + // to avoid corrupt state and potential crashes as zoom is expected to be a number + const zoom = viewport.zoom || mapState.zoom; + + newMapState.longitude = viewport.center[0]; + newMapState.latitude = viewport.center[1]; newMapState.zoom = zoom + Number(Math.log2(scale) || 0); } diff --git a/src/reducers/map-state-updaters.js b/src/reducers/map-state-updaters.js index 96fed7595a..b6c33c7c67 100644 --- a/src/reducers/map-state-updaters.js +++ b/src/reducers/map-state-updaters.js @@ -113,20 +113,19 @@ export const updateMapUpdater = (state, action) => ({ export const fitBoundsUpdater = (state, action) => { const bounds = validateBounds(action.payload); if (!bounds) { - Console.warn('invalid map bounds provided') + Console.warn('invalid map bounds provided'); return state; - } - const {zoom} = geoViewport.viewport(bounds, [state.width, state.height]); - // center being calculated by geo-vieweport.viewport has a complex logic that - // projects and then unprojects the coordinates to determine the center - // Calculating a simple average instead as that is the expected behavior in most of cases - const center = [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2]; + } + + const viewport = geoViewport.viewport(bounds, [state.width, state.height]); return { ...state, - latitude: center[1], - longitude: center[0], - zoom + latitude: viewport.center[1], + longitude: viewport.center[0], + // For marginal or invalid bounds, zoom may be NaN. Make sure to provide a valid value in order + // to avoid corrupt state and potential crashes as zoom is expected to be a number + ...(Number.isFinite(viewport.zoom) ? {zoom: viewport.zoom} : {}) }; };