百度地图是国内使用最广泛的互联网地图之一,在WebGIS开发中,有广泛的应用。但不同于谷歌、天地图、高德等互联网地图,百度地图的坐标系(百度09)、切片方式自成体系。本文详细介绍如何通过Leaflet加载百度地图,如使用其他JS SDK,参照本文的加载思路,进行相应修改即可。
Leaflet加载百度地图的开发示例(load-baidu-map.html)
一、自定义百度坐标系
百度地图的切片原点与谷歌、天地图等不一致,且坐标系与常用的WGS84、GCJ02不一致,因此需自定义空间参考,在Leaflet中定义的方式如下所示。
L.CRS.Baidu = new L.Proj.CRS(
"EPSG:900913",
"+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs",
{
resolutions: (function () {
level = 19;
re = 18;
var res = [];
res[0] = Math.pow(2, re);
for (var i = 1; i < level; i++) {
res[i] = Math.pow(2, re - i);
}
return res;
})(),
origin: [0, 0],
bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244]),
}
);
二、定义百度地图加载函数
下面定义加载百度各类型地图的加载函数,方便在不同地图间的切换,Leaflet中定义方式如下所示。
L.tileLayer.baidu = function (option) {
option = option || {};
var layer;
var subdomains = "0123456789";
switch (option.layer) {
//单图层
case "vec":
default:
//"http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=pl&b=0&limit=60&scaler=1&udt=20170525"
// layer = L.tileLayer("http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=" + (option.bigfont ? "ph" : "pl") + "&scaler=1&p=1", {
// name: option.name, subdomains: subdomains, tms: true
// });
layer = L.tileLayer(
"https://maponline0.bdimg.com/tile/?qt=vtile&x={x}&y={y}&z={z}&styles=pl&scaler=2&udt=20230105&from=jsapi2_0",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
case "img_d":
layer = L.tileLayer(
"http://shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
case "img_z":
layer = L.tileLayer(
"http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=" +
(option.bigfont ? "sh" : "sl") +
"&v=020",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
case "custom": //Custom 各种自定义样式
//可选值:dark,midnight,grayscale,hardedge,light,redalert,googlelite,grassgreen,pink,darkgreen,bluish
option.customid = option.customid || "dark";
layer = L.tileLayer(
// "http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&scale=1&customid=" + option.customid,
"http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&ak=yipxfCwhMDozKT3GDCM7UGARmSKbAMXh&scale=1&customid=" +
option.customid,
{
name: option.name,
subdomains: "012",
tms: true,
}
);
break;
case "time": //实时路况
var time = new Date().getTime();
layer = L.tileLayer(
"http://its.map.baidu.com:8002/traffic/TrafficTileService?x={x}&y={y}&level={z}&time=" +
time +
"&label=web2D&v=017",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
//合并
case "img":
layer = L.layerGroup([
L.tileLayer.baidu({
name: "底图",
layer: "img_d",
bigfont: option.bigfont,
}),
L.tileLayer.baidu({
name: "注记",
layer: "img_z",
bigfont: option.bigfont,
}),
]);
break;
}
return layer;
};
三、添加图层控制控件
Leaflet提供了图层控制的控件,方便在地图底图的切换和业务图层的显示与隐藏进行控制,下面以上述百度地图加载类函数为例,对图层控制的使用进行说明。
let vec = new L.tileLayer.baidu({ layer: "vec", name: "矢量图" });
let img_d = new L.tileLayer.baidu({ layer: "img_d", name: "影像图" });
let img_z = new L.tileLayer.baidu({ layer: "img_z", name: "影像注记" });
let img = new L.tileLayer.baidu({ layer: "img", name: "影像图(含注记)" });
let custom = new L.tileLayer.baidu({ layer: "custom", name: "自定义图" });
let time = new L.tileLayer.baidu({ layer: "time", name: "实时路况" });
const baseLayers = {
矢量图: vec,
影像图: img_d,
影像注记: img_z,
"影像图(含注记)": img,
自定义图: custom,
实时路况: time,
};
// 添加图层控制控件
L.control.layers(baseLayers).addTo(map);
四、加载百度地图的完整代码
<!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>LeafletJS加载百度地图 - 优吉斯(YouGIS)</title>
<link href="../lib/leaflet/leaflet.css" rel="stylesheet" />
<script src="../lib/jquery/jquery.min.js"></script>
<script src="../lib/leaflet/leaflet.js"></script>
<script src="../lib/proj4/proj4.min.js"></script>
<script src="../lib/proj4/proj4leaflet.min.js"></script>
<style>
* {
padding: 0;
margin: 0;
}
#location {
position: fixed;
padding: 5px;
left: 0;
bottom: 0;
background-color: #fff;
z-index: 999;
font-size: 12px;
font-weight: bold;
color: blue;
border-top-right-radius: 5px;
/* width: 255px; */
}
#mapdiv {
width: 100vw;
height: calc(100vh - 156px);
}
#promptInfo {
z-index: 999;
position: absolute;
color: red;
font-size: large;
font-weight: bold;
margin-left: 80px;
margin-top: 20px;
}
</style>
</head>
<body>
<!-- https://www.cnblogs.com/echohye/p/17040982.html -->
<iframe src="../yougis.html" style="width: 100vw; height: 156px"></iframe>
<div id="mapdiv">
<div id="promptInfo"></div>
</div>
<div id="location"></div>
<script>
L.CRS.Baidu = new L.Proj.CRS(
"EPSG:900913",
"+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs",
{
resolutions: (function () {
level = 19;
re = 18;
var res = [];
res[0] = Math.pow(2, re);
for (var i = 1; i < level; i++) {
res[i] = Math.pow(2, re - i);
}
return res;
})(),
origin: [0, 0],
bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244]),
}
);
L.tileLayer.baidu = function (option) {
option = option || {};
var layer;
var subdomains = "0123456789";
switch (option.layer) {
//单图层
case "vec":
default:
//"http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=pl&b=0&limit=60&scaler=1&udt=20170525"
// layer = L.tileLayer("http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=" + (option.bigfont ? "ph" : "pl") + "&scaler=1&p=1", {
// name: option.name, subdomains: subdomains, tms: true
// });
layer = L.tileLayer(
"https://maponline0.bdimg.com/tile/?qt=vtile&x={x}&y={y}&z={z}&styles=pl&scaler=2&udt=20230105&from=jsapi2_0",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
case "img_d":
layer = L.tileLayer(
"http://shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
case "img_z":
layer = L.tileLayer(
"http://online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=" +
(option.bigfont ? "sh" : "sl") +
"&v=020",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
case "custom": //Custom 各种自定义样式
//可选值:dark,midnight,grayscale,hardedge,light,redalert,googlelite,grassgreen,pink,darkgreen,bluish
option.customid = option.customid || "dark";
layer = L.tileLayer(
// "http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&scale=1&customid=" + option.customid,
"http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&ak=yipxfCwhMDozKT3GDCM7UGARmSKbAMXh&scale=1&customid=" +
option.customid,
{
name: option.name,
subdomains: "012",
tms: true,
}
);
break;
case "time": //实时路况
var time = new Date().getTime();
layer = L.tileLayer(
"http://its.map.baidu.com:8002/traffic/TrafficTileService?x={x}&y={y}&level={z}&time=" +
time +
"&label=web2D&v=017",
{
name: option.name,
subdomains: subdomains,
tms: true,
}
);
break;
//合并
case "img":
layer = L.layerGroup([
L.tileLayer.baidu({
name: "底图",
layer: "img_d",
bigfont: option.bigfont,
}),
L.tileLayer.baidu({
name: "注记",
layer: "img_z",
bigfont: option.bigfont,
}),
]);
break;
}
return layer;
};
let vec = new L.tileLayer.baidu({ layer: "vec", name: "矢量图" });
let img_d = new L.tileLayer.baidu({ layer: "img_d", name: "影像图" });
let img_z = new L.tileLayer.baidu({ layer: "img_z", name: "影像注记" });
let img = new L.tileLayer.baidu({ layer: "img", name: "影像图(含注记)" });
let custom = new L.tileLayer.baidu({ layer: "custom", name: "自定义图" });
let time = new L.tileLayer.baidu({ layer: "time", name: "实时路况" });
$(document).ready(function () {
var options = {
center: [31.245414, 121.506379], // The initial center(baidu BD-09 format) of map
zoom: 15, // initial zoom of map
crs: L.CRS.Baidu,
layers: [vec],
};
var map = L.map("mapdiv", options);
L.marker([31.245414, 121.506379])
.addTo(map)
.bindTooltip("上海东方明珠")
.openTooltip();
const baseLayers = {
矢量图: vec,
影像图: img_d,
影像注记: img_z,
"影像图(含注记)": img,
自定义图: custom,
实时路况: time,
};
// 添加图层控制控件
L.control.layers(baseLayers).addTo(map);
// 设置初始显示内容
let initInfo = "请通过右上角图层控制切换地图, 点击地图左下角展示坐标|https协议下访问受限<br/>";
initInfo += "当前选择地图:" + vec.options.name + "<br/>";
initInfo += "服务地址:" + vec._url;
document.getElementById("promptInfo").innerHTML = initInfo;
// 图层切换事件, 设置显示的提示信息
map.on('baselayerchange', function (e) {
let info = "请通过右上角图层控制切换地图, 点击地图左下角展示坐标|https协议下访问受限<br/>";
info += "当前选择地图:" + e.name + "<br/>";
if (e.layer._url) {
info += "服务地址:" + e.layer._url;
} else if (e.layer._layers) {
for (k in e.layer._layers) {
let v = e.layer._layers[k]
info += "服务地址" + k + ":" + v._url + "<br/>";
}
}
document.getElementById("promptInfo").innerHTML = info;
});
map.on("click", (e) => {
let lnglat = "鼠标点击位置坐标:" + e.latlng.lng + " , " + e.latlng.lat;
$("#location")[0].innerText = lnglat;
});
window.map = map;
});
</script>
</body>
</html>
评论区