【Leaflet + 天地图】通过经纬度、角度方向、距离(米)计算偏移后的经纬度
一、天地图
1.1 简介
百度和高德是大家经常使用的地图平台,他们的优点非常多,它们存在着广大的开源社区。但是缺点也非常明显,如不能对卫星图进行较大级别的查看,很多地区存在无法查看的现象。
那么在很多业务场景中需要我们查看清晰的卫星图,怎么办呢?这就用到了天地图。
天地图:“天地图”是国家测绘地理信息局建设的地理信息综合服务网站。它是“数字中国”的重要组成部分,是国家地理信息公共服务平台的公众版。“天地图”的目的在于促进地理信息资源共享和高效利用,提高测绘地理信息公共服务能力和水平,改进测绘地理信息成果的服务方式,更好地满足国家信息化建设的需要,为社会公众的工作和生活提供方便。
它是国家绘制地理信息局建设的,依靠着强大的背景,也就完全避免了上述两种地图的问题,但是区域仅限于中国
官网地址
数字化管理平台
Vue3+Vite+VueRouter+Pinia+Axios+ElementPlus
个人博客
使用天地图,需要先到官网(国家地理信息公共服务平台 天地图)进行注册并登录。

找到开发资源->地图API,可以看到地图服务列表
找到 网页API->JavaScript API 查看相关实例和类参考。
1.2 实现天地图一个简单的渲染需要六步:
-
准备页面
<!DOCTYPE html> <html> <head><meta charset="UTF-8"/><title>HELLO WORLD</title><script type="text/javascript" src="http://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥"></script><script>var map;var zoom = 12;function onLoad() {map = new T.Map('mapDiv');map.centerAndZoom(new T.LngLat(116.40769, 39.89945), zoom);}</script> </head> <body onLoad="onLoad()"> <div id="mapDiv" style="position:absolute;width:500px; height:400px"></div> </body> </html> -
引入天地图 JS 文件
<script src="http://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥" type="text/javascript"></script> -
创建容器元素
地图需要一个HTML元素作为容器,这样才能展现到页面上。这里我们创建了一个div元素。将div元素的宽和高分别设置为100%,使其充满整个屏幕,或者您也可以计算浏览器窗口的大小并进行设置。 -
创建地图实例
//初始化地图对象 var map=new T.Map('mapDiv'); -
确定经纬度坐标
var lnglat = new T.LngLat(116.40969,39.89945)这里我们使用T命名空间下的T.Lnglat类来创建一个坐标点。T.Lnglat类描述了一个地理坐标点,其中116.40969表示经度,39.89945表示纬度。
-
地图初始化
map.centerAndZoom(lnglat,12);在创建地图实例后,我们需要对其进行初始化,map.centerAndZoom方法要求设置中心点坐标和地图级别。 地图必须经过初始化才可以执行其他操作。
1.3 工具类代码
var lineConfig = {showLabel: true,color: 'red'
};var lineTool = new T.PolylineTool(this.map, lineConfig); // 创建测距工具lineTool.open() // 打开测距工具 可以开始打点测距lineTool.close() ;// 关闭测距工具lineTool.clear() ;// 清除所有点var polygonConfig = {showLabel: true,color: "red", weight: 3, opacity: 0.5, fillColor: "#FFFFFF", fillOpacity: 0.5
};var polygonTool = new T.PolygonTool(this.map, polygonConfig);// 创建测面工实例, 其使用方式与测距相同
1.4 信息窗体显示与隐藏
var infoWindow = new T.InfoWindow(); // 创建信息窗体实例infoWindow.setContent(''); // 设置信息窗体内容, 也可以在vue中使用refinfoWindow.setLngLat(new T.LngLat(e['lnglat']['lng'], e['lnglat']['lat'])); // 设置信息窗标准点map.addOverLay(infoWindow);// 打开信息窗体map.removeOverLay(infoWindow);//关闭信息窗体
1.5 地图上标记点
var icon = new T.Icon({iconUrl: imgsrc, // 图标urliconSize: new T.Point(30, 40) // 图标大小}); // 创建标记点使用的图标var marker = new T.Marker(new T.LngLat(info['oriLongitude'] , info['oriLatitude']), {icon: icon}) ; // 创建标记点实例, 第一个参数为坐标点天地图经纬度, 第二个参数是配置项map.addOverLay(marker); // 显示此坐标点map.removeOverLay(marker); // 隐藏此坐标点marker.addEventListener("click", callback); // 绑定marker的点击事件, 这里我们可以做一些操作, 比如弹出信息窗体等
1.5 绘制线
var line = new T.Polyline(path, {weight: 8,opacity: 0.7}); //path为天地图经纬度数组,第二个参数为配置项map.addOverLay(line); // 绘制线到地图上map.removeOverLay(line);// 移除线
其它相关绘制如:绘制圆、多边形等详见官方文档,不再一一赘述。
二、Leaflet
2.1 简介
Leaflet.js 是目前最流行的映射库之一。它是一个灵活、轻量级的开源 JavaScript 库,用于创建交互式地图。 它大小仅仅只有 42 KB of JS, 并且拥有绝大部分开发者所需要的所有地图特性 。
Leaflet 是一个用于呈现地图数据的框架。数据以及底图图层必须由开发人员提供。地图由切片图层以及浏览器支持、默认交互性、平移和缩放功能组成。您还可以添加更多自定义图层和插件,以及 Leaflet 中的所有映射。该地图库将您的数据转换为地图图层,并提供出色的支持,使其成为大多数开发人员的首选。它在主要的桌面和移动平台上运行良好,使其成为移动和大屏幕地图的完美 JavaScript 库。
Leaflet 中文站点
Leaflet 官方站点

一些 Leaflet 简单的使用,如:设置 Leaflet 地图、使用标记、折线和弹出窗口,以及处理事件。

2.2 准备一个html页面,并引入相应的文件
- 在文档的 head 部分引入 Leaflet CSS 文件:
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="crossorigin=""/>
- 在引入 Leaflet CSS 文件之后引入 Leaflet JavaScript 文件:
<!-- Make sure you put this AFTER Leaflet's CSS --><script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="crossorigin=""></script>
- 将具有特定 id 的 div 元素放置在你希望地图所在的位置:
<div id="map"></div>
- 确保地图容器定义了固定高度,例如在 CSS 中设置:
#mapid { height: 180px; }
2.3 初始化地图并设置地理坐标、缩放级别
var map = L.map('map').setView([51.505, -0.09], 13);
默认情况下,地图上的所有鼠标和触摸交互都处于启用状态,并且具有缩放和属性控制。
setView 调用还会返回地图对象,事实上大多数 Leaflet 方法在不返回显式值时的行为都是这样的,这允许你可以很方便的进行类似 jQuery 的链式调用。
2.4 添加一个瓦片(Tile)图层到地图中
创建一个瓦片(Tile)图层通常会涉及为瓦片(Tile)图像、归属文本和图层的最大缩放级别设置 URL 模板。
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom: 19,attribution: '© OpenStreetMap'
}).addTo(map);
确保引入 leaflet.js 文件并配置好 div 后运行所有代码。就是这样,你现在拥有一个运行正常的 Leaflet 地图。
2.5 绘制标记、圆和多边形
-
绘制标记点
var marker = L.marker([51.5, -0.09]).addTo(map); -
绘制圆形
var circle = L.circle([51.508, -0.11], {color: 'red',fillColor: '#f03',fillOpacity: 0.5,radius: 500 }).addTo(map); -
绘制多边形
var polygon = L.polygon([[51.509, -0.08],[51.503, -0.06],[51.51, -0.047]]).addTo(map);
2.6 添加 popups

当您想将某些信息附加到地图上的特定对象时,通常会使用 Popups。Leaflet 有一个快捷方式:
marker.bindPopup("Hello world!
I am a popup.").openPopup();
circle.bindPopup("I am a circle.");
polygon.bindPopup("I am a polygon.");
尝试点击我们的对象。该 bindPopup 方法将带有指定 HTML 内容的弹出窗口附加到您的标记,以便在您单击对象时显示弹出窗口,并且该 openPopup 方法(仅适用于标记)立即打开附加的弹出窗口。
2.7 处理事件
每次在 Leaflet 中触发某些事件时,例如用户单击标记或地图缩放更改,相应的对象都会发送一个事件,您可以使用函数订阅该事件。它允许您对用户交互做出反应:
function onMapClick(e) {alert("You clicked the map at " + e.latlng);
}map.on('click', onMapClick);
监听器、函数的第一个参数是一个事件对象——它包含关于发生的事件的有用信息。例如,地图点击事件对象(在上面的例子中的e)有一个 latlng 属性,它是点击发生的位置。
通过使用 popup 而不是 alert 来改进示例:
var popup = L.popup();function onMapClick(e) {popup.setLatLng(e.latlng).setContent("You clicked the map at " + e.latlng.toString()).openOn(map);
}map.on('click', onMapClick);
其它详情文档

2.8 其它一些插件
- Leaflet.pm插件
- Leaflet.draw插件
三、根据一个经纬度及距离角度,算出另外一个经纬度
/*** 根据一个经纬度及距离角度,算出另外一个经纬度* @param {*} lng 经度 113.3960698* @param {*} lat 纬度 22.941386* @param {*} brng 方位角 45 ---- 正北方:000°或360° 正东方:090° 正南方:180° 正西方:270°* @param {*} dist 90000距离(米)* 1、角度转换为弧度公式:弧度=角度×(π ÷度180 )* 2、弧度转换为角度公式: 角度=弧度×(180÷π)
*/
function getLonAndLat(lng, lat, brng, dist) {//大地坐标系资料WGS-84 长半径a=6378137 短半径b=6356752.3142 扁率f=1/298.2572236var a = 6378137;var b = 6356752.3142;var f = 1 / 298.257223563;var lon1 = lng * 1;var lat1 = lat * 1;var s = dist;var alpha1 = brng * (Math.PI / 180)//mapNumberUtil.rad(brng);var sinAlpha1 = Math.sin(alpha1);var cosAlpha1 = Math.cos(alpha1);//var tanU1 = (1 - f) * Math.tan(mapNumberUtil.rad(lat1));var tanU1 = (1 - f) * Math.tan(lat1 * (Math.PI / 180));var cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1;var sigma1 = Math.atan2(tanU1, cosAlpha1);var sinAlpha = cosU1 * sinAlpha1;var cosSqAlpha = 1 - sinAlpha * sinAlpha;var uSq = cosSqAlpha * (a * a - b * b) / (b * b);var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));var sigma = s / (b * A), sigmaP = 2 * Math.PI;while (Math.abs(sigma - sigmaP) > 1e-12) {var cos2SigmaM = Math.cos(2 * sigma1 + sigma);var sinSigma = Math.sin(sigma);var cosSigma = Math.cos(sigma);var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));sigmaP = sigma;sigma = s / (b * A) + deltaSigma;}var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;var lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,(1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));var L = lambda - (1 - C) * f * sinAlpha *(sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));var revAz = Math.atan2(sinAlpha, -tmp); // final bearingvar lngLatObj = { lng: lon1 + L * (180 / Math.PI), lat: lat2 * (180 / Math.PI) }return lngLatObj;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
