以前加載的百度地圖,偏移較大,一直沒有再測試,因而將騰訊、高德、天地圖的整理一下,方便查看。web
騰訊js代碼:app
1 OpenLayers.Layer.QQ = OpenLayers.Class(OpenLayers.Layer.TileCache, { 2 sateTiles: !1, 3 initialize: function(a, b, c) { 4 var d = OpenLayers.Util.extend({ 5 format: "image/png", 6 isBaseLayer: !0 7 }, 8 c); 9 OpenLayers.Layer.TileCache.prototype.initialize.apply(this, [a, b, {}, 10 d]), 11 this.extension = this.format.split("/")[1].toLowerCase(), 12 this.extension = "jpg" == this.extension ? "jpeg": this.extension, 13 this.transitionEffect = "resize", 14 this.buffer = 0 15 }, 16 getURL: function(a) { 17 var b = this.map.getResolution(), 18 c = this.map.getMaxExtent(), 19 d = this.tileSize, 20 e = this.map.zoom, 21 f = Math.round((a.left - c.left) / (b * d.w)), 22 g = Math.round((c.top - a.top) / (b * d.h)), 23 h = new Array(0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 7, 0, 7, 0, 15, 0, 15, 0, 31, 0, 31, 0, 63, 4, 59, 0, 127, 12, 115, 0, 225, 28, 227, 356, 455, 150, 259, 720, 899, 320, 469, 1440, 1799, 650, 929, 2880, 3589, 1200, 2069, 5760, 7179, 2550, 3709, 11520, 14349, 5100, 7999, 23060, 28689, 10710, 15429, 46120, 57369, 20290, 29849, 89990, 124729, 41430, 60689, 184228, 229827, 84169, 128886), 24 i = 4 * e, 25 j = h[i++], 26 k = h[i++], 27 l = h[i++], 28 h = h[i], 29 m = this.sateTiles ? ".jpg": ".png"; 30 if (f >= j && k >= f && g >= l && h >= g) { 31 g = Math.pow(2, e) - 1 - g; 32 var n = 'z=' + e + '&x=' + f + '&y=' + g + '&type=vector&style=0&v=1.1.1' 33 } 34 var o = this.url; 35 return OpenLayers.Util.isArray(o) && n && (o = this.selectUrl(n, o)), 36 o + n 37 }, 38 clone: function(a) { 39 return null == a && (a = new OpenLayers.Layer.QQ(this.name, this.url, this.options)), 40 a = OpenLayers.Layer.TileCache.prototype.clone.apply(this, [a]) 41 }, 42 CLASS_NAME: "OpenLayers.Layer.QQ" 43 });
QQ地圖的服務地址換了,這裏記下之前的地址(屏蔽的代碼)和如今的地址。ide
1 //QQ地圖 2 map.addLayer( 3 new OpenLayers.Layer.QQ("QQ地圖", 4 [ 5 //"http://p0.map.soso.com/maptilesv2/", 6 //"http://p1.map.soso.com/maptilesv2/", 7 //"http://p2.map.soso.com/maptilesv2/", 8 //"http://p3.map.soso.com/maptilesv2/" 9 'http://rt0.map.gtimg.com/realtimerender?', 10 'http://rt1.map.gtimg.com/realtimerender?', 11 'http://rt2.map.gtimg.com/realtimerender?', 12 'http://rt3.map.gtimg.com/realtimerender?' 13 ], 14 { 15 sateTiles: false 16 } 17 ) 18 );
QQ地圖和高德地圖爲火星座標,糾正座標能夠用同一套方法,網上有js文件能夠下載。測試
高德地圖:this
1 OpenLayers.Layer.Gaode = OpenLayers.Class(OpenLayers.Layer.TileCache, { 2 initialize: function (name, url, options) { 3 var tempoptions = OpenLayers.Util.extend({ 4 'format': 'image/png', 5 isBaseLayer: true 6 }, options); 7 OpenLayers.Layer.TileCache.prototype.initialize.apply(this, [name, url, {}, tempoptions]); 8 this.extension = this.format.split('/')[1].toLowerCase(); 9 this.extension = (this.extension == 'jpg') ? 'jpeg' : this.extension; 10 this.transitionEffect = "resize"; 11 this.buffer = 0; 12 }, 13 getURL: function (bounds) { 14 var retUrl = this.url+"lang=zh_cn&size=1&scale=1&style=8&"; 15 var res = this.map.getResolution(); 16 var bbox = this.map.getMaxExtent(); 17 var size = this.tileSize; 18 //計算列號 19 var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); 20 //計算行號 21 var tileY = Math.round((bbox.top - bounds.top) / (res * size.h)); 22 //當前的等級 23 debugger; 24 var tileZ = this.map.zoom-1; 25 if (tileX < 0) tileX = tileX + Math.round(bbox.getWidth() / bounds.getWidth()); 26 if (tileY < 0) tileY = tileY + Math.round(bbox.getHeight() / bounds.getHeight()); 27 //tileY = (Math.pow(2, tileZ) - 1 - tileY); 28 //tileY = Math.pow(2, tileZ)-tileY+Math.pow(2,this.map.zoom-3); 29 tileY = 1+tileY+Math.pow(2,this.map.zoom-3); 30 console.log(tileY+" =tileY"); 31 return retUrl+"x="+tileX+"&y="+tileY+"&z="+this.map.zoom; 32 }, 33 34 clone: function (obj) { 35 if (obj == null) { 36 obj = new OpenLayers.Layer.Gaode(this.name, this.url, this.options); 37 } 38 obj = OpenLayers.Layer.TileCache.prototype.clone.apply(this, [obj]); 39 return obj; 40 }, 41 CLASS_NAME: "OpenLayers.Layer.Gaode" 42 });
加載高德地圖的地址,其中屏蔽的地址是下載到本機的離線地圖使用的瓦片地址,其餘離線地圖也相似。url
1 //高德地圖 2 var vecLayer = new OpenLayers.Layer.XYZ("高德地圖", [ 3 "http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x=${x}&y=${y}&z=${z}", 4 "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x=${x}&y=${y}&z=${z}", 5 "http://webrd03.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x=${x}&y=${y}&z=${z}", 6 "http://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x=${x}&y=${y}&z=${z}" 7 //"data/roadmap/${z}/${x}/${y}.png" 8 ], { 9 isBaseLayer: true, 10 visibility: true, 11 displayInLayerSwitcher: true 12 }); 13 map.addLayer(vecLayer);
天地圖能夠直接使用,WGS84座標,除了長得醜了點之外,其餘都還好。spa
1 OpenLayers.Layer.TDT = OpenLayers.Class(OpenLayers.Layer.Grid, { 2 3 mapType: null, 4 mirrorUrls: null, 5 topLevel: null, 6 bottomLevel: null, 7 8 topLevelIndex: 0, 9 bottomLevelIndex: 20, 10 topTileFromX: -180, 11 topTileFromY: 90, 12 topTileToX: 180, 13 topTileToY: -270, 14 15 isBaseLayer: true, 16 17 initialize: function (name,options) { 18 19 options.topLevel = options.topLevel ? options.topLevel : this.topLevelIndex; 20 options.bottomLevel = options.bottomLevel ? options.bottomLevel : this.bottomLevelIndex; 21 options.maxResolution = this.getResolutionForLevel(options.topLevel); 22 options.minResolution = this.getResolutionForLevel(options.bottomLevel); 23 24 var newArguments = [name, {}, {}, options]; 25 OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); 26 }, 27 28 clone: function (obj) { 29 30 if (obj == null) { 31 obj = new OpenLayers.Layer.TDTLayer(this.name, this.url, this.options); 32 } 33 34 obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); 35 36 return obj; 37 }, 38 39 getURL: function (bounds) { 40 var level = this.getLevelForResolution(this.map.getResolution()); 41 var coef = 360 / Math.pow(2, level); 42 var x_num = this.topTileFromX < this.topTileToX ? Math.round((bounds.left - this.topTileFromX) / coef) : Math.round((this.topTileFromX - bounds.right) / coef); 43 var y_num = this.topTileFromY < this.topTileToY ? Math.round((bounds.bottom - this.topTileFromY) / coef) : Math.round((this.topTileFromY - bounds.top) / coef); 44 45 switch(level){ 46 case 8: 47 url="http://tile6.tianditu.com/DataServer?T=tdt_vip_img_2_10_120627"; 48 break 49 case 9: 50 url="http://tile5.tianditu.com/DataServer?T=tdt_vip_img_2_10_120627"; 51 break 52 case 10: 53 url="http://tile5.tianditu.com/DataServer?T=tdt_vip_img_2_10_120627"; 54 break 55 case 11: 56 url:"http://tile1.tianditu.com/DataServer?T=E11N"; 57 break 58 case 12: 59 url="http://tile6.tianditu.com/DataServer?T=E12N"; 60 break 61 case 13: 62 url="http://tile3.tianditu.com/DataServer?T=E13N"; 63 break 64 case 14: 65 url="http://tile2.tianditu.com/DataServer?T=E14N"; 66 break 67 case 15: 68 url="http://tile5.tianditu.com/DataServer?T=tdt_vip_img_120627_dyd" 69 break 70 case 16: 71 url="http://tile2.tianditu.com/DataServer?T=tdt_vip_img_120627_dyd"; 72 break 73 case 17: 74 url="http://tile1.tianditu.com/DataServer?T=tdt_vip_img_120627_dyd"; 75 break 76 case 18: 77 url="http://tile0.tianditu.com/DataServer?T=tdt_vip_img_120627_dyd"; 78 break 79 } 80 81 return this.getFullRequestString({ T: null, X: x_num, Y: y_num, L: level }, url); 82 }, 83 selectUrl: function (a, b) { return b[a % b.length] }, 84 getLevelForResolution: function (res) { 85 var ratio = this.getMaxResolution() / res; 86 if (ratio < 1) return 0; 87 for (var level = 0; ratio / 2 >= 1; ) 88 { level++; ratio /= 2; } 89 return level; 90 }, 91 getResolutionForLevel: function (level) { 92 return 360 / 256 / Math.pow(2, level); 93 }, 94 getMaxResolution: function () { 95 return this.getResolutionForLevel(this.topLevelIndex) 96 }, 97 getMinResolution: function () { 98 return this.getResolutionForLevel(this.bottomLevelIndex) 99 }, 100 addTile: function (bounds, position) { 101 var url = this.getURL(bounds); 102 return new OpenLayers.Tile.Image(this, position, bounds, url, this.tileSize); 103 }, 104 105 CLASS_NAME: "OpenLayers.Layer.TDT" 106 });
天地圖底圖和標註,分爲兩個圖層來加載顯示的。prototype
1 //天地圖 2 map.addLayers([ 3 new OpenLayers.Layer.XYZ( 4 "天地圖", 5 [ 6 "http://t0.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}", 7 "http://t1.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}", 8 "http://t2.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}", 9 "http://t3.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}", 10 "http://t4.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}", 11 "http://t5.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}", 12 "http://t6.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}", 13 "http://t7.tianditu.com/DataServer?T=vec_w&X=${x}&Y=${y}&L=${z}" 14 ], 15 { 16 projection: new OpenLayers.Projection("EPSG:900913"), 17 isBaseLayer: true 18 } 19 ), 20 new OpenLayers.Layer.XYZ( 21 "天地圖標註", 22 [ 23 "http://t0.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}", 24 "http://t1.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}", 25 "http://t2.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}", 26 "http://t3.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}", 27 "http://t4.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}", 28 "http://t5.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}", 29 "http://t6.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}", 30 "http://t7.tianditu.com/DataServer?T=cva_w&X=${x}&Y=${y}&L=${z}" 31 ], 32 { 33 projection: new OpenLayers.Projection("EPSG:900913"), 34 isBaseLayer: false, 35 visibility:false 36 37 } 38 ) 39 ] 40 );
火星座標和WGS84座標相互轉換的js文件,百度搜一下有下載的文件:debug
1 var GPS = { 2 PI: 3.14159265358979324, 3 x_pi: 3.14159265358979324 * 3000.0 / 180.0, 4 delta: function (lat, lon) { 5 // Krasovsky 1940 6 // 7 // a = 6378245.0, 1/f = 298.3 8 // b = a * (1 - f) 9 // ee = (a^2 - b^2) / a^2; 10 var a = 6378245.0; // a: 衛星橢球座標投影到平面地圖座標系的投影因子。 11 var ee = 0.00669342162296594323; // ee: 橢球的偏愛率。 12 var dLat = this.transformLat(lon - 105.0, lat - 35.0); 13 var dLon = this.transformLon(lon - 105.0, lat - 35.0); 14 var radLat = lat / 180.0 * this.PI; 15 var magic = Math.sin(radLat); 16 magic = 1 - ee * magic * magic; 17 var sqrtMagic = Math.sqrt(magic); 18 dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * this.PI); 19 dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * this.PI); 20 return { 'lat': dLat, 'lon': dLon }; 21 }, 22 23 //WGS-84 to GCJ-02 24 gcj_encrypt: function (wgsLat, wgsLon) { 25 if (this.outOfChina(wgsLat, wgsLon)) 26 return { 'lat': wgsLat, 'lon': wgsLon }; 27 28 var d = this.delta(wgsLat, wgsLon); 29 return { 'lat': wgsLat + d.lat, 'lon': wgsLon + d.lon }; 30 }, 31 //GCJ-02 to WGS-84 32 gcj_decrypt: function (gcjLat, gcjLon) { 33 if (this.outOfChina(gcjLat, gcjLon)) 34 return { 'lat': gcjLat, 'lon': gcjLon }; 35 36 var d = this.delta(gcjLat, gcjLon); 37 return { 'lat': gcjLat - d.lat, 'lon': gcjLon - d.lon }; 38 }, 39 //GCJ-02 to WGS-84 exactly 40 gcj_decrypt_exact: function (gcjLat, gcjLon) { 41 var initDelta = 0.01; 42 var threshold = 0.000000001; 43 var dLat = initDelta, dLon = initDelta; 44 var mLat = gcjLat - dLat, mLon = gcjLon - dLon; 45 var pLat = gcjLat + dLat, pLon = gcjLon + dLon; 46 var wgsLat, wgsLon, i = 0; 47 while (1) { 48 wgsLat = (mLat + pLat) / 2; 49 wgsLon = (mLon + pLon) / 2; 50 var tmp = this.gcj_encrypt(wgsLat, wgsLon) 51 dLat = tmp.lat - gcjLat; 52 dLon = tmp.lon - gcjLon; 53 if ((Math.abs(dLat) < threshold) && (Math.abs(dLon) < threshold)) 54 break; 55 56 if (dLat > 0) pLat = wgsLat; else mLat = wgsLat; 57 if (dLon > 0) pLon = wgsLon; else mLon = wgsLon; 58 59 if (++i > 10000) break; 60 } 61 //console.log(i); 62 return { 'lat': wgsLat, 'lon': wgsLon }; 63 }, 64 //GCJ-02 to BD-09 65 bd_encrypt: function (gcjLat, gcjLon) { 66 var x = gcjLon, y = gcjLat; 67 var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * this.x_pi); 68 var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * this.x_pi); 69 bdLon = z * Math.cos(theta) + 0.0065; 70 bdLat = z * Math.sin(theta) + 0.006; 71 return { 'lat': bdLat, 'lon': bdLon }; 72 }, 73 //BD-09 to GCJ-02 74 bd_decrypt: function (bdLat, bdLon) { 75 var x = bdLon - 0.0065, y = bdLat - 0.006; 76 var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_pi); 77 var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_pi); 78 var gcjLon = z * Math.cos(theta); 79 var gcjLat = z * Math.sin(theta); 80 return { 'lat': gcjLat, 'lon': gcjLon }; 81 }, 82 //WGS-84 to Web mercator 83 //mercatorLat -> y mercatorLon -> x 84 mercator_encrypt: function (wgsLat, wgsLon) { 85 var x = wgsLon * 20037508.34 / 180.; 86 var y = Math.log(Math.tan((90. + wgsLat) * this.PI / 360.)) / (this.PI / 180.); 87 y = y * 20037508.34 / 180.; 88 return { 'lat': y, 'lon': x }; 89 /* 90 if ((Math.abs(wgsLon) > 180 || Math.abs(wgsLat) > 90)) 91 return null; 92 var x = 6378137.0 * wgsLon * 0.017453292519943295; 93 var a = wgsLat * 0.017453292519943295; 94 var y = 3189068.5 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a))); 95 return {'lat' : y, 'lon' : x}; 96 //*/ 97 }, 98 // Web mercator to WGS-84 99 // mercatorLat -> y mercatorLon -> x 100 mercator_decrypt: function (mercatorLat, mercatorLon) { 101 var x = mercatorLon / 20037508.34 * 180.; 102 var y = mercatorLat / 20037508.34 * 180.; 103 y = 180 / this.PI * (2 * Math.atan(Math.exp(y * this.PI / 180.)) - this.PI / 2); 104 return { 'lat': y, 'lon': x }; 105 /* 106 if (Math.abs(mercatorLon) < 180 && Math.abs(mercatorLat) < 90) 107 return null; 108 if ((Math.abs(mercatorLon) > 20037508.3427892) || (Math.abs(mercatorLat) > 20037508.3427892)) 109 return null; 110 var a = mercatorLon / 6378137.0 * 57.295779513082323; 111 var x = a - (Math.floor(((a + 180.0) / 360.0)) * 360.0); 112 var y = (1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * mercatorLat) / 6378137.0)))) * 57.295779513082323; 113 return {'lat' : y, 'lon' : x}; 114 //*/ 115 }, 116 // two point's distance 117 distance: function (latA, lonA, latB, lonB) { 118 var earthR = 6371000.; 119 var x = Math.cos(latA * this.PI / 180.) * Math.cos(latB * this.PI / 180.) * Math.cos((lonA - lonB) * this.PI / 180); 120 var y = Math.sin(latA * this.PI / 180.) * Math.sin(latB * this.PI / 180.); 121 var s = x + y; 122 if (s > 1) s = 1; 123 if (s < -1) s = -1; 124 var alpha = Math.acos(s); 125 var distance = alpha * earthR; 126 return distance; 127 }, 128 outOfChina: function (lat, lon) { 129 if (lon < 72.004 || lon > 137.8347) 130 return true; 131 if (lat < 0.8293 || lat > 55.8271) 132 return true; 133 return false; 134 }, 135 transformLat: function (x, y) { 136 var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); 137 ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0; 138 ret += (20.0 * Math.sin(y * this.PI) + 40.0 * Math.sin(y / 3.0 * this.PI)) * 2.0 / 3.0; 139 ret += (160.0 * Math.sin(y / 12.0 * this.PI) + 320 * Math.sin(y * this.PI / 30.0)) * 2.0 / 3.0; 140 return ret; 141 }, 142 transformLon: function (x, y) { 143 var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); 144 ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0; 145 ret += (20.0 * Math.sin(x * this.PI) + 40.0 * Math.sin(x / 3.0 * this.PI)) * 2.0 / 3.0; 146 ret += (150.0 * Math.sin(x / 12.0 * this.PI) + 300.0 * Math.sin(x / 30.0 * this.PI)) * 2.0 / 3.0; 147 return ret; 148 } 149 };