0
点赞
收藏
分享

微信扫一扫

vue2使用高德地图获取的GCJ-02 坐标,转换为 WGS84 坐标,传给后端

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坐标转换功能:

  1. 坐标转换

    • 输入GCJ-02坐标(高德地图坐标系)
    • 使用转换算法得到WGS84坐标(标准GPS坐标系)
    • 算法考虑了国内坐标偏移
  2. 地图展示

    • 集成高德地图JS API
    • 显示转换后的坐标位置
    • 标记当前坐标点
  3. 历史记录

    • 保存最近的5次转换记录
    • 可以快速恢复历史坐标
  4. 后端集成

    • 模拟发送转换结果到后端API
    • 显示API响应结果
  5. 用户界面

    • 响应式设计,适配各种屏幕
    • 美观的渐变背景和卡片设计
    • 直观的操作按钮和反馈

使用说明

  1. 在左侧输入GCJ-02坐标(高德地图获取的坐标)
  2. 点击"转换坐标"按钮进行转换
  3. 查看右侧地图上的位置标记
  4. 点击"发送到后端"按钮模拟API请求
  5. 历史记录中可查看和恢复之前的转换

注意事项

  1. 此应用需要替换高德地图API key(在代码底部)
  2. 转换算法为近似转换,精度在1-5米左右
  3. 实际项目中后端API需要实现真实的数据接收

这个工具非常适合需要将高德地图坐标转换为标准GPS坐标并发送到后端的场景。

举报

相关推荐

WGS84坐标系转换到J2000坐标系

0 条评论