代码之家  ›  专栏  ›  技术社区  ›  E. Erfan

如何在Angular和ngx传单编写的传单地图中添加图例

  •  0
  • E. Erfan  · 技术社区  · 7 年前

    我试图在Asymmetrik/ngx传单创建的地图上添加一个图例。地图是按照中的教程创建的 https://github.com/Asymmetrik/ngx-leaflet 。有两个不同的层,每个层应有不同的图例。代码是使用angular CLI和传单生成的。有一个贴图组件。地图。组成部分ts文件如下:

    import {Component, Input, OnChanges, OnInit} from '@angular/core';
    import {circle, geoJSON, GeoJSONOptions, latLng, Layer, LeafletMouseEvent, polygon, tileLayer} from 'leaflet';
    import * as L from 'leaflet';
    import {SimpleResult} from '../../models/SimpleResult';
    import {HttpClient} from '@angular/common/http';
    import {IDrilldownResult} from '../../models/DrilldownResult';
    
    @Component({
      selector: 'app-map-chart',
      templateUrl: './map-chart.component.html',
      styleUrls: ['./map-chart.component.css']
    })
    export class MapChartComponent implements OnInit, OnChanges {
    
      @Input() private data: IDrilldownResult;
      public options: any;
      public layersControl = {
        baseLayers: { }
      };
    
      private getColor(value, max, min) {
        const val = (value - min) / (max - min) ;
        const hue = (val * 120).toString(10);
        return ['hsl(', hue, ',100%,50%)'].join('');
      }
    
      constructor(
        private http: HttpClient
      ) { }
    
      ngOnInit() {
        this.createChart();
        /*if (this.data) {
          this.updateChart();
        }*/
      }
    
      ngOnChanges() {
        this.updateChart();
      }
    
      private createChart() {
        this.options = {
          layers: [
            tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' }),
          ],
          zoom: 6,
          center: latLng(51.5167, 9.9167)
        };
      }
    
      private createGermanyLayer() {
        this.http.get('assets/bundeslaender.geojson')
          .subscribe((res: any) => {
            const deIndex = this.data.children.findIndex(e => e.name === 'de');
            const germanData = this.data.children[deIndex];
            res.features.forEach(feat => {
              const stateIndex = germanData.children.findIndex(e => {
                if (e.name) {
                  return e.name.toLowerCase() === feat.properties.NAME_1.toLowerCase();
                }
              });
              feat.properties.SALES = germanData.children[stateIndex].label;
            });
            const max = Math.max.apply(Math, res.features.map(feat => feat.properties.SALES));
            const min = Math.min.apply(Math, res.features.map(feat => feat.properties.SALES));
    
            const geoJsonGermanyLayer = {
              id: 'geoJSON',
              name: 'Geo JSON Polygon',
              enabled: true,
              layer: geoJSON(
                res as any,
                {
                  style: (d) => {
                    const color = this.getColor(d.properties.SALES, max, min);
                    return ({
                      color: color,
                      weight: 1
                    });
                  },
                  onEachFeature: (feature, layer) => {
                    layer.bindPopup('<h5>' + feature.properties.NAME_1 + '</h5><p>Revenue: ' + feature.properties.SALES.toFixed(2) + '</p>');
                  }
                })
            };
            this.layersControl.baseLayers['Germany'] = geoJsonGermanyLayer.layer;
    
            // begining of legend
    
            const v1 = min;
            const v2 = min + Math.round((max - min ) / 2);
            const v3 = max;
            const legend = new (L.Control.extend({
              options: { position: 'bottomright' }
            }));
            // const legend = L.control({position: 'bottomright'});
            const vm = this;
            legend.onAdd = function (map) {
              const div = L.DomUtil.create('div', 'legend');
              const labels = [
                'Sales greater than ' + v1,
                'Sales greater than ' + v2,
                'Sales equal or less than ' + v3
              ];
              const grades = [v1 + 1, v2 + 1, v3 ];
              div.innerHTML = '<div><b>Legend</b></div>';
              for (let i = 0; i < grades.length; i++) {
                div.innerHTML += '<i style="background:' + vm.getColor(grades[ i ], this.max, this.min) + '"> &nbsp; &nbsp;</i> &nbsp; &nbsp;'
                + labels[i] + '<br/>';
              }
              return div;
            };
            legend.addTo(geoJsonGermanyLayer);
            // end of legend
    
    
          });
    
    
    
      }
    
      private createEuropeLayer() {
        this.http.get('assets/europe.geojson')
          .subscribe((res: any) => {
            res.features.forEach(feat => {
              const countryIndex = this.data.children.findIndex(e => {
                if (e.name) {
                  return e.name.toLowerCase() === feat.properties.FIPS.toLowerCase() || e.name.toLowerCase() === feat.properties.ISO2.toLowerCase();
                }
              });
              feat.properties.SALES = countryIndex !== -1 ? this.data.children[countryIndex].label : undefined;
            });
            const max = Math.max.apply(Math, res.features.filter(feat => feat.properties.SALES !== undefined).map(feat => feat.properties.SALES));
            const min = Math.min.apply(Math, res.features.filter(feat => feat.properties.SALES !== undefined).map(feat => feat.properties.SALES));
            const maxLog = Math.log(max);
            const minLog = Math.log(min);
    
            const geoJsonEuropeLayer = {
              id: 'geoJSON',
              name: 'Geo JSON Polygon',
              enabled: true,
              layer: geoJSON(
                res as any,
                {
                  style: (d) => {
                    const color = this.getColor(Math.log(d.properties.SALES), maxLog, minLog);
                    return ({
                      color: color,
                      weight: 1
                    });
                  },
                  onEachFeature: (feature, layer) => {
                    const sales = feature.properties.SALES !== undefined ? feature.properties.SALES.toFixed(2) : 'No orders';
                    layer.bindPopup('<h5>' + feature.properties.NAME + '</h5>' +
                '<p>Revenue: ' + sales + '</p>');
                  }
                })
            };
            this.layersControl.baseLayers['Europe'] = geoJsonEuropeLayer.layer;
          });
      }
    
      private updateChart() {
        this.createGermanyLayer();
        this.createEuropeLayer();
      }
    
    }
    

    图例不会显示在页面上。控制台显示以下错误:无法读取未定义的属性“bottomright”,如下图所示:

    enter image description here

    地图显示正确,但没有图例。如果您能告诉我我的代码有什么问题,以及为什么没有显示图例,我将不胜感激。感谢您的关注。

    1 回复  |  直到 7 年前
        1
  •  4
  •   E. Erfan    7 年前

    好的,我自己根据评论找到答案。图例只能添加到地图本身,而不能添加到图层。但使用以下代码时,地图不可用:

    private createChart() {
        this.options = {
            layers: [
                tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' }),
           ],
            zoom: 6,
            center: latLng(51.5167, 9.9167)
        };
    }
    

    为了获得由传单本身制作的地图,您需要将其绑定。这在模板文件中完成:

    <div style="height: 700px;"
         leaflet
         [leafletOptions]="options"
         [leafletLayersControl]="layersControl"
         (leafletMapReady)="onMapReady($event)">
    </div>
    

    然后我定义了onMapReady()函数,如下所示:

    onMapReady(map: Map) {
        this.updateChart();
        // Do stuff with map
        map.on('baselayerchange', (eventLayer) => {
          const v1 = this.min;
          const v2 = this.min + Math.round((this.max - this.min ) / 2);
          const v3 = this.max;
          const legend = new (L.Control.extend({
            options: { position: 'bottomright' }
          }));
    
          const vm = this;
          legend.onAdd = function (map) {
            const div = L.DomUtil.create('div', 'legend');
            const labels = [
              'Sales greater than ' + v1,
              'Sales greater than ' + v2,
              'Sales equal or less than ' + v3
            ];
            const grades = [v1+ 1, v2+ 1, v3 ];
            div.innerHTML = '<div><b>Legend</b></div>';
            for (let i = 0; i < grades.length; i++) {
              div.innerHTML += '<i style="background:' + vm.getColor(grades[ i ], v3, v1) + '"> &nbsp; &nbsp;</i> &nbsp; &nbsp;'
            + labels[i] + '<br/>';
            }
            return div;
          };
          legend.addTo(map);
        });
    
    }
    

    图例仅在地图准备就绪后显示。贴图是创建的第一件事,然后图层出现。因此,我在onMapReady()中调用了updateChart(),以访问每个层的最小值和最大值。

    仍然存在一个问题,即在更改图层时添加了另一个图例。但这与这个问题无关。