Hwf 4 mesi fa
parent
commit
6eef597e2c
3 ha cambiato i file con 200 aggiunte e 23 eliminazioni
  1. 5 2
      src/components/Map/index.vue
  2. 23 0
      src/utils/index.ts
  3. 172 21
      src/utils/olMap/olMap.ts

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

@@ -35,7 +35,7 @@ const props = withDefaults(defineProps<Props>(), {});
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
 
-const emits = defineEmits(['onLoadCompleted', 'update:drawing', 'selectGraphics', 'unSelectGraphics', 'showTextEditBox', 'onDrawCompleted', 'handleShowVideo', 'handleShowWarehouse']);
+const emits = defineEmits(['onLoadCompleted', 'selectGraphics', 'unSelectGraphics', 'showTextEditBox', 'onDrawCompleted', 'handleShowVideo', 'handleShowWarehouse']);
 
 const mapState = reactive({
   center: [110.925175, 21.678955],
@@ -262,7 +262,10 @@ watch(() => props.eventDetails, () => {
 const getMapUtils = () => {
   return mapUtils;
 };
-defineExpose({ getMapUtils, addMarker, addSearchMarker, getMarkers, clearMarker, getMap, drawTool, handleHover });
+const getDrawTool = () => {
+  return mapUtils.getDrawTool();
+};
+defineExpose({ getDrawTool, getMapUtils, addMarker, addSearchMarker, getMarkers, clearMarker, getMap, drawTool, handleHover });
 const handleResize = () => {
   map.resize();
 };

+ 23 - 0
src/utils/index.ts

@@ -40,3 +40,26 @@ export const getRgba = (rgbaString) => {
 const getTableRowClass = ({rowIndex}) => {
     return rowIndex % 2 === 0 ? '' : 'common-table-tr';
 }
+
+export const hexToRgba = (hex, alpha) => {
+    // 确保输入是一个有效的十六进制颜色值,并以 # 开头
+    hex = hex.replace(/^#/, '');
+    // 如果十六进制颜色值是3位的简写形式(如 #f80),则扩展为6位
+    if (hex.length === 3) {
+        hex = hex
+            .split('')
+            .map((x) => x + x)
+            .join('');
+    }
+    // 如果十六进制颜色值的长度不是6位,则抛出错误
+    if (hex.length !== 6) {
+        return hex;
+    }
+    // 解析红、绿、蓝分量
+    const bigint = parseInt(hex, 16);
+    const r = (bigint >> 16) & 255;
+    const g = (bigint >> 8) & 255;
+    const b = bigint & 255;
+    // 返回 RGBA 字符串
+    return `rgba(${r}, ${g}, ${b}, ${alpha || 1})`;
+};

+ 172 - 21
src/utils/olMap/olMap.ts

@@ -25,17 +25,24 @@ import { fromLonLat } from 'ol/proj';
 import axios from 'axios';
 import { fromExtent } from 'ol/geom/Polygon';
 import { LinearRing, LineString, Polygon } from 'ol/geom';
-import {Graticule} from "ol/layer";
+import { Graticule } from 'ol/layer';
 import { getPointsCenter, mergeGeoJsonPolygons } from '@/utils/gisUtils';
 import { Cluster } from 'ol/source';
 import CircleStyle from 'ol/style/Circle';
 import Overlay from 'ol/Overlay';
-import { Select } from 'ol/interaction';
+import { Draw, Select } from 'ol/interaction';
 import { click } from 'ol/events/condition';
+import Circle from 'ol/geom/Circle';
+import { hexToRgba } from '@/utils';
+import { createBox } from 'ol/interaction/Draw';
 
+const tk = 'a8df87f1695d224d2679aa805c1268d9';
 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');
-proj4.defs('EPSG:4490', 'GEOGCS["China Geodetic Coordinate System 2000",DATUM["China_2000",SPHEROID["CGCS2000",6378137,298.257222101,AUTHORITY["EPSG","1024"]],AUTHORITY["EPSG","1043"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4490"]]');
+proj4.defs(
+    'EPSG:4490',
+    'GEOGCS["China Geodetic Coordinate System 2000",DATUM["China_2000",SPHEROID["CGCS2000",6378137,298.257222101,AUTHORITY["EPSG","1024"]],AUTHORITY["EPSG","1043"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4490"]]'
+);
 // proj4.defs('EPSG:4525', '+proj=tmerc +lat_0=0 +lon_0=111 +k=1 +x_0=37500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs');
 register(proj4);
 const projection = new Projection({
@@ -43,8 +50,8 @@ const projection = new Projection({
   units: 'degrees',
   axisOrientation: 'neu'
 });
-projection.setExtent([-180, -90, 180, 90])
-projection.setWorldExtent([-180, -90, 180, 90])
+projection.setExtent([-180, -90, 180, 90]);
+projection.setWorldExtent([-180, -90, 180, 90]);
 const projectionExtent = [-180, -90, 180, 90];
 const size = getWidth(projectionExtent) / 256;
 const resolutions = [];
@@ -66,6 +73,8 @@ export class olMap {
     strokeStyle: 'solid'
   };
   private plot;
+  private drawVector;
+  private drawTool;
   private vectorLayer;
   // 边界遮罩图层
   private maskLayer;
@@ -146,6 +155,7 @@ export class olMap {
           options.onMarkerClick(extData);
         } else {
           // 聚合要素
+          this.select.getFeatures().clear();
           const currentZoom = this.map.getView().getZoom();
           this.map.getView().setZoom(currentZoom + 1);
           const points = [];
@@ -167,12 +177,14 @@ export class olMap {
     // 添加新的图层
     if (Array.isArray(options.id)) {
       for (const layer of options.id) {
-        if (typeof layer === "string") {
+        if (typeof layer === 'string') {
           await this.formatXml(layer); // 等待当前 layer 处理完成
         } else {
           await this.formatXml(layer.id, layer.minZoom, layer.maxZoom, layer.zIndex, layer.visible); // 等待当前 layer 处理完成
         }
       }
+    } else if (options.id === 'tianditu') {
+      await this.formatXml2();
     } else if (options.id) {
       // 如果 options.id 不是数组,但确实是一个图层,则直接处理
       await this.formatXml(options.id, options.minZoom, options.maxZoom, options.zIndex, options.visible);
@@ -188,7 +200,30 @@ export class olMap {
       this.options.onLoadCompleted(this.map);
     }
   }
-
+  formatXml2() {
+    const baseUrl = 'https://t{0-7}.tianditu.gov.cn/';
+    const vecType = 'vec'; // 矢量图层类型
+    const projType = 'w'; // 投影类型:web mercator
+    const reqParams = {
+      SERVICE: 'WMTS',
+      REQUEST: 'GetTile',
+      VERSION: '1.0.0',
+      LAYER: '',
+      STYLE: 'default',
+      TILEMATRIXSET: projType,
+      FORMAT: 'tiles',
+      TILECOL: '{x}',
+      TILEROW: '{y}',
+      TILEMATRIX: '{z}',
+      tk: key
+    };
+    const newParams = Object.assign({}, params, { LAYER: dataType });
+    let paramsStr = '';
+    for (const [k, v] of Object.entries(newParams)) {
+      paramsStr += `${k}=${v}&`;
+    }
+    return `${baseUrl}${dataType}_${projType}/wmts?${paramsStr.slice(0, -1)}`;
+  }
   formatXml(code: string, minZoom?: number, maxZoom?: number, zIndex?: number, visible?: boolean) {
     const xml = new WMTSCapabilities();
     return this.getCapabilities(code).then((lists) => {
@@ -249,11 +284,13 @@ export class olMap {
       fillOpacity: options.drawType === '1' ? 0 : 0.5,
       strokeStyle: 'solid'
     };
-    // this.plot = new olPlot(this.map, {
-    //   zoomToExtent: true,
-    //   ...this.drawOptions
-    // });
-    // this.plot.plotDraw.on('drawEnd', this.onDrawEnd.bind(this));
+    // 创建矢量图层用于绘制
+    this.drawVector = new Vector({
+      source: new VectorSource({
+        features: []
+      })
+    });
+    this.map.addLayer(this.drawVector);
   }
 
   // 绘制结束事件
@@ -280,10 +317,60 @@ export class olMap {
       this.plot.plotDraw.activate('FreePolygon');
     }
   }
-
+  // 空间分析绘制图形
+  drawGraphics2(newOptions: MouseTool) {
+    const typeList = {
+      circle: 'Circle',
+      rectangle: 'Circle',
+      polygon: 'Polygon'
+    };
+    let geometryFunction = null;
+    if (newOptions.graphicsType === 'rectangle') {
+      // 绘制矩形的方法
+      geometryFunction = createBox();
+    }
+    if (!!typeList[newOptions.graphicsType]) {
+      this.drawOptions = {
+        type: newOptions.graphicsType,
+        strokeColor: newOptions.color,
+        strokeOpacity: 1,
+        strokeWeight: 1,
+        fillColor: newOptions.color,
+        fillOpacity: newOptions.drawType === '1' ? '0' : '0.5',
+        strokeStyle: 'solid'
+      };
+      this.closeDraw();
+      // 创建绘制交互
+      const style = new Style({
+        stroke: new Stroke({
+          color: hexToRgba(this.drawOptions.strokeColor, this.drawOptions.strokeOpacity),
+          width: this.drawOptions.strokeWeight
+        }),
+        fill: new Fill({
+          color: hexToRgba(this.drawOptions.fillColor, this.drawOptions.fillOpacity)
+        })
+      });
+      this.drawTool = new Draw({
+        source: this.drawVector.getSource(),
+        type: typeList[newOptions.graphicsType],
+        geometryFunction: geometryFunction,
+        style: style
+      });
+      // 添加绘制交互到地图
+      this.map.addInteraction(this.drawTool);
+      // 监听绘制结束事件
+      this.drawTool.on('drawend', (event) => {
+        const feature = event.feature;
+        // 获取几何对象
+        feature.setStyle(style);
+      });
+    }
+  }
   // 关闭绘制
   closeDraw() {
-    this.plot.plotDraw.deactivate();
+    if (!this.drawTool) return;
+    this.map.removeInteraction(this.drawTool);
+    // this.drawTool.abortDrawing();
   }
 
   // 切换图层
@@ -295,7 +382,7 @@ export class olMap {
 
     if (Array.isArray(newLayers)) {
       for (const layer of newLayers) {
-        if (typeof layer === "string") {
+        if (typeof layer === 'string') {
           await this.formatXml(layer); // 等待当前 layer 处理完成
         } else {
           await this.formatXml(layer.id, layer.minZoom, layer.maxZoom, layer.zIndex, layer.visible); // 等待当前 layer 处理完成
@@ -432,7 +519,7 @@ export class olMap {
     this.map.removeOverlay(this.infoWindow);
     this.infoWindow = null;
     if (!!flag && this.select) {
-      this.select.clear();
+      this.select.getFeatures().clear();
     }
   }
   /**
@@ -630,12 +717,13 @@ export class olMap {
     const graticule = new Graticule({
       name: 'Graticule',
       showLabels: true, // 为每条刻度线绘制一个带有各自纬度/经度的标签
-      wrapX: false,     // 是否水平重复经纬网
+      wrapX: false, // 是否水平重复经纬网
       targetSize: 230,
       zIndex: 99999,
-      strokeStyle: new Stroke({ // 用于绘制刻度线的样式
+      strokeStyle: new Stroke({
+        // 用于绘制刻度线的样式
         color: '#dcdcdc', // 线条颜色
-        width: 1,       // 线条宽度
+        width: 1 // 线条宽度
       }),
       lonLabelStyle: new Text({
         font: '12px Calibri,sans-serif',
@@ -655,9 +743,9 @@ export class olMap {
       })
     });
     if (visible) {
-      this.map.addLayer(graticule)
+      this.map.addLayer(graticule);
     } else {
-      this.removeLayer('Graticule')
+      this.removeLayer('Graticule');
     }
   }
   /**
@@ -673,10 +761,73 @@ export class olMap {
       }
     });
   }
+  // 创建图形
+  createGraphics(data: any) {
+    if (data.type === 'circle') {
+      // 绘制圆形
+      return this.createCircle(data);
+    } else if (['polygon', 'rectangle'].includes(data.type)) {
+      // 绘制矩形、多边形
+      return this.createPolygon(data);
+    }
+    // else if (data.type === 'marker') {
+    //   // 绘制图标
+    //   return createMarker(data);
+    // } else if (data.type === 'measureArea') {
+    //   // 绘制面积
+    //   return createMeasureArea(data);
+    // } else if (data.type === 'text') {
+    //   // 文字
+    //   return addText(data);
+    // } else if (data.type === 'straightLine') {
+    //   // 直线
+    //   return createStraightLine(data);
+    // }
+  }
+  createCircle(data) {
+    const circle = new Circle(data.center, data.radius);
+    const feature = new Feature(circle);
+    feature.setStyle(
+        new Style({
+          stroke: new Stroke({
+            color: hexToRgba(data.strokeColor, data.strokeOpacity),
+            width: data.strokeWeight
+          }),
+          fill: new Fill({
+            color: hexToRgba(data.fillColor, data.fillOpacity)
+          })
+        })
+    );
+    this.drawVector.getSource().addFeature(feature);
+    return feature;
+  }
+  createPolygon(data) {
+    const polygon = new Polygon([data.path]);
+    const feature = new Feature(polygon);
+    feature.setStyle(
+        new Style({
+          stroke: new Stroke({
+            color: hexToRgba(data.strokeColor, data.strokeOpacity),
+            width: data.strokeWeight
+          }),
+          fill: new Fill({
+            color: hexToRgba(data.fillColor, data.fillOpacity)
+          })
+        })
+    );
+    this.drawVector.getSource().addFeature(feature);
+    return feature;
+  }
   getVectorLayer() {
     return this.vectorLayer;
   }
+  getDrawVector() {
+    return this.drawVector;
+  }
   getMap() {
     return this.map;
   }
+  getMouseTool() {
+    return this.drawTool;
+  }
 }