基于Bootstrap选择输入更新ngx-leaflet映射

时间:2018-06-05 21:05:32

标签: angular drop-down-menu leaflet bootstrap-select ngx-leaflet

当您在基于this example的ngx-leaflet中单击地图上的多边形时,我有一个更新Bootstrap选择输入下拉菜单的应用程序。我希望能够从选择输入中选择多边形名称,并具有与click事件相同的功能 - 在这种情况下,使用fitBounds平移和缩放到所选多边形。

我添加了事件绑定到我的HTML模板,该模板从下拉菜单中检测每个新选择。我向该事件传递了一个新函数onChange()。但是我很难过去哪里。在click事件中,我可以使用e.target来访问所选多边形的边界。但是在onChange()里面,我可以访问的是所选多边形的名称,但我实际上并没有与该多边形相关联的几何体。那么我如何使用下拉选择输入来选择多边形名称并让地图更新与该名称相关联的多边形? (请注意,我希望能够做出灵活的回复,因为我希望在此示例之外的实际应用中不仅仅需要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);
  }
}

2 个答案:

答案 0 :(得分:0)

如果要绑定select对象的对象,则应使用[ngValue]显式设置value对象:

<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设置为区域对象。因此,您可能需要更改地图单击代码的工作方式,以确保在单击地图时可以获得对正确对象的引用。

答案 1 :(得分:0)

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

app.component.ts update

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();
      }
    });
  }
}