如何将图例添加到Angular和ngx-leaflet编写的传单地图中

时间:2018-03-04 13:52:02

标签: angular typescript leaflet ngx-leaflet

我正在尝试将图例添加到由Asymmetrik / ngx-leaflet创建的地图中。按照https://github.com/Asymmetrik/ngx-leaflet中的教程创建地图。有两个不同的层,每层都有一个不同的传说。代码是使用角度CLI和传单制作的。有一个地图组件。 map.component.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();
  }

}

图例未显示在页面上。控制台显示以下错误:无法读取属性&#39; bottomright&#39;未定义的,如下图所示:

enter image description here

地图显示正确,但没有图例。如果你告诉我我的代码有什么问题以及为什么传奇没有显示,我感谢你。谢谢你的关注。

1 个答案:

答案 0 :(得分:1)

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

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

}

图例仅在地图准备好后才会显示。 Map是第一个被创建的东西然后出现层。因此,我在onMapReady()中调用了updateChart()来访问每个层的最小值和最大值。

还有一个问题是在更改图层时添加了另一个图例。但这与这个问题无关。