根据 Bootstrap select 输入更新 ngx-leaflet 地图

Updating ngx-leaflet map based on Bootstrap select input

我有一个应用程序,当您在基于 的 ngx-leaflet 中单击地图上的多边形时,它会更新 Bootstrap select 输入下拉菜单。我还希望能够 select 来自 select 输入的多边形名称并具有与单击事件相同的功能——在本例中,使用 fitBounds 平移和缩放到selected 多边形。

我将事件绑定添加到我的 HTML 模板,它从下拉菜单中检测每个新的 selection。我向该事件传递了一个新函数 onChange()。但我很难过从这里去哪里。在点击事件中,我可以使用 e.target 访问 selected 多边形的边界。但是在 onChange() 中,我只能访问 selected 多边形的名称,但我实际上并没有与该多边形关联的几何图形。那么我如何使用下拉菜单 select 输入到 select 多边形名称并让地图更新与该名称关联的多边形? (请注意,我希望得到灵活的回应,因为我想在这个示例之外的实际应用程序中做的不仅仅是 fitBounds()。)

这是我的示例代码:

polygons.geojson(在 assets 文件夹中)

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "stroke": "#555555",
        "stroke-width": 2,
        "stroke-opacity": 1,
        "fill": "#555555",
        "fill-opacity": 0.5,
        "name": "poly1"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -121.95098876953125,
              46.82966386051541
            ],
            [
              -121.78482055664061,
              46.82966386051541
            ],
            [
              -121.78482055664061,
              46.91368905872705
            ],
            [
              -121.95098876953125,
              46.91368905872705
            ],
            [
              -121.95098876953125,
              46.82966386051541
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "stroke": "#555555",
        "stroke-width": 2,
        "stroke-opacity": 1,
        "fill": "#555555",
        "fill-opacity": 0.5,
        "name": "poly2"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -121.77726745605469,
              46.83107318799318
            ],
            [
              -121.62963867187499,
              46.83107318799318
            ],
            [
              -121.62963867187499,
              46.913220009605624
            ],
            [
              -121.77726745605469,
              46.913220009605624
            ],
            [
              -121.77726745605469,
              46.83107318799318
            ]
          ]
        ]
      }
    }
  ]
}

app.component.html

<div class="map"
  leaflet
  [leafletLayers]="layers"
     [leafletFitBounds]="fitBounds"></div>
<div class="form-group">
  <select [(ngModel)]="selected" class="form-control" id="selectRegion" [value]="clicked" (change)="onChange()">
    <option *ngFor="let region of regions">{{ region }}</option>
  </select>
</div>

app.component.ts

import {Component, NgZone, OnInit} from '@angular/core';
import { HttpClient } from '@angular/common/http';

import * as L from 'leaflet';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  layers: L.Layer[];
  fitBounds = [[46.67, -122.25], [47.01, -121.302]];
  regions = [];
  clicked = '';
  selected = '';

  constructor(private http: HttpClient, private zone: NgZone) { }

  ngOnInit() {

    // read in geojson of poly
    this.http.get<any>('/assets/polygons.geojson')
      .subscribe(poly => {

        const tileLayer = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}.png', {
          subdomains: 'abcd',
          maxZoom: 19
        });

        const polyLayer = L.geoJSON(poly, {
          onEachFeature: this.onEachFeature.bind(this)
        });

        this.layers = [ tileLayer, polyLayer ];
      });
  }

  // loop through each feature of polyLayer
  onEachFeature(feature, layer) {
    this.zone.run(() => {
      // push polygon names to regions array
      this.regions.push(feature.properties.name);

      layer.on('click', <LeafletMouseEvent> (e) => {
        this.zone.run(() => {
          this.fitBounds = e.target.getBounds();
          this.clicked = e.target.feature.properties.name;
        });
      });
    });
  }

  onChange() {
    console.log(this.selected);
  }
}

如果要为select输入绑定对象,应该使用[ngValue]显式设置值对象:

<div class="map"
     leaflet
     [leafletLayers]="layers"
     [leafletFitBounds]="fitBounds"></div>

<div class="form-group">
  <select class="form-control" id="selectRegion"
          (change)="onChange()"
          [(ngModel)]="selected" >
    <option *ngFor="let region of regions"
            [ngValue]="region">{{ region }}</option>
  </select>
</div>

但是,您仍然遇到问题,现在您必须在单击地图时将 selected 设置为区域对象。因此,您可能需要更改地图点击代码的工作方式,以确保您在点击地图时可以获得对正确对象的引用。

我能够通过在 constructor() 之前首先将 polyLayer 初始化为我的应用程序组件 class 顶部的空属性来解决这个问题。因此,我在其余代码中将 polyLayer 的实例更新为 this.polyLayer。有了这个,我现在可以访问 onChange() 内的多边形,使用 eachLayer() 进行过滤,并适合地图的边界:

app.component.ts更新

import {Component, NgZone, OnInit} from '@angular/core';
import { HttpClient } from '@angular/common/http';

import * as L from 'leaflet';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  layers: L.Layer[];
  fitBounds = [[46.67, -122.25], [47.01, -121.302]];
  regions = [];
  clicked = '';
  selected = '';
  polyLayer = null;

  constructor(private http: HttpClient, private zone: NgZone) { }

  ngOnInit() {

    // read in geojson of poly
    this.http.get<any>('/assets/polygons.geojson')
      .subscribe(poly => {

        const tileLayer = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}.png', {
          subdomains: 'abcd',
          maxZoom: 19
        });

        this.polyLayer = L.geoJSON(poly, {
          onEachFeature: this.onEachFeature.bind(this)
        });

        this.layers = [ tileLayer, this.polyLayer ];
      });
  }

  // loop through each feature of polyLayer
  onEachFeature(feature, layer) {
    this.zone.run(() => {
      // push polygon names to regions array
      this.regions.push(feature.properties.name);

      layer.on('click', <LeafletMouseEvent> (e) => {
        this.zone.run(() => {
          this.fitBounds = e.target.getBounds();
          this.clicked = e.target.feature.properties.name;
        });
      });
    });
  }

  onChange() {

    let that = this;

    // console.log(this.polyLayer._layers);
    this.polyLayer.eachLayer(function(layer){
      if(layer.feature.properties.name === that.selected){
        that.fitBounds = layer.getBounds();
      }
    });
  }
}