Search code examples
reactjsmapboxreact-map-gldeck.gl

Fit bounds with padding deck.gl mapbox


I'm trying to use fiBounds with the WebMercatorViewport object but getting an error about the padding property.

my code:

const initialViewState: IViewport | WebMercatorViewport = useMemo(() => {
if (locationsFitBounds) {
  const minLat: number = Math.min(...locationsFitBounds.map((l: MapLocation) => l.latitude))
  const maxLat: number = Math.max(...locationsFitBounds.map((l: MapLocation) => l.latitude))
  const minLng: number = Math.min(...locationsFitBounds.map((l: MapLocation) => l.longitude))
  const maxLng: number = Math.max(...locationsFitBounds.map((l: MapLocation) => l.longitude))
  const southWest: [number, number] = [minLng, minLat]
  const northEast: [number, number] = [maxLng, maxLat]
    return new WebMercatorViewport({ width: 1920, height: 400 }).fitBounds([southWest, northEast], {padding: 200})
} else {
  return viewport
}
}, [locationsFitBounds, viewport])

 <React.Fragment>
  <DeckGL
    width="100%"
    height="100%"
    controller={true}
    initialViewState={initialViewState}
  >
    <Map
      attributionControl={false}
      style={{ width: "100%", height: "100%" }}
    />
  </DeckGL>
</React.Fragment>

The inital render is working well but when the state is changing (closing the map, updating states) I'm getting the error:

   Uncaught TypeError: Cannot assign to read only property 'padding' of object '#<WebMercatorViewport>'
    at positionChildrenUnderViews (position-children-under-views.ts:60:1)
    at deckgl.ts:254:1
    at renderWithHooks (react-dom.development.js:16175:1)
    at updateForwardRef (react-dom.development.js:20023:1)
    at beginWork (react-dom.development.js:22465:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4161:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4210:1)
    at invokeGuardedCallback (react-dom.development.js:4274:1)
    at beginWork$1 (react-dom.development.js:27405:1)
    at performUnitOfWork (react-dom.development.js:26513:1)

I'm using: deck.gl: "8.8.20" react-map-gl": "7.0.20"


Solution

  • Got a solution from git discussion The useMemo should return a simple viewport and not a WebMercatorViewport object:

      const initialViewState: IViewport = useMemo(() => {
        if (fitLocations) {
          const minLat: number = Math.min(...fitLocations.map((l: MapLocation) => l.latitude))
          const maxLat: number = Math.max(...fitLocations.map((l: MapLocation) => l.latitude))
          const minLng: number = Math.min(...fitLocations.map((l: MapLocation) => l.longitude))
          const maxLng: number = Math.max(...fitLocations.map((l: MapLocation) => l.longitude))
          const southWest: [number, number] = [minLng, minLat]
          const northEast: [number, number] = [maxLng, maxLat]
          const { latitude, longitude, zoom } = new WebMercatorViewport({ width: 800, height: 600 }).fitBounds(
            [southWest, northEast],
            { padding: 100 }
          )
          return { ...viewport, latitude, longitude, zoom }
        } else {
          return viewport
        }
      }, [fitLocations, viewport])