GCJ-02 转 WGS84 坐标转换工具
下面是一个完整的Vue2应用,用于将高德地图获取的GCJ-02坐标转换为WGS84坐标并发送到后端:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GCJ-02 转 WGS84 坐标转换工具</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #2a5298, #3498db);
color: #fff;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
header {
text-align: center;
padding: 30px 0;
margin-bottom: 30px;
}
h1 {
font-size: 2.8rem;
margin-bottom: 10px;
text-shadow: 0 2px 5px rgba(0,0,0,0.3);
}
.subtitle {
font-size: 1.2rem;
opacity: 0.9;
max-width: 700px;
margin: 0 auto;
line-height: 1.6;
}
.content {
display: flex;
flex-wrap: wrap;
gap: 30px;
margin-bottom: 40px;
}
.card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 15px;
padding: 25px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.15);
}
.converter {
flex: 1;
min-width: 300px;
}
.map-container {
flex: 2;
min-width: 400px;
height: 500px;
}
.history {
width: 100%;
}
h2 {
font-size: 1.8rem;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
h2 i {
color: #3498db;
}
.input-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
input {
width: 100%;
padding: 12px 15px;
border-radius: 8px;
border: none;
background: rgba(255, 255, 255, 0.15);
color: white;
font-size: 1rem;
}
input:focus {
outline: none;
background: rgba(255, 255, 255, 0.25);
}
::placeholder {
color: rgba(255, 255, 255, 0.6);
}
.btn-group {
display: flex;
gap: 15px;
margin-top: 30px;
}
button {
flex: 1;
padding: 14px 0;
border: none;
border-radius: 8px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
}
.btn-convert {
background: linear-gradient(to right, #3498db, #2980b9);
color: white;
}
.btn-copy {
background: rgba(255, 255, 255, 0.15);
color: white;
}
.btn-convert:hover {
background: linear-gradient(to right, #2980b9, #2573a7);
transform: translateY(-2px);
}
.btn-copy:hover {
background: rgba(255, 255, 255, 0.25);
}
.result {
margin-top: 25px;
padding: 20px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.2);
}
.result-title {
font-weight: 600;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
#map {
width: 100%;
height: 100%;
border-radius: 10px;
overflow: hidden;
}
.history-content {
max-height: 200px;
overflow-y: auto;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
th {
background: rgba(255, 255, 255, 0.1);
font-weight: 600;
}
tr:hover {
background: rgba(255, 255, 255, 0.05);
}
.copy-btn {
background: none;
border: none;
color: #3498db;
cursor: pointer;
font-size: 1rem;
padding: 5px;
}
.footer {
text-align: center;
padding: 20px;
font-size: 0.9rem;
opacity: 0.8;
border-top: 1px solid rgba(255, 255, 255, 0.1);
margin-top: 20px;
}
@media (max-width: 768px) {
.content {
flex-direction: column;
}
.map-container {
height: 400px;
}
h1 {
font-size: 2.2rem;
}
}
.coordinates {
display: flex;
gap: 20px;
}
.coordinates > div {
flex: 1;
}
.marker-info {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px 15px;
border-radius: 8px;
font-size: 14px;
z-index: 1000;
max-width: 300px;
}
.success-message {
background-color: rgba(46, 204, 113, 0.3);
border: 1px solid #2ecc71;
padding: 10px;
border-radius: 5px;
margin-top: 10px;
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<header>
<i class="fas fa-map-marked-alt"></i> 高德地图坐标转换工具
<p class="subtitle">将高德地图获取的GCJ-02坐标系转换为WGS84坐标系,并发送到后端服务</p>
</header>
<div class="content">
<div class="card converter">
<h2><i class="fas fa-exchange-alt"></i> 坐标转换</h2>
<div class="input-group">
<label for="gcj-lng">GCJ-02 经度</label>
<input type="number" id="gcj-lng" v-model="gcj02.lng" placeholder="输入经度">
</div>
<div class="input-group">
<label for="gcj-lat">GCJ-02 纬度</label>
<input type="number" id="gcj-lat" v-model="gcj02.lat" placeholder="输入纬度">
</div>
<div class="btn-group">
<button class="btn-convert" @click="convertCoordinates">
<i class="fas fa-sync-alt"></i> 转换坐标
</button>
<button class="btn-copy" @click="copyResult">
<i class="fas fa-copy"></i> 复制结果
</button>
</div>
<div class="result">
<div class="result-title">
<i class="fas fa-map-marker-alt"></i> WGS84 转换结果
</div>
<div class="coordinates">
<div>
<label>经度</label>
<input type="text" :value="wgs84.lng" readonly>
</div>
<div>
<label>纬度</label>
<input type="text" :value="wgs84.lat" readonly>
</div>
</div>
</div>
<div class="btn-group">
<button class="btn-convert" @click="sendToBackend" :disabled="!wgs84.lng">
<i class="fas fa-paper-plane"></i> 发送到后端
</button>
</div>
<div v-if="apiResponse" class="result">
<div class="result-title">
<i class="fas fa-server"></i> 后端响应
</div>
<pre>{{ apiResponse }}</pre>
</div>
</div>
<div class="card map-container">
<h2><i class="fas fa-map"></i> 地图预览</h2>
<div id="map"></div>
<div v-if="wgs84.lng" class="marker-info">
<div>当前位置: {{ wgs84.lng.toFixed(6) }}, {{ wgs84.lat.toFixed(6) }}</div>
<div>坐标系: WGS84</div>
</div>
</div>
<div class="card history">
<h2><i class="fas fa-history"></i> 转换历史</h2>
<div class="history-content">
<table>
<thead>
<tr>
<th>时间</th>
<th>GCJ-02 坐标</th>
<th>WGS84 坐标</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(record, index) in history" :key="index">
<td>{{ record.time }}</td>
<td>{{ record.gcj02.lng.toFixed(6) }}, {{ record.gcj02.lat.toFixed(6) }}</td>
<td>{{ record.wgs84.lng.toFixed(6) }}, {{ record.wgs84.lat.toFixed(6) }}</td>
<td>
<button class="copy-btn" @click="useHistory(record)">
<i class="fas fa-undo"></i> 恢复
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="footer">
<p>© 2023 高德地图坐标转换工具 | 基于Vue2开发 | GCJ-02转WGS84算法</p>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
gcj02: {
lng: 116.397428,
lat: 39.90923
},
wgs84: {
lng: null,
lat: null
},
history: [],
apiResponse: null
},
mounted() {
this.initMap();
this.convertCoordinates();
},
methods: {
// 初始化地图
initMap() {
// 创建地图实例
const map = new AMap.Map('map', {
zoom: 13,
center: [116.397428, 39.90923],
viewMode: '3D'
});
// 添加缩放控件
map.addControl(new AMap.Zoom());
// 添加比例尺
map.addControl(new AMap.Scale());
// 添加标记
const marker = new AMap.Marker({
position: map.getCenter()
});
map.add(marker);
// 保存地图实例
this.map = map;
this.marker = marker;
},
// GCJ-02 转 WGS84 算法
convertCoordinates() {
if (!this.gcj02.lng || !this.gcj02.lat) {
alert('请输入有效的坐标值');
return;
}
const gcjLng = parseFloat(this.gcj02.lng);
const gcjLat = parseFloat(this.gcj02.lat);
// 转换算法(GCJ-02 转 WGS84)
const PI = Math.PI;
const a = 6378245.0; // 长半轴
const ee = 0.00669342162296594323; // 扁率
// 判断是否在国内
if (gcjLng < 72.004 || gcjLng > 137.8347 || gcjLat < 0.8293 || gcjLat > 55.8271) {
this.wgs84 = { lng: gcjLng, lat: gcjLat };
} else {
let dLat = this.transformLat(gcjLng - 105.0, gcjLat - 35.0);
let dLng = this.transformLng(gcjLng - 105.0, gcjLat - 35.0);
const radLat = gcjLat / 180.0 * PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
this.wgs84 = {
lng: gcjLng - dLng,
lat: gcjLat - dLat
};
}
// 更新地图位置
this.updateMapPosition();
// 添加到历史记录
this.addToHistory();
},
// 辅助转换函数
transformLat(x, y) {
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 * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
return ret;
},
transformLng(x, y) {
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 * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0;
return ret;
},
// 更新地图位置
updateMapPosition() {
if (!this.wgs84.lng || !this.wgs84.lat) return;
// 移动地图中心
this.map.setCenter([this.wgs84.lng, this.wgs84.lat]);
// 移动标记
this.marker.setPosition([this.wgs84.lng, this.wgs84.lat]);
},
// 添加到历史记录
addToHistory() {
const now = new Date();
const timeStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
this.history.unshift({
time: timeStr,
gcj02: { ...this.gcj02 },
wgs84: { ...this.wgs84 }
});
// 只保留最近5条记录
if (this.history.length > 5) {
this.history.pop();
}
},
// 使用历史记录
useHistory(record) {
this.gcj02 = { ...record.gcj02 };
this.wgs84 = { ...record.wgs84 };
this.updateMapPosition();
},
// 复制结果
copyResult() {
if (!this.wgs84.lng || !this.wgs84.lat) {
alert('没有可复制的内容');
return;
}
const text = `${this.wgs84.lng}, ${this.wgs84.lat}`;
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
alert('坐标已复制到剪贴板: ' + text);
},
// 发送到后端
sendToBackend() {
if (!this.wgs84.lng || !this.wgs84.lat) {
alert('请先转换坐标');
return;
}
// 模拟API请求
this.apiResponse = null;
setTimeout(() => {
this.apiResponse = {
status: 200,
message: "坐标接收成功",
data: {
wgs84_lng: this.wgs84.lng,
wgs84_lat: this.wgs84.lat,
timestamp: new Date().toISOString()
}
};
}, 1500);
}
}
});
</script>
<!-- 高德地图API -->
<script src="https://webapi.amap.com/maps?v=2.0&key=您的高德地图key"></script>
</body>
</html>
功能说明
这个Vue2应用提供了完整的GCJ-02到WGS84坐标转换功能:
-
坐标转换:
- 输入GCJ-02坐标(高德地图坐标系)
- 使用转换算法得到WGS84坐标(标准GPS坐标系)
- 算法考虑了国内坐标偏移
-
地图展示:
- 集成高德地图JS API
- 显示转换后的坐标位置
- 标记当前坐标点
-
历史记录:
- 保存最近的5次转换记录
- 可以快速恢复历史坐标
-
后端集成:
- 模拟发送转换结果到后端API
- 显示API响应结果
-
用户界面:
- 响应式设计,适配各种屏幕
- 美观的渐变背景和卡片设计
- 直观的操作按钮和反馈
使用说明
- 在左侧输入GCJ-02坐标(高德地图获取的坐标)
- 点击"转换坐标"按钮进行转换
- 查看右侧地图上的位置标记
- 点击"发送到后端"按钮模拟API请求
- 历史记录中可查看和恢复之前的转换
注意事项
- 此应用需要替换高德地图API key(在代码底部)
- 转换算法为近似转换,精度在1-5米左右
- 实际项目中后端API需要实现真实的数据接收
这个工具非常适合需要将高德地图坐标转换为标准GPS坐标并发送到后端的场景。