You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用WebMercatorViewport的fitBounds时遇padding只读属性错误

问题:WebMercatorViewport调用fitBounds设置padding后触发只读属性错误

在使用WebMercatorViewport的fitBounds方法并传入padding参数时,初始渲染正常,但状态变化(如关闭地图、更新状态)时出现以下错误:

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)

使用的依赖版本:

  • deck.gl: "8.8.20"
  • react-map-gl: "7.0.20"

相关代码:

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>

解决方案

问题根源是直接返回WebMercatorViewport实例给initialViewState,DeckGL内部会尝试修改该实例的padding属性,但实例的属性是只读的。需要将Viewport实例转换为普通可写对象。

修改后的代码:

const initialViewState: IViewport | Record<string, any> = 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]
    
    // 将Viewport实例转为普通可写对象
    const viewportInstance = new WebMercatorViewport({ width: 1920, height: 400 })
    return viewportInstance.fitBounds([southWest, northEast], {padding: 200}).toJSON()
  } else {
    // 若viewport是实例,同样转为普通对象
    return viewport instanceof WebMercatorViewport ? viewport.toJSON() : viewport
  }
}, [locationsFitBounds, viewport])

关键说明

  • WebMercatorViewport实例的内部属性被设置为只读,DeckGL在状态更新时需要修改padding等属性,直接传入实例会触发只读属性错误。
  • toJSON()方法会将实例转换为包含所有视图状态(如经度、纬度、缩放级别、padding等)的普通JavaScript对象,该对象的属性可正常修改,符合DeckGL对initialViewState的要求。

内容的提问来源于stack exchange,提问作者Ar26

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 13:43:04