Leaflet 百度、高德地图瓦片坐标 偏移 纠偏
实现地图瓦片纠偏的leaflet.mapCorrection.js代码:
//坐标转换 L.CoordConvertor = function () { /**百度转84*/ this.bd09_To_gps84 = function (lng, lat) { var gcj02 = this.bd09_To_gcj02(lng, lat); var map84 = this.gcj02_To_gps84(gcj02.lng, gcj02.lat); return map84; } /**84转百度*/ this.gps84_To_bd09 = function (lng, lat) { var gcj02 = this.gps84_To_gcj02(lng, lat); var bd09 = this.gcj02_To_bd09(gcj02.lng, gcj02.lat); return bd09; } /**84转火星*/ this.gps84_To_gcj02 = function (lng, lat) { var dLat = transformLat(lng - 105.0, lat - 35.0); var dLng = transformLng(lng - 105.0, lat - 35.0); var radLat = lat / 180.0 * pi; var magic = Math.sin(radLat); magic = 1 - ee * magic * magic; var sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); var mgLat = lat + dLat; var mgLng = lng + dLng; var newCoord = { lng: mgLng, lat: mgLat }; return newCoord; } /**火星转84*/ this.gcj02_To_gps84 = function (lng, lat) { var coord = transform(lng, lat); var lontitude = lng * 2 - coord.lng; var latitude = lat * 2 - coord.lat; var newCoord = { lng: lontitude, lat: latitude }; return newCoord; } /**火星转百度*/ this.gcj02_To_bd09 = function (x, y) { var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi); var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi); var bd_lng = z * Math.cos(theta) + 0.0065; var bd_lat = z * Math.sin(theta) + 0.006; var newCoord = { lng: bd_lng, lat: bd_lat }; return newCoord; } /**百度转火星*/ this.bd09_To_gcj02 = function (bd_lng, bd_lat) { var x = bd_lng - 0.0065; var y = bd_lat - 0.006; var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi); var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi); var gg_lng = z * Math.cos(theta); var gg_lat = z * Math.sin(theta); var newCoord = { lng: gg_lng, lat: gg_lat }; return newCoord; } var pi = 3.1415926535897932384626; var a = 6378245.0; var ee = 0.00669342162296594323; var x_pi = pi * 3000.0 / 180.0; var R = 6378137; function transform(lng, lat) { var dLat = transformLat(lng - 105.0, lat - 35.0); var dLng = transformLng(lng - 105.0, lat - 35.0); var radLat = lat / 180.0 * pi; var magic = Math.sin(radLat); magic = 1 - ee * magic * magic; var sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); var mgLat = lat + dLat; var mgLng = lng + dLng; var newCoord = { lng: mgLng, lat: mgLat }; return newCoord; } function transformLat(x, y) { 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)); ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; return ret; } function transformLng(x, y) { var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0; return ret; } } L.coordConvertor = function () { return new L.CoordConvertor() } L.tileLayer.chinaProvider = function (type, options) { options = options || {} options.coordType = getCoordType(type); return new L.TileLayer.ChinaProvider(type, options); //获取坐标类型 function getCoordType(type) { var parts = type.split('.'); var providerName = parts[0]; var zbName = "wgs84" switch (providerName) { case "Geoq": case "GaoDe": case "Google": zbName = "gcj02"; break; case "Baidu": zbName = "bd09"; break; case "OSM": case "TianDiTu": zbName = "wgs84"; break; } return zbName; } }; L.GridLayer.include({ _setZoomTransform: function (level, _center, zoom) { var center = _center; if (center != undefined && this.options) { if (this.options.coordType == 'gcj02') { center = L.coordConvertor().gps84_To_gcj02(_center.lng, _center.lat); } else if (this.options.coordType == 'bd09') { center = L.coordConvertor().gps84_To_bd09(_center.lng, _center.lat); } } var scale = this._map.getZoomScale(zoom, level.zoom), translate = level.origin.multiplyBy(scale) .subtract(this._map._getNewPixelOrigin(center, zoom)).round(); if (L.Browser.any3d) { L.DomUtil.setTransform(level.el, translate, scale); } else { L.DomUtil.setPosition(level.el, translate); } }, _getTiledPixelBounds: function (_center) { var center = _center; if (center != undefined && this.options) { if (this.options.coordType == 'gcj02') { center = L.coordConvertor().gps84_To_gcj02(_center.lng, _center.lat); } else if (this.options.coordType == 'bd09') { center = L.coordConvertor().gps84_To_bd09(_center.lng, _center.lat); } } var map = this._map, mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(), scale = map.getZoomScale(mapZoom, this._tileZoom), pixelCenter = map.project(center, this._tileZoom).floor(), halfSize = map.getSize().divideBy(scale * 2); return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize)); } });
Demo主要代码:
index.html代码:
<!DOCTYPE html> <html> <head> <title>Leaflet</title> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="libs/leaflet/leaflet.css"> <link rel="stylesheet" href="css/index.css"> <script type="text/javascript" src="libs/jquery-1.9.1.js"></script> <script type="text/javascript" src="libs/leaflet/leaflet-src.js"></script> <script type="text/javascript" src="libs/leaflet-plugins/proj4-compressed.js"></script> <script type="text/javascript" src="libs/leaflet-plugins/proj4leaflet.js"></script> <script type="text/javascript" src="libs/leaflet-plugins/leaflet.baidu.js"></script> <script type="text/javascript" src="libs/leaflet-plugins/leaflet.ChineseTmsProviders.js"></script> <script type="text/javascript" src="libs/leaflet-plugins/leaflet.mapCorrection.js"></script> </head> <body> <div id="map" style="cursor:default;"></div> <div id="mouseposition"></div> <div id="mapzoom"></div> <!-- 用于显示调试信息 --> <div style="display:none; position:absolute; right:0; bottom:30px; background-color:transparent; width:1000px; height:30px; margin-right:3px; z-index:99999; border:solid 1px transparent;"> <input type="text" id="msg" value="" style="width:990px; font-size:12px; padding-left:3px; padding-right:3px; " /> </div> <div style="display:none; position:absolute; left:20px; top:20px; background-color:transparent; width:1200px; height:30px; z-index:99998; border:solid 1px transparent;"> <input type="button" onclick="alert('1')" value="测试按钮" /> </div> <script type="text/javascript" src="config/config.js"></script> <script type="module" src="js/index.js"></script> </body> </html>
index.js代码:
import { Map } from './map.js' import { Marker } from './marker.js' let map = new Map(tileUrl, { centerLatLng: L.latLng(31.81880456, 117.18087366), mapBounds: L.latLngBounds(L.latLng(31.0, 116.6), L.latLng(32.6, 117.8)) }); let marker = new Marker(117.18087366, 31.81880456, { id: 1, name: '测试marker' }); map.deviceLayer.addLayer(marker.marker);
map.js代码:
代码中 new L.TileLayer 时,添加属性 coordType: 'gcj02' ,即可实现高德地图瓦片偏移的纠偏
如果是百度地图瓦片,则添加属性 coordType: 'bd09' 即可
/** * 地图 */ class Map { map deviceLayer = L.layerGroup() options = { // L.latLng centerLatLng: undefined, // L.latLngBounds mapBounds: undefined } constructor(tileUrl, options) { Object.assign(this.options, options); let tileLayer = new L.TileLayer(tileUrl, { minZoom: 8, maxZoom: 18, coordType: 'gcj02' }); this.map = new L.Map('map', { center: this.options.centerLatLng, zoom: 12, minZoom: 8, maxZoom: 18, maxBounds: this.options.mapBounds, layers: [tileLayer], attributionControl: false, doubleClickZoom: false, zoomControl: false }); this.map.addLayer(this.deviceLayer); //设备图层 L.control.scale().addTo(this.map); //比例尺 //显示经纬度和地图层级 let this_ = this; this.map.addEventListener("mousemove", function (e) { this_.showMousePosition(e); this_.showMapZoom(); }); this.map.addEventListener("zoomend", function (e) { this_.showMapZoom(); }); } showMousePosition(e) { if (!this.mousePositionDiv) { this.mousePositionDiv = $('#mouseposition'); } this.mousePositionDiv.text(e.latlng.lng.toFixed(8) + ", " + e.latlng.lat.toFixed(8)); } showMapZoom() { if (!this.mapZoomDiv) { this.mapZoomDiv = $('#mapzoom'); } this.mapZoomDiv.text(this.map.getZoom().toString()); } } export { Map }
完整Demo代码下载:
代码实现的功能:百度、高德离线地图瓦片加载和纠偏
代码使用了ES6模块化开发,必须部署在服务器上才能在浏览器中访问,可以使用IIS或Tomcat部署
效果图:
高德地图:
百度地图:
参考github:
https://github.com/gisarmory/Leaflet.InternetMapCorrection