【问题标题】:Updating ngx-leaflet map based on Bootstrap select input基于 Bootstrap 选择输入更新 ngx-leaflet 映射
【发布时间】:2018-11-15 11:05:00
【问题描述】:

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

我在我的 HTML 模板中添加了事件绑定,该模板会检测下拉菜单中的每个新选择。我向该事件传递了一个新函数onChange()。但我很难过从这里去哪里。在点击事件中,我可以使用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);
  }
}

【问题讨论】:

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


    【解决方案1】:

    我能够通过在constructor() 之前在我的应用组件类顶部将polyLayer 初始化为空属性来解决此问题。所以我在其余代码中将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();
          }
        });
      }
    }
    

    【讨论】:

      【解决方案2】:

      如果要为选择输入绑定对象,应该使用[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 设置为区域对象。因此,您可能需要更改地图点击代码的工作方式,以确保您在点击地图时可以获得对正确对象的引用。

      【讨论】:

      • 我不确定这个绑定有何不同。您对如何访问onChange() 中的地图/多边形以执行与传单事件相同的操作有任何见解吗?我尝试在onChange 中添加geojson 调用,但我仍然无法根据选择输入而不是onEachFeature 中的单击或鼠标悬停等传单事件来更新地图。基本上,我需要一种方法将选择输入中的字符串“poly1/2”关联到以相同方式命名的实际 geojson。
      • 使用此代码SN-P的想法是绑定到ngModel的值将是您在选择该选项时与@ 987654328绑定的值。因此,在此示例中,区域可以是对象的集合,每个对象都包含一个标签和对多边形的引用。您只需要将每个对象的显示值更新为标签,而 ngValue 是对象,因此您可以直接访问多边形。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-29
      • 2017-11-07
      相关资源
      最近更新 更多