如何将图例添加到 Angular 和 ngx-leaflet 编写的传单地图
How to add legend to leaflet map written by Angular and ngx-leaflet
我正在尝试为 Asymmetrik/ngx-leaflet 创建的地图添加图例。该地图是按照 https://github.com/Asymmetrik/ngx-leaflet 中的教程创建的。有两个不同的层,每一层都应该有不同的图例。该代码是使用 angular 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) + '"> </i> '
+ 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' of undefined 如下图所示:
地图显示正确,但没有图例。如果您能告诉我我的代码有什么问题以及为什么没有显示图例,我将不胜感激。感谢您的关注。
好的,我根据评论自己找到了答案。图例只能添加到地图本身,而不能添加到图层。但是当您使用以下代码时地图不可用:
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)
};
}
要获取leaflet自己制作的地图,需要绑定。这是在模板文件中完成的:
<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) + '"> </i> '
+ labels[i] + '<br/>';
}
return div;
};
legend.addTo(map);
});
}
图例仅在地图准备就绪后出现。地图是第一个被创建的东西然后图层出现。因此,我在 onMapReady() 中调用了 updateChart() 来访问每一层的最小值和最大值。
还有一个问题,就是换图层的时候又多了一个图例。但与本题无关
我正在尝试为 Asymmetrik/ngx-leaflet 创建的地图添加图例。该地图是按照 https://github.com/Asymmetrik/ngx-leaflet 中的教程创建的。有两个不同的层,每一层都应该有不同的图例。该代码是使用 angular 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) + '"> </i> '
+ 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' of undefined 如下图所示:
地图显示正确,但没有图例。如果您能告诉我我的代码有什么问题以及为什么没有显示图例,我将不胜感激。感谢您的关注。
好的,我根据评论自己找到了答案。图例只能添加到地图本身,而不能添加到图层。但是当您使用以下代码时地图不可用:
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)
};
}
要获取leaflet自己制作的地图,需要绑定。这是在模板文件中完成的:
<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) + '"> </i> '
+ labels[i] + '<br/>';
}
return div;
};
legend.addTo(map);
});
}
图例仅在地图准备就绪后出现。地图是第一个被创建的东西然后图层出现。因此,我在 onMapReady() 中调用了 updateChart() 来访问每一层的最小值和最大值。
还有一个问题,就是换图层的时候又多了一个图例。但与本题无关