Browse Source

添加圆

Hwf 6 months ago
parent
commit
27ab2e65c9

+ 6 - 13
src/components/Map/YztMap/index.vue

@@ -38,7 +38,7 @@ const props = withDefaults(defineProps<Props>(), {});
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
 const appStore = useAppStore();
-const emits = defineEmits(['update:drawing', 'update:showMask', 'selectGraphics', 'handleShowWarehouse', 'handleShowVideo', 'handleShowPeople']);
+const emits = defineEmits(['update:showMask', 'selectGraphics', 'handleShowWarehouse', 'handleShowVideo', 'handleShowPeople']);
 
 const mapRef = ref(null);
 const mapState = reactive({
@@ -55,17 +55,6 @@ const width = ref('100%');
 const height = ref('100%');
 let map, mapUtils;
 
-// 监听是否开启绘制
-watch(
-  () => props.drawing,
-  (value) => {
-    if (value) {
-      mapUtils.drawGraphics(props.graphicsType);
-    } else {
-      mapUtils.closeDraw();
-    }
-  }
-);
 watch(
   () => appStore.showLeftSection,
   () => {
@@ -144,6 +133,7 @@ const init = () => {
       if (props.showMask) {
         mapUtils.createVecByJson2(mmJson, { strokeWeight: 2 });
       }
+      // let drawTool = new DrawTool({ mapUtils, map });
       handleResize();
     },
     onMarkerClick: (data) => {
@@ -363,6 +353,9 @@ const getScale = () => {
 const getMapUtils = () => {
   return mapUtils;
 };
+const getDrawTool = () => {
+  return mapUtils.getDrawTool();
+};
 // 加载事件
 onMounted(() => {
   init();
@@ -375,7 +368,7 @@ onUnmounted(() => {
 provide('getMapUtils', getMapUtils);
 provide('getMap', getMap);
 provide('getScale', getScale);
-defineExpose({ getMapUtils, addMarker, clearMarker });
+defineExpose({ getMap, getDrawTool, getMapUtils, addMarker, clearMarker });
 </script>
 
 <style scoped>

+ 1 - 15
src/components/Map/index.vue

@@ -38,7 +38,6 @@ const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
 const appStore = useAppStore();
 
 const emits = defineEmits([
-  'update:drawing',
   'update:showMask',
   'selectGraphics',
   'unSelectGraphics',
@@ -99,7 +98,7 @@ const mapUtils = useAMap({
     if (props.showMask) {
       creatMask2(mmJson, { strokeWeight: 2 });
     }
-    drawTool.initMouseTool({ container: 'aMap', map, AMap });
+    drawTool.initMouseTool({ map, AMap });
     handleResize();
   },
   onMarkerClick: (data) => {
@@ -319,19 +318,6 @@ watch(
     }
   }
 );
-// watc h(
-//   () => props.mouseToolState,
-//   () => {
-//     if (props.drawing) {
-//       drawGraphics(props.mouseToolState);
-//     } else {
-//       closeDraw();
-//     }
-//   },
-//   {
-//     deep: true
-//   }
-// );
 // 缩放级别变化
 const zoomChangeHandler = () => {
   mapState.zoom = map.getZoom();

+ 1 - 10
src/hooks/AMap/useDrawTool.ts

@@ -1,15 +1,7 @@
 import { nanoid } from 'nanoid';
 import { useHistory } from '@/hooks/useHistory';
 import { deepClone, getRgba } from '@/utils';
-import { countCircleArea, countRectangleArea } from '@/utils/geometryUtil';
 
-interface DrawToolOptions {
-  color: string;
-  drawType: string;
-  lineWidth: string;
-  graphicsType: string;
-  onDrawCompleted?: Function;
-}
 export function useDrawTool() {
   let drawOptions = {
     strokeColor: '#f80102',
@@ -22,10 +14,9 @@ export function useDrawTool() {
   const { currentState, commit, undo, history, future } = useHistory();
   const overlays = [];
   const overlaysData = [];
-  let mouseTool, contextMenu, container, map, AMap, rightClickObj;
+  let mouseTool, contextMenu, map, AMap, rightClickObj;
   let drawEndMethod;
   const initMouseTool = (options2) => {
-    container = document.getElementById('aMap');
     map = options2.map;
     AMap = options2.AMap;
     // 初始化绘制工具

+ 1 - 1
src/utils/gisUtils.ts

@@ -186,4 +186,4 @@ export const mergeGeoJsonPolygons = (geoJsonData) => {
 export const getPointsCenter = (points) => {
   const features = turf.points(points);
   return turf.center(features);
-}
+};

+ 23 - 0
src/utils/index.ts

@@ -377,3 +377,26 @@ export const getRgba = (rgbaString) => {
     opacity: opacity
   };
 };
+
+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})`;
+};

+ 28 - 4
src/utils/olMap/drawTool.ts

@@ -1,10 +1,34 @@
 export class DrawTool {
   private drawOptions = {
-    strokeColor: options.color,
+    strokeColor: '#f80102',
     strokeOpacity: 1,
-    strokeWeight: 2,
-    fillColor: options.color,
-    fillOpacity: options.drawType === '1' ? 0 : 0.5,
+    strokeWeight: '1',
+    fillColor: '#f80102',
+    fillOpacity: 0.5,
     strokeStyle: 'solid'
   };
+  private container;
+  private mapUtils;
+  private map;
+  constructor(options) {
+    this.container = document.getElementById('aMap');
+    this.mapUtils = options.map;
+    this.map = options.AMap;
+    this.drawOptions = {
+      graphicsType: options.graphicsType ? options.graphicsType : 'cirlce',
+      strokeColor: options.color,
+      strokeOpacity: 1,
+      strokeWeight: 2,
+      fillColor: options.color,
+      fillOpacity: options.drawType === '1' ? 0 : 0.5,
+      strokeStyle: 'solid'
+    };
+    // // 初始化绘制工具
+    // mouseTool = new AMap.MouseTool(map);
+    // //创建右键菜单
+    // contextMenu = new AMap.ContextMenu();
+    // if (options2.drawEndMethod) {
+    //   drawEndMethod = options2.drawEndMethod;
+    // }
+  }
 }

+ 65 - 13
src/utils/olMap/olMap.ts

@@ -30,8 +30,10 @@ 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';
 
 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');
@@ -43,8 +45,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 +68,8 @@ export class olMap {
     strokeStyle: 'solid'
   };
   private plot;
+  private drawVector;
+  private drawTool;
   private vectorLayer;
   // 边界遮罩图层
   private maskLayer;
@@ -146,6 +150,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 = [];
@@ -160,8 +165,6 @@ export class olMap {
           this.map.getView().setCenter(newFeature.geometry.coordinates);
           event.selected = [];
         }
-      } else {
-
       }
     });
   }
@@ -251,11 +254,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);
   }
 
   // 绘制结束事件
@@ -282,10 +287,54 @@ export class olMap {
       this.plot.plotDraw.activate('FreePolygon');
     }
   }
-
+  // 空间分析绘制图形
+  drawGraphics2(newOptions: MouseTool) {
+    const typeList = {
+      circle: 'Circle',
+      // rectangle: 'Rectangle',
+      polygon: 'Polygon'
+    };
+    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],
+        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();
   }
 
   // 切换图层
@@ -637,7 +686,7 @@ export class olMap {
       zIndex: 99999,
       strokeStyle: new Stroke({ // 用于绘制刻度线的样式
         color: '#dcdcdc', // 线条颜色
-        width: 1,       // 线条宽度
+        width: 1       // 线条宽度
       }),
       lonLabelStyle: new Text({
         font: '12px Calibri,sans-serif',
@@ -681,4 +730,7 @@ export class olMap {
   getMap() {
     return this.map;
   }
+  getMouseTool() {
+    return this.drawTool;
+  }
 }

+ 93 - 3
src/views/globalMap/RightMenu/DrawTools.vue

@@ -52,6 +52,7 @@
     </div>
     <div class="draw-item" @click="openDraw">{{ mouseToolState.drawing ? '关闭绘制' : '开启绘制' }}</div>
     <div class="draw-item" @click="handleUndo">撤销</div>
+    <div id="control-box"></div>
   </div>
 </template>
 
@@ -59,11 +60,16 @@
 import { useHistory } from '@/hooks/useHistory';
 import { nanoid } from 'nanoid';
 import { deepClone } from '@/utils';
+import * as turf from '@turf/turf';
 
 interface ListItem {
   label: string;
   value: string;
 }
+const props = defineProps({
+  activeMap: String
+});
+const AMapType = ['vectorgraph', 'satellite'];
 const getDrawTool = inject('getDrawTool');
 const getMap = inject('getMap');
 const emits = defineEmits(['handleAnalysisData']);
@@ -85,7 +91,11 @@ watch(
       drawOptions.drawType = mouseToolState.drawType;
       drawOptions.graphicsType = mouseToolState.graphicsType;
       drawTool.drawGraphics2(drawOptions);
-      drawTool.getMouseTool().on('draw', onDraw);
+      if (AMapType.includes(props.activeMap)) {
+        drawTool.getMouseTool().on('draw', onDraw);
+      } else {
+        drawTool.getMouseTool().on('drawend', onDraw2);
+      }
     } else {
       mouseToolState.drawing = false;
       drawTool.closeDraw();
@@ -175,6 +185,7 @@ onClickOutside(selectBoxRef3, () => {
 const openDraw = () => {
   mouseToolState.drawing = !mouseToolState.drawing;
 };
+// 高德地图绘制结束
 const onDraw = (event) => {
   const obj = event.obj;
   const id = nanoid();
@@ -201,7 +212,6 @@ const onDraw = (event) => {
   overlays.push(obj);
   overlaysData.push(data);
   commit(deepClone(overlaysData));
-  console.log(data);
   // 右击进入编辑
   obj.on('rightclick', handleRightClick);
   if (overlaysData.length === 1) {
@@ -215,10 +225,68 @@ const onDraw = (event) => {
     }
   });
 };
+// 粤政图绘制结束
+const onDraw2 = (event) => {
+  const feature = event.feature;
+  const geometry = feature.getGeometry();
+  const geometryType = geometry.getType();
+  const id = nanoid();
+  feature.set('id', id);
+  const data: any = {
+    id: id,
+    type: drawOptions.graphicsType,
+    // color: feature._opts.strokeColor,
+    // drawType: feature._opts.fillOpacity === 0 ? '1' : '2'
+  };
+  // 获取绘制的几何信息(包括经纬度)
+  if (geometryType === 'Point') {
+    const coordinates = geometry.getCoordinates();
+    console.log('绘制了一个点:', coordinates);
+  } else if (geometryType === 'LineString') {
+    const coordinates = geometry.getCoordinates();
+    console.log('绘制了一条线:', coordinates);
+    // 线的坐标是点的数组,每个点都是一个经纬度数组
+  } else if (geometryType === 'Polygon') {
+    const coordinates = geometry.getCoordinates();
+    console.log('绘制了一个多边形:', coordinates);
+    // 多边形的坐标是环的数组,每个环是点的数组,每个点都是一个经纬度数组
+  } else if (geometryType === 'Circle') {
+    data.center = geometry.getCenter();
+    data.radius = geometry.getRadius();
+    const data2 = turf.sector(data.center, data.radius, 0, 360);
+    const pathArr = data2.geometry.coordinates[0];
+    data.path = pathArr;
+    console.log('绘制了一个圆:', data);
+  }
+  // const path = geometry.getCoordinates();
+  // debugger
+  // // 将AMap.LngLat对象数组转换为经纬度数组
+  // const pathArr = path.map((lngLat) => {
+  //   // 返回经度和纬度的数组
+  //   return [lngLat.lng, lngLat.lat];
+  // });
+  // data.path = pathArr;
+  overlays.push(feature);
+  overlaysData.push(data);
+  commit(deepClone(overlaysData));
+  // 右击进入编辑
+  feature.on('contextmenu', handleRightClick);
+  if (overlaysData.length === 1) {
+    analysisSpatial(data);
+  }
+  // // 点击空间分析
+  // feature.on('click', function () {
+  //   // 没在编辑时
+  //   if (!mouseToolState.drawing) {
+  //     analysisSpatial(data);
+  //   }
+  // });
+};
 let rightClickObj;
 // 图形右击事件
 let initContextMenu = false;
 const handleRightClick = (event) => {
+  debugger
   rightClickObj = event.target;
   const contextMenu = getDrawTool().getContextMenu();
   if (!initContextMenu) {
@@ -283,7 +351,7 @@ const handleUndo = () => {
           fillColor: restoreData.color,
           fillOpacity: restoreData.drawType === '1' ? 0 : 0.5
         };
-        if (restoreData.type === 'circlr') {
+        if (restoreData.type === 'circle') {
           newData.center = restoreData.center;
           newData.radius = restoreData.radius;
         }
@@ -340,6 +408,28 @@ const analysisSpatial = (data) => {
   }
   emits('handleAnalysisData', location);
 };
+onMounted(() => {
+  // 监听右击事件
+  getMap().on('contextmenu', (event) => {
+    event.preventDefault(); // 阻止默认上下文菜单
+
+    // 获取右击位置的要素
+    const featuresAtPixel = getMap().getFeaturesAtPixel(event.pixel);
+
+    // 检查是否有要素在右击位置
+    if (featuresAtPixel && featuresAtPixel.length > 0) {
+      // 遍历要素并检查条件(这里可以根据需要添加条件)
+      featuresAtPixel.forEach(function(feature) {
+        // 执行你想要的动作,例如显示一个信息框或弹出菜单
+        console.log('右击了要素:', feature.get('id')); // 假设要素有一个'id'属性
+
+        // 你可以在这里显示一个自定义的右击菜单
+        // 例如,创建一个<div>元素,设置其内容和样式,然后添加到DOM中
+        // 并监听菜单项的点击事件来执行相应的动作
+      });
+    }
+  });
+})
 onBeforeUnmount(() => {
   //
 });

+ 3 - 3
src/views/globalMap/index.vue

@@ -35,7 +35,7 @@
       <SwitchMapTool :active-map="activeMap" class="tool-box" @switch-map="switchMap" />
       <!--时间轴-->
       <TimeAxis />
-      <DrawTools v-if="showDrawTools" @handle-analysis-data="handleAnalysisData" />
+      <DrawTools v-if="showDrawTools" :active-map="activeMap" @handle-analysis-data="handleAnalysisData" />
       <NearbyVideos v-if="showNearbyVideos" v-model="showNearbyVideos" :location="location" />
       <GridPointRainfall v-if="showRainfall" v-model="showRainfall" :location="location" />
       <MaterialDetail v-if="showWarehouse" v-model="showWarehouse" :warehouse-data="warehouseData" />
@@ -73,7 +73,7 @@ let map2Ref = ref(null);
 let leftMenuRef = ref(null);
 let showMask = ref(true);
 //  vectorgraph satellite imageMap imageMap3 logical satellite2 satellite3
-let activeMap = ref('satellite');
+let activeMap = ref('imageMap');
 // 附近视频菜单数据
 let tempMenu = ref({
   name: '',
@@ -262,7 +262,7 @@ const showDetail = (data, dataType) => {
 };
 const getDrawTool = () => {
   if (YMapType.includes(activeMap.value)) {
-    return map2Ref.value.drawTool;
+    return map2Ref.value.getMapUtils();
   } else if (AMapType.includes(activeMap.value)) {
     return mapRef.value.drawTool;
   }