leafletwx是基于leaflet,使用微信原生组件开发的一套开源地图组件,目标是替换小程序的原生map组件,项目开源地址:leatletwx。>
本示例开源地址在leafletwx的qqmap_infinite页面。>
本示例使用的其他组件:> 1.本示例的主要功能来自于leaflet插件Leaflet.TileLayer.Fallback
背景及原理:
国内地图瓦片服务商提供的放大级数一般在0-18级,例如QQ地图、百度地图、高德地图、天地图等等,建筑物较小而marker较多时,会导致marker过于拥挤,而无法通过继续放大地图进行分散。
leaflet插件Leaflet.TileLayer.Fallback的主要思想是当地图放到到瓦片服务器的最大级别时,采用放大最大一级的图片大小来实现继续放大地图的效果。例如:QQ地图,原始瓦片图片的大小为256*256像素,最大18级。当放大到第19级时,将第18级图片放大到512*512;当放大到第20级时,将18级图片放大到1024*1024。
具体实现:
qqlayers.infinite.js
var L = require('../../components/zhgeo/leafletwx')
L.TileLayer.TXMapTileLayer = L.TileLayer.extend({
options: {
minNativeZoom: 0
},
initialize: function (urlTemplate, options) {
L.TileLayer.prototype.initialize.call(this, urlTemplate, options);
},
createTile: function (coords, done) {
var tile = L.TileLayer.prototype.createTile.call(this, coords, done);
tile._originalCoords = coords;
tile._originalSrc = tile.src;
return tile;
},
_clampZoom: function (zoom) {
var options = this.options;
if (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {
return options.minNativeZoom;
}
return zoom;
},
_addTile: function (coords) {
var tile = L.TileLayer.prototype._addTile.call(this, coords);
var options = this.options;
var zoom = coords.z;
if (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {
return this._tileOutError(tile);
}
return tile;
},
_createCurrentCoords: function (originalCoords) {
var currentCoords = this._wrapCoords(originalCoords);
currentCoords.fallback = true;
return currentCoords;
},
_tileOutError: function (tile) {
var options = this.options;
var layer = this, // `this` is bound to the Tile Layer in L.TileLayer.prototype.createTile.
originalCoords = tile._originalCoords,
currentCoords = tile._currentCoords = tile._currentCoords || layer._createCurrentCoords(originalCoords),
fallbackZoom = options.maxNativeZoom,
scale = Math.pow(2, (originalCoords.z - options.maxNativeZoom)),
tileSize = layer.getTileSize(),
newUrl, top, left;
// Modify tilePoint for replacement img.
currentCoords.z = fallbackZoom;
currentCoords.x = Math.floor(currentCoords.x / scale);
currentCoords.y = Math.floor(currentCoords.y / scale);
// Generate new src path.
newUrl = layer.getTileUrl(currentCoords);
// Zoom replacement img.
tile.width = (tileSize.x * scale) + 'px';
tile.height = (tileSize.y * scale) + 'px';
// Compute margins to adjust position.
top = (originalCoords.y - currentCoords.y * scale) * tileSize.y;
tile.top = (tile.top - top);
left = (originalCoords.x - currentCoords.x * scale) * tileSize.x;
tile.left = (tile.left - left);
// Crop (clip) image.
// `clip` is deprecated, but browsers support for `clip-path: inset()` is far behind.
// http://caniuse.com/#feat=css-clip-path
// tile.clip = 'rect(' + top + 'px ' + (left + tileSize.x) + 'px ' + (top + tileSize.y) + 'px ' + left + 'px)';
tile.src = newUrl;
return tile;
},
getTileUrl: function (tilePoint) {
var urlArgs,
getUrlArgs = this.options.getUrlArgs;
if (getUrlArgs) {
var urlArgs = getUrlArgs(tilePoint);
} else {
urlArgs = {
z: tilePoint.z,
x: tilePoint.x,
y: tilePoint.y,
s: this._getSubdomain(tilePoint)
};
}
if (this._map && !this._map.options.crs.infinite) {
var invertedY = this._globalTileRange.max.y - tilePoint.y;
if (this.options.tms) {
urlArgs['y'] = invertedY;
}
urlArgs['-y'] = invertedY;
}
return L.Util.template(this._url, L.extend(urlArgs, this.options));
}
});
L.tileLayer.txMapTileLayer = function (type, options) {
var getUrlArgs, url, subdomain = '012';
if (type == 'Normal') { //地图带路线轮廓 有轮廓/有路线
url = 'http://rt1.map.gtimg.com/realtimerender/?z={z}&x={x}&y={y}&type=vector&style=1&v=1.1.1'; //ok //普通地图
getUrlArgs = function (tilePoint) {
return {
//地图
z: tilePoint.z,
x: tilePoint.x,
y: Math.pow(2, tilePoint.z) - 1 - tilePoint.y
};
}
} else if (type == 'Satellite') { //卫星图,无轮廓/无路线
url = 'http://p3.map.gtimg.com/sateTiles/{z}/{x}/{y}/{G}_{H}.jpg?version=229';
getUrlArgs = function (tilePoint) {
return {
//卫星图
z: tilePoint.z,
x: Math.floor(tilePoint.x / 16),
y: Math.floor((Math.pow(2, tilePoint.z) - 1 - tilePoint.y) / 16),
G: tilePoint.x,
H: Math.pow(2, tilePoint.z) - 1 - tilePoint.y
};
}
} else if (type=='Landform') {//地形图,有轮廓/有路线
url = 'http://rt1.map.gtimg.com/tile?z={z}&x={x}&y={y}&type=vector&styleid=3&version=263' //ok //地形地图
getUrlArgs = function (tilePoint) {
return {
//地形图
z: tilePoint.z,
x: tilePoint.x,
y: Math.pow(2, tilePoint.z) - 1 - tilePoint.y
};
}
}
options = L.extend(options, {
subdomain:'012',
getUrlArgs:getUrlArgs,
})
return new L.TileLayer.TXMapTileLayer(url, options);
};
qqmap_infinite.js
// pages/qqmap/qqmap.js
var L = require('../../components/zhgeo/leafletwx')
require('./qqlayers.infinite')
import {createMap} from '../../components/zhgeo/base.map'
import {DefaultIcons} from '../../components/zhgeo/config.js';
const defaultIcons = new DefaultIcons();
Page({
onLoad(options) {
const container = this.selectComponent('#qq-leafletwx')
let min_zoom = 17
let max_zoom = 20
createMap(container, {
}, function(map) {
console.log(map)
var Normal = L.tileLayer.txMapTileLayer("Normal", {
minNativeZoom: 3, // 瓦片服务器最小级别
maxNativeZoom: 18, // 瓦片服务器最大级别
minZoom: min_zoom, // 用户地图最小级别
maxZoom: max_zoom, // 用户地图最大级别
}); //调用 腾讯地图
Normal.addTo(map)
map.setView([31.294516,120.625814], 18);
// 限定地图范围
var corner1 = L.latLng(31.29571,120.623941),
corner2 = L.latLng(31.289586,120.63455),
bounds = L.latLngBounds(corner1, corner2);
map.setMaxBounds(bounds);
// 添加marker
let m = L.marker([31.2948516,120.625814], {
src: defaultIcons.locationNow,
width: 32,
height: 32,
showInCenter: false,
}).addTo(map);
// 删除marer
// map.removeLayer( m );
// popup
m.bindPopup("这是个弹框", {
width: 60,
});
// 添加路线
let l = L.polyline([[31.293516,120.625814], [31.294516,120.625214], [31.294516,120.626114]], {color: '#ff0000', weight: 3}).addTo(map);
// 删除线路
// map.removeLayer( l );
// 添加区域
let y = L.polygon([[31.2930516,120.625814], [31.2940516,120.625214], [31.2940516,120.626114]], {color: '#ff0000', weight: 4}).addTo(map);
// 删除区域
// map.removeLayer( y );
m = L.marker([31.2944516,120.625814], {
src: defaultIcons.location,
width: 32,
height: 32,
title: '沧浪亭',
showFooter: true,
footerWidth: 60,
footerPosition: 1, // 0:左 1:右 2:上 3:下
left_badge: '左', // 为空时不显示
right_badge: '右', // 为空时不显示
showInCenter: true, // ture: 图标中心在POI中心 false:图标下边缘中心位于POI中心
}).addTo(map);
// 删除线路
// map.removeLayer( l );
});
},
})
效果展示(QQ地图第19级):