ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

高德地图百度地图纠偏

2020-09-12 15:03:01  阅读:368  来源: 互联网

标签:function map 地图 纠偏 let 坐标 var gcoord 高德


1、写在前面

在使用高德地图API和百度地图API的时候,如果要加载地图服务如WMS,WMTS等,这些地图服务常用的投影坐标系是EPSG:3857。加载上去会发现存在偏移,因为投影坐标系不一致。

高德的坐标系是GCJ-02,而百度的坐标系是在GCJ-02再次偏移的BD-09,这些坐标系是没有收录在EPSG中的,所以无法用Proj.4库来做坐标转换。

我们是否可以通过整体的偏移来做呢?不行的,因为GCJ-02坐标系相对于WMS坐标系的偏差是非线性随机的。这么做感觉就是在为难国内的开发者,一方面不能不使用WGS坐标,因为这个是国际通用的,另一方面又在设置重重障碍让WGS坐标和GCJ-02坐标难以转化。

不过也不是束手无策的,高德和百度都有提供单点的坐标转换功能,我们可以利用单点的坐标转换来实现切片的偏移。也有一个开源的项目 gcoord 融合了百度高德的转化

2、思路

百度高德在请求切片图层的时候,对于每一个切片来说,切片的BBOX坐标是可以计算出来的。在默认情况下,会使用计算出来的BBOX坐标请求WMS或是WMTS服务,这样是有偏差的。我们可以对计算出来的BBOX坐标进行单点偏移,使用偏移后的BBOX坐标请求地图服务就可以实现地图的吻合。

3、实现

百度地图:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        html,
        body {
            margin: 0;
            padding: 0;
        }

        #allmap {
            width: 100%;
            height: 100vh;
        }
    </style>
    <script type="text/javascript" src="./util.js"></script>
    <script src="https://unpkg.com/gcoord/dist/gcoord.js"></script>
</head>

<body>
    <div id="allmap"></div>
    <script type="text/javascript">
        var map = null;
        //百度地图API功能
        function loadJScript() {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = "https://api.map.baidu.com/api?v=2.0&ak=你的秘钥&callback=init";
            document.body.appendChild(script);
        }
        
        function init() {
            map = new BMap.Map("allmap");            // 创建Map实例
            var point = new BMap.Point(116.997528, 36.676244); // 创建点坐标
            map.centerAndZoom(point, 15);
            map.enableScrollWheelZoom();                 //启用滚轮放大缩小
            addWMSLayer();
            map.addEventListener("click", e => {
                console.log(e);
            })
        }


        function addWMSLayer() {
            let tileLayer = new BMap.TileLayer({
                transparentPng: true
            })

            // 不同的分辨率,数值上等于一像素对应的距离
            var resolutions = []
            for (var i = 0; i < 19; i++) {
                resolutions[i] = Math.pow(2, 18 - i);
            }

            tileLayer.getTilesUrl = function (tileCoord, zoom) {

                // x,y瓦片左上角横纵坐标(米)
                var x = tileCoord.x;
                var y = tileCoord.y;

                var resolution = resolutions[zoom];
                var tileWidth = 256;
                
                // 计算瓦片的BBOX
                var minx = x * tileWidth * resolution;
                var miny = y * tileWidth * resolution;
                var maxx = (x + 1) * tileWidth * resolution;
                var maxy = (y + 1) * tileWidth * resolution;

                // 将BBOX的BD-09米制坐标转为EPSG:3857
                var bottomLeft = gcoord.transform(
                    [minx, miny],
                    gcoord.BD09MC,
                    gcoord.EPSG3857
                );
                var topRight = gcoord.transform(
                    [maxx, maxy],
                    gcoord.BD09MC,
                    gcoord.EPSG3857
                );
                
                let bbox = [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]];

                // wms参数
                let baseUrl = "http://{host}:{port}/geoserver/{workspace}/wms?";
                let params = {
                    SERVICE: "WMS",
                    VERSION: "1.1.1",
                    REQUEST: "GetMap",
                    FORMAT: "image/png",
                    TRANSPARENT: true,
                    LAYERS: "{workspace:layerName}",
                    WIDTH: 256,
                    HEIGHT: 256,
                    SRS: "EPSG:3857"
                }

                var url = baseUrl + objToParams(params) + `&bbox=${bbox.join(",")}`
                return url;
            }
            map.addTileLayer(tileLayer);
        }

        window.onload = loadJScript;  //异步加载地图
    </script>
</body>

</html>

高德地图:

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
    <title>异步加载地图</title>
    <link rel="stylesheet" href="https://cache.amap.com/lbs/static/main1119.css" />
    <script src="https://unpkg.com/gcoord/dist/gcoord.js"></script>
    <script src="./util.js"></script>

</head>

<body>
    <div id="container"></div>
    <script>
        var map = null;
        function onApiLoaded() {
            map = new AMap.Map('container', {
                center: [117.11116783127187, 36.67459186502283],
                zoom: 15
            });
            map.on("click", e => {
                console.log(e);
            })
            addWMSLayer();
        }

        // 切片转经度
        function tile2lon(x, z) {
            return (x / Math.pow(2, z) * 360 - 180);
        }

        // 切片转纬度
        function tile2lat(y, z) {
            var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
            return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
        }

        function addWMSLayer() {

            var resolutions = []
            for (var i = 0; i < 19; i++) {
                resolutions[i] = Math.pow(2, 18 - i);
            }

            var tileLayer = new AMap.TileLayer({
                tileSize: 256,
                tileUrl: function (x, y, z) {
                   	// 获取瓦片BBOX的经纬度坐标,这里和百度坐标的转化不一样,因为没有在gcoord中找到GCJ-02米制坐标转化,只好通过经纬度了
                    let xmin = tile2lon(x, z);
                    let xmax = tile2lon(x + 1, z);
                    let ymin = tile2lat(y + 1, z);
                    let ymax = tile2lat(y, z);

                    // 将BBOX的GCJ02坐标转为EPSG:3857
                    let t1 = gcoord.transform([xmin, ymin], gcoord.GCJ02, gcoord.EPSG3857);
                    let t2 = gcoord.transform([xmax, ymax], gcoord.GCJ02, gcoord.EPSG3857);

                    // wms配置
                    let url = 'http://{host}:{port}/geoserver/{workspace}/wms?';
                    let params = {
                        service: "WMS",
                        version: "1.1.0",
                        transparent: true,
                        request: "GetMap",
                        layers: "{workspace:layerName}",
                        width: 256,
                        height: 256,
                        srs: "EPSG:3857",
                        format: "image/png",
                        bbox: [t1[0], t1[1], t2[0], t2[1]].join(',')
                    };

                    // 构建查询字符串
                    let str = objToParams(params);

                    return url + str;
                },
                zIndex: 10
            })
            map.add(tileLayer);
        }

        var url = 'https://webapi.amap.com/maps?v=1.4.15&key=你的秘钥&callback=onApiLoaded';
        var jsapi = document.createElement('script');
        jsapi.charset = 'utf-8';
        jsapi.src = url;
        document.head.appendChild(jsapi);
    </script>
</body>

</html>

帮助类

// 对象转为查询字符串
function objToParams(obj){
    return Object.keys(obj).map(function (key) {
        return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(obj[key]));
      }).join('&');
}

4、源码

源码地址

标签:function,map,地图,纠偏,let,坐标,var,gcoord,高德
来源: https://www.cnblogs.com/asdlijian/p/13657043.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有