angularleafletngx-leaflet

angular - ngx-leaflet auto centralize to specific area regarding loading data


I am using angular 6 and ngx-leaflet. I am loading data backend, and I trying to zoom to area (in this case India) once data loaded on the map.

My html looks:

<div leaflet style="height: 800px; width: 100%"
    [leafletOptions]="options"
    (leafletMapReady)="onMapReady($event)"
    [leafletBaseLayers]="baseLayers"
    [leafletLayersControlOptions]="layersControlOptions"
    [leafletMarkerCluster]="markerClusterData"
    [leafletMarkerClusterOptions]="markerClusterOptions"
    (leafletMarkerClusterReady)="markerClusterReady($event)">
</div>

In .ts

@Component({
    templateUrl: 'details.component.html'
})

export class DetailsComponent implements OnInit {

LAYER_OSM = {
    enabled: false,
    layer: L.tileLayer('http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', {
        maxZoom: 17,
        minZoom: 2,
        subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
        detectRetina: true,
    })
};

layersControlOptions = { position: 'bottomright' };
baseLayers = {
    'Google': this.LAYER_OSM.layer
};
options = {
    zoom: 3,
    center: L.latLng([0.0, 0.0])
};
markerClusterGroup: L.MarkerClusterGroup;
markerClusterData: any[] = [];
markerClusterOptions: L.MarkerClusterGroupOptions = {};
fitBounds: any = null; // = [[46.67, -122.25], [47.01, -121.302]];
fGroup = L.featureGroup();
constructor(private mapDataService: MapDataService) { }

ngOnInit() {
    this.mapDataService.getMapData(this.nav)
        .subscribe(res => { this.generateData(res) });
}

onMapReady(map: L.Map) {
    map.fitBounds(map.getBounds(),{
        maxZoom: 12,
        animate: true
      });
 }

markerClusterReady(group: L.MarkerClusterGroup) {
    this.markerClusterGroup = L.markerClusterGroup();
}

generateData(res: any[]) {
    const data: any[] = [];
    res.forEach(function (item) {
        const icon = L.icon({
            iconSize: [25, 41],
            iconAnchor: [13, 41],
            iconRetinaUrl: 'leaflet/marker-icon-2x.png',
            iconUrl: 'leaflet/marker-icon.png',
            shadowUrl: 'leaflet/marker-shadow.png'
        });

        data.push(L.marker([item.latitude, item.longitude], { icon }));
    })

    this.markerClusterData = data;
}
}

onMapReady(map: L.Map), map.getBounds() is returning always one coordination, but not the one I need.

I Have also tried to use [leafletFitBounds], but I am not able to get correct bounce. The first is how it is now. The second that I am trying to achieve.

Thanks in advance.

What I have

What I would like to have

this.markerClusterData looks like this

markerClusterData


Solution

  • map.getBounds() is returning the current boundry of the map, not the boundry of the data loaded into your markerClusterData.

    In your html, add a line to bind the "leafletFitBounds" Input property to a property in your .ts file, e.g:

    [leafletFitBounds]="mapFitToBounds"
    

    In your ts file, add the new property

    mapFitToBounds: L.LatLngBounds;
    

    To control the max zoom and padding etc, you can also add the "[leafletFitBoundsOptions]" property to your html and ts e.g:

    [leafletFitBoundsOptions]="mapFitToBoundsOptions"
    

    In your ts file, add the new property

    mapFitToBoundsOptions: L.FitBoundsOptions;
    

    To make use of these input properties in your ts, you will need to configure your "mapFitToBoundsOptions" in ngOnInit(), e.g:

    this.mapFitToBoundsOptions = {maxZoom: 12, animate: true};
    

    For more settings that are configurable check: https://leafletjs.com/reference-1.3.2.html#fitbounds-options

    Now to get the correct bounds you will need to call .getBounds() on this.markerClusterData once you have loaded the data, you can do this inside your subscription or your generateData function, if you change your subscription, here's an example of what it would look like:

    this.mapDataService.getMapData(this.nav).subscribe(res => { 
      this.generateData(res);
    
      // Focus the map view to the boundaries of the marker group
      this.mapFitToBounds = this.markerClusterData.getBounds();
    });
    

    Remove the onMapReady event from your code and after making the above changes, your map should focus on your data.