天地图开发
天地图开发
安徽省-天地图:http://anhui.tianditu.gov.cn/home/page/index.html
https://blog.csdn.net/dnvtkhbn/article/details/126303163
解决天地图key使用限定 : https://blog.csdn.net/qq_40772640/article/details/130920905
以vue开发为例
1.基础用法
1.1 引入api
public/index.html
<script src="http://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥" type="text/javascript"></script>
1.2. 创建容器
<template>
<div id="map_wrap" class="map_wrap pr" >
<div id="container" ></div>
</div>
</template>
<script>
export default{
name:"Map",
components:{},
data() {// 定义 全局变量
return {
}
},
mounted(){
this.initMap();
},
methods:{
// 初始化天地图
initMap() {
// vue项目需要先声明 T = window.T,不然后面无法获取到。
var T = window.T;
this.map = new T.Map('container',{projection: "EPSG:4326"});// 申明天地图采用的坐标系的类型为EPSG:4326,也就是最通用的84坐标系
// 传参中心点经纬度,以及放大程度,最小1,最大18
this.map.centerAndZoom(new T.LngLat(117.2594242812,31.9364424285), 18);
},
},
</script>
<style lang="scss" scoped >
/*定义容器尺寸*/
#map_wrap,#container{
padding:0px;
margin: 0px;
width: 100%;
height: 100%;
}
#map_wrap{
/*font-family: "Bahnschrift";*/
overflow: hidden;
}
</style>
1.3 添加我的位置
可能出现 自定义图形无法修改图标的情况,注意
const marker = new T.Marker(point, {icon: icon});而不是new T.Marker(point,icon).否则图形默认是http://api.tianditu.gov.cn/v4.0/image/marker-icon.png
//1. 标记 当前我的位置
initMarker(lng,lat){
const point = new T.LngLat(lng,lat);
// 8.创建覆盖使用的图标
var icon = new T.Icon({
iconUrl: this.myselfImg,//require('@/assets/images/map/dw.png')
// iconUrl: "http://api.tianditu.gov.cn/img/map/markerA.png",
iconSize: new T.Point(19, 27),
iconAnchor: new T.Point(10, 25)
});
// 9. 创建在该坐标上的一个图像标注实例
const marker = new T.Marker(point, {icon: icon});
// 10.将覆盖物添加到地图中,一个覆盖物实例只能向地图中添加一次
map.addOverLay(marker);
},
1.4 添加点
1.5 添加线路
根据 电压等级 讲线路 分类
initLine(line_item){
var this_=this;
// {id: '67', name: '500k孔L', subType: '10', paths: [[117,23],[117.1,23.3],........]}
var lineMarker = new T.Polyline(this_.getList(line_item.paths),this_._createLineStyle(line_item));
lineMarker.addEventListener("click", this_.getinfo);
},
// 4.1.1 创建线路样式和自定义属性
_createLineStyle(line_item){
var item={
color: this.line_color_type[line_item.subType],// 根据电压等级 获取线路颜色
weight: 3,
weight_check: 4,// 计划作为选中后 线路宽带值
opacity: 1,
fillColor: "#003300",
lineExtData:{
name: line_item.name,
label_name:line_item.name,
id: line_item.id,
}
}
return item;
},
getinfo(e){
var Content = e.target.options.lineExtData; //设置信息窗口要显示的内容,此处可使用html代码;现在显示的就是之前在polygon实例中添加的数据
console.log(e.target.options);
},
//坐标处理,天地图无法使用json 格式的 坐标,需要 创建 LngLat 对象 ,,,,[[117,23],[],[]]
getList(obj){
let item=obj
let list=[]
item.forEach(lnglat=>{
list.push(new T.LngLat(lnglat[0],lnglat[1]))
})
return list;
},
/* 4.2 创建线路 label*/
_createLineLabelMarker (extData,linePaths) {
var position = linePaths[Math.ceil(linePaths.length/2)];
var latlng = new T.LngLat(position[0],position[1]);
var lebelMarker = new T.Label({
text:extData.label_name,
position: latlng,
offset: new T.Point(-9, 0),
});
//lebelMarker.setFontColor("#ffff");
lebelMarker.setBorderLine(0);
//lebelMarker.setFontSize (12);
//lebelMarker.setBackgroundColor("rgb(0,0,0,0)");
return lebelMarker;
},
initLabel(){
var lineLabelMarker = this_._createLineLabelMarker(lineExtData,line_item.paths);/// 构造 LabelMarker 格式参数
map.addOverLay(lineLabelMarker);// 通过 line.onRemove() 删除
}
1.5 添加面
1.7 LayerGroup使用
1.8 聚合
创建marker 点
this.markerObject = [] // 初始化聚合点集合数组
let icon = new T.Icon({
iconUrl: require(`自己的点位图标`),
id: 'test', // 类型id
iconSize: new T.Point(27, 36), // 图标大小
iconAnchor: new T.Point(0, 0) // 位移量
})
let marker = new T.Marker(new T.LngLat(xy[0], xy[1]),{ icon:icon});
this.markerObject.push(marker);
marker.extData = extData // 这里可以像这样给点位添加自定义属性
marker.addEventListener("click", (e) => {
console.log(e.target); // 可以从这里取出自定义的属性
});
属性range控制 图层显示范围,从而给我们自定义字体和图标的大小
注意:无法通过 MarkerClustererOptions 设置 最大的聚合级别 ,只能通过
markerCluster.setMaxZoom(number)进行设置
// 添加聚合
addMarkerCluster() {
this.removeMarkerCluster();// 删除聚合
if(!markerClusterPoints|| markerClusterPoints.length==0){
return;
}
this.sbMarkerCluster = new T.MarkerClusterer(map, {markers:this.markerObject,styles:this._createClusterMarkerStyle()});
this.sbMarkerCluster.setMaxZoom(14);//到14 就不进行聚合(最大的聚合级别,大于该级别就不进行聚合。)
this.sbMarkerCluster.on('click', this.checkMarkerCluster);
},
_createClusterMarkerStyle(){
var markerStyle= [
{
url:this.getIconByType('jh'),
size:[34, 34], //图片大小
offset:new T.Point(-15, -23), //显示图片的偏移量
textColor:'#000000', //显示数字的颜色
textSize:8,//显示文字的大小
range:[0, 200],//设置 范围 ,可以用来解决 数据量大 超出背景图片
},
{
url:this.getIconByType('jh'),
size:[40, 40], //图片大小
offset:new T.Point(-15, -23), //显示图片的偏移量
textColor:'#000000', //显示数字的颜色
textSize:8,//显示文字的大小
range:[200, 500],
}
]
return markerStyle;
},
1.9 热力图
官网提供的热力图,会导致 热力图讲laber 图层挤跑,所以需要对其改造一下
在 Canvas2dRenderer 方法 container.style.position = 'relative'; 行下添加container.style.float = 'left'; 使其 脱离文档流
<!-- index.html 引入 HeatmapOverlay-->
<script src="./lib/TMap/HeatmapOverlay.js"></script>
1.20 行政区域规划/描边
var map;
var zoom = 12;
function onLoad() {
//初始化地图对象
map = new T.Map("mapDiv");
//设置显示地图的中心点和级别
map.centerAndZoom(new T.LngLat(116.38969, 39.90940), zoom);
var outer = [];
outer.push(new T.LngLat(-360, 90));
outer.push(new T.LngLat(-360, -90));
outer.push(new T.LngLat(360, -90));
outer.push(new T.LngLat(360, 90));
// 描边时 通过 行政区域规划数据 创建 inner_area 数值 实现 区域的描边
var inner_area = [];
inner_area.push(new T.LngLat(116.349330,35.941590));
inner_area.push(new T.LngLat(117.350620,39.900650));
inner_area.push(new T.LngLat(118.353110,40.898670));
//创建面对象
var polygon = new T.Polygon([outer,inner_area],{
color: "#00eeff",
weight: 1,
opacity: 0.2,
fillColor: "#71B3ff",
fillOpacity: 0.5
});
//向地图上添加面
outlinePolygon.extData = { id: 'outline', name: name+'-描边/蒙层', type: 'outline' } //添加自定义说明
map.addOverLay(polygon);
}
案例
/*行政区域规划*/
outlineProvince (name) {
// 外边距
var outer_area = [
new T.LngLat(-360, 90, true),
new T.LngLat(-360, -90, true),
new T.LngLat(360, -90, true),
new T.LngLat(360, 90, true),
]
var inner_area = []
inner_area = borderline1.split(' ')
inner_area.forEach((n, i) => {
n = n.replace(/^\s*|\s*$/g, '')
var lnglat = n.split(',')
inner_area[i] = new T.LngLat(lnglat[0], lnglat[1])
})
//创建面对象
outlinePolygon = new T.Polygon([outer_area, inner_area], {
color: '#13dfee',
weight: 1,
opacity: 0.9,
fillColor: '#010d1c',
fillOpacity: 1//0.5
})
//向地图上添加面
outlinePolygon.extData = { id: 'outline', name: name+'-描边/蒙层', type: 'outline' }
map.addOverLay(outlinePolygon)
},
1.21 轨迹
用到的工具类 CarTrack.js
demo 天地图-轨迹.html
1.22 加载GeoJSON数据
https://blog.csdn.net/josiecici/article/details/118551879

<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>天地图-地图API-范例-加载geojson数据</title>
<link href="../../../../images/favicon.ico" type="image/x-icon" rel="Shortcut Icon"/>
<style type="text/css">
html {
height: 100%
}
body {
height: 100%;
margin: 0;
padding: 0
}
#map-canvas {
height: 100%;
fill: #000000;
}
</style>
</head>
<body>
<div id="map-canvas"></div>
<script src=" http://api.tianditu.gov.cn/api?v=4.0&tk=406edc64b943d6cb1a10260f4cae6d27" type="text/javascript"></script>
<script src="http://cdn.bootcss.com/d3/3.5.17/d3.js " charset="utf-8"></script>
<script src="http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/D3SvgOverlay.js"></script>
<script>
var countries = [];
var countriesOverlay = new T.D3Overlay(init,redraw);
var map = new T.Map("map-canvas");
map.centerAndZoom(new T.LngLat(116.39769, 40.25945), 9)
d3.json("https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json", function (data) {
countries = data.features;
map.addOverLay(countriesOverlay)
countriesOverlay.bringToBack();
});
function init(sel, transform) {
var upd = sel.selectAll('path.geojson').data(countries);
upd.enter()
.append('path')
.attr("class", "geojson")
.attr('stroke', 'black')
.attr('fill', function (d, i) {
return d3.hsl(Math.random() * 360, 0.9, 0.5)
})
.attr('fill-opacity', '0.5')
}
function redraw(sel, transform) {
sel.selectAll('path.geojson').each(
function (d, i) {
d3.select(this).attr('d', transform.pathFromGeojson)
// .on("mouseover",function(){
// console.log('这是点击了',);
// })
}
)
}
</script>
</body>
</html>
1.23 wmts
[案例](#15. 自定义底图 wms)
var imageURL = "http://49.4.95.196:18088/geoserver/gwc/service/wmts?" + "layer=ah16&style=&tilematrixset=EPSG:3857_ah16&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&TileMatrix=EPSG:3857_ah16:{z}" +"&TileRow={y}&TileCol={x}";
//创建自定义图层对象
var lay = new T.TileLayer(imageURL, {minZoom: 1, maxZoom: 18});
//将图层增加到地图上
map.addLayer(lay);
案例
考虑到 自定义发布的 底图服务,不可能讲全国底图都下载下来,所以 底图中肯定会出现破图
通过 errorTileUrl: this.errorTileUrl 自定义 破图的 替换图
// errorTileUrl: require('@/assets/image/map/mapLarye404.png')// 底图如果破图,用空白替换
// 卫星、街道图 切换
changeLayer () {
this.titleLayerIndex++
if (this.layerCheckActive == 'sl') {// 矢量图
map.setMapType(window.TMAP_NORMAL_MAP)// 底图
if (!vectorTileLayer) {
// 自发布的 wmts-矢量图
var imageURL = this.geoserver_url + '/gwc/service/wmts?' +
'layer=ah16&style=&tilematrixset=EPSG:3857_ah16&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&TileMatrix=EPSG:3857_ah16:{z}' + '&TileRow={y}&TileCol={x}'
vectorTileLayer = new T.TileLayer(imageURL, { minZoom: 1, maxZoom: 18, errorTileUrl: this.errorTileUrl })
vectorTileLayer.extData = { id: 'vectorTileLayer', name: '矢量图', type: 'TileLayer' }
map.addLayer(vectorTileLayer)
}
if (satelliteLayer) {
satelliteLayer.setZIndex(0)
}
vectorTileLayer.setZIndex(100)
} else if (this.layerCheckActive == 'wx') {// 卫星
map.setMapType(window.TMAP_SATELLITE_MAP)//TMAP_SATELLITE_MAP
if (!satelliteLayer) {
var imageURL = this.geoserver_url + '/gwc/service/wmts?' +
'layer=gaode&style=&tilematrixset=EPSG:3857_gaode&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&TileMatrix=EPSG:3857_gaode:{z}' +
'&TileRow={y}&TileCol={x}'
satelliteLayer = new T.TileLayer(imageURL, { minZoom: 1, maxZoom: 18,errorTileUrl: this.errorTileUrl})// errorTileUrl:'@/assets/images/map/mapLarye404.png'
satelliteLayer.extData = { id: 'satelliteLayer', name: '卫星', type: 'TileLayer' }
map.addLayer(satelliteLayer)
}
if (vectorTileLayer) {
vectorTileLayer.setZIndex(0)
}
satelliteLayer.setZIndex(100)
} else {// 三维
//addCluster(2);
Toast.fail('暂未开发~')
}
this.initMapLayer()
},
1.24 加载wms
addWmsLayer (item) {
var layers='cite:fb30';
var url='http://49.4.95.196:18088/geoserver/cite/wms';
var config = {
version: "1.1.0", //请求服务的版本
layers: layers,
transparent: true, //输出图像背景是否透明
styles: "", //每个请求图层的用","分隔的描述样式
format: "image/png", //输出图像的类型
zIndex: 100
};
if (wmsLayer) {
map.removeLayer(wmsLayer);
}
wmsLayer = new T.TileLayer.WMS(url, config);
map.addLayer(wmsLayer);
},
layers 即为 图层的名称

其他用法
1. 去掉logo
document.getElementsByClassName("tdt-control-copyright tdt-control")[0].style.display = 'none'
2.自定义地图类型/切换地图
如果不需要 api提供的 控制器,则可以 map.setMapType 指定服务
常量
| 常量 | 描述 |
|---|---|
| TMAP_NORMAL_MAP | 此地图类型展示普通街道视图。 |
| TMAP_SATELLITE_MAP | 此地图类型展示卫星视图。 |
| TMAP_HYBRID_MAP | 此地图类型展示卫星和路网的混合视图。 |
| TMAP_TERRAIN_MAP | 此地图类型展示地形视图。 |
| TMAP_TERRAIN_HYBRID_MAP | 此地图类型展示地形和路网的混合视图。 |
if(check_type=='sl'){// 街道/地形
map.setMapType(window.TMAP_NORMAL_MAP);
}else if(check_type=='wx'){// 卫星
map.setMapType(window.TMAP_HYBRID_MAP);
// map.setMapType(window.TMAP_SATELLITE_MAP);
}
通过MapTypeapi提供的 控制器
initMap(lng,lat) {
// vue项目需要先声明 T = window.T,不然后面无法获取到。
var T = window.T;
map = new T.Map('container',{projection: "EPSG:4326"});// 申明天地图采用的坐标系的类型为EPSG:4326,也就是最通用的84坐标系
// 传参中心点经纬度,以及放大程度,最小1,最大18
map.centerAndZoom(new T.LngLat(lng,lat), this.zoom);
// 5.创建地图类型控件
const ctrl = new T.Control.MapType([{
title: '地图',
icon:'http://api.tianditu.gov.cn/v4.0/image/map/maptype/vector.png', //地图控件上所要显示的图层图标(默认图标大小80x80)
layer: window.TMAP_NORMAL_MAP
},{
title: '卫星',
icon:'http://api.tianditu.gov.cn/v4.0/image/map/maptype/satellite.png',
layer: window.TMAP_SATELLITE_MAP
}]);
// 6.将控件添加到地图,一个控件实例只能向地图中添加一次。
map.addControl(ctrl);
},
**注:**如果想实现 自定义 底图切换,则new T.Map('container',{projection: "EPSG:4326"}); 不能指定 EPSG:4326 ,会导致定位严重便宜
var imageURL = "http://t0.tianditu.gov.cn/img_w/wmts?" +"SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles" +"&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=406edc64b943d6cb1a10260f4cae6d27";
//创建自定义图层对象
satelliteLayer = new T.TileLayer(imageURL, {minZoom: 1, maxZoom: 18});
map.addLayer(satelliteLayer);
3. Marker
3.1 setLngLat (lnglat:LngLat) 使用
注意LngLat 格式,否则会报错
// setLngLat (lnglat:LngLat) 使用
var lnglat = new T.LngLat(116.40969,39.89945)
map.setLngLat(lnglat);
4. 删除覆盖物
marker.onRemove();// 从地图中删除覆盖物,后面通过
ap.addOverLay(labelMarker)也无法加到地图中map.removeOverLay(marker); // 从地图中移除覆盖物 ,覆盖物还在,只是不在地图中显示了
overlayGroupMap[key].forEach( marker =>{
// marker.onRemove();// 用这个移除,是删除覆盖物,后期无法通过 map.addOverLay(labelMarker) 添加到地图中的
map.removeOverLay(marker);
})
4. 自定义属性& 点击事件
2种方式
let marker = new T.Marker(new T.LngLat(xy[0], xy[1]),{ icon:icon});
marker.extData = extData // 这里可以像这样给点位添加自定义属性
marker.addEventListener("click", (e) => {
console.log(e.target.extData); // 可以从这里取出自定义的属性
});
let marker = new T.Marker(new T.LngLat(xy[0], xy[1]),{ icon:icon,extData:extData});
marker.extData = extData // 这里可以像这样给点位添加自定义属性
marker.addEventListener("click", (e) => {
console.log(e.target.options.extData); // 可以从这里取出自定义的属性
});
点击事件( 以线路为例)
e.target 表示当前选中的覆盖物对象
marker.addEventListener("click", (e) => {
var currentCheckMarker=e.target;
currentCheckMarker.setWeight(item.strokeWeight_check);// 修改线路宽度
// 设置地图视野
var bounds=currentCheckMarker.getBounds();
map.setViewport([bounds.getSouthWest(),bounds.getNorthEast()]);// 设置地图视野
this_.markerFlashing(currentCheckMarker);// 线路 闪烁
});
5.线路闪烁
var markerFlashingTimer;// 闪烁定时器(用于强行关闭)
markerFlashing(marker){
let temp = 0;
markerFlashingTimer = setInterval(function() {
if (temp <= 10) {
if(temp%2 ==0){
marker.setOpacity(1);
}else{
marker.setOpacity(0);
}
}else if (temp > 4) {
clearInterval(markerFlashingTimer);
markerFlashingTimer = null;
marker.setOpacity(1);
}
temp++;
}, 600);
},
// 关闭闪烁
markerCloseFlashing(){
clearInterval(markerFlashingTimer);// 清除,闪烁功能
if(this.lastCheckMarker){// 上一个选中marker
this.lastCheckMarker.setOpacity(1);
}
},
6. 加载可视区域内的图形
/* 加载当前视角 范围的 GT*/
boundsTowerMarker (callback) {
if (tempTowerLabelMarkerArr != undefined && tempTowerLabelMarkerArr.length > 0) {
tempTowerLabelMarkerArr.forEach(marker => {
map.removeOverLay(marker)
})
tempTowerLabelMarkerArr = []
}
if (this.zoom < this.needTowerZoom) {
return
}
//获取当前视角的
var currentViewRectangle = this.getCurrentViewRectangle()
var voltageGradeCheck = this.getVoltageGradeCheck()//获取当前选中 的 电压等级*
var this_ = this
var tempTowerLabelMarkerArr_ = []
voltageGradeCheck.forEach(function (key, index) {
var itemArr = towerMarkerMap[key]// 获取当前选中的电压等级 下的 GT
if (itemArr == undefined) {
return
}
itemArr.forEach(function (itemObj, index) {
var myLngLat = new T.LngLat(itemObj.position[0], itemObj.position[1])
if (currentViewRectangle.getBounds().contains(myLngLat)) {//如果点在矩形内则输出
var towerMarker = this_._createMarker(itemObj)//GT
var towerLabelMarker = this_._createLabelMarker(itemObj, [-25, -40])// GT名称
map.addOverLay(towerMarker)
map.addOverLay(towerLabelMarker)
towerMarker.on('click', this_.checkMarker)//touchstart
tempTowerLabelMarkerArr_.push(towerMarker)// GT
tempTowerLabelMarkerArr_.push(towerLabelMarker)// GT名称
}
})
})
if (tempTowerLabelMarkerArr_ != undefined && tempTowerLabelMarkerArr_.length > 0) {
tempTowerLabelMarkerArr = tempTowerLabelMarkerArr_
}
if (callback) {
callback(true)
}
},
// 记录当前视角 用于 验证 覆盖物是否在当前视角范围
getCurrentViewRectangle () {
//获取当前视角的
var bounds = map.getBounds()
/// 以前视角的区域创建 Rectangle 用于验证指定图形 是否在当前 区域内
var currentViewRectangle = new T.Rectangle(bounds, {
map: map,
color: '#FFFFFF',
weight: 1,
opacity: 0,
zIndex: 0,
})
return currentViewRectangle
},
7. map.getOverlays() 方法
查询当前地图中添加的覆盖物
为了方便区分覆盖物类型,最好 使用 marker.extData = extData; 自定义属性
8.设置地图视野 setViewport
对于线和面,存在 地图视野的讲法,否则无法看到全貌
var bounds=currentCheckMarker.getBounds();
map.setViewport([bounds.getSouthWest(),bounds.getNorthEast()]);// 设置地图视野
10. 通过 自定义图层 添加 覆盖物
updateMarkerAddMap (key) {
var markers = locaLaryerDataMap.get(key)
if (markers && markers.length > 0) {
if (locaLayer) {
locaLayer.clearLayers()
}
locaLayer = new T.LayerGroup(markers)
map.addOverLay(locaLayer)
} else {
if (locaLayer) {
locaLayer.clearLayers()
}
}
},
11. 图层添加自定义属性
this.lineMarker = _createLineMarker(paths, extData, this.layerCheckActive, this.checkMarker);// 创建线路
// map.addOverLay(this.lineMarker); // 直接 添加到 地图中
// 添加到 自定义图层中
this.lineMarker.extData = { id: 'towerLine', name: lineItem.line_name, type: 'line' }
map.addLayer(this.lineMarker)