Przeglądaj źródła

增加右键功能

louhangfei 2 lat temu
rodzic
commit
5c2a39ae17

+ 18 - 4
src/views/map-config/mini-map/MapBase/CameraMap.ts

@@ -15,16 +15,22 @@ const isCanvas = (canvas: Canvas | null): canvas is Canvas => {
 };
 
 type OnSelect = (image: CameraImage | null) => unknown;
+type OnRightClick = (e: fabric.IEvent<MouseEvent>) => unknown;
 fabricSetting(fabric);
 
 class CameraMap {
   public canvas: fabric.Canvas | null = null;
   private onSelect: OnSelect;
+  private onRightClick: OnRightClick;
 
-  constructor(param: { canvasId: string; onSelect: OnSelect }) {
-    this.canvas = new fabric.Canvas(param.canvasId);
+  constructor(param: { canvasId: string; onSelect: OnSelect; onRightClick: OnRightClick }) {
+    this.canvas = new fabric.Canvas(param.canvasId, {
+      fireRightClick: true, // 启用右键,button的数字为3
+      stopContextMenu: true, // 禁止默认右键菜单
+    });
     this.addListener();
     this.onSelect = param.onSelect;
+    this.onRightClick = param.onRightClick;
     // window.canvas = this.canvas;
   }
 
@@ -36,8 +42,16 @@ class CameraMap {
     canvas.on('mouse:down', (options) => {
       const target = options.target as CameraImage;
       const cameraId = target?.cameraId;
-      console.log('当前选中的id是', cameraId);
-      console.log(options.target);
+      // console.log('当前选中的id是', cameraId);
+      console.log(options);
+
+      // 判断:右键,且在元素上右键
+      // opt.button: 1-左键;2-中键;3-右键
+      // 在画布上点击:opt.target 为 null
+      if (options.button === 3 && options.target) {
+        this.onRightClick(options);
+        return;
+      }
 
       canvas.forEachObject((object) => {
         if (object === options.target) return;

+ 66 - 0
src/views/map-config/mini-map/MapBase/ContextMenu.vue

@@ -0,0 +1,66 @@
+<template>
+  <div
+    id="canvasMenu"
+    class="menu-x"
+    v-if="props.visible"
+    :style="{ left: props.position.left + 'px', top: props.position.top + 'px' }"
+  >
+    <div class="menu-li" @click="props.setDefault">设为默认</div>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { onMounted, defineProps } from 'vue';
+
+  const props = defineProps<{
+    position: { left: number; top: number };
+    visible: boolean;
+    setDefault: () => unknown;
+  }>();
+
+  onMounted(() => {
+    const contextMenu = document.querySelector('#canvasMenu');
+    if (!contextMenu) return;
+    contextMenu.addEventListener('contextmenu', (e) => {
+      console.log('e', e);
+      e.preventDefault();
+    });
+  });
+</script>
+<style scoped>
+  .menu-x {
+    position: absolute;
+    top: 0;
+    left: 0;
+    box-sizing: border-box;
+    border-radius: 4px;
+    box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
+    background-color: #fff;
+    font-size: 12px;
+  }
+
+  /* 菜单每个选项 */
+  .menu-li {
+    box-sizing: border-box;
+    padding: 4px 8px;
+    border-bottom: 1px solid #ccc;
+    cursor: pointer;
+  }
+
+  /* 鼠标经过的选项,更改背景色 */
+  .menu-li:hover {
+    background-color: antiquewhite;
+  }
+
+  /* 第一个选项,顶部两角是圆角 */
+  .menu-li:first-child {
+    border-top-left-radius: 4px;
+    border-top-right-radius: 4px;
+  }
+
+  /* 最后一个选项,底部两角是圆角,底部不需要边框 */
+  .menu-li:last-child {
+    border-bottom: none;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+  }
+</style>

+ 32 - 2
src/views/map-config/mini-map/MiniMapConfig.vue

@@ -81,13 +81,18 @@
             </div>
           </div>
         </div>
-        <div style="overflow: auto">
+        <div style="overflow: auto; position: relative">
           <canvas
             width="400"
             height="400"
             id="mapEditCanvas"
             style="border: 1px solid #ccc"
           ></canvas>
+          <ContextMenu
+            :visible="menuVisible"
+            :position="mousePosition"
+            :set-default="handleSetDefault"
+          />
         </div>
       </div>
     </div>
@@ -107,6 +112,7 @@
   import { useGlobSetting } from '@/hooks/setting';
   import { computed } from 'vue';
   import { Search } from '@element-plus/icons-vue';
+  import ContextMenu from './MapBase/ContextMenu.vue';
 
   const miniMap = useMiniMap();
   const globSetting = useGlobSetting();
@@ -115,10 +121,15 @@
 
   let map: CameraMap;
   const selectedCamera = ref<CameraImage | null>(null);
+  /** 右键选中的摄像机 */
+  const rightSelectedCamera = ref<CameraImage | null>(null);
   const cameraOptions = ref<{ label: string; value: string }[]>([]);
   const defaultCameraId = ref('');
   const searchKey = ref('');
 
+  const mousePosition = ref<{ left: number; top: number }>({ left: 0, top: 0 });
+  const menuVisible = ref(false);
+
   const handleAvatarSuccess = (e) => {
     const imgPath = e.data;
     const imgUrl = urlJoin(globSetting.imgUrl!, imgPath);
@@ -151,7 +162,11 @@
     if (selectedShopId.value) {
       getShopContent();
     }
-    map = new CameraMap({ canvasId: 'mapEditCanvas', onSelect: onSelectCamera });
+    map = new CameraMap({
+      canvasId: 'mapEditCanvas',
+      onSelect: onSelectCamera,
+      onRightClick: handleRightClick,
+    });
   });
 
   const keyupListener = (e) => {
@@ -203,6 +218,13 @@
   const onSelectCamera = (cameraImg: CameraImage) => {
     console.log('onSelectCamera', cameraImg);
     selectedCamera.value = cameraImg;
+    menuVisible.value = false;
+  };
+
+  const handleRightClick = (e) => {
+    mousePosition.value = { left: e.pointer.x, top: e.pointer.y };
+    menuVisible.value = true;
+    rightSelectedCamera.value = e.target;
   };
 
   const mapJSONToOptions = () => {
@@ -238,6 +260,14 @@
     }
     selectedCamera.value = null;
   };
+
+  const handleSetDefault = () => {
+    const cameraId = rightSelectedCamera.value?.cameraId;
+    if (!cameraId) return;
+    defaultCameraId.value = cameraId;
+    /** 选择完成后隐藏 */
+    menuVisible.value = false;
+  };
 </script>
 
 <style scoped>