地图区域是一个市,偏移量可以近似认为是固定不变的,通过修改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);
2、在_update方法中修改如下代码:

for (i = 0; i < queue.length; i++) { this._addTile(queue[i], fragment, ratio); }
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);
_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); } },
_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 }); },
如何使用:
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 });
还有另一种纠偏方法,可以通过处理瓦片图进行纠偏:https://www.cnblogs.com/s0611163/p/12034779.html