Leaflet 地图偏移 地图纠偏

    地图区域是一个市,偏移量可以近似认为是固定不变的,通过修改Leaflet-src.js源码中的_update方法和_addTile方法对瓦片进行偏移纠偏。

    Leaflet版本v1.3.4,要修改的_update和_addTile方法和最新版本1.6.0区别不大。

1、在_update方法中添加如下代码,瓦片图偏移后,在边缘位置需要补充瓦片图显示,不然边缘会出现空白:

        //处理纠偏后瓦片显示
        var ratio = 1 / Math.pow(2, (18 - this._tileZoom)); //计算纠偏比率
        var deltaX = 0;
        var deltaY = 0;
        if (this._map.options.offsetX) deltaX = this._map.options.offsetX * ratio / 256;
        if (this._map.options.offsetY) deltaY = this._map.options.offsetY * ratio / 256;
        if (deltaX > 0) tileRange.max.x += (Math.round(deltaX) + 1);
        if (deltaY > 0) tileRange.max.y += (Math.round(deltaY) + 1);
        if (deltaX < 0) tileRange.min.x -= (Math.floor(deltaX) - 1);
        if (deltaY < 0) tileRange.min.y -= (Math.floor(deltaY) - 1);
View Code

2、在_update方法中修改如下代码:

            for (i = 0; i < queue.length; i++) {
                this._addTile(queue[i], fragment, ratio);
            }
View Code

3、在_addTile方法中添加如下代码,重新计算瓦片的像素位置:

        //纠偏
        if (this._map.options.offsetX) tilePos.x -= Math.floor(this._map.options.offsetX * ratio);
        if (this._map.options.offsetY) tilePos.y -= Math.floor(this._map.options.offsetY * ratio);
View Code

 

_update方法完整代码:

    // Private method to load tiles in the grid's active zoom level according to map bounds
    _update: function (center) {
        var map = this._map;
        if (!map) { return; }
        var zoom = this._clampZoom(map.getZoom());

        if (center === undefined) { center = map.getCenter(); }
        if (this._tileZoom === undefined) { return; }    // if out of minzoom/maxzoom

        var pixelBounds = this._getTiledPixelBounds(center),
            tileRange = this._pxBoundsToTileRange(pixelBounds),
            tileCenter = tileRange.getCenter(),
            queue = [],
            margin = this.options.keepBuffer,
            noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
                                      tileRange.getTopRight().add([margin, -margin]));

        // Sanity check: panic if the tile range contains Infinity somewhere.
        if (!(isFinite(tileRange.min.x) &&
              isFinite(tileRange.min.y) &&
              isFinite(tileRange.max.x) &&
              isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }

        for (var key in this._tiles) {
            var c = this._tiles[key].coords;
            if (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {
                this._tiles[key].current = false;
            }
        }

        // _update just loads more tiles. If the tile zoom level differs too much
        // from the map's, let _setView reset levels and prune old tiles.
        if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }

        //处理纠偏后瓦片显示
        var ratio = 1 / Math.pow(2, (18 - this._tileZoom)); //计算纠偏比率
        var deltaX = 0;
        var deltaY = 0;
        if (this._map.options.offsetX) deltaX = this._map.options.offsetX * ratio / 256;
        if (this._map.options.offsetY) deltaY = this._map.options.offsetY * ratio / 256;
        if (deltaX > 0) tileRange.max.x += (Math.round(deltaX) + 1);
        if (deltaY > 0) tileRange.max.y += (Math.round(deltaY) + 1);
        if (deltaX < 0) tileRange.min.x -= (Math.floor(deltaX) - 1);
        if (deltaY < 0) tileRange.min.y -= (Math.floor(deltaY) - 1);

        // create a queue of coordinates to load tiles from
        for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
            for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
                var coords = new Point(i, j);
                coords.z = this._tileZoom;

                if (!this._isValidTile(coords)) { continue; }

                var tile = this._tiles[this._tileCoordsToKey(coords)];
                if (tile) {
                    tile.current = true;
                } else {
                    queue.push(coords);
                }
            }
        }

        // sort tile queue to load tiles in order of their distance to center
        queue.sort(function (a, b) {
            return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
        });

        if (queue.length !== 0) {
            // if it's the first batch of tiles to load
            if (!this._loading) {
                this._loading = true;
                // @event loading: Event
                // Fired when the grid layer starts loading tiles.
                this.fire('loading');
            }

            // create DOM fragment to append tiles in one batch
            var fragment = document.createDocumentFragment();

            for (i = 0; i < queue.length; i++) {
                this._addTile(queue[i], fragment, ratio);
            }

            this._level.el.appendChild(fragment);
        }
    },
View Code

_addTile方法完整代码:

    _addTile: function (coords, container, ratio) {
        var tilePos = this._getTilePos(coords),
            key = this._tileCoordsToKey(coords);

        var tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords));

        this._initTile(tile);

        // if createTile is defined with a second argument ("done" callback),
        // we know that tile is async and will be ready later; otherwise
        if (this.createTile.length < 2) {
            // mark tile as ready, but delay one frame for opacity animation to happen
            requestAnimFrame(bind(this._tileReady, this, coords, null, tile));
        }

        //纠偏
        if (this._map.options.offsetX) tilePos.x -= Math.floor(this._map.options.offsetX * ratio);
        if (this._map.options.offsetY) tilePos.y -= Math.floor(this._map.options.offsetY * ratio);

        setPosition(tile, tilePos);

        // save tile in cache
        this._tiles[key] = {
            el: tile,
            coords: coords,
            current: true
        };

        container.appendChild(tile);
        // @event tileloadstart: TileEvent
        // Fired when a tile is requested and starts loading.
        this.fire('tileloadstart', {
            tile: tile,
            coords: coords
        });
    },
View Code

 

如何使用:

1、JS引用由leaflet.js修改为引用leaflet-src.js

2、创建地图见如下代码,注意offsetX和offsetY参数,不同的城市,参数值不同,参数值可以用太乐地图下载器软件中的纠偏工具计算:

var map = new L.Map('map', { center: centerLatLng, zoom: 12, minZoom: 8, maxZoom: 18, maxBounds: mapBounds, offsetX: 1020, offsetY: 517, layers: [tileLayer], attributionControl: false, doubleClickZoom: false, zoomControl: false });
View Code

 

还有另一种纠偏方法,可以通过处理瓦片图进行纠偏:https://www.cnblogs.com/s0611163/p/12034779.html

 

posted @ 2020-07-29 14:09  秋荷雨翔  阅读(50)  评论(0编辑  收藏