这是我参与更文挑战的第8天,活动详情查看: 更文挑战 !
👽 概论
前几天和大家分享了Echarts热力图的制作方法,但有个问题在于:Echarts中使用百度地图时,不能很好的控制百度地图的样式,部分百度地图的扩展功能使用也受限。有时能用百度地图解决的,不引入Echarts也挺好。
这次主要实现两个功能:一是实现自定义边界的绘制,二是实现热力图的绘制。
👻 开发准备
- 引入百度地图API(常规操作,无需多言);
- 引入百度热力图开源库(这个很关键)。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>百度热力地图</title>
<style>
html,
body {
height: 100%;
padding: 0;
}
#map {
height: 1200px;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
</body>
<!-- 百度地图API -->
<script
type="text/javascript"
src="http://api.map.baidu.com/api?v=3.0&ak=xxxxxxxxx"
></script>
<!-- 百度热力图开源库 -->
<script
type="text/javascript"
src="http://api.map.baidu.com/library/Heatmap/2.0/src/Heatmap_min.js"
></script>
<!-- 热力图数据 -->
<script type="text/javascript" src="./data/jsonArr.js"></script>
<!-- 区块边界数据 -->
<script type="text/javascript" src="./data/features.js"></script>
<!-- 逻辑JS -->
<script type="text/javascript" src="index.js"></script>
</html>
👽 初始化百度地图
这部分都是基本操作,此处只做简单介绍。
function initMap(domID, centerPoint, styleId) {
let map = new BMap.Map(domID); // 创建地图实例
map.centerAndZoom(centerPoint, 15); //设置中心点及缩放级别
map.setMapStyleV2({ styleId }); //设置样式ID
map.enableScrollWheelZoom();
map.enableDragging();
map.disableDoubleClickZoom();
return map;
}
window.onload = function () {
let centerPoint = new BMap.Point(104.084207, 30.695243);
let styleId = '02f2d7d1f52e7261479d4a9755a8485e';
let mapInstance = initMap('map', centerPoint, styleId);
}
此阶段效果如图:
👽 区域边界的绘制
区域边界线实现的原理是借助一系列边界点的坐标,结合百度地图中的多边形类Polygon来实现,但在实践中有两种情况:一种是市、县等行政区域,另一种是类似功能区、商圈这种非行政区划类的区域。
对于第一种,我们一般通过借助百度地图API先获取区划边界数据点,再进行描边绘制; 对于第二种,只需准备好边界点数据即可直接绘制。
···
//自定义边界绘制
function generateBoundary(mapInstance, points, style) {
let polygon = new BMap.Polygon(points, style); //创建多边形
mapInstance.addOverlay(polygon); //添加多边形
return polygon;
}
//行政区域边界绘制
function generateDistrictBoundary(mapInstance, districtName, style) {
let bdary = new BMap.Boundary();
bdary.get(districtName, function (res) {
let boundaries = res.boundaries;
let points = [];
//之所以用循环,是因为部分行政区存在飞地,区划会分为多块,所以需要遍历生成
boundaries.forEach(boundary => {
let polygon = generateBoundary(mapInstance, boundary, style);
let path = polygon.getPath();
points = points.concat(path);
});
});
}
window.onload = function () {
···
let style = {
strokeWeight: 3,
strokeColor: '#2c2a2a',
strokeStyle: 'dashed',
fillColor: 'transparent',
};
generateDistrictBoundary(mapInstance, '金牛区', style);
let config = [
{
sort: 1,
fillColor: 'rgb(248,195,201)',
},
{
sort: 2,
fillColor: 'rgb(158,202,244)',
},
{
sort: 3,
fillColor: 'rgb(238,253,133)',
},
{
sort: 4,
fillColor: 'transparent',
},
];
//features数据结构
//features:[ { sort: 1, lat: 30.745365, lng: 104.124755 }···]
config.forEach(obj => {
let points = features
.filter(item => item.sort == obj.sort)
.map(item => new BMap.Point(item.lng, item.lat));
generateBoundary(mapInstance, points, {
strokeWeight: 3,
strokeColor: '#2c2a2a',
strokeStyle: 'dashed',
fillColor: obj.fillColor,
fillOpacity: 0.7,
});
});
};
此阶段效果如图(左上角为典型的飞地):
👽 热力图绘制
热力图的绘制需要借助百度的开源热力图库。完整代码如下:
function initMap(domID, centerPoint, styleId) {
let mapInstance = new BMap.Map(domID); // 创建地图实例
mapInstance.centerAndZoom(centerPoint, 15); //设置中心点及缩放级别
mapInstance.setMapStyleV2({ styleId }); //设置样式ID
mapInstance.enableScrollWheelZoom();
mapInstance.enableDragging();
mapInstance.disableDoubleClickZoom();
return mapInstance;
}
function generateBoundary(mapInstance, points, style) {
let polygon = new BMap.Polygon(points, style); //创建多边形
// 添加覆盖物
mapInstance.addOverlay(polygon); //增加多边形
return polygon;
}
function generateHeat(mapInstance, data) {
const heatmapOverlay = new BMapLib.HeatmapOverlay({ radius: 30 });
mapInstance.addOverlay(heatmapOverlay);
heatmapOverlay.setDataSet({
data, //热力值数据
max: 10000, // 热力权重最大值
});
}
function generateDistrictBoundary(mapInstance, districtName, style) {
let bdary = new BMap.Boundary();
bdary.get(districtName, function (res) {
let boundaries = res.boundaries;
let points = [];
//之所以用循环,是因为部分行政区存在飞地,区划会分为多块,所以需要遍历生成
boundaries.forEach(boundary => {
let polygon = generateBoundary(mapInstance, boundary, style);
let path = polygon.getPath();
points = points.concat(path);
});
setTimeout(() => generateHeat(mapInstance, jsonArr), 0);
});
}
window.onload = function () {
let centerPoint = new BMap.Point(104.084207, 30.695243);
let styleId = '02f2d7d1f52e7261479d4a9755a8485e';
let mapInstance = initMap('map', centerPoint, styleId);
let style = {
strokeWeight: 3,
strokeColor: '#2c2a2a',
strokeStyle: 'dashed',
fillColor: 'transparent',
};
generateDistrictBoundary(mapInstance, '金牛区', style);
let config = [
{
sort: 1,
fillColor: 'rgb(248,195,201)',
},
{
sort: 2,
fillColor: 'rgb(158,202,244)',
},
{
sort: 3,
fillColor: 'rgb(238,253,133)',
},
{
sort: 4,
fillColor: 'transparent',
},
];
//features数据结构
//features:[ { sort: 1, lat: 30.745365, lng: 104.124755 }···]
config.forEach(obj => {
let points = features
.filter(item => item.sort == obj.sort)
.map(item => new BMap.Point(item.lng, item.lat));
generateBoundary(mapInstance, points, {
strokeWeight: 3,
strokeColor: '#2c2a2a',
strokeStyle: 'dashed',
fillColor: obj.fillColor,
fillOpacity: 0.7,
});
});
};
此阶段的效果如图:
👽 结语
详细的介绍都在代码注释,如有疑惑欢迎交流~