Parcourir la source

坐标系转换

Hwf il y a 5 mois
Parent
commit
b62d719d53

+ 2 - 2
src/components/Map/index.vue

@@ -113,8 +113,8 @@ const mapUtils = useAMap({
     map.on('zoomchange', zoomChangeHandler);
     // 添加遮罩
     if (props.showMask) {
-      // creatMask2(mmJson, { strokeWeight: 2 });
-      creatMask([{ strokeWeight: 2 }]);
+      creatMask2(mmJson, { strokeWeight: 2 });
+      // creatMask([{ strokeWeight: 2 }]);
     }
     drawTool.initMouseTool({ container: 'aMap', map, AMap });
     placeSearch = new AMap.PlaceSearch({

+ 83 - 13
src/hooks/AMap/useAMap.ts

@@ -1,6 +1,7 @@
 import AMapLoader from '@amap/amap-jsapi-loader';
 import { nanoid } from 'nanoid';
 import { deepClone } from '@/utils';
+import { wgs_gcj_encrypts } from '@/utils/gisUtils';
 
 export function useAMap(options) {
   let AMap, map, nowLayer, labelsLayer, scale, cluster;
@@ -19,7 +20,19 @@ export function useAMap(options) {
       version: !!options.version ? options.version : '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
       plugins: options.plugins
         ? options.plugins
-        : ['AMap.Scale', 'AMap.RangingTool', 'AMap.MouseTool', 'AMap.PolygonEditor', 'AMap.MarkerCluster', 'AMap.DistrictSearch', 'AMap.MoveAnimation', 'AMap.Driving', 'AMap.Geocoder', 'AMap.PlaceSearch', 'AMap.GeoJSON']
+        : [
+            'AMap.Scale',
+            'AMap.RangingTool',
+            'AMap.MouseTool',
+            'AMap.PolygonEditor',
+            'AMap.MarkerCluster',
+            'AMap.DistrictSearch',
+            'AMap.MoveAnimation',
+            'AMap.Driving',
+            'AMap.Geocoder',
+            'AMap.PlaceSearch',
+            'AMap.GeoJSON'
+          ]
     }).then((res) => {
       AMap = res;
       map = new AMap.Map(options.el ? options.el : 'aMap', {
@@ -82,7 +95,7 @@ export function useAMap(options) {
     }
     addPoints = points;
     const count = points.length;
-    const _renderClusterMarker = function(context) {
+    const _renderClusterMarker = function (context) {
       // 聚合中点个数
       const clusterCount = context.count;
       const div = document.createElement('div');
@@ -103,7 +116,7 @@ export function useAMap(options) {
         map.setZoomAndCenter(map.getZoom() + 1, bounds.getCenter());
       });
     };
-    const _renderMarker = function(context) {
+    const _renderMarker = function (context) {
       const content =
         '<div style="display: flex;flex-direction: column;align-items: center;justify-content: center">' +
         '<div style="background: url(' +
@@ -119,7 +132,7 @@ export function useAMap(options) {
       context.marker.setContent(content);
       context.marker.setOffset(offset);
       context.marker.setExtData(context.data[0]);
-      context.marker.on('click', function(e) {
+      context.marker.on('click', function (e) {
         const extData = e.target.getExtData();
         let index = 0;
         let index2 = 0;
@@ -241,7 +254,7 @@ export function useAMap(options) {
     new AMap.DistrictSearch({
       extensions: 'all',
       subdistrict: 0
-    }).search(name, function(status, result) {
+    }).search(name, function (status, result) {
       // 外多边形坐标数组和内多边形坐标数组
       const outer = [
         new AMap.LngLat(-360, 90, true),
@@ -251,7 +264,7 @@ export function useAMap(options) {
       ];
       options.forEach((option) => {
         const holes = result.districtList[0].boundaries;
-        let pathArray = [outer];
+        const pathArray = [outer];
         pathArray.push.apply(pathArray, holes);
         maskPolygon = new AMap.Polygon({
           pathL: pathArray,
@@ -282,12 +295,13 @@ export function useAMap(options) {
     ];
     //outer
     const pathArray = [outer];
+    data = convertCoordinates(data);
     data.features.forEach((item, index) => {
       let arr = [];
       const geometry = item.geometry;
       geometry.coordinates.forEach((coordinate) => {
         if (geometry.type === 'MultiPolygon') {
-          coordinate[0].forEach(coordinate2 => {
+          coordinate[0].forEach((coordinate2) => {
             arr.push(coordinate2);
           });
           pathArray.push(arr);
@@ -345,12 +359,12 @@ export function useAMap(options) {
       strokeWeight: 6 //线宽
     });
 
-    moveMarker.on('moving', function(e) {
+    moveMarker.on('moving', function (e) {
       movePassedPolyline.setPath(e.passedPath);
       map.setCenter(e.target.getPosition(), true);
     });
 
-    moveMarker.on('moveend', function(e) {
+    moveMarker.on('moveend', function (e) {
       index++;
       if (index === lineArr.length - 1) {
         timerId = setTimeout(() => {
@@ -360,16 +374,16 @@ export function useAMap(options) {
         }, 5000);
       }
     });
-    moveMarker.moveAlong(lineArr, {
+    moveMarker.moveAlngg(lineArr, {
       // 每一段的时长
       duration: 1000, //可根据实际采集时间间隔设置
-      // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
+      // JSAPI2.0 是否延道路自动设置角度在 moveAlngg 里设置
       autoRotation: true
     });
   };
 
   const drawData = (data) => {
-    let res = [];
+    const res = [];
     data.forEach((item) => {
       let graphic;
       if (['rectangle', 'polygon', 'anyLine'].includes(item.type)) {
@@ -446,7 +460,7 @@ export function useAMap(options) {
       } else if (item.type === 'marker') {
         // 创建标注点
         const marker = new AMap.Marker({
-          position: new AMap.LngLat(item.longitude, item.latitude), // 标注点的位置
+          position: new AMap.LngLat(item.lnggitude, item.latitude), // 标注点的位置
           icon: new AMap.Icon({
             size: item.size, //图标所处区域大小
             image: item.icon
@@ -495,6 +509,62 @@ export function useAMap(options) {
     data.id = id;
     return { text, data };
   };
+
+  const convertCoordinates = (geoJson) => {
+    const features = geoJson.features.map((feature) => {
+      const geometry = feature.geometry;
+      let newGeometry;
+      if (geometry.type === 'Point') {
+        const [x, y] = geometry.coordinates;
+        const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
+        newGeometry = { ...geometry, coordinates: [obj.lng, obj.lat] };
+      } else if (geometry.type === 'MultiPoint') {
+        const newCoordinates = geometry.coordinates.map((coords) => {
+          const [x, y] = coords;
+          const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
+          return [obj.lng, obj.lat];
+        });
+        newGeometry = { ...geometry, coordinates: newCoordinates };
+      } else if (geometry.type === 'LineString') {
+        const newCoordinates = geometry.coordinates.map((coords) => {
+          const [x, y] = coords;
+          const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
+          return [obj.lng, obj.lat];
+        });
+        newGeometry = { ...geometry, coordinates: newCoordinates };
+      } else if (geometry.type === 'MultiLineString') {
+        const newCoordinates = geometry.coordinates.map((line) =>
+          line.map((coords) => {
+            const [x, y] = coords;
+            const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
+            return [obj.lng, obj.lat];
+          })
+        );
+        newGeometry = { ...geometry, coordinates: newCoordinates };
+      } else if (geometry.type === 'Polygon') {
+        const newCoordinates = geometry.coordinates.map((ring) => {
+          const obj = wgs_gcj_encrypts(ring);
+          return obj;
+        });
+        newGeometry = { ...geometry, coordinates: newCoordinates };
+      } else if (geometry.type === 'MultiPolygon') {
+        const newCoordinates = geometry.coordinates.map((polygon) =>
+          polygon.map((ring) =>
+            ring.map((coords) => {
+              const [x, y] = coords;
+              const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
+              return [obj.lng, obj.lat];
+            })
+          )
+        );
+        newGeometry = { ...geometry, coordinates: newCoordinates };
+      }
+
+      return { ...feature, geometry: newGeometry };
+    });
+
+    return { ...geoJson, features };
+  };
   onMounted(() => {
     initMap(options);
   });

+ 163 - 0
src/utils/gisUtils.ts

@@ -0,0 +1,163 @@
+//转换常数
+const x_pi = (3.14159265358979324 * 3000.0) / 180.0;
+const pi = 3.14159265358979324;
+const a = 6378245.0;
+const ee = 0.00669342162296594323;
+
+function transformLon(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 * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0) / 3.0;
+  ret += ((20.0 * Math.sin(x * pi) + 40.0 * Math.sin((x / 3.0) * pi)) * 2.0) / 3.0;
+  ret += ((150.0 * Math.sin((x / 12.0) * pi) + 300.0 * Math.sin((x / 30.0) * pi)) * 2.0) / 3.0;
+  return ret;
+}
+
+function 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 * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0) / 3.0;
+  ret += ((20.0 * Math.sin(y * pi) + 40.0 * Math.sin((y / 3.0) * pi)) * 2.0) / 3.0;
+  ret += ((160.0 * Math.sin((y / 12.0) * pi) + 320 * Math.sin((y * pi) / 30.0)) * 2.0) / 3.0;
+  return ret;
+}
+// 判断是否在国内
+function outOfChina(lat, lon) {
+  if (lon < 72.004 || lon > 137.8347) return true;
+  if (lat < 0.8293 || lat > 55.8271) return true;
+  return false;
+}
+
+/*
+ WGS-84转换GCJ-02
+(即 天地图转高德、腾讯地图)
+[{lat: 21, lng: 110}]
+ */
+export const wgs_gcj_encrypts = (latlngs) => {
+  const point = [];
+  for (const latlng of latlngs) {
+    if (outOfChina(latlng.lat, latlng.lng)) {
+      point.push({
+        lat: latlng.lat,
+        lng: latlng.lng
+      });
+      return point;
+    }
+    let dLat = transformLat(latlng.lng - 105.0, latlng.lat - 35.0);
+    let dLon = transformLon(latlng.lng - 105.0, latlng.lat - 35.0);
+    const radLat = (latlng.lat / 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);
+    dLon = (dLon * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * pi);
+    const lat = latlng.lat + dLat;
+    const lng = latlng.lng + dLon;
+    point.push({
+      lat: lat,
+      lng: lng
+    });
+  }
+  return point;
+};
+
+/*
+ WGS-84转换GCJ-02
+(即 天地图转高德、腾讯地图)
+[[21,110]]
+ */
+export const wgs_gcj_encrypts2 = (latlngs) => {
+  const point = [];
+  for (const latlng of latlngs) {
+    // if (outOfChina(latlng[0], latlng[1])) {
+    //   point.push({
+    //     lat: latlng[0],
+    //     lng: latlng[1]
+    //   });
+    //   return point;
+    // }
+    let dLat = transformLat(latlng[1] - 105.0, latlng[0] - 35.0);
+    let dLon = transformLon(latlng[1] - 105.0, latlng[0] - 35.0);
+    const radLat = (latlng[0] / 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);
+    dLon = (dLon * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * pi);
+    const lat = latlng[0] + dLat;
+    const lng = latlng[1] + dLon;
+    point.push([lat, lng]);
+  }
+  return point;
+};
+/*
+ BD-09转换GCJ-02
+ (即 百度转高德、腾讯地图)
+ */
+export const bd_google_encrypt = (latlngs) => {
+  const point = [];
+  for (const latlng of latlngs) {
+    const x = latlng.lng - 0.0065;
+    const y = latlng.lat - 0.006;
+    const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
+    const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
+    const gg_lon = z * Math.cos(theta);
+    const gg_lat = z * Math.sin(theta);
+    point.push({
+      lat: gg_lon,
+      lng: gg_lat
+    });
+  }
+  return point;
+};
+
+/*
+ GCJ-02转换BD-09
+ (即 高德、腾讯转百度地图)
+ */
+export const google_bd_encrypt = (latlngs) => {
+  const point = [];
+  for (const latlng of latlngs) {
+    const x = latlng.lng;
+    const y = latlng.lat;
+    const z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
+    const theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
+    const bd_lon = z * Math.cos(theta) + 0.0065;
+    const bd_lat = z * Math.sin(theta) + 0.006;
+    point.push({
+      lat: bd_lat,
+      lng: bd_lon
+    });
+  }
+  return point;
+};
+
+/*
+ GCJ-02 到 WGS-84 的转换
+ (即 高德、腾讯转天地图)
+ */
+export const gcj_wgs_encrypts = (latlngs) => {
+  const point = [];
+  for (const latlng of latlngs) {
+    if (outOfChina(latlng.lat, latlng.lng)) {
+      point.push({
+        lat: latlng.lat,
+        lng: latlng.lng
+      });
+      return point;
+    }
+    let dLat = transformLat(latlng.lng - 105.0, latlng.lat - 35.0);
+    let dLon = transformLon(latlng.lng - 105.0, latlng.lat - 35.0);
+    const radLat = (latlng.lat / 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);
+    dLon = (dLon * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * pi);
+    const lat = dLat;
+    const lng = dLon;
+    point.push({
+      lat: lat,
+      lng: lng
+    });
+  }
+  return point;
+};

+ 2 - 2
src/utils/index.ts

@@ -375,8 +375,8 @@ export const getRgba = (rgbaString) => {
   return {
     color: 'rgb(' + r + ',' + g + ',' + b + ')',
     opacity: opacity
-  }
-}
+  };
+};
 
 export const setHighText = (text: string, highArray) => {
   highArray.forEach((item) => {

+ 17 - 6
src/views/emergencyCommandMap/LeftSection/Communication.vue

@@ -98,12 +98,14 @@
         </div>
       </div>
     </div>
-    <Dialog v-if="showJoinMeeting" customShow type="xs" height="300px" title="加入会议" @confirm="handleJoinMeeting" @close="closeDialog">
-      <el-form ref="formRef" :model="meetingForm" :rules="rules">
-        <el-form-item label="会议号" label-width="80px" prop="roomcode">
-          <el-input v-model="meetingForm.roomcode" class="custom-input2" clearable placeholder="请输入会议号" />
-        </el-form-item>
-      </el-form>
+    <Dialog v-if="showJoinMeeting" customShow type="xs" height="180px" title="加入会议" @confirm="handleJoinMeeting" @close="closeDialog">
+      <div class="dialog-content">
+        <el-form ref="formRef" :model="meetingForm" :rules="rules">
+          <el-form-item label="会议号" label-width="80px" prop="roomcode">
+            <el-input v-model="meetingForm.roomcode" class="custom-input2" clearable placeholder="请输入会议号" />
+          </el-form-item>
+        </el-form>
+      </div>
     </Dialog>
   </div>
 </template>
@@ -592,4 +594,13 @@ onMounted(() => {
   left: 141px;
   font-size: 60px;
 }
+.dialog-content {
+  :deep(.el-form) {
+    .el-form-item__label {
+      color: #fff !important;
+      font-weight: bold !important;
+      margin-right: 5px !important;
+    }
+  }
+}
 </style>