javascript
基于ArcGIS API for JavaScript加载百度各种类型切片地图
文章目錄
- 應用場景
- 需求分析
- 效果圖
- 實現代碼
- 原理解讀
應用場景
部分項目基于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
<!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這塊:
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
總結
以上是生活随笔為你收集整理的基于ArcGIS API for JavaScript加载百度各种类型切片地图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Chrome中的from memory
- 下一篇: The difference betwe