1.4. 交互式Choropleth地图

这是一个案例研究,在GeoJSON和一些自定义控件的帮助下,创建了一个彩色交互的美国州人口密度地图。

Show the example

1.4.1. 数据源

我们将美国人口密度的数据可视化。由于数据量不是很大,存储和显示数据的最简单方式是GeoJSON。

GeoJSON数据的每个要素如下所示:

{
"type": "Feature",
"properties": {
    "name": "Alabama",
    "density": 94.65
},
"geometry": ...
...
}

1.4.2. 基本状态图

让我们以自定义Mapbox样式在地图上显示状态数据。

var mapboxAccessToken = {your access token here};
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=' + mapboxAccessToken, {
id: 'mapbox.light',
attribution: ...
}).addTo(map);
L.geoJson(statesData).addTo(map);
Show the example

1.4.3. 添加颜色

现在我们需要根据人口密度给各州上色。为地图选择好的颜色可能需要一些技巧,但有一个很好的工具可以帮助我们-ColorBrewer。我们创建了一个函数,该函数基于从ColorBrewer获得的值返回基于种群的密度:

function getColor(d) {
return d > 1000 ? '#800026' :
       d > 500  ? '#BD0026' :
       d > 200  ? '#E31A1C' :
       d > 100  ? '#FC4E2A' :
       d > 50   ? '#FD8D3C' :
       d > 20   ? '#FEB24C' :
       d > 10   ? '#FED976' :
                  '#FFEDA0';
}

接下来,定义GeoJSON图层的样式函数,以便其 fill color 取决于 feature.properties.density 。同时还调整了外观,增加了优美的笔触。

function style(feature) {
return {
    fillColor: getColor(feature.properties.density),
    weight: 2,
    opacity: 1,
    color: 'white',
    dashArray: '3',
    fillOpacity: 0.7
};
}
L.geoJson(statesData, {style: style}).addTo(map);

现在看起来好多了!

View this example

1.4.4. 添加交互组件

现在,当将鼠标移到地图上代表美国各州的色块上时,让颜色块突出显示。首先,我们将为图层的鼠标事件定义一个事件侦听器:

function highlightFeature(e) {
var layer = e.target;

layer.setStyle({
    weight: 5,
    color: '#666',
    dashArray: '',
    fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
    layer.bringToFront();
}
}

在这里通过 e.target 将鼠标悬停在层上,并在该层上设置一个宽大的灰色边框作为高亮显示,同时将该层放在最上面的层上,这样边框就不会与附近的状态(而不是IE、Opera或Edge)冲突。

接下来将定义 mouseout

function resetHighlight(e) {
    geojson.resetStyle(e.target);
}

使用方便的Geojson.setStyle方法可以将图层的样式重置为默认状态(由 style 功能)。要执行此操作,请确保之前的监听程序可以定义GeoJSON图层 geojson 变量访问权限,并将此GeoJSON图层分配给 geojson 变量:

var geojson;
// ... our listeners
geojson = L.geoJson(...);

让我们定义一个点击监听程序来放大状态:

function zoomToFeature(e) {
    map.fitBounds(e.target.getBounds());
}

现在将使用 onEachFeature 用于将监听程序添加到州所在层的选项:

function onEachFeature(feature, layer) {
layer.on({
    mouseover: highlightFeature,
    mouseout: resetHighlight,
    click: zoomToFeature
});
}
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);

这使地图上的状态在鼠标经过时变得突出,并能够向监听器添加其他交互功能。

1.4.5. 自定义信息控件

通常我们使用弹出窗口来显示信息,但现在使用一种不同的方法-将鼠标悬停在自定义控件上时在该控件中显示信息。

以下是控制代码:

var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this.update();
return this._div;
};

// method that we will use to update the control based on feature properties passed
info.update = function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' +  (props ?
    '<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
    : 'Hover over a state');
};
info.addTo(map);

当用户将鼠标悬停在某个状态上时,需要更新控件,因此可按如下方式修改监听器:

function highlightFeature(e) {
...
info.update(layer.feature.properties);
}

function resetHighlight(e) {
...
info.update();
}

该控件需要一些css样式才能使其看起来很好:

.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}

1.4.6. 自定义图例控件

创建带有图例的控件更容易,因为它是静态的,并且在状态悬停时不会更改。JavaScript代码:

var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
     var div = L.DomUtil.create('div', 'info legend'),
     grades = [0, 10, 20, 50, 100, 200, 500, 1000],
     labels = [];

     // loop through our density intervals and generate a label with a colored square for each interval
     for (var i = 0; i < grades.length; i++) {
         div.innerHTML +=
             '<i style="background:' + getColor(grades[i] + 1) + '"></i> ' +
             grades[i] + (grades[i + 1] ? '&ndash;' + grades[i + 1] + '<br>' : '+');
     }
     return div;
};
legend.addTo(map);

控件的css样式(还重用了先前定义的 info 类):

.legend {
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}

请在此页面顶部或在单独的页面上享受<a href=“./clopple.html”>结果</a>。