基于ArcGIS API for JavaScript加载百度各种类型切片地图

应用场景

部分项目基于ArcGIS平台,但是甲方只提供部分矢量数据,用作底图的地形图数据没有,表示可以使用百度地图作为底图。所以才会有使用ArcGIS JS API加载百度地图的这种特殊需求。

需求分析

上面描述的需求场景有两种解决方案:

  1. 下载指定区域的百度地图(.tif格式),将下载好的地图在ArcMap中处理之后,通过ArcGIS Server发布成切片地图服务,之后就可以直接用API加载了。问题在于需要借助地图下载工具下载数据,数据量可能会比较大。

  2. 基于ArcGIS API for JavaScript中的TiledMapServiceLayer类进行扩展,直接使用百度地图在线切片。优势:数据无需单独下载,可以使用百度各种类型切片地图,如道路、午夜黑等。

这里通过方案二入手。

效果图

BaiDuMap

实现代码

封装模块: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

<!DOCTYPE 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这块:

扫描二维码关注公众号,回复: 6117470 查看本文章
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切片坐标定义方式:

ArGIS_Tile

ArcGIS的切片坐标定义方式是从左上角开始,按照行列号划分。高德地图、Open Street Map、Google地图同样采用此种切片方式。

百度地图切片坐标定义方式如下图:

Baidu_tile

两者的切片坐标系不太一样,要想将切片放到正确的位置就要进行坐标转换了,公式已经在代码里面里了,就是简单的数学转换。关于国内主要地图瓦片坐标系定义及计算原理

源代码下载地址:https://download.csdn.net/download/wml00000/11055976

猜你喜欢

转载自blog.csdn.net/wml00000/article/details/88784277