腾讯地图在线瓦片分三种,分别是
//p{s}.map.gtimg.com/sateTiles/{z}/{sx}/{sy}/{x}_{ry}.jpg /*影像底图地址*/
//p{s}.map.gtimg.com/demTiles/{z}/{sx}/{sy}/{x}_{ry}.jpg /*地形底图地址*/
//rt{s}.map.gtimg.com/tile?z={z}&x={x}&y={ry}&{p} /*其他电子地图、标注底图等的地址*/
腾讯地图采用 GCJ02 火星坐标系,叠加到 Leaflet 和 Cesium 默认的 WGS84 通用坐标系需要进行纠偏。
相关参数:
{p}(代码中 param 参数) | 对应图层 | 瓦片级别 |
---|---|---|
img | 影像底图 | [1,18] |
dem | 地形底图 | [1,15] |
type=vector&styleid=1 | 电子地图 | [1,18] |
type=vector&styleid=2 | 影像标注,路网 + 注记 | [1,15] |
type=vector&styleid=3 | 电子地图,路网 + 注记 + 楼块+水系 | [1,18] |
type=vector&styleid=4 | 电子地图,暗色地图 | [1,18] |
type=vector&styleid=8 | 电子地图,暖色地图 | [1,18] |
type=vector&styleid=9 | 电子地图,暖色地图,突出学校、医院等公共设施 | [1,18] |
在线运行
DOCTYPE html>
<html>
<head>
<title>title>
<meta charset="utf-8">
<style type="text/css">
body { padding: 0; margin: 0; }
html, body, #map { height: 100%; }
#param-test { position: absolute; z-index: 999; left: 10px; top: 10px; background: white; padding: 0 3px; line-height: 28px; font-size: 14px }
#url-input { width: 450px; height: 18px; margin-bottom: 3px; }
style>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js">script>
<script src="https://unpkg.com/[email protected]/dist/gcoord.js">script>
head>
<body>
<div id="param-test">
测试参数:<input id="url-input" type="text" placeholder="输入地址参数, 例:type=vector&styleid=1、img 或 dem, 并回车" onkeydown="loadTile(this.value)" />
div>
<div id="map" />
body>
<script type="text/javascript">
L.TileLayer.TencentTileLayer = L.TileLayer.extend({
initialize: function (param, options) {
var templateImgUrl = "//p{s}.map.gtimg.com/sateTiles/{z}/{sx}/{sy}/{x}_{ry}.jpg"
var templateDemUrl = "//p{s}.map.gtimg.com/demTiles/{z}/{sx}/{sy}/{x}_{ry}.jpg"
var templateUrl = "//rt{s}.map.gtimg.com/tile?z={z}&x={x}&y={ry}&{p}"
var myUrl = (param === "img" ? templateImgUrl : (param === "dem" ? templateDemUrl : templateUrl))
options = L.extend({// 位运算符:a >> b 等价于 Math.floor(a / Math.pow(2, b)),a << b 等价于 Math.floor(a * Math.pow(2, b))
getUrlArgs: (o) => { return { x: o.x, ry: (1 << o.z) - o.y - 1, z: o.z, sx: o.x >> 4, sy: ((1 << o.z) - o.y - 1) >> 4 } },
p: param, subdomains: "0123", minZoom: 0, maxZoom: 23, minNativeZoom: 1, maxNativeZoom: param === "dem" ? 15 : 18
}, options)
L.TileLayer.prototype.initialize.call(this, myUrl, options)
},
getTileUrl: function (coords) {
if (this.options.getUrlArgs) {
return L.Util.template(this._url, L.extend({ s: this._getSubdomain(coords), r: L.Browser.retina ? '@2x' : '' }, this.options.getUrlArgs(coords), this.options))
} else {
return L.TileLayer.prototype.getTileUrl.call(this, coords)
}
},
_setZoomTransform: function (level, center, zoom) {
center = L.latLng(gcoord.transform([center.lng, center.lat], gcoord.WGS84, gcoord.GCJ02).reverse()) // 采用 gcoord 库进行纠偏
L.TileLayer.prototype._setZoomTransform.call(this, level, center, zoom)
},
_getTiledPixelBounds: function (center) {
center = L.latLng(gcoord.transform([center.lng, center.lat], gcoord.WGS84, gcoord.GCJ02).reverse()) // 采用 gcoord 库进行纠偏
return L.TileLayer.prototype._getTiledPixelBounds.call(this, center)
},
})
L.tileLayer.tencentTileLayer = function (param, options) { return new L.TileLayer.TencentTileLayer(param, options) }
var img_Layer = L.tileLayer.tencentTileLayer("img"), // 影像底图
dem_Layer = L.tileLayer.tencentTileLayer("dem"), // 地形底图
tvs1_Layer = L.tileLayer.tencentTileLayer("type=vector&styleid=1"), // 电子地图,区域面 + 路网 + 注记 + 楼块
tvs2_Layer = L.tileLayer.tencentTileLayer("type=vector&styleid=2"), // 影像标注,路网 + 注记
tvs3_Layer = L.tileLayer.tencentTileLayer("type=vector&styleid=3"), // 简化地图,区域面 + 路网 + 注记 + 楼块
tvs4_Layer = L.tileLayer.tencentTileLayer("type=vector&styleid=4"), // 电子地图,暗色地图
tvs8_Layer = L.tileLayer.tencentTileLayer("type=vector&styleid=8"), // 电子地图,淡色地图
tvs9_Layer = L.tileLayer.tencentTileLayer("type=vector&styleid=9") // 电子地图,淡色地图,突出学校、医院等公共设施
var map = L.map("map", { center: [29.708050, 118.321499], zoom: 15, zoomControl: false, attributionControl: false, doubleClickZoom: false })
var overlayLayers = {
"影像底图": img_Layer, "地形底图": dem_Layer, "电子地图,区域面 + 路网 + 注记 + 楼块": tvs1_Layer, "影像标注,路网 + 注记": tvs2_Layer, "简化地图,区域面 + 路网 + 注记 + 楼块": tvs3_Layer,
"电子地图,暗色地图": tvs4_Layer, "电子地图,淡色地图": tvs8_Layer, "电子地图,淡色地图,突出学校、医院等公共设施": tvs9_Layer
}
L.control.layers([], overlayLayers, { autoZIndex: false }).addTo(map)
L.marker([29.708050, 118.321499]).addTo(map) // 添加点用于纠偏测试
// map.on('dblclick', function (e) { console.dir(e.latlng.lng + "," + e.latlng.lat) })
var test_Layer = null
function loadTile (param) {
if (!window.event || window.event.keyCode === 13) { // keyCode ===13 表示按下回车
if (test_Layer !== null) {
map.removeLayer(test_Layer)
test_Layer = null
}
if (!param) return
test_Layer = L.tileLayer.tencentTileLayer(param)
map.addLayer(test_Layer)
}
}
var param = "img"
document.getElementById("url-input").value = param
loadTile(param)
script>
html>
在线运行
DOCTYPE html>
<html>
<head>
<title>title>
<meta charset="utf-8" />
<style type="text/css">
body { padding: 0; margin: 0; }
html, body, #map { height: 100%; }
#param-test { position: absolute; z-index: 999; left: 10px; top: 10px; background: white; padding: 0 3px; line-height: 28px; font-size: 14px }
#url-input { width: 450px; height: 18px; margin-bottom: 3px; }
.cesium-viewer .cesium-viewer-bottom { display: none; }
.cesium-viewer .cesium-baseLayerPicker-item { display: block; width: auto; margin: 3px 10px; }
.cesium-viewer .cesium-baseLayerPicker-itemIcon, .cesium-viewer .cesium-baseLayerPicker-sectionTitle { display: none; }
.cesium-viewer .cesium-baseLayerPicker-itemLabel { text-align: left; }
.cesium-viewer .cesium-baseLayerPicker-dropDown { width: 250px; padding: 0; margin: 0; }
.cesium-viewer .cesium-baseLayerPicker-choices { border: none; }
.cesium-viewer .cesium-baseLayerPicker-selectedItem .cesium-baseLayerPicker-itemLabel { color: #00cbff; }
style>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/Build/Cesium/Widgets/widgets.css" />
<script src="https://unpkg.com/[email protected]/Build/Cesium/Cesium.js">script>
<script src="https://unpkg.com/[email protected]/dist/gcoord.js">script>
head>
<body>
<div id="param-test">
测试参数:<input id="url-input" type="text" placeholder="输入地址参数, 例:type=vector&styleid=1、img 或 dem, 并回车" onkeydown="loadTile(this.value)" />
div>
<div id="map" />
body>
<script type="text/javascript">
class TencentMercatorProjection extends Cesium.WebMercatorProjection {
project (cartographic, result) {
const correct = gcoord.transform([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)], gcoord.WGS84, gcoord.GCJ02)
cartographic.longitude = Cesium.Math.toRadians(correct[0])
cartographic.latitude = Cesium.Math.toRadians(correct[1])
return super.project(cartographic, result)
}
unproject (cartesian, result) {
result = super.unproject(cartesian, result)
const correct = gcoord.transform([Cesium.Math.toDegrees(result.longitude), Cesium.Math.toDegrees(result.latitude)], gcoord.GCJ02, gcoord.WGS84)
result.longitude = Cesium.Math.toRadians(correct[0])
result.latitude = Cesium.Math.toRadians(correct[1])
return result
}
}
Cesium.TencentMercatorProjection = TencentMercatorProjection
class TencentMercatorTilingScheme extends Cesium.WebMercatorTilingScheme {
constructor (options) {
super(options)
this._projection = new Cesium.TencentMercatorProjection(this._ellipsoid);
}
}
Cesium.TencentMercatorTilingScheme = TencentMercatorTilingScheme
class TencentImageryProvider extends Cesium.UrlTemplateImageryProvider {
constructor (param, options = {}) {
var templateImgUrl = "//p{s}.map.gtimg.com/sateTiles/{z}/{sx}/{sy}/{x}_{ry}.jpg"
var templateDemUrl = "//p{s}.map.gtimg.com/demTiles/{z}/{sx}/{sy}/{x}_{ry}.jpg"
var templateUrl = "//rt{s}.map.gtimg.com/tile?z={z}&x={x}&y={ry}&{p}"
var myUrl = (param === "img" ? templateImgUrl : (param === "dem" ? templateDemUrl : templateUrl)).replace(/\{p\}/g, param)
super(Object.assign({}, {
url: myUrl, subdomains: "0123", minimumLevel: 1, maximumLevel: param === "dem" ? 15 : 18, tilingScheme: new Cesium.TencentMercatorTilingScheme(),
customTags: {
x: (l, x, y, z) => { return x },
ry: (l, x, y, z) => { return (1 << z) - y - 1 },
z: (l, x, y, z) => { return z },
sx: (l, x, y, z) => { return x >> 4 },
sy: (l, x, y, z) => { return ((1 << z) - y - 1) >> 4 }
}
}, options))
}
}
Cesium.TencentImageryProvider = TencentImageryProvider
Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIwNGNmNWUwMi02NWEyLTQxNzItOTNhNC1mY2NiZTcxNDc2OWYiLCJpZCI6MTU5NDQsInNjb3BlcyI6WyJhc2wiLCJhc3IiLCJhc3ciLCJnYyJdLCJpYXQiOjE1NjkyMjk3MTN9.PYUfCHykW23NuwRzzz04yW7JyZ4vQlcb4kToZ44r42w"
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(118.282527, 29.692229, 118.360733, 29.724694) // 设置相机默认范围为自定义区域
Cesium.Camera.DEFAULT_VIEW_FACTOR = 0
// console.debug(viewer.camera.computeViewRectangle()) // 可以返回当前区域矩形,以弧度为单位
var viewer = new Cesium.Viewer("map", {
animation: false, // 是否显示动画控件
baseLayerPicker: true, // 是否显示图层选择控件
vrButton: false, // 是否显示VR控件
fullscreenButton: false, // 是否显示全屏按钮
geocoder: false, // 是否显示地名查找控件
homeButton: false, // 是否显示返回主视角控件
sceneModePicker: false, // 是否显示投影方式控件
selectionIndicator: false, // 是否显示选中指示框
timeline: false, // 是否显示时间线控件
navigationHelpButton: false, // 是否显示帮助信息控件
infoBox: false, // 是否显示点击要素之后显示的信息
})
viewer.imageryLayers.removeAll(viewer.imageryLayers.get(0)) // 移除 Cesium 默认图层
viewer.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 0) // 设置地球背景色黑色
var img_Layer = new Cesium.TencentImageryProvider("img"), // 影像底图
dem_Layer = new Cesium.TencentImageryProvider("dem"), // 地形底图
tvs1_Layer = new Cesium.TencentImageryProvider("type=vector&styleid=1"), // 电子地图,区域面 + 路网 + 注记 + 楼块
tvs2_Layer = new Cesium.TencentImageryProvider("type=vector&styleid=2"), // 影像标注,路网 + 注记
tvs3_Layer = new Cesium.TencentImageryProvider("type=vector&styleid=3"), // 简化地图,区域面 + 路网 + 注记 + 楼块
tvs4_Layer = new Cesium.TencentImageryProvider("type=vector&styleid=4"), // 电子地图,暗色地图
tvs8_Layer = new Cesium.TencentImageryProvider("type=vector&styleid=8"), // 电子地图,淡色地图
tvs9_Layer = new Cesium.TencentImageryProvider("type=vector&styleid=9") // 电子地图,淡色地图,突出学校、医院等公共设施
viewer.baseLayerPicker._dropPanel.children[0].innerHTML = "底图"
viewer.baseLayerPicker.viewModel.imageryProviderViewModels = [
new Cesium.ProviderViewModel({ creationFunction: function () { return img_Layer }, name: "影像底图" }),
new Cesium.ProviderViewModel({ creationFunction: function () { return dem_Layer }, name: "地形底图" }),
new Cesium.ProviderViewModel({ creationFunction: function () { return tvs1_Layer }, name: "电子地图,区域面 + 路网 + 注记 + 楼块" }),
new Cesium.ProviderViewModel({ creationFunction: function () { return tvs2_Layer }, name: "影像标注,路网 + 注记" }),
new Cesium.ProviderViewModel({ creationFunction: function () { return tvs3_Layer }, name: "简化地图,区域面 + 路网 + 注记 + 楼块" }),
new Cesium.ProviderViewModel({ creationFunction: function () { return tvs4_Layer }, name: "电子地图,暗色地图" }),
new Cesium.ProviderViewModel({ creationFunction: function () { return tvs8_Layer }, name: "电子地图,淡色地图" }),
new Cesium.ProviderViewModel({ creationFunction: function () { return tvs9_Layer }, name: "电子地图,淡色地图,突出学校、医院等公共设施" })
]
// viewer.baseLayerPicker.viewModel.selectedImagery = viewer.baseLayerPicker.viewModel.imageryProviderViewModels[0]
viewer.baseLayerPicker._dropPanel.children[2].innerHTML = "地形"
viewer.baseLayerPicker.viewModel.terrainProviderViewModels = []
viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(118.321499, 29.708050), point: { pixelSize: 5, color: Cesium.Color.RED } }) //添加点用于纠偏测试
var test_Layer = null
function loadTile (param) {
if (!window.event || window.event.keyCode === 13) { // keyCode === 13 表示按下回车
if (test_Layer !== null) {
viewer.imageryLayers.remove(test_Layer, true)
test_Layer = null
}
if (!param) return
test_Layer = viewer.imageryLayers.addImageryProvider(new Cesium.TencentImageryProvider(param))
}
}
var param = "type=vector&styleid=1"
document.getElementById("url-input").value = param
loadTile(param)
script>
html>
其他文章:https://blog.csdn.net/shaxiaozilove/article/details/118685919
腾讯地图控制台(2022年11月11日停服):https://map.qq.com/