leaflet地图分级设色
2021-05-27 本文已影响0人
嘀灬学生卡
关键词:leaflet; geojson; wkt; 分级设色; 地图渲染;颜色映射;颜色转换;图例
案例需求:各省级专题数据分级设色
数据准备:1.地图数据geojson格式(https://geo.datav.aliyun.com/areas_v2/bound/100000_full.json)
2.专题数据,通过随机数生成
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>leaflet分层渲染</title>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/leaflet/1.7.1/leaflet.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/leaflet/1.7.1/leaflet.min.js"></script>
<style>
body{
width: calc(100vw);
height: calc(100vh);
padding: 0;
margin: 0;
}
.map{
width: 100%;
height: 100%;
background-color: #fff;
}
.legend{
position: absolute;
right: 20px;
bottom: 20px;
z-index: 999;
}
.legend ul li{
padding:0;
margin:0;
list-style:none;
display: flex;
align-items: center;
margin-bottom: 5px;
}
.legend ul li i{
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 5px;
}
</style>
</head>
<body onload="init()">
<div id="map" class="map"></div>
<div class="legend"></div>
</body>
<script>
let map;
let separatedColors = ['#DAF7A6', '#FFC300', '#FF5733', '#C70039', '#900C3F', '#581845'];//离散颜色
let minVal = 1;
let maxVal = 100;
function init(){
initMap();
initLegend();
}
function initMap(){
map = L.map('map', {
crs: L.CRS.EPSG4326,
center: [40.83, 113.31],
zoom: 3,
zoomControl: true
});
let vecUrl = 'http://t0.tianditu.gov.cn/DataServer?T=vec_c&X={x}&Y={y}&L={z}&tk=c04e7575a1f250c6f22ba42fa9c8aa63';
let baseLayer = L.tileLayer(vecUrl, {zoomOffset: 1});
map.addLayer(baseLayer)
let url = 'https://geo.datav.aliyun.com/areas_v2/bound/100000_full.json';
axios.get(url).then(res => {
let geojson = res.data;
L.geoJSON(geojson, {
onEachFeature: function(feature, layer){
//生成1-100的随机整数,作为每个要素的某一专题属性值
feature.properties.value = random(1, 100);
feature.properties.color = getSeparatedColorByVal(minVal, maxVal, separatedColors, feature.properties.value);
layer.setStyle({
stroke: false,//取消边框
color: feature.properties.color,
fillOpacity: 0.6//默认0.2
});
}
}).addTo(map);
});
}
//初始化图例
function initLegend(){
let legend = getLegend(minVal, maxVal, separatedColors);
let legendDom = document.getElementsByClassName('legend')[0];
let insertDom = document.createElement('ul');
let str = ``;
for(let i = 0; i < legend.length; i++){
str += `<li><i style="background: ${legend[i].color}"></i>${legend[i].region.join('-')}</li>`;
}
insertDom.innerHTML = str;
legendDom.appendChild(insertDom);
}
//生成指定范围的随机整数
function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
//根据离散颜色及数据范围生成对应值的颜色
function getSeparatedColorByVal(minVal, maxVal, colors, val){
let length = colors.length;
let avg = ((maxVal - minVal)/length).toFixed(4);
//生成等分区间
let regions = [];
for(let i = 0; i < length; i++){
if(i === length -1){
regions.push([(minVal + avg * i), maxVal]);
}else{
regions.push([(minVal + avg * i), (minVal + avg * (i + 1))]);
}
}
//返回对应值颜色
for(let i = 0; i < regions.length; i++){
if(val >= regions[i][0] && val <= regions[i][1]){
return colors[i];
}
}
}
//生成图例
function getLegend(minVal, maxVal, colors){
let length = colors.length;
let avg = ((maxVal - minVal)/length).toFixed(4);
//生成等分区间
let regions = [];
for(let i = 0; i < length; i++){
if(i === length -1){
regions.push([(minVal + avg * i).toFixed(2), maxVal.toFixed(2)]);
}else{
regions.push([(minVal + avg * i).toFixed(2), (minVal + avg * (i + 1)).toFixed(2)]);
}
}
let legend = [];
for(let i = 0; i< length; i++){
legend.push({
color: colors[i],
region: regions[i]
});
}
return legend;
}
</script>
</html>
效果
渲染效果以上使用的离散颜色数组渲染,生成连续颜色可使用如下方法
//根据数值范围、颜色范围(16进制类型),获取数值范围中某一数值对应颜色范围中的颜色
//颜色要求:选择相邻色系
function getContinuationColorByVal(minVal, maxVal, firstColor, secondColor, val){
let ratio = (val-minVal)/(maxVal - minVal);
let fArr = hex2RgbArr(firstColor);
let sArr = hex2RgbArr(secondColor);
let color = [];
for(let i = 0; i < fArr.length; i++){
let c = (fArr[i]<sArr[i]?fArr[i]:sArr[i]) + Math.abs(((sArr[i]-fArr[i])*ratio).toFixed(0));
color.push(c);
}
return rgbArr2Hex(color);
}
//16进制颜色转rgb颜色数组
function hex2RgbArr(hex){
// 16进制颜色值的正则
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
// 把颜色值变成小写
var color = hex.toLowerCase();
if (reg.test(color)) {
// 如果只有三位的值,需变成六位,如:#fff => #ffffff
if (color.length === 4) {
var colorNew = '#';
for (var i = 1; i < 4; i += 1) {
colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1));
}
color = colorNew;
}
// 处理六位的颜色值,转为RGB
var colorChange = [];
for (var i = 1; i < 7; i += 2) {
colorChange.push(parseInt('0x' + color.slice(i, i + 2)));
}
return colorChange;
}
}
//rgb颜色数组[255, 255, 255]转16进制颜色#ffffff
function rgbArr2Hex(rgbArr){
let strHex = '#';
// 转成16进制
for (var i = 0; i < rgbArr.length; i++) {
let hex = Number(rgbArr[i]).toString(16);
hex = hex.length == 1 ? '0' + hex : hex;
strHex += hex;
}
return strHex;
}
实际开发,地图要素范围数据可能后端返回wkt类型数据,wkt数据转换layer图层,需用leaflet插件leaflet-omnivore
//wkt转leaflet layer
wkt2Layer(wktShape) {
if(!!wktShape){
var geoJson = omnivore.wkt.parse(wktShape);
let feature = geoJson.getLayers()[0].feature;
return L.GeoJSON.geometryToLayer(feature);
}
}
参考资料:
https://blog.csdn.net/mossbaoo/article/details/93484635
https://htmlcolorcodes.com/zh/yanse-xuanze-qi/
http://datav.aliyun.com/tools/atlas/#&lat=30.37018632615852&lng=106.68898666525287&zoom=3.5
https://www.jianshu.com/p/1cbfa0ed2051