地图视野范围如何设置
==========

#### 问题现象

当地图上显示多个Marker标记等覆盖物时，如何自动缩放和移动相机视野，使所有覆盖物都在一屏内展示出来。

#### 背景知识

*   开发准备：使用地图服务，需要先[开通地图服务](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/map-config-agc#section16133115441516)。
*   [newLatLngBounds](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-map-functions#newlatlngbounds)：设置地图经纬度范围、地图区域和边界之间的距离。
*   [moveCamera](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-map-mapcomponentcontroller#section141021341974)：更新相机状态。

#### 解决方案

1.  计算覆盖物的边界：遍历所有添加到地图上的覆盖物所在的坐标，计算每个覆盖物坐标的最小和最大经纬度。
    
    calculateBounds(positions: mapCommon.LatLng\[\]): mapCommon.LatLngBounds {
      let minLat: number = 31.9844;
      let maxLat: number = 31.9844;
      let minLng: number = 118.7662;
      let maxLng: number = 118.7662;
    
      positions.forEach(pos => {
        minLat = Math.min(minLat, pos.latitude);
        maxLat = Math.max(maxLat, pos.latitude);
        minLng = Math.min(minLng, pos.longitude);
        maxLng = Math.max(maxLng, pos.longitude);
      });
      return {
        southwest: { latitude: minLat, longitude: minLng },
        northeast: { latitude: maxLat, longitude: maxLng }
      };
    }
    
2.  设置地图视图：使用计算出的边界范围，创建一个LatLngBounds对象，使用newLatLngBounds方法创建一个CameraUpdate对象，传入刚才创建的LatLngBounds和适当的padding值，以确保覆盖物边缘有足够的缓冲空间。
    
    最后，使用moveCamera或animateCamera方法应用这个CameraUpdate对象到地图上，实现视图的更新。
    
    const latLngBounds = this.calculateBounds(this.markerPositions);
    _// 自动调整视野_
    try {
      let cameraUpdate = map.newLatLngBounds(latLngBounds, 50); _// 50是padding值，可以根据需要调整_
      this.mapController.moveCamera(cameraUpdate);
    } catch (error) {
      console.error('Adjust camera failed:', (error as BusinessError).message);
    }
    
    效果图：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/cd/v3/jsq32cDTTLimtAob5Uo4qQ/zh-cn_image_0000002628554288.png?HW-CC-KV=V1&HW-CC-Date=20260709T134310Z&HW-CC-Expire=86400&HW-CC-Sign=D94C702954B6E182D228DCE1383E2C91398EC63CDBB51AE4A649B92E53EA1B5F "点击放大")
    
    完整代码：
    
    import { MapComponent, mapCommon, map } from '@kit.MapKit';
    import { AsyncCallback } from '@kit.BasicServicesKit';
    import { display } from '@kit.ArkUI';
    
    @Entry
    @Component
    struct AdjustCamera {
      private mapOptions?: mapCommon.MapOptions;
      private callback?: AsyncCallback<map.MapComponentController>;
      private mapController?: map.MapComponentController;
      private markerPositions: Array<mapCommon.LatLng> = \[
        { latitude: 31.9844, longitude: 118.7662 },
        { latitude: 32.0844, longitude: 118.8662 },
        { latitude: 32.0044, longitude: 118.9062 },
        { latitude: 31.9544, longitude: 118.7262 },
        { latitude: 32.0244, longitude: 118.7962 }
      \];
      @State mapHeight: number = 0;
    
      calculateBounds(positions: mapCommon.LatLng\[\]): mapCommon.LatLngBounds {
        let minLat: number = 31.9844;
        let maxLat: number = 31.9844;
        let minLng: number = 118.7662;
        let maxLng: number = 118.7662;
    
        positions.forEach(pos => {
          minLat = Math.min(minLat, pos.latitude);
          maxLat = Math.max(maxLat, pos.latitude);
          minLng = Math.min(minLng, pos.longitude);
          maxLng = Math.max(maxLng, pos.longitude);
        });
        return {
          southwest: { latitude: minLat, longitude: minLng },
          northeast: { latitude: maxLat, longitude: maxLng }
        };
      }
    
    
      aboutToAppear(): void {
        let displayClass = display.getDefaultDisplaySync();
        this.mapHeight = this.getUIContext().px2vp(displayClass.height);
     _   // 初始化地图中心点参数_
        let cameraPosition: mapCommon.CameraPosition = {
          target: { latitude: 32.0, longitude: 118.8 }, _// 初始中心点_
          zoom: 10 _// 初始缩放级别_
        };
        this.mapOptions = { position: cameraPosition };
    
      _  // 地图初始化回调_
        this.callback = async (err, mapController) => {
          if (!err) {
            this.mapController = mapController;
           _ // 创建5个不同位置的Marker_
            await Promise.all(this.markerPositions.map(pos =>
            this.mapController?.addMarker({
              position: pos,
              anchorU: 0.5,
              anchorV: 0.5
            })
            ));
            const latLngBounds = this.calculateBounds(this.markerPositions);
           _ // 自动调整视野_
            try {
              let cameraUpdate = map.newLatLngBounds(latLngBounds, 50); _// 50是padding值，可以根据需要调整_
              this.mapController.moveCamera(cameraUpdate);
            } catch (error) {
              console.error('Adjust camera failed:', (error as BusinessError).message);
            }
          }
        };
      }
    
      build() {
        Stack() {
          Column() {
            MapComponent({
              mapOptions: this.mapOptions,
              mapCallback: this.callback
            })
              .height(this.mapHeight);
          }
          .width('100%');
        }
        .ignoreLayoutSafeArea();
      }
    }
    

#### 常见FAQ

Q：为什么开启3D地球效果后，地图上绘制的点，线，图片覆盖物在地图缩放为球体后不显示？

A：3D状态下，传统2D覆盖物（如点、线、图片覆盖物）不会被渲染，只有当地图放大到2D平面模式（缩放级别较高）时，这些覆盖物才会重新显示。当地图需要显示覆盖物时，通过[setSphereEnabled](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-map-mapcomponentcontroller#section67801022102716)动态关闭3D效果。