Browse Source

粤政图 点聚合效果

Hwf 7 tháng trước cách đây
mục cha
commit
25b7e60405
2 tập tin đã thay đổi với 219 bổ sung28 xóa
  1. 148 13
      src/hooks/AMap/useAMap.ts
  2. 71 15
      src/utils/olMap/olMap.ts

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

@@ -2,6 +2,7 @@ import AMapLoader from '@amap/amap-jsapi-loader';
 import { nanoid } from 'nanoid';
 import { deepClone } from '@/utils';
 import {onMounted} from "vue";
+import { mergeGeoJsonPolygons, wgs_gcj_encrypts } from '@/utils/gisUtils';
 
 export function useAMap(options) {
   let AMap, map, nowLayer, labelsLayer, scale, cluster;
@@ -20,7 +21,7 @@ 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.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', {
@@ -83,7 +84,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');
@@ -104,7 +105,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(' +
@@ -120,7 +121,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;
@@ -242,7 +243,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),
@@ -252,12 +253,6 @@ export function useAMap(options) {
       ];
       options.forEach((option) => {
         const holes = result.districtList[0].boundaries;
-        // if (option.offset) {
-        //
-        //   holes.forEach((items) => {
-        //
-        //   })
-        // }
         let pathArray = [outer];
         pathArray.push.apply(pathArray, holes);
         maskPolygon = new AMap.Polygon({
@@ -279,6 +274,86 @@ export function useAMap(options) {
       maskPolygon = null;
     }
   };
+  let maskPolygon2 = [];
+  const creatMask2 = (data, option) => {
+    if (maskPolygon2 && maskPolygon2.length > 0) {
+      maskPolygon2.forEach((polygon) => {
+        polygon.show();
+      });
+    } else {
+      data = convertCoordinates(data);
+      // 遮罩部分
+      // const outer = [
+      //   new AMap.LngLat(-180, 90, true),
+      //   new AMap.LngLat(-180, -90, true),
+      //   new AMap.LngLat(180, -90, true),
+      //   new AMap.LngLat(180, 90, true)
+      // ];
+      // const pathArray = [outer];
+      // 合并区边界
+      // const data2 = mergeGeoJsonPolygons(data);
+      // data2.geometry.coordinates.forEach((coords) => {
+      //   pathArray.push(coords[0]);
+      // });
+      // const maskPolygon = new AMap.Polygon({
+      //   path: pathArray,
+      //   strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
+      //   strokeOpacity: 1,
+      //   strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
+      //   fillColor: option.fillColor ? option.fillColor : '#10243b',
+      //   fillOpacity: option.fillOpacity ? option.fillOpacity : 0.65
+      // });
+      // maskPolygon2.push(maskPolygon);
+      // map.add(maskPolygon);
+      // 边界部分
+      data.features.forEach((feature) => {
+        if (feature.geometry.type === 'Polygon') {
+          const polygonPath = feature.geometry.coordinates[0].map((coord) => {
+            return [coord[0], coord[1]];
+          });
+          const polygon = new AMap.Polyline({
+            path: polygonPath,
+            strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
+            strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
+            strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
+            clickable: false
+          });
+          maskPolygon2.push(polygon);
+          map.add(polygon);
+        } else if (feature.geometry.type === 'MultiPolygon') {
+          feature.geometry.coordinates.forEach((polygonCoords) => {
+            const polygonPath = polygonCoords.map((ring) => {
+              return ring.map((coord) => {
+                return [coord[0], coord[1]];
+              });
+            });
+            const outerPath = polygonPath[0];
+            const innerPaths = polygonPath.slice(1);
+            const polygon = new AMap.Polyline({
+              path: outerPath,
+              holes: innerPaths,
+              strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
+              strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
+              strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
+              clickable: false
+            });
+            maskPolygon2.push(polygon);
+            map.add(polygon);
+          });
+        }
+      });
+    }
+  };
+  const removeMask2 = (isHidden) => {
+    if (maskPolygon2 && maskPolygon2.length > 0) {
+      maskPolygon2.forEach((polygon) => {
+        polygon.hide();
+      });
+      if (!isHidden) {
+        maskPolygon2 = [];
+      }
+    }
+  };
   let moveMarker, movePolyline, movePassedPolyline, timerId;
   const trackPlayback = (lineArr) => {
     if (timerId) {
@@ -315,12 +390,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(() => {
@@ -465,6 +540,64 @@ 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((polygon) =>
+            polygon.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 === '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);
   });
@@ -483,6 +616,8 @@ export function useAMap(options) {
     handleHover,
     creatMask,
     removeMask,
+    creatMask2,
+    removeMask2,
     trackPlayback,
     drawData
   };

+ 71 - 15
src/utils/olMap/olMap.ts

@@ -25,10 +25,10 @@ import { fromLonLat } from 'ol/proj';
 import axios from 'axios';
 import { fromExtent } from 'ol/geom/Polygon';
 import { LinearRing, Polygon } from 'ol/geom';
-import { Tile } from 'ol';
 import {Graticule} from "ol/layer";
-// import olPlot from 'ol-plot';
-// import { activate } from '../ol-plot/ol-plot'
+import { mergeGeoJsonPolygons } from '@/utils/gisUtils';
+import { Cluster } from 'ol/source';
+import CircleStyle from 'ol/style/Circle';
 
 const commonUrl = import.meta.env.VITE_APP_BASE_API2 + 'api/oneShare/proxyHandler/gd/';
 // proj4.defs('EPSG:4490', '+proj=longlat +ellps=GRS80 +no_defs +type=crs');
@@ -68,6 +68,7 @@ export class olMap {
   private graphicsType = '';
   private plot;
   private vectorLayer;
+  private cluster;
   private maskLayer;
   private maskLayer2 = [];
 
@@ -253,14 +254,57 @@ export class olMap {
       loadendFunc();
     }
   }
+  // 集群点样式
+  clusterStyle(feature) {
+    const originalFeature = feature.get('features')[0];
+    const size = feature.get('features').length;
+    if (size > 1) {
+      const outerCircle = new CircleStyle({
+        radius: 20,
+        fill: new Fill({
+          color: 'rgba(79, 176, 206, 0.5)'
+        }),
+        stroke: new Stroke({
+          color: 'rgba(79, 176, 206, 1)'
+        })
+      });
+      return [
+        new Style({
+          image: outerCircle,
+          text: new Text({
+            text: size.toString(),
+            font: '14px sans-serif',
+            fill: new Fill({
+              color: '#ffff'
+            })
+          })
+        })
+      ];
+    }
 
+    return new Style({
+      geometry: originalFeature.getGeometry(),
+      image: new Icon({
+        anchor: [0.5, 0.5],
+        scale: 0.146,
+        anchorXUnits: 'fraction',
+        anchorYUnits: 'pixels',
+        src: originalFeature.get('icon')
+      })
+    });
+  }
   addMarker(points) {
-    this.clearMarker('point');
+    this.clearMarker();
+    const features = [];
     points.forEach((point) => {
       // 创建标注点
       const feature = new Feature({
-        geometry: new Point(point.lnglat),
-        name: point.name
+        // 必须是数字类型,字符串不识别
+        geometry: new Point([Number(point.longitude), Number(point.latitude)]),
+        name: point.name,
+        icon: point.icon,
+        size: point.size,
+        type: 'point'
       });
       // 定义样式
       const style = new Style({
@@ -282,15 +326,22 @@ export class olMap {
           })
         })
       });
-
       feature.setStyle(style);
+      features.push(feature);
       this.markers.push(point);
-      this.vectorLayer.getSource().addFeature(feature);
     });
+    const vectorSource = new VectorSource({
+      features: features
+    });
+    const clusterSource = new Cluster({
+      distance: 30,
+      source: vectorSource
+    });
+    this.vectorLayer.setStyle(this.clusterStyle);
+    this.vectorLayer.setSource(clusterSource);
   }
-
   // 清除所有标加
-  clearMarker(id) {
+  clearMarker() {
     if (!this.vectorLayer) return;
     this.vectorLayer.getSource().clear();
   }
@@ -303,7 +354,7 @@ export class olMap {
   createVecByJson(json, options) {
     const format = new GeoJSON();
     const fs = format.readFeatures(json);
-    const converLayer = new VectorLayer({
+    this.maskLayer = new VectorLayer({
       source: new VectorSource(),
       style: new Style({
         fill: new Fill({
@@ -316,7 +367,7 @@ export class olMap {
       }),
       zIndex: options.zIndex ? options.zIndex : 99
     });
-    this.map.addLayer(converLayer);
+    this.map.addLayer(this.maskLayer);
     const extent = [-180, -90, 180, 90];
     const polygonRing = fromExtent(extent);
     fs.forEach((x) => {
@@ -330,7 +381,7 @@ export class olMap {
     const convertFt = new Feature({
       geometry: polygonRing
     });
-    converLayer.getSource().addFeature(convertFt);
+    this.maskLayer.getSource().addFeature(convertFt);
   }
   createVecByJson2(json, options) {
     if (this.maskLayer2 && this.maskLayer2.length > 0) {
@@ -457,7 +508,6 @@ export class olMap {
           width: 1
         })
       });
-
       // 遮罩图层的矢量数据源(初始为空)
       const maskSource = new VectorSource();
       // 创建一个多边形特征
@@ -550,8 +600,14 @@ export class olMap {
     layers.forEach((element) => {
       if (!!element && element.get('name') === layerName) {
         //移除
-        this.map.removeLayer(element)
+        this.map.removeLayer(element);
       }
     });
   }
+  getVectorLayer() {
+    return this.vectorLayer;
+  }
+  getMap() {
+    return this.map;
+  }
 }