地图开发

lishihuan大约 16 分钟

地图开发

开发前的想法记录

  • 定义的实体字段
    • id、pid、lng、lat
    • name --> 覆盖物的name,比如点击的时候显示,比label具体,label可能考虑需要讲话比如,只显示杆塔号,而name 显示 线路+杆塔号
    • label --> 做标label标签显示用的
    • type--> 大类
    • subType --> 小类 【主要考虑同一个类型肯能存在多个类型,具体的图标也有他决定】

发布离线地图的多个方法 :https://blog.csdn.net/u014220146/article/details/125012813open in new window

坐标转换工具:https://www.opengps.cn/Map/offset/offset.aspxopen in new window

待整理VUE3-Cesium:https://blog.csdn.net/damadashen/article/details/125354344open in new window

公司: 谷歌地图:31.9344120986,117.2649120808 GCJ-02(火星坐标系) 百度地图:31.9405040000,117.2714210000 腾讯高德:31.9344119085,117.2649256012 GCJ-02(火星坐标系) 图吧地图:31.9378224285,117.2620342812 谷歌地球:31.9364424285,117.2594242812 WGS84坐标系 (奥维地图采集的也是 WGS84坐标系 ) 北纬N31°56′11.19″ 东经E117°15′33.93″

坐标转换

coordtransform 转换用法

coordtransform.js

  • 下载coordtransform

    cnpm i -S coordtransform   
    
  • 引入

    import coordtransform from 'coordtransform';
    

Turf.js中文网 地理空间分析库,处理各种地图算法

Turf.js中文网

1.当前互联网地图的坐标系现状

腾讯、高德是GCJ02坐标系【国标】,百度是BD09坐标系,谷歌、必应是WGS84坐标系,天地图是CGCS2000坐标系,瓦片地图都是平面墨卡托投影。WGS84和CGCS2000坐标系,近似认为它们相等就可以了。

地球坐标 (WGS84)

WGS84 是为 GPS 全球定位系统建立的坐标系统,是世界上第一个统一的地心坐标系,因此也被称为大地坐标系、原始坐标系。一般通过 GPS 记录仪记录下来的经纬度,就是基于 WGS84 坐标系的数据。Google 和高德地图定位的的经纬度(国外)都是基于WGS84坐标系的;但是在国内是不允许直接用 WGS84 坐标系标注的,必须经过加密后才能使用 【不是获取不到,比如奥维地图 就能采集到WGS84 坐标系的数据。国内地图 APP、地图 SDK、地图服务 必须把坐标加密后才能显示】

  • 国际标准,从 GPS 设备中取出的数据的坐标系【GPS 硬件:永远输出 WGS84,比如安卓原生开发获取的GPS坐标系就是WGS84 】

  • 国际地图提供商使用的坐标系谷歌地球 osm、谷歌、arcgisonline

火星坐标 (GCJ-02)也叫国测局坐标系

  • 中国标准,从国行移动设备中定位获取的坐标数据使用这个坐标系

  • 国家规定: 国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密。

    腾讯(搜搜)地图、阿里云地图、Google和高德(国内)都是使用 GCJ02 坐标系

百度坐标 (BD-09)

  • 百度标准,百度 SDK,百度地图,Geocoding 使用
  • 在火星坐标上来个二次加密

天地图

天地图采用的是CGCS-2000坐标系(2000坐标系),但是因为CGCS-2000坐标系它与WGS84坐标系都是地心坐标系,因此两者相差不大。况且,考虑到EPSG(地图的一种唯一身份标识),天地图在调用初始化的时候,可以申明天地图采用的坐标系的类型为EPSG:4326,也就是最通用的84坐标系,如下图:

const map = new T.Map(id, { projection: "EPSG:4326" });

其他说明

水经注下载的地图,arcgis提供的卫星图是WGS84 ,矢量图等都是 GCJ-02 ,天地图全部 CGCS-2000 可以看作是 WGS84

可以认为天地图和arcgis使用的是WGS84,所以再选择自己发布的底图服务是存在位移的,如果想正常使用,可以将卫星和矢量图都换成同一坐标系下的

  1. 高德地图 (Amap)
    • 使用 GCJ02 坐标系。
  2. 百度地图 (Baidu Maps)
    • 使用 BD-09 坐标系。
  3. GPS
    • 使用 WGS84 坐标系。
  4. 谷歌地图 (Google Maps)
    • 使用 WGS84 坐标系(在中国大陆地区使用 GCJ02)。
  5. 腾讯地图 (Tencent Maps)
    • 使用 GCJ02 坐标系。
  6. 图吧地图 (Mapbar)
    • 使用 GCJ02 坐标系。
  7. 谷歌地球 (Google Earth)
    • 使用 WGS84 坐标系。

底图服务

街道图,卫星图,地形图

https://blog.csdn.net/qq_51424616/article/details/121384481open in new window

WMS、WFS、WMTS服务接口说明

https://blog.csdn.net/Tmraz/article/details/108749365open in new window

地图开发选型

https://blog.csdn.net/QQ98281642/article/details/117514585open in new window

https://blog.csdn.net/gis_witch/article/details/123419231open in new window

https://blog.csdn.net/gis1205/article/details/126299338open in new window

img
img

地图核心库对比

库 / 平台功能侧重优点(偏应用)典型使用建议缺点 / 风险(关键)商用
OpenLayers全功能地图引擎• 支持点线面、聚合、热力、轨迹、专题图
• 坐标/投影支持最强(WGS84/GCJ02/自定义)
• 离线/内网/专网完全可控
• 开源、免费、可商用
复杂应用地图 / 内网系统 / 长期项目• 上手成本高
• 需要自己组织业务能力(搜索/定位)
• 视觉偏“工程风”
能商用,
可以部署离线瓦片或者申请天地图瓦片
Leaflet轻量地图• 体积小,上手快
• 插件生态丰富
• 适合简单点线面
小型项目 / 快速原型• 海量点性能弱
• 专题图能力有限
• 投影/坐标支持弱
能商用【同上】
高德地图 JS API业务地图服务定位 / 搜索 / 路径规划天花板
• 聚合、热力、轨迹、动画现成
• 文档齐全,Demo 多
• 对业务地图非常友好
公网项目 / 效率优先❌ 坐标强制 GCJ02
❌ 底图不能离线
❌ 内网/专网基本不可用
⚠️ 商用调用量 & 合规风险
收费
百度地图 JS API百度生态地图• API 简单
• 覆盖面广
不推荐新项目❌ BD09 二次加密坐标
❌ 与其他地图体系兼容差
❌ GIS & 内网不友好
收费
天地图 JS官方地图• 合规性强
• 行政区数据权威
政务/强合规项目• SDK 能力弱
• 文档和示例少
• 交互体验一般
免费,需要申请【注册企业开发者调用量会大很多】
Cesium3D 地球引擎3D 视觉效果非常强
• 支持轨迹、飞线、时间轴
• 地形/高程/空间可视化优秀
三维展示 / 可视化❌ 不是 2D 地图引擎
❌ 学习成本高
❌ 做常规业务地图很重
只用引擎 + 自建数据 → 免费、可商用、可内网
调用官方瓦片 / 高程 / 3D Tiles → 收费、需 API Key
引擎 + 自建数据 → 免费
ArcGIS JS API商业 GIS 平台• 功能全面
• 专业 GIS 能力强
已采购 ArcGIS❌ 不开源
❌ 商用需授权
❌ 强绑定 Esri 生态
不能商用
Mapbox GL JS(v2+)WebGL 矢量地图• 视觉效果优秀
• 矢量地图体验好
不推荐新项目❌ 商用收费
❌ License 风险大
❌ 国内合规问题
不能商用
Turf.js空间分析库• 缓冲、裁剪、叠加等空间分析
• 与 OL/Leaflet 配合好
专题图 / 空间计算• 不负责渲染
• 必须配合地图引擎

功能支持度对照表

功能 / 框架高德地图百度地图天地图OpenLayersLeafletArcGIS JSCesium
点 / 线 / 面
自定义图标⚠️
GIF 动态点⚠️(hack)⚠️⚠️
海量点⚠️⚠️
点聚合⚠️⚠️
热力图⚠️⚠️
图层切换⚠️⚠️⚠️⚠️
行政区描边 / 高亮⚠️⚠️⚠️⚠️
搜索(POI)⚠️❌(接服务)⚠️
定位⚠️⚠️⚠️
轨迹 / 动画⚠️⚠️
分级设色专题图⚠️⚠️⚠️⚠️
2D 地图
3D 地图⚠️(外接)
离线 / 内网⚠️⚠️
多坐标系⚠️⚠️⚠️
商用自由度⚠️⚠️⚠️

辅助网站

  1. 在线直观绘制或可视化图形,获取GeoJSON数据。 http://geojson.ioopen in new window

  2. 在线转换地图文件,主要包括Shapefile、GeoJSON、TopoJSON、DBF、CSV。 https://mapshaper.org/open in new window

  3. 在线获取行政边界数据 http://datav.aliyun.com/portal/school/atlas/area_selectoropen in new window

    https://hxkj.vip/demo/echartsMap/open in new window

    http://horizon2021.xyz/open in new window

    https://zhuanlan.zhihu.com/p/114711062open in new window

  4. GPS,经度,纬度,距离在线计算器

    https://www.osgeo.cn/app/s1884open in new window

  5. 预览/编辑geojson数据:【比如场景:生成的中国GeoJSON 文件中包含省界,需要去掉,只要最外围】

http://geojson.ioopen in new window

https://www.strerr.com/geojson/geojson.htmlopen in new window

  1. GCJ-02坐标系转换为WGS84坐标系。解决方案有两种:

ESRI Shapefile(SHP)格式数据处理

  • 将其转为GeoJSON格式来使用
  • 通过geoserver发布shp服务【可以在QGIS 设置样式,这样发布的shp服务,直接加载地图中就能使用】
  • 通过网站 https://mapshaper.org/open in new window 导入 .shp+.shx+.dbf 文件【3个文件一起导入,否则不完整】 然后导出GeoJSON格式
  • QGIS打开方式:启动 QGIS → 点击左侧「浏览器」→ 找到 SHP 文件所在文件夹 → 双击.shp文件即可加载; 结合geoserver 发布shp服务【直接在地图服务中加载,类似GeoJSON直接加载数据,其中样式可以在QGIS 中设置,发布后直接就能看到效果】
image-20260206175045903
image-20260206175045903

java组装GeoJSON格式数据

/**
	 * 根据 类型 组装 GeoJSON 格式数据
	 *
	 * @return
	 */
	public JSONObject createGeoJSONForPointByType(List<MapPointVo> queryList) {
		// 数据分组
		Map<String, List<MapPointVo>> groupMap = Maps.newHashMap();
		for (MapPointVo mapPointVo : queryList) {
			String key = mapPointVo.getSubType();
			//============containsKey是用来判断某个key是否存在
			if (!groupMap.containsKey(key)) { //=====不存在就新new一个map对象,并将此时的设备名称作为key存入。
				groupMap.put(key, Lists.newArrayList());
			}
			groupMap.get(key).add(mapPointVo);
		}

		JSONObject GeoJSONMap = new JSONObject();
		for (String key : groupMap.keySet()) {
			List<MapPointVo> groupArr = groupMap.get(key);
			GeoJSONMap.put(key, createGeoJSONForPoint(groupArr));
		}
		return GeoJSONMap;
	}
	// 返回的是 GeoJSON 中的features 数组 ,其他格式由 前端 更具需要 组装数据
	public JSONArray createGeoJSONForPoint(List<MapPointVo> groupArr) {
//		JSONObject root = new JSONObject();
//		root.put("type","FeatureCollection");
		JSONArray features = new JSONArray();
		for (MapPointVo mapPointVo : groupArr) {
//			JSONObject item = new JSONObject();
//			item.put("type","Feature");
//
//			JSONObject geometry = new JSONObject();
//			geometry.put("type","Point");
//			JSONArray coordinates = new JSONArray();
//			coordinates.add(0,Float.parseFloat(mapPointVo.getLng()));// 经度
//			coordinates.add(1,Float.parseFloat(mapPointVo.getLat()));// 纬度
//			geometry.put("coordinates",coordinates);
//			item.put("geometry",geometry);
			JSONObject properties = new JSONObject();// 存储 参数
			properties.put("id", mapPointVo.getId());
			properties.put("name", mapPointVo.getName());
			properties.put("labelName", mapPointVo.getLabelName());
			properties.put("type", mapPointVo.getType());
			properties.put("subType", mapPointVo.getSubType());
			properties.put("lng", Float.parseFloat(mapPointVo.getLng()));
			properties.put("lat", Float.parseFloat(mapPointVo.getLat()));
//			item.put("properties",properties);

			String itemStr = " { 'type': 'Feature'," +
					"      'geometry': {'type': 'Point', 'coordinates': [" + Float.parseFloat(mapPointVo.getLng()) + ',' + Float.parseFloat(mapPointVo.getLat()) + "]}," +
					"      'properties': " + properties.toString() +
					" }";

			JSONObject item = JSONObject.fromObject(itemStr);
			features.add(item);
		}
		//root.put("features",features);
		return features;
	}

坐标获取

https://cloud.tencent.com/developer/article/2220490open in new window

奥维地图apk

奥维地图 获取2个坐标

  • 第一个是wgs84 【经纬度】-- 不区分国内国外,标准的经纬度
  • 第二个是 火星坐标系【高德坐标系/国标】
image-20251011150545728
image-20251011150545728

H5通过原生定位

需要通过https

navigator.geolocation.getCurrentPosition(pos => {
  console.log('GPS坐标:', pos.coords.latitude, pos.coords.longitude);
}, error => console.error('用户拒绝授权或定位失败'));

纯IP定位(无需HTTPS)

  • 实现原理:通过客户端IP地址调用第三方接口解析地理位置(城市级精度,误差1-10公里)。
  • 示例代码(天地图API):
fetch('http://api.tianditu.gov.cn/geocoder?ds={"keyWord":"IP定位"}&tk=YOUR_KEY')
  .then(response => response.json())
  .then(data => console.log(data.location));
  • 优势:无需用户授权,兼容性强
  • 限制:仅适合粗略位置需求(如地域统计)。

通过IP地址查询位置信息

fetch('http://ip-api.com/json/你的IP?fields=61439&lang=zh-CN')
  .then(res => res.json())
  .then(data => console.log(data.lat, data.lon));

1. ip-api.comopen in new window

  • 请求示例

    JavaScriptfetch('http://ip-api.com/json/你的IP?fields=status,lat,lon&lang=zh-CN')
      .then(res => res.json())
      .then(data => console.log(data.lat, data.lon))
    

    特性

    • 支持HTTP协议,返回字段lat(纬度)、lon(经度)
    • 免费版每分钟45次请求,误差约城市级(1-10公里)。

2. ip2location.ioopen in new window

  • 请求示例

    JavaScriptfetch('https://api.ip2location.io/?key=YOUR_KEY&ip=IP地址')
      .then(res => res.json())
      .then(data => console.log(data.latitude, data.longitude))
    

    特性

    • 返回字段latitude/longitude 需注册免费API密钥
    • 支持HTTP/HTTPS,精度与ip-api类似。

IP 数据云

IP 数据云支持全球IP 定位,速度快,免费 1000次/日

官网地址:https://www.ipdatacloud.com/open in new window

API 使用方法

代码语言:javascript

https://api.ipdatacloud.com/v2/query?ip={待查询 IP}&key={用户 Key}

调用示例:

https://api.ipdatacloud.com/v2/query?ip=101.88.133.75&key=xxxxxxxxxxxx-->{"code":200,"data":{"area_code":"310100","city":"上海","city_code":"021","continent":"亚洲","country":"中国","country_code":"CN","country_english":"","district":"","elevation":"15","ip":"101.88.133.75","isp":"电信","latitude":"31.231706","local_time":"2023-01-17 22:56","longitude":"121.472644","province":"上海","street":"","version":"V4","weather_station":"CHXX0116","zip_code":"200000"},"msg":"success"}

速度很快

demo通过 ip-api 查询IP然后通过Ip查询GPS信息

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>公网IP与坐标查询</title>
    <style>
        #result { padding: 20px; margin: 20px; border: 1px solid #ccc; }
        button { padding: 10px; background: #007bff; color: white; border: none; cursor: pointer; }
    </style>
</head>
<body>
    <button onclick="getIP()">点击获取公网IP和坐标</button>
    <div id="result">等待数据...</div>

    <script>
        // 可替换的API列表(按优先级排序)
        const API_LIST = [
            'http://ip-api.com/json/?fields=61439&lang=zh-CN', // 综合数据API
            'https://api.seeip.org/jsonip?',                    // 备用API1
            'https://ipinfo.io/json'                             // 备用API2
        ];

        async function fetchIP(apiUrl) {
            try {
                const response = await fetch(apiUrl);
                if (!response.ok) throw new Error('API响应异常');
                return await response.json();
            } catch (error) {
                console.warn(`${apiUrl} 请求失败,尝试备用API`);
                return null;
            }
        }

        async function getIP() {
            let result = document.getElementById('result');
            result.innerHTML = '数据加载中...';

            // 顺序尝试API列表
            for (const api of API_LIST) {
                const data = await fetchIP(api);
                if (data) {
                    const output = `
                        <p>公网IP:${data.ip || data.query}</p>
                        <p>经纬度:${data.lat || data.latitude}, ${data.lon || data.longitude}</p>
                        <p>位置:${data.country} ${data.regionName} ${data.city}</p>
                        <p>运营商:${data.isp || data.org}</p>
                    `;
                    result.innerHTML = output;
                    return;
                }
            }
            
            result.innerHTML = '所有API均请求失败,请稍后重试或检查网络';
        }
    </script>
</body>
</html>

EPSG:3857 和 EPSG:4326

坐标投影选择 : WGS84 Web墨卡托投影(EPSG:3857)

  • EPSG:4326(WGS84,经纬度)

    • 坐标: [经度, 纬度](单位:度)
    • 范围: 经度 -180~180,纬度 -90~90
    • 用途: 通用标准坐标系,定位、接口、数据库常用
    • 优缺点: 保持真实经纬度;不能直接用于 Web 瓦片切图(非等距,缩放不均匀)
  • EPSG:3857(Web Mercator,Web 墨卡托)

    • 坐标: 平面米(单位:米)
    • 范围: x 约 -20037508~20037508,y 同
    • 用途: Web 地图瓦片的行业标准(Google/OSM/高德/WMTS 常用)
    • 优缺点: 贴图/切片效率高,缩放分辨率规则;高纬度形变大(面积被拉伸)

在 OpenLayers 中怎么用

  • 地图 View 通常用 EPSG:3857(便于加载切片):
new View({ projection: 'EPSG:3857', center: fromLonLat([117.27, 31.88]), zoom: 10 })
  • 经纬度转 Web 墨卡托(4326 -> 3857):
import { fromLonLat } from 'ol/proj'
const xy3857 = fromLonLat([lng, lat]) // 输入经纬度
  • Web 墨卡托转经纬度(3857 -> 4326):
import { toLonLat } from 'ol/proj'
const [lng, lat] = toLonLat([x, y]) // 输出经纬度

选择建议

  • 需要显示瓦片图(WMTS/XYZ)→ 用 EPSG:3857
  • 需要存储/交互真实坐标、对接接口/GIS 数据 → 用 EPSG:4326,渲染时再转换为 3857

如果你计划后续切换到卫星图层(如 ahwx16),继续使用 EPSG:3857 是最佳实践;点、线、面数据可用 4326 存储,渲染前用 fromLonLat 转换即可。

地图瓦片介绍

XYZ瓦片与WMTS瓦片对比总结

1)概述

地图瓦片是将大幅地图切分成小块图片的技术,主要有两种标准:XYZ瓦片(事实标准)和WMTS瓦片(OGC标准)

目前XYZ瓦片 可以配合nginx 直接使用,而WMTS瓦片需要使用GeoServerMapServer 进行部署【本身服务就存在漏洞,在严格情况下可能无法使用】

2) 选型

选择XYZ瓦片的情况:

  • ✅ 简单的地图展示需求
  • 希望部署简单(只需nginx) -- 也是选择XYZ瓦片 的优势
  • ✅ 瓦片数据相对固定
  • ✅ 性能要求高

选择WMTS瓦片的情况:

  • ✅ 需要多种坐标系支持
  • ✅ 需要动态样式切换
  • ✅ 企业级GIS应用
  • ✅ 需要丰富的元数据

3)瓦片生成工具

XYZ瓦片生成:

WMTS瓦片生成:

  • GeoServer - 最常用 【目前被扫除有漏洞】
  • MapServer - 开源选择
  • ArcGIS Server - 商业方案

水经注离线地图下载

https://blog.csdn.net/m0_53584457/article/details/136217224open in new window

image-20251013101211946
image-20251013101211946
image-20250923192344524
image-20250923192344524

水经注的"导出大图、导出瓦片、导出离线包"是第三种导出方式介绍

离线地图开发

1.下载地图瓦片

通过水经注,目前有2种方式 水经注离线地图下载

  • WMTS瓦片 需要通过通过 GeoServer 来发布服务 geoserver发布服务
  • XYZ瓦片,通过nginx代理可使用

2.通过OpenLayers 实现离线地图的加载

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>OpenLayers 离线 XYZ 瓦片 Demo</title>

  <!-- OpenLayers -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@7.5.2/ol.css">
  <script src="https://cdn.jsdelivr.net/npm/ol@7.5.2/dist/ol.js"></script>

  <style>
    html, body {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
    }
    #map {
      width: 100%;
      height: 100%;
    }
  </style>
</head>
<body>

<div id="map"></div>

<script>
  // 离线 XYZ 瓦片图层
  const offlineLayer = new ol.layer.Tile({
    source: new ol.source.XYZ({
      url: 'http://localhost:8080/tiles/osm/{z}/{x}/{y}.png',
      minZoom: 0,
      maxZoom: 18
    })
  });

  // 地图
  const map = new ol.Map({
    target: 'map',
    layers: [
      offlineLayer
    ],
    view: new ol.View({
      projection: 'EPSG:3857',
      center: ol.proj.fromLonLat([117.150471, 31.833143]), // 安徽附近
      zoom: 7
    })
  });
</script>

</body>
</html>

OpenLayers 学习

地图涉及到相关功能清单

  • 构造地图
  • 切片加载
  • 点【自定义图标(能支持gif ,提高选中效果)】
  • 线
  • 海量点标记
  • 聚合
  • 热力
  • 图层切换
  • 行政区域规划[描边,比如凸显安徽区域]
  • 选中效果&搜索定位【高亮&闪烁&定位&最佳视角】
  • 轨迹【比如模拟出一个人员巡视的路线,模拟看用户的行进路径】
  • 2D,3D
  • 分级设色专题图
  • 事件监听
  • 沿线文字样式
  • 动态样式函数和静态样式

地图开发触屏双指缩放导致页面变化

1️⃣ 防止浏览器页面缩放 - index.html

<!-- 之前 -->
<meta name="viewport" content="... maximum-scale=1, user-scalable=no">

<!-- 现在 -->
<meta name="viewport" content="... maximum-scale=1, minimum-scale=1, user-scalable=no">
                                                    ↑新增
/* 之前 */
html, body, #app {
  height: 100%;
}

/* 现在 */
html, body, #app {
  height: 100%;
  touch-action: pan-x pan-y;  /* 只允许水平/垂直平移,禁止缩放 */
}

2️⃣ 地图容器特殊处理 - OlMap.vue

.map {
  flex: 1;
  touch-action: none;  /* 地图内触摸完全由OpenLayers接管 */
}

作用分层:

  • 页面级别(html/body):禁止双指缩放页面
  • 地图容器(.map):允许OpenLayers处理触摸(地图平移、缩放)