地图
天地图基础
官方网址: 天地图国家地理信息公共服务平台
-
登录
-
创建新应用
-
public/index.html
注:代码内{}表示注释,需连同大括号一起替换
<html lang="">
<head>
<script src="http://api.tianditu.gov.cn/api?v=4.0&tk={天地图-应用管理-Key名称}" type="text/javascript"></script>
</head>
</html>
旧项目改用天地图
历史坐标点会有偏移的原因
坐标点偏移原因:使用坐标系不同
百度地图【百度坐标】(BD-09)
天地图【CGCS2000】(2000国家大地坐标系)
高德地图【GCJ-02】(国家测量局02号标准)
参考链接:
链接1: 简单介绍坐标关系
链接2: 对互联网中常见地图的坐标系探讨
转换方法,百度地图bd09II坐标转换天地图CGCS2000坐标
链接1: 百度地图bd09II坐标转换天地图CGCS2000坐标
import { ElMessage } from 'element-plus';
// 转大地坐标系(传前两个参数表示从百度坐标转,传后两个参数表示从高德坐标转)
export const coordinateTransformation: any = (
bdLon: number | undefined,
bdLat: number | undefined,
marsLon: number | undefined,
marsLat: number | undefined
) => {
const mars_point = { lon: 0, lat: 0 };
if (bdLon && bdLat) {
const x_pi = (3.141592653589793 * 3000.0) / 180.0;
//百度坐标转成火星坐标
const x = bdLon - 0.0065;
const y = bdLat - 0.006;
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
mars_point.lon = z * Math.cos(theta);
mars_point.lat = z * Math.sin(theta);
} else if (marsLon && marsLat) {
mars_point.lon = marsLon;
mars_point.lat = marsLat;
} else {
ElMessage.warning('coordinateTransformation方法传参错误!');
return { lng: undefined, lat: undefined };
}
//把火星坐标GCJ02转地球坐标系WGS84
const gcjLon = mars_point.lon;
const gcjLat = mars_point.lat;
const d = delta(gcjLon, gcjLat);
function delta(lon: number, lat: number) {
const PI = 3.141592653589793;
const a = 6378245.0;
const ee = 0.006693421622965943;
let dLon = transformLon(lon - 105.0, lat - 35.0);
let dLat = transformLat(lon - 105.0, lat - 35.0);
const radLat = (lat / 180.0) * PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLon = (dLon * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * PI);
dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * PI);
return {
lon: dLon,
lat: dLat,
};
}
function transformLon(x: number, y: number) {
const PI = 3.141592653589793;
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0;
ret += ((20.0 * Math.sin(x * PI) + 40.0 * Math.sin((x / 3.0) * PI)) * 2.0) / 3.0;
ret += ((150.0 * Math.sin((x / 12.0) * PI) + 300.0 * Math.sin((x / 30.0) * PI)) * 2.0) / 3.0;
return ret;
}
function transformLat(x: number, y: number) {
const PI = 3.141592653589793;
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0;
ret += ((20.0 * Math.sin(y * PI) + 40.0 * Math.sin((y / 3.0) * PI)) * 2.0) / 3.0;
ret += ((160.0 * Math.sin((y / 12.0) * PI) + 320 * Math.sin((y * PI) / 30.0)) * 2.0) / 3.0;
return ret;
}
return {
lng: gcjLon - d.lon,
lat: gcjLat - d.lat,
};
};
边框线
在天地图官方文档中,服务类-行政区划接口返回有:“points”(行政区划范围),但目前实际测试中并没有返回,所以通过一下三种方法设置边缘线。
svg(需要设计人员帮助)
所需数据来源:DataV.GeoAtlas(高德地图)
-
下载svg图片,找设计人员帮忙把svg图片截取一下,移除多余的空白部分。
-
处理后的图片导入项目
-
设置svg背景图
function setSVG() {
let imgURL = require('@/assets/img/chinamap.svg');
var bd = new T.LngLatBounds(new T.LngLat(bounds[0], bounds[1]), new T.LngLat(bounds[2], bounds[3]));
let img = new T.ImageOverlay(imgURL, bd, {
opacity: 1,
alt: '中国',
});
tdtMap.value.addOverLay(img);
}
json转化
所需数据来源:DataV.GeoAtlas(高德地图)
- 下载json文件
- 调用下面的方法
- 将控制台打印的结果拷贝保存到项目中
import { datavJson } from './datavJson';
/**
* 新项目通过这个方法将datav获取的边框线转为天地图坐标线,只需要运行一次,会将转化后的结果打印在控制台
* datavJson:datav拷贝下来的数据
* logList:转化后的结果,格式应为:
* [
* [
* [点lng,点lat], // 单个点
* [点lng,点lat]
* ], // 一条线
* ……
* ]
*/
export const getTransformRes: any = () => {
const logList: any = [];
datavJson.features.map((el) => {
el.geometry.coordinates.map((coordinatesItem) => {
coordinatesItem.map((lineItem) => {
const line: any = [];
lineItem.map((point) => {
const pointObj = coordinateTransformation(undefined, undefined, point[0], point[1]);
line.push([pointObj.lng, pointObj.lat]);
});
logList.push(line);
});
});
});
console.log(logList);
};
bigemap网站获取(可以获取街道数据)
参考文档1:https://blog.csdn.net/weixin_44861708/article/details/114223258
参考文档2:https://www.yuucn.com/a/1565092.html
所需数据来源:
kml文件:http://www.bigemap.com/reader/download/
转geojson:http://www.bigemap.com/reader/download/
展示页完整示例代码(中国范围,后端接口提供每个省相关信息)
<template>
<div ref="tdtMapRef" class="divTdtMap"></div>
<div ref="infoRef" class="infoDiv" v-show="currentWindow.title">
<div class="title">{{ currentWindow.title }}</div>
<div class="contentDiv">弹框详细信息:{{ currentWindow.detail }}</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import { GetMapDataApi } from '@/api/mapData';
import { AnyObject } from '@/types/common';
// 获取接口参数
const unitguid = route.query.unitguid as string;
const tdtMap: any = ref({});
const tdtMapRef = ref(); // 地图
const infoRef = ref(); // 弹框内容
let T = (window as any).T;
let infoWin = new T.InfoWindow();
let administrative = new T.AdministrativeDivision();
let markerIcon = new T.Icon({
iconUrl: require(`@/assets/icon/map_icon.png`), // 自定义标记点图标
iconSize: new T.Point(25, 41), // 标记图标大小
iconAnchor: new T.Point(12, 41), // 标记图标箭头位置
});
// 窗口信息
let currentWindow = reactive({
title: '',
detail: '',
});
const provinceList = ref([]); // 省份信息
let bounds = []; // 范围,new T.LngLat(bounds[0], bounds[1])记录左上点,new T.LngLat(bounds[2], bounds[3])记录右下点
const markersInfo = ref<AnyObject[]>([]); // 标记点与相关信息
onMounted(() => {
try {
initTdtMap(); // 初始化天地图
} catch (error) {
console.log(error);
}
});
onBeforeUnmount(() => {
window.removeEventListener('resize', resizeFn);
});
function initTdtMap() {
tdtMap.value = new T.Map(tdtMapRef.value);
let postStr = {
searchWord: '中国', // 查询关键字
searchType: '1', // 查询类型(0:根据code查询,1:根据名称。)。
needSubInfo: true, // 是否需要下一级信息
needAll: false, // 是否需要所有子节点
needPolygon: true, // 是否需要行政区划范围
needPre: false, // 是否需要上一级所有信息
};
administrative.search(postStr, (res) => {
if (res.getStatus() == 100) {
let data = res.getData()[0];
provinceList.value = data.child ?? []; // 记录省份信息
// console.log(data);
setMap(data);
} else {
res.getMsg();
}
});
}
// 设置中心点、级别和可拖动范围
function setMap(data) {
// 范围、中心点、缩放级别
bounds = data.bound.split(',');
tdtMap.value.centerAndZoom(
new T.LngLat((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2),
4
); // 第一个参数中心点坐标(我这里根据范围自动计算的),第二个参数缩放级别
setPoint(); // 设置标记点
setSVG(); // 设置边缘线背景图SVG
window.addEventListener('resize', resizeFn); // 自适应大小
}
const resizeFn = () => {
try {
tdtMap.value.checkResize();
} catch (error) {
console.log(error);
}
};
// 设置标记点
async function setPoint() {
tdtMap.value.clearOverLays(); // 清空已有标记
// 初始化标记点信息弹框
infoWin = new T.InfoWindow();
infoWin.setContent(infoRef.value);
infoWin.addEventListener('close', function () {
currentWindow.detail = '';
});
let res = await GetMapDataApi({unitguid: unitguid});
if (res) {
markersInfo.value = res?.obj ?? [];
markersInfo.value.map((row) => {
let item: any = provinceList.value.find((el: AnyObject) => el.name?.includes(row.Province)); // 找到对应身份信息
let point = new T.LngLat(item.lnt, item.lat); // 设置点
let marker = new T.Marker(point, { icon: markerIcon }); // 创建标注
tdtMap.value.addOverLay(marker);
marker.addEventListener('mouseover', function () {
currentWindow.title = row?.title || '';
currentWindow.detail = row?.detail || '';
marker.openInfoWindow(infoWin); // 点击标注打开弹框
});
});
}
}
// 设置边缘线背景图SVG
function setSVG() {
let imgURL = require('@/assets/img/chinamap.svg');
var bd = new T.LngLatBounds(new T.LngLat(bounds[0], bounds[1]), new T.LngLat(bounds[2], bounds[3]));
let img = new T.ImageOverlay(imgURL, bd, {
opacity: 1,
alt: '中国',
});
tdtMap.value.addOverLay(img);
}
</script>
<style lang="scss" scoped></style>
.divTdtMap {
margin: 16px;
padding: 0px;
width: 100%;
z-index: 0;
}
:deep(.tdt-infowindow-content-wrapper) {
padding: 0;
width: 150px;
.tdt-infowindow-content {
margin: 0;
width: 150px;
}
}
.infoDiv {
width: 150px;
.title {
padding-left: 10px;
padding-right: 30px;
color: #3a76e4;
background-color: #eaf4ff;
line-height: 30px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.contentDiv {
padding: 10px;
}
}