打造一个简洁实用的经纬度查询工具

打造一个简洁实用的经纬度查询工具

最近折腾了一个基于Web的经纬度查询工具,挺有意思的,分享一下开发过程和心得。

我是先做了这个网页再改成小程序。本次将web端版本开源。

这个工具主要是为了方便查询地图上的经纬度坐标,支持实时显示鼠标位置的坐标、点击固定坐标点,还能切换不同的地图和坐标格式,适合需要快速定位或者研究地图数据的朋友。

image-20250821160740217

项目背景

有时候我们需要精确地获取某个地点的经纬度,比如做地理信息相关的开发、户外活动规划,或者只是单纯好奇某个地方的坐标。市面上虽然有不少地图工具,但要么功能复杂,要么需要注册账号,或者界面不够直观。于是我就想着自己动手做一个简单易用的工具,核心需求是:

  • 支持高德地图和OpenStreetMap切换
  • 鼠标移动时实时显示坐标
  • 点击地图可以固定坐标点
  • 支持GCJ02、WGS84三种坐标系转换
  • 界面简洁,适配手机和电脑

最终成品是一个纯前端的Web应用,部署在GitHub Pages上,打开浏览器就能用,体验还不错。

功能亮点

这个工具虽然简单,但功能还算实用:

  1. 双地图支持:可以切换高德地图和OpenStreetMap。高德地图适合国内场景,OpenStreetMap则是国际通用,数据覆盖全球。
  2. 实时坐标显示:鼠标在地图上移动时,右下角会实时显示当前坐标,精确到小数点后6位。
  3. 固定坐标:点击地图会在点击位置添加一个标记,同时显示固定坐标,方便记录特定地点的经纬度。
  4. 坐标格式切换:支持小数点格式(比如116.404, 39.904)和度分秒格式(比如116°24’14.4”E, 39°54’14.4”N),满足不同使用习惯。
  5. 坐标系转换:内置了GCJ02(高德/腾讯地图用)、WGS84(GPS原始坐标)、BD09(百度地图用)之间的转换逻辑,确保坐标在不同场景下都能用。
  6. 地名搜索:输入地名可以直接定位到对应地点,比如输入“北京天安门”就能跳转过去。
  7. 响应式设计:界面适配了手机和电脑,触摸屏也能很好地操作。

在线体验地址:https://ytkz.tech/querygps/

技术实现

整个项目用的是前端技术栈,主要包括HTML5、CSS3、JavaScript(ES6+),地图功能基于Leaflet.js实现。以下是核心部分的开发思路。

1. 地图初始化

用Leaflet.js来渲染地图,初始化时默认显示中国中心位置(北京,坐标[39.9042, 116.4074],缩放级别10)。支持两种地图图层:

  • 高德地图:通过高德的瓦片服务API加载,国内体验更好。
  • OpenStreetMap:用标准的OSM瓦片服务,适合国际场景。

代码上,先初始化地图容器,然后添加图层切换逻辑:

initMap() {
    this.map = L.map('map', {
        center: [39.9042, 116.4074], // 北京坐标
        zoom: 10,
        zoomControl: true,
        attributionControl: false
    });
    this.initMapLayers();
}

initMapLayers() {
    this.mapLayers.gaode = L.tileLayer('https://webst0{s}.is.autonavi.com/appmaptile?style=7&x={x}&y={y}&z={z}', {
        subdomains: ['1', '2', '3', '4'],
        attribution: '© 高德地图'
    });
    this.mapLayers.osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    });
    this.mapLayers.gaode.addTo(this.map);
}

2. 实时坐标和固定坐标

鼠标移动时,通过Leaflet的mousemove事件捕获鼠标位置的经纬度,实时更新到界面右下角的动态坐标面板。点击地图时,通过click事件记录固定坐标,并在地图上添加一个红色图钉标记(用emoji📍实现的,挺有趣)。

为了适配移动端,还加了touchend事件处理,确保单指触摸也能触发固定坐标功能。代码片段如下:

this.map.on('mousemove', (e) => {
    this.updateDynamicCoordinates(e.latlng);
});

this.map.on('click', (e) => {
    this.setFixedCoordinates(e.latlng);
});

this.map.on('touchend', (e) => {
    if (e.originalEvent.changedTouches.length === 1) {
        const touch = e.originalEvent.changedTouches[0];
        const point = this.map.mouseEventToContainerPoint(touch);
        const latlng = this.map.containerPointToLatLng(point);
        this.setFixedCoordinates(latlng);
    }
});

3. 坐标系转换

国内地图服务(如高德)用的是GCJ02坐标系,和国际通用的WGS84有偏差,直接用WGS84坐标在高德地图上定位会偏离。所以我实现了一个CoordConverter类,支持GCJ02、WGS84、BD09之间的相互转换。核心算法参考了Python版本的坐标转换代码,移植到JavaScript。

比如,WGS84转GCJ02的代码如下:

wgs84ToGcj02(lng, lat) {
    if (this.outOfChina(lng, lat)) {
        return [lng, lat];
    }
    let dlat = this._transformLat(lng - 105.0, lat - 35.0);
    let dlng = this._transformLng(lng - 105.0, lat - 35.0);
    const radlat = lat / 180.0 * Math.PI;
    let magic = Math.sin(radlat);
    magic = 1 - this.ee * magic * magic;
    const sqrtmagic = Math.sqrt(magic);
    dlat = (dlat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtmagic) * Math.PI);
    dlng = (dlng * 180.0) / (this.a / sqrtmagic * Math.cos(radlat) * Math.PI);
    const mglat = lat + dlat;
    const mglng = lng + dlng;
    return [mglng, mglat];
}

高德地图显示时,会把WGS84坐标转成GCJ02,确保定位准确。反过来,显示给用户时会把GCJ02转回WGS84,方便在其他平台使用。

4. 地名搜索

地名搜索用的是OpenStreetMap的Nominatim API,输入地名后发送请求获取坐标,然后在地图上定位并添加标记。如果用的是高德地图,会把返回的WGS84坐标转成GCJ02。代码如下:

async searchPlace() {
    const query = document.getElementById('placeSearch').value.trim();
    if (!query) {
        alert('请输入要搜索的地名');
        return;
    }
    try {
        const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}&limit=1`);
        const results = await response.json();
        if (results.length === 0) {
            alert(`未找到"${query}"的位置信息`);
            return;
        }
        const { lat, lon } = results[0];
        let mapLng = lon, mapLat = lat;
        if (this.currentMapType === 'gaode') {
            const gcj02 = this.coordConverter.wgs84ToGcj02(lon, lat);
            mapLng = gcj02[0];
            mapLat = gcj02[1];
        }
        this.map.setView([mapLat, mapLng], 15);
        this.setFixedCoordinates({lat: mapLat, lng: mapLng});
    } catch (error) {
        alert('搜索失败,请稍后重试');
    }
}

5. 界面设计

界面尽量做得简洁直观,顶部是地图类型选择和搜索框,右下角显示动态和固定坐标,底部有GitHub链接。还加了一个模态框,方便手动输入经纬度定位。CSS用的是纯手写样式,配合媒体查询实现响应式布局。手机上用触摸操作,体验跟PC差不多。

部署和运行

项目是纯前端的,部署在GitHub Pages上,省去了后端服务器的麻烦。想自己跑的话,步骤很简单:

  1. 克隆仓库:

    git clone https://github.com/your-username/lat-lon-query-tool.git
    cd lat-lon-query-tool
  2. 安装依赖(如果需要本地开发):

    npm install
  3. 启动本地服务器:

    npm start
  4. 浏览器访问 http://localhost:3000

直接部署到GitHub Pages的话,把代码推到main分支,启用Pages功能,选择docs文件夹就行。

遇到的问题和优化

开发过程中遇到几个小坑:

  1. 坐标系偏差:高德地图用GCJ02坐标,OpenStreetMap用WGS84,直接用会导致定位偏差。解决办法是加了坐标转换逻辑,确保显示和输入的坐标统一。
  2. 移动端兼容:一开始没考虑触摸事件,手机上点击没反应。后来加了touchend事件处理,单指触摸也能正常固定坐标。
  3. 搜索API限制:Nominatim API有每秒1次的请求限制,频繁搜索会报错。加了按钮禁用和加载动画,避免用户连续点击。
  4. 界面适配:手机屏幕小,坐标面板容易挡住地图。调整了面板位置,改成半透明背景,视觉上更舒服。

总结

这个经纬度查询工具虽然小,但从需求设计到开发实现,还是花了不少心思。整个过程让我对地图API和坐标系转换有了更深的理解,也学到了一些前端优化的技巧。如果你也有类似的需求,可以试试这个工具,或者直接拿代码改改,部署到自己的服务器上。

源码和在线演示都在GitHub上,欢迎去体验和提建议!https://ytkz.tech/querygps