部分项目基于ArcGIS平台,但是甲方只提供部分矢量数据,用作底图的地形图数据没有,表示可以使用百度地图作为底图。所以才会有使用ArcGIS JS API加载百度地图的这种特殊需求。
上面描述的需求场景有两种解决方案:
下载指定区域的百度地图(.tif格式),将下载好的地图在ArcMap中处理之后,通过ArcGIS Server发布成切片地图服务,之后就可以直接用API加载了。问题在于需要借助地图下载工具下载数据,数据量可能会比较大。
基于ArcGIS API for JavaScript中的TiledMapServiceLayer类进行扩展,直接使用百度地图在线切片。优势:数据无需单独下载,可以使用百度各种类型切片地图,如道路、午夜黑等。
这里通过方案二入手。
封装模块:BaiduLayer.js
define(["dojo/_base/declare", "esri/layers/TiledMapServiceLayer", "esri/geometry/Extent", "esri/SpatialReference", "esri/layers/TileInfo"],
function (declare, TiledMapServiceLayer, Extent, SpatialReference, TileInfo) {
return declare(TiledMapServiceLayer, {
layertype: "midNightStyle", //图层类型
baiduAK: "1H8Dhi2pGmOMYbN4EcaAGr1rv8f7Gmjz", //百度开发密钥
// 构造函数
constructor: function (properties) {
this.spatialReference = new SpatialReference({
wkid: 102100 //webMercator投影
});
declare.safeMixin(this, properties);
// 图层提供的起始显示范围以及整个图层的地理范围
// this.fullExtent = new Extent(-16777360, -16797630, 16777360, 16797630, this.spatialReference);
this.fullExtent = new Extent(-20037508.342787, -20037508.342787, 20037508.342787, 20037508.342787, this.spatialReference);
this.initialExtent = new Extent(5916776.8, 1877209.3, 19242502.6, 7620381.8, this.spatialReference);
// 图层提供的切片信息
this.tileInfo = new TileInfo({
"rows": 256,
"cols": 256,
"compressionQuality": 0,
"origin": {
"x": -16777360, //济南适用
"y": 16802960
},
"spatialReference": {
"wkid": 102100
},
"lods": [{
"level": 0,
"resolution": 131072,
"scale": 131072 * 256
},
{
"level": 1,
"resolution": 65536,
"scale": 65536 * 256
},
{
"level": 2,
"resolution": 32768,
"scale": 32768 * 256
},
{
"level": 3,
"resolution": 16384,
"scale": 16384 * 256
},
{
"level": 4,
"resolution": 8192,
"scale": 8192 * 256
},
{
"level": 5,
"resolution": 4096,
"scale": 4096 * 256
},
{
"level": 6,
"resolution": 2048,
"scale": 2048 * 256
},
{
"level": 7,
"resolution": 1024,
"scale": 1024 * 256
},
{
"level": 8,
"resolution": 512,
"scale": 512 * 256
},
{
"level": 9,
"resolution": 256,
"scale": 256 * 256
},
{
"level": 10,
"resolution": 128,
"scale": 128 * 256
},
{
"level": 11,
"resolution": 64,
"scale": 64 * 256
},
{
"level": 12,
"resolution": 32,
"scale": 32 * 256
},
{
"level": 13,
"resolution": 16,
"scale": 16 * 256
},
{
"level": 14,
"resolution": 8,
"scale": 8 * 256
},
{
"level": 15,
"resolution": 4,
"scale": 4 * 256
},
{
"level": 16,
"resolution": 2,
"scale": 2 * 256
},
{
"level": 17,
"resolution": 1,
"scale": 1 * 256
},
{
"level": 18,
"resolution": 0.5,
"scale": 0.5 * 256
},
{
"level": 19,
"resolution": 0.25,
"scale": 0.25 * 256
}
]
});
// 设置图层的loaded属性,并触发onLoad事件
this.loaded = true;
this.onLoad(this);
},
getTileUrl: function (level, row, col) {
var url = "";
var zoom = level - 1;
var offsetX = Math.pow(2, zoom);
var offsetY = offsetX - 1;
var numX = col - offsetX;
var numY = (-row) + offsetY;
zoom = level + 1;
var num = (col + row) % 8 + 1;
switch (this.layertype) {
case "road":
url = "http://online1.map.bdimg.com/tile/?qt=tile&x=" + numX + "&y=" + numY + "&z=" + zoom + "&styles=pl";
break;
case "st":
//url = "http://q"+num+".baidu.com/it/u=x="+numX+";y="+numY+";z="+zoom+";v=009;type=sate&fm=46";
url = "http://shangetu" + num + ".map.bdimg.com/it/u=x=" + numX + ";y=" + numY + ";z=" + zoom + ";v=009;type=sate&fm=46";
break;
case "label":
url = "http://online1.map.bdimg.com/tile/?qt=tile&x=" + numX + "&y=" + numY + "&z=" + zoom + "&styles=sl&v=020";
break;
case "simpleStyle":
url = "http://api1.map.bdimg.com/customimage/tile?&x=" + numX + "&y=" + numY + "&z=" + zoom + "&ak=" + this.baiduAK + "&styles=t%3Aroad%7Ce%3Aall%7Cl%3A20%2Ct%3Ahighway%7Ce%3Ag%7Cc%3A%23f49935%2Ct%3Arailway%7Ce%3Aall%7Cv%3Aoff%2Ct%3Alocal%7Ce%3Al%7Cv%3Aoff%2Ct%3Awater%7Ce%3Aall%7Cc%3A%23d1e5ff%2Ct%3Apoi%7Ce%3Al%7Cv%3Aoff";
break;
case "grassGreenStyle":
url = "http://api0.map.bdimg.com/customimage/tile?&x=" + numX + "&y=" + numY + "&z=" + zoom + "&ak=" + this.baiduAK + "&styles=t%3Awater%7Ce%3Aall%7Cc%3A%2372b8fe%2Ct%3Aroad%7Ce%3Ag.f%7Cc%3A%23ffffff%2Ct%3Aroad%7Ce%3Ag.s%7Cc%3A%23bababa%2Ct%3Aroad%7Ce%3Al.t.f%7Cc%3A%23767676%2Ct%3Aroad%7Ce%3Al.t.s%7Cc%3A%23ffffff%2Ct%3Aland%7Ce%3Aall%7Cc%3A%23b8cb93";
break;
case "midNightStyle":
url = "http://api1.map.bdimg.com/customimage/tile?&x=" + numX + "&y=" + numY + "&z=" + zoom + "&ak=" + this.baiduAK + "&styles=t%3Awater%7Ce%3Aall%7Cc%3A%23021019%2Ct%3Ahighway%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Ahighway%7Ce%3Ag.s%7Cc%3A%23147a92%2Ct%3Aarterial%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Aarterial%7Ce%3Ag.s%7Cc%3A%230b3d51%2Ct%3Alocal%7Ce%3Ag%7Cc%3A%23000000%2Ct%3Aland%7Ce%3Aall%7Cc%3A%2308304b%2Ct%3Arailway%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Arailway%7Ce%3Ag.s%7Cc%3A%2308304b%2Ct%3Asubway%7Ce%3Ag%7Cl%3A-70%2Ct%3Abuilding%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Aall%7Ce%3Al.t.f%7Cc%3A%23857f7f%2Ct%3Aall%7Ce%3Al.t.s%7Cc%3A%23000000%2Ct%3Abuilding%7Ce%3Ag%7Cc%3A%23022338%2Ct%3Agreen%7Ce%3Ag%7Cc%3A%23062032%2Ct%3Aboundary%7Ce%3Aall%7Cc%3A%231e1c1c%2Ct%3Amanmade%7Ce%3Ag%7Cc%3A%23022338%2Ct%3Apoi%7Ce%3Aall%7Cv%3Aoff%2Ct%3Aall%7Ce%3Al.i%7Cv%3Aoff%2Ct%3Aall%7Ce%3Al.t.f%7Cv%3Aon%7Cc%3A%232da0c6";
break;
case "darkStyle":
url = "http://api2.map.bdimg.com/customimage/tile?&x=" + numX + "&y=" + numY + "&z=" + zoom + "&ak=" + this.baiduAK + "&styles=t%3Aland%7Ce%3Ag%7Cc%3A%23212121%2Ct%3Abuilding%7Ce%3Ag%7Cc%3A%232b2b2b%2Ct%3Ahighway%7Ce%3Aall%7Cl%3A-42%7Cs%3A-91%2Ct%3Aarterial%7Ce%3Ag%7Cl%3A-77%7Cs%3A-94%2Ct%3Agreen%7Ce%3Ag%7Cc%3A%231b1b1b%2Ct%3Awater%7Ce%3Ag%7Cc%3A%23181818%2Ct%3Asubway%7Ce%3Ag.s%7Cc%3A%23181818%2Ct%3Arailway%7Ce%3Ag%7Cl%3A-52%2Ct%3Aall%7Ce%3Al.t.s%7Cc%3A%23313131%2Ct%3Aall%7Ce%3Al.t.f%7Cc%3A%238b8787%2Ct%3Amanmade%7Ce%3Ag%7Cc%3A%231b1b1b%2Ct%3Alocal%7Ce%3Ag%7Cl%3A-75%7Cs%3A-91%2Ct%3Asubway%7Ce%3Ag%7Cl%3A-65%2Ct%3Arailway%7Ce%3Aall%7Cl%3A-40%2Ct%3Aboundary%7Ce%3Ag%7Cc%3A%238b8787%7Cl%3A-29%7Cw%3A1";
break;
default:
url = "http://online1.map.bdimg.com/tile/?qt=tile&x=" + numX + "&y=" + numY + "&z=" + zoom + "&styles=pl";
break;
}
return url;
}
});
}
)
index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ArcGIS调用百度在线切片title>
head>
<link rel="stylesheet" href="https://js.arcgis.com/3.27/esri/css/esri.css">
<style>
html, body, #map {
height: 100%;
margin: 0;
padding: 0;
}
style>
<script>
var package_path = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/'));
var dojoConfig = {
// The locationPath logic below may look confusing but all its doing is
// enabling us to load the api from a CDN and load local modules from the correct location.
packages: [{
name: "modules",
location: package_path + '/modules'
}]
};
script>
<script src="https://js.arcgis.com/3.27/">script>
<script>
require([
"esri/map",
"modules/BaiduLayer",
"dojo/domReady!"], function(Map,BaiduLayer) {
var map = new Map("map");
var options = {
layertype: "darkStyle"
}
var layer = new BaiduLayer(options);
map.addLayer(layer);
});
script>
head>
<body>
<div id="map">div>
body>
html>
以下为个人见解,如有不当敬请指出,核心代码主要在getTile这块:
getTileUrl: function (level, row, col) {
var url = "";
var zoom = level - 1;
var offsetX = Math.pow(2, zoom);
var offsetY = offsetX - 1;
var numX = col - offsetX;
var numY = (-row) + offsetY;
zoom = level + 1;
var num = (col + row) % 8 + 1;
url = "http://api2.map.bdimg.com/customimage/tile?&x=" + numX + "&y=" + numY + "&z=" + zoom + "&ak=" + this.baiduAK + '太长了省略';
return url;
}
关键在于切片坐标的转换,通过下图可以看到ArcGIS切片坐标定义方式:
ArcGIS的切片坐标定义方式是从左上角开始,按照行列号划分。高德地图、Open Street Map、Google地图同样采用此种切片方式。
百度地图切片坐标定义方式如下图:
两者的切片坐标系不太一样,要想将切片放到正确的位置就要进行坐标转换了,公式已经在代码里面里了,就是简单的数学转换。关于国内主要地图瓦片坐标系定义及计算原理
源代码下载地址:https://download.csdn.net/download/wml00000/11055976