浏览代码

增加了退出编辑和进入编辑功能

louhangfei 2 年之前
父节点
当前提交
4e939f3986

二进制
src/assets/images/camera/delete.png


二进制
src/assets/images/camera/enlarge.png


二进制
src/assets/images/camera/mousePointer.png


二进制
src/assets/images/camera/pen.png


二进制
src/assets/images/camera/redo.png


二进制
src/assets/images/camera/save.png


二进制
src/assets/images/camera/shrink.png


二进制
src/assets/images/camera/undo.png


二进制
src/assets/images/camera/video-live.png


+ 12 - 0
src/views/result/components/CameraLiveVideo/CameraLiveVideo.vue

@@ -0,0 +1,12 @@
+<template>
+  <img :src="bg" alt="" class="videoLive" />
+</template>
+<script lang="ts" setup>
+  import bg from '@/assets/images/camera/video-live.png';
+</script>
+<style scoped>
+  .videoLive {
+    width: 720px;
+    height: 405px;
+  }
+</style>

+ 51 - 3
src/views/result/components/CameraViewSetting/CameraViewSetting.vue

@@ -1,11 +1,59 @@
 <template>
   <div>
-    <FenceToolbar />
-    <!-- <FenceEditor /> -->
+    <FenceToolbar
+      @remove="handleRemove"
+      @save="handleSave"
+      @toggle-editable="toggleEditable"
+      :is-edit="isEdit"
+    />
+    <div class="cameraViewSettingWrapper">
+      <FenceEditor ref="fenceEditorRef" />
+      <div class="cameraVideo"><CameraLiveVideo /></div>
+    </div>
   </div>
 </template>
 <script lang="ts" setup>
+  import { ref } from 'vue';
   import FenceToolbar from '../FenceToolbar/FenceToolbar.vue';
   import FenceEditor from '../FenceEditor/FenceEditor.vue';
+  import CameraLiveVideo from '../CameraLiveVideo/CameraLiveVideo.vue';
+
+  const fenceEditorRef = ref<typeof FenceEditor | null>(null);
+
+  const handleRemove = () => {
+    console.log('handleRemove');
+    fenceEditorRef.value?.remove();
+  };
+
+  const isEdit = ref(true);
+
+  /** 退出编辑模式 */
+  const toggleEditable = (val: boolean) => {
+    isEdit.value = val;
+    if (val) {
+      fenceEditorRef.value?.setEditMode();
+    } else {
+      fenceEditorRef.value?.exitEditMode();
+    }
+  };
+
+  const handleSave = () => {
+    const json = fenceEditorRef.value?.toObject();
+    console.log('save json', json);
+  };
 </script>
-<style scoped></style>
+<style scoped>
+  .cameraViewSettingWrapper {
+    position: relative;
+    width: 720px;
+    height: 405px;
+    border: 1px solid #ccc;
+  }
+
+  .cameraVideo {
+    position: absolute;
+    background: #ccc;
+    width: 100%;
+    height: 100%;
+  }
+</style>

+ 50 - 14
src/views/result/components/FenceEditor/FenceEditor.vue

@@ -5,14 +5,7 @@
 <script lang="ts" setup>
   import Konva from 'konva';
   import { ref, onMounted, onUnmounted } from 'vue';
-  import {
-    GROUP_NAME,
-    POLYGON_NAME,
-    Points,
-    ServerLine,
-    ToolObjectItem,
-    toolObject,
-  } from './constants';
+  import { GROUP_NAME, POLYGON_NAME, Points, ToolObjectItem, toolObject } from './constants';
   import { ElMessage } from 'element-plus';
   import { getDefaultScale } from './utils';
   import { Group } from 'konva/lib/Group';
@@ -20,6 +13,8 @@
   const mapRef = ref<HTMLCanvasElement | null>(null);
   let currentTool: ToolObjectItem = toolObject[1];
 
+  let isEdit = true;
+
   let stage: Konva.Stage | null = null;
   let layer: Konva.Layer | null = null;
   let currentDrawingShape: Konva.Group | null = null; //现在绘画的图形
@@ -77,6 +72,7 @@
     stage?.on('mousedown', (e) => {
       //鼠标左键开始
       console.log('stage mousedown', e);
+      if (!isEdit) return;
       if (e.evt.button == 0) {
         if (e.target === stage) {
           stageMousedown(currentTool!);
@@ -100,6 +96,7 @@
     });
     //鼠标移动
     stage?.on('mousemove', () => {
+      if (!isEdit) return;
       if (currentTool && drawing) {
         //绘画中
         stageMousemove();
@@ -107,6 +104,8 @@
     });
     //鼠标放开
     stage?.on('mouseup', (e: Konva.KonvaEventObject<any>) => {
+      if (!isEdit) return;
+
       if (e.evt.button == 0) {
         if (drawing) {
           stageMouseup(e);
@@ -125,6 +124,8 @@
     container.tabIndex = 1;
     container?.focus();
     container?.addEventListener('keydown', (e) => {
+      if (!isEdit) return;
+
       //删除的快捷键
       if (e.keyCode === 46) {
         removeCurrent();
@@ -143,7 +144,7 @@
   };
 
   /** 设置当前选中的group */
-  function setCurrentGroup(group: Konva.Group) {
+  function setCurrentGroup(group: Konva.Group | null) {
     currentDrawingShape = group;
     setGroupActive(group);
     currentDel = group;
@@ -155,6 +156,8 @@
    * @param e 传入的event对象
    */
   function stageMousedown(currentTool: ToolObjectItem) {
+    if (!isEdit) return;
+
     console.log('stagemousedown');
 
     //如果数组长度小于2,初始化多边形和顶点,使它们成为一组,否则什么都不做
@@ -221,6 +224,8 @@
    * @param e 传入的event对象
    */
   function stageMousemove() {
+    if (!isEdit) return;
+
     const container = stage?.container();
     if (!container) return;
 
@@ -252,6 +257,8 @@
    * @param e 传入的event对象
    */
   function stageMouseup(e: Konva.KonvaEventObject<any>) {
+    if (!isEdit) return;
+
     if (e.evt.button == 2) {
       if (polygonPoints.length != 0) {
         //最好使用konva提供的鼠标xy点坐标
@@ -381,6 +388,8 @@
       c.style.cursor = 'pointer';
     });
     circle.on('mousedown', (e) => {
+      if (!isEdit) return;
+
       console.log('circle,');
       if (!drawing) {
         circle.draggable(true);
@@ -392,11 +401,15 @@
       e.cancelBubble = true;
     });
     circle.on('mouseleave', () => {
+      if (!isEdit) return;
+
       const c = stage?.container();
       if (!c) return;
       c.style.cursor = 'crosshair';
     });
     circle.on('dragstart', () => {
+      if (!isEdit) return;
+
       switch (currentTool?.type) {
         case 'poly':
           //查找拖拽了多边形的哪个点
@@ -416,6 +429,8 @@
       }
     });
     circle.on('dragmove', () => {
+      if (!isEdit) return;
+
       switch (currentTool?.type) {
         case 'poly':
           var x = circle.x();
@@ -429,6 +444,8 @@
       }
     });
     circle.on('dragend', (e) => {
+      if (!isEdit) return;
+
       switch (currentTool?.type) {
         case 'poly':
           //使所有顶点在顶层显示
@@ -459,7 +476,7 @@
   }
 
   /** 设置当前的group为active */
-  function setGroupActive(activeGroup: Group) {
+  function setGroupActive(activeGroup: Group | null) {
     const groups = stage?.find(GROUP_NAME) as Konva.Group[];
     if (!groups) return;
     /** 将其他组的线条设为非高亮 */
@@ -473,7 +490,7 @@
         (circle as Konva.Circle).hide();
       });
     });
-
+    if (!activeGroup) return;
     const thisLine = activeGroup.findOne(POLYGON_NAME) as Konva.Line;
     if (thisLine) {
       thisLine.stroke(currentTool.activeColor);
@@ -497,9 +514,9 @@
       points: points,
       /*  fill: currentTool.color, */
       stroke: currentTool.color,
-      strokeWidth: 1,
+      strokeWidth: 3,
       draggable: false,
-      opacity: 0.5,
+      opacity: 1,
       lineCap: 'round',
       lineJoin: 'round',
       closed: true,
@@ -509,12 +526,16 @@
     setCurrentGroup(group);
     const pParent = group;
     pParent?.on('mouseleave', () => {
+      if (!isEdit) return;
+
       const c = stage?.container();
       if (c) {
         c.style.cursor = 'crosshair';
       }
     });
     pParent?.on('mousedown', (e) => {
+      if (!isEdit) return;
+
       console.log('group mouse down');
       if (e.evt.button == 0) {
         //绘画结束
@@ -541,6 +562,8 @@
     });
 
     pParent?.on('dragend', () => {
+      if (!isEdit) return;
+
       console.log('dragend');
       /** 这里可以把工具的类型用枚举值定义 */
 
@@ -628,12 +651,24 @@
     return stage?.toObject();
   };
 
+  /** 退出编辑模式 */
+  const exitEditMode = () => {
+    setCurrentGroup(null);
+    isEdit = false;
+  };
+  /** 进入编辑模式 */
+  const setEditMode = () => {
+    isEdit = true;
+  };
+
   defineExpose({
     remove: removeCurrent,
     toObject,
     toRawObject,
     createGroupByPoints,
     initStageByJSON,
+    exitEditMode,
+    setEditMode,
   });
 </script>
 
@@ -644,6 +679,7 @@
     top: 0;
     width: 100%;
     height: 100%;
-    border: 2px solid #0f0;
+    z-index: 8;
+    /* border: 2px solid #0f0; */
   }
 </style>

+ 4 - 7
src/views/result/components/FenceEditor/constants.ts

@@ -3,18 +3,16 @@ export const toolObject: ToolObjectItem[] = [
     name: 'rect',
     type: 'rect',
     /* 矩形颜色 */ color: '#75fb4c',
-    /* 边框颜色 */ lineColor: '#75fb4c',
     /* 顶点颜色 */ anchorColor: 'green',
     activeColor: '#0f0',
   },
   {
     name: 'poly',
     type: 'poly',
-    /* 多边形颜色 */ color: '#E63F00',
-    /* 边框颜色 */ lineColor: '#E63F00 ',
-    /* 顶点颜色 */ anchorColor: 'red',
+    /* 多边形颜色 */ color: '#52FFDA',
+    /* 顶点颜色 */ anchorColor: '#fff',
     /** 选中模式状态下的边框颜色 */
-    activeColor: '#0f0',
+    activeColor: '#52FFDA',
   },
 ];
 
@@ -23,8 +21,7 @@ export interface ToolObjectItem {
   type: string;
   /* 矩形颜色 */
   color: string;
-  /* 边框颜色 */
-  lineColor: string;
+
   /* 顶点颜色 */
   anchorColor: string;
 

+ 34 - 52
src/views/result/components/FenceToolbar/FenceToolbar.vue

@@ -1,39 +1,40 @@
 <template>
-  <div class="camera-wrapper">
-    <div style="text-align: center"> camera 画面 </div>
-    <div class="editor-wrapper" v-if="isFenceOn">
-      <div class="toolbar">
-        <div>
-          <ElButton>编辑</ElButton>
-          <ElButton @click="remove">删除</ElButton>
-          <ElButton @click="toObject">保存到localStorage</ElButton>
-          <ElButton @click="loadGroup">从local加载group</ElButton>
-          <ElButton @click="toRawObject">保存Raw</ElButton>
-        </div>
-      </div>
-      <PolygonEditor class="polygonEditor" ref="polygonEditorRef" />
-    </div>
-  </div>
-  <div>
-    <div
-      >打开电子围栏
-      <ElSwitch v-model="isFenceOn" />
-    </div>
+  <div class="toolbar">
+    <!-- <ElButton>编辑</ElButton>
+    <ElButton @click="remove">删除</ElButton>
+    <ElButton @click="toObject">保存到localStorage</ElButton>
+    <ElButton @click="loadGroup">从local加载group</ElButton>
+    <ElButton @click="toRawObject">保存Raw</ElButton> -->
+    <ToolbarIcon :src="mousePointerIcon" :active="false" />
+    <!-- <ToolbarIcon :src="editIcon" :active="false" @click="emits('setEditable')" /> -->
+    <ToolbarIcon :src="deleteIcon" :active="false" @click="emits('remove')" />
+    <ToolbarIcon :src="saveIcon" :active="false" @click="emits('save')" />
+    <ElButton type="primary" size="small" @click="toggleEdit">{{
+      props.isEdit ? '退出编辑' : '编辑'
+    }}</ElButton>
   </div>
 </template>
 <script setup lang="ts">
-  import { ref } from 'vue';
+  import { ref, defineEmits } from 'vue';
   import { ElButton, ElSwitch } from 'element-plus';
   import PolygonEditor from '../FenceEditor/FenceEditor.vue';
   import { ServerLines } from '../FenceEditor/constants';
+  import ToolbarIcon from '../ToolbarIcon/ToolbarIcon.vue';
+  import saveIcon from '@/assets/images/camera/save.png';
+  import deleteIcon from '@/assets/images/camera/delete.png';
+  import mousePointerIcon from '@/assets/images/camera/mousePointer.png';
+  import editIcon from '@/assets/images/camera/pen.png';
 
   const isFenceOn = ref(true);
+  const props = defineProps<{ isEdit: boolean }>();
 
   const polygonEditorRef = ref<typeof PolygonEditor | null>(null);
 
-  const remove = () => {
-    polygonEditorRef.value?.remove();
-  };
+  const emits = defineEmits<{
+    (e: 'toggleEditable', editState: boolean): unknown;
+    (e: 'remove'): unknown;
+    (e: 'save'): unknown;
+  }>();
 
   const toObject = () => {
     const json = polygonEditorRef.value?.toObject();
@@ -63,39 +64,20 @@
     polygonEditorRef.value?.createGroupByPoints(points);
   };
 
-  const preview = () => {
-    polygonEditorRef.value?.preview();
+  const toggleEdit = () => {
+    emits('toggleEditable', !props.isEdit);
   };
 </script>
 
 <style scoped>
-  .camera-wrapper {
-    position: relative;
-    border: 1px solid #f00;
-    background: #fff;
-    height: 600px;
-  }
-
   .toolbar {
-    width: 100px;
-    height: 400px;
-    position: absolute;
-    left: 0;
-    top: 50px;
-    border: 1px solid #f00;
-    z-index: 10;
-    color: #000;
-  }
-
-  .editor-wrapper {
-    position: absolute;
-    left: 0;
-    top: 0;
-    width: 100%;
-    height: 100%;
-  }
+    background-color: #b0b3b3;
+    display: flex;
 
-  .polygonEditor {
-    flex-grow: 1;
+    align-items: center;
+    z-index: 10;
+    padding: 5px 30px;
+    border-radius: 50px;
+    left: 100px;
   }
 </style>

+ 18 - 0
src/views/result/components/ToolbarIcon/ToolbarIcon.vue

@@ -0,0 +1,18 @@
+<template>
+  <img :src="props.src" alt="" class="toolbarIcon" :class="props.active ? 'active' : ''" />
+</template>
+<script lang="ts" setup>
+  const props = defineProps<{ active: boolean; src: string }>();
+</script>
+<style scoped>
+  .toolbarIcon {
+    width: 24px;
+    height: 24px;
+    padding: 4px;
+    cursor: pointer;
+    margin-right: 20px;
+    &.active {
+      background: #1890ff;
+    }
+  }
+</style>

+ 6 - 0
src/views/result/success.vue

@@ -32,6 +32,12 @@
     border: 1px solid #ccc;
   }
 
+  .cameraParamsSetting {
+    width: 350px;
+    min-height: 300px;
+    border: 1px solid #ccc;
+  }
+
   .algorithmsSetting {
     flex: 1;
     border: 1px solid #ccc;