在缩放之前在传单中获取 GeoJson 区域的地图边界

Getting the map bounds of a GeoJson region in leaflet prior to zooming

我正在使用 leaflet 并根据当前查看的地图的边界框坐标从数据库动态加载我的地​​图区域。当我放大时,每个新图层的细节都会增加。地图的每一层都会存在相同的区域,不同缩放级别的相同区域将具有相同的id。

我目前正在尝试计算目标地图边界和目标缩放级别,以便我可以加载新地图边界框内的所有相交区域。我目前有以下代码。

zoomToFeature(e) {
    //e.g. map zoom for currently visible map is 3
    const layer = e.target;
    let padding = [5, 5];
    let layerBounds = layer.getBounds();
    
    //e.g layerBounds returns:
    //ne = lat: -37.770025, lng: 145.02439
    //sw = lat: -37.834451, lng: 144.900952

    let targetZoom = this.map.getBoundsZoom(layerBounds, false, padding);
    targetZoom = Math.min(this.map.getMaxZoom(), targetZoom);
    //e.g.targetZoom for this feature is 12

    let center = layer.getCenter()
    //e.g. center for this layer is lat: -37.78808138412046, lng: 144.93164062500003

    let targetPixelBounds = this.map.getPixelBounds(center, targetZoom);
    //e.g. targetPixelBounds: max: Point{x: 946751, y: 643578} min:{x:946114,y:643078}
    //this looks very wrong, and so causes everything below to fail I think.
    //am I supposed to reset the origin? am I meant to project the center and targetZoom?

    let sw = this.map.unproject(targetPixelBounds.getBottomLeft());
    let ne = this.map.unproject(targetPixelBounds.getTopRight());
    let targetMapBounds = new L.LatLngBounds(sw, ne);
    
    this.map.flyTo(center,targetZoom);

    this.loadMapData(targetMapBounds, targetZoom).subscribe(() => {
      
      this.removeOldRegions(); // deletes existing geojson
      this.loadRegions(); // adds retrieved data to new geojson layer
      //find the same region but in the new zoom layer
      let newLayer = this.getLayerById(layer.feature.properties.id);
      this.highlightFeature(newLayer);
    });
    
  }

出错了 让 targetPixelBounds = this.map.getPixelBounds(center, targetZoom) 线.

知道如何解决这个问题吗?

此操作的默认行为是读出边界并将其传递给地图:

map.fitBounds(e.target.getBounds());

那么你的函数可以看起来像:

zoomToFeature(e) {
    let padding = [5, 5];
    let layerBounds = e.target.getBounds();

    let targetZoom = this.map.getBoundsZoom(layerBounds, false, padding);
    targetZoom = Math.min(this.map.getMaxZoom(), targetZoom);
    //e.g.targetZoom for this feature is 12

    map.fitBounds(layerBounds , {padding: padding, maxZoom: targetZoom });
    
    this.loadMapData(layerBounds , targetZoom).subscribe(() => {      
      this.removeOldRegions(); // deletes existing geojson
      this.loadRegions(); // adds retrieved data to new geojson layer
      //find the same region but in the new zoom layer
      let newLayer = this.getLayerById(layer.feature.properties.id);
      this.highlightFeature(newLayer);
    });
}

这会移动地图并将其缩放到图层。

好的,我破案了

上面原始代码中的unproject行将缩放级别作为参数,我没有在原始代码中输入。所以我重构了代码,我在下面发布了。

基本上,一旦我有了地图边界框,我就可以执行飞行,并执行代码以在新的缩放级别检索新的 geojson。当动画完成时,新的 geojson 层已经加载。 (用 TypeScript 编写。对不起非 TypeScript 的人)

zoomToFeature(e) {
    const layer = e.target;
    let padding = [5, 5];
    let layerBounds = layer.getBounds();
    let targetMapBoundsZoom = this.getTargetMapBoundsZoom(layerBounds, { padding: padding });
    this.map.flyToBounds(targetMapBoundsZoom.bounds);
    this.loadMapData(targetMapBoundsZoom.bounds, targetMapBoundsZoom.zoom).subscribe(() => {
      this.removeOldRegions();
      this.loadRegions();
      //find the same region but in the new zoom layer
      let newLayer = this.getLayerById(layer.feature.properties.id);
      this.highlightFeature(newLayer);
    });
  }

  getTargetMapBoundsZoom(bounds, options) {
    let newBoundsCenterZoom = this._getBoundsCenterZoom(bounds, options);
    let targetMapBoundsPixels = this.map.getPixelBounds(newBoundsCenterZoom.center, newBoundsCenterZoom.zoom);
    let targetSw = this.map.unproject(targetMapBoundsPixels.getBottomLeft(), newBoundsCenterZoom.zoom);
    let targetNe = this.map.unproject(targetMapBoundsPixels.getTopRight(), newBoundsCenterZoom.zoom);
    let targetMapBounds = new L.LatLngBounds(targetSw, targetNe);
    return {
      bounds: targetMapBounds,
      zoom: newBoundsCenterZoom.zoom
    }
  }


loadMapData(bounds, zoom): Observable<any[]> {
    const boundingBox = Util.GetMapBounds(bounds);
    const regionTypeId = this.regionTypeIds[this._regionType];
    return this.mapService.getGeoJsonData("AU",
      regionTypeId,
      zoom,
      boundingBox.n,
      boundingBox.s,
      boundingBox.e,
      boundingBox.w).pipe(map((response: any) => {
        this.mapGeoJsonData = this.createFeatureCollection(response.data);
        return this.mapGeoJsonData;
      }));
  }

//this is a copy of the original _getBoundsCenterZoom that is internal to leaflet, with minor modifications.
_getBoundsCenterZoom(bounds, options) {
    
     options = options || {};
     bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);
    
     var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
         paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
    
     zoom = this.map.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
     zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
    
     if (zoom === Infinity) {
        return {
           center: bounds.getCenter(),
           zoom: zoom
        };
     }
    
     var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
     swPoint = this.map.project(bounds.getSouthWest(), zoom),
     nePoint = this.map.project(bounds.getNorthEast(), zoom),
     center = this.map.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
    
     return {
       center: center,
       zoom: zoom
     };
}

createFeatureCollection(data: any) {
    let featureCollection = {
      type: "FeatureCollection",
      features: data.map(r => {
        const geoJson = JSON.parse(r.geoJson);
        if (geoJson.type === "GeometryCollection") {
          geoJson.geometries = geoJson.geometries.filter(r => r.type === "Polygon" || r.type === "MultiPolygon");
        }
        let feature = {
          type: "Feature",
          id: r.id,
          properties: { id: r.id },
          geometry: geoJson
        }
        return feature;
      })
    };
    return featureCollection;
  }