Browse Source

完成设置默认摄像头和点击高亮图片功能

louhangfei 2 years ago
parent
commit
f7cad358c6

BIN
src/assets/camera/favorites - 副本.png


BIN
src/assets/camera/favorites.png


+ 71 - 0
src/views/map-config/mini-map/MapBase/CameraGroup-bak.ts

@@ -0,0 +1,71 @@
+import { fabric } from 'fabric';
+import cameraActiveImg from '@/assets/camera/camera-active.png';
+import cameraImg from '@/assets/camera/camera.png';
+import favoritesImg from '@/assets/camera/favorites.png';
+import { getRandomPosition } from './utils';
+import { CameraImage } from './types';
+
+class CameraGroup extends fabric.Group {
+  g: fabric.Group | null = null;
+  cameraImg: CameraImage | null = null;
+  favImg: CameraImage | null = null;
+  cameraId = '';
+
+  constructor() {
+    super();
+    fabric.Image.fromURL(cameraActiveImg, (cImg) => {
+      cImg.set({
+        left: 0,
+        top: 0,
+      });
+      this.cameraImg = cImg;
+      fabric.Image.fromURL(favoritesImg, (favImg) => {
+        favImg.set({
+          left: 50,
+          top: 0,
+        });
+        this.favImg = favImg as CameraImage;
+        this.g = new fabric.Group([cImg, favImg]);
+      });
+    });
+  }
+
+  init() {}
+
+  /** 提供copy功能,每次新建的时候执行copy就行了 */
+  clone(): Promise<CameraGroup> {
+    console.log('clone');
+    return new Promise((resolve) => {
+      this.g?.clone((e) => {
+        console.log('clone', e);
+        resolve(e as CameraGroup);
+      });
+    });
+  }
+
+  setSelected() {
+    this.cameraImg?.setSrc(cameraActiveImg);
+  }
+
+  setUnSelected() {
+    this.cameraImg?.setSrc(cameraImg);
+  }
+  /** 设为默认摄像头 */
+  setDefault() {
+    this.favImg?.set('visible', true);
+  }
+  /** 取消默认摄像头 */
+  cancelDefault() {
+    this.favImg?.set('visible', false);
+  }
+
+  setAttr(attr: { cameraId: string; left: number; top: number }) {
+    if (attr.cameraId) {
+      this.cameraId = attr.cameraId;
+    }
+    this.g?.set(attr);
+    return this.g;
+  }
+}
+
+export default CameraGroup;

+ 88 - 0
src/views/map-config/mini-map/MapBase/CameraGroup.ts

@@ -0,0 +1,88 @@
+import { fabric } from 'fabric';
+import cameraActiveImg from '@/assets/camera/camera-active.png';
+import cameraImg from '@/assets/camera/camera.png';
+import favoritesImg from '@/assets/camera/favorites.png';
+import { CameraImage } from './types';
+
+class CameraGroup extends fabric.Group {
+  g: fabric.Group;
+  cameraImg: CameraImage | null = null;
+  favImg: CameraImage | null = null;
+  cameraId = '';
+
+  constructor() {
+    super();
+    this.init();
+  }
+
+  init() {
+    fabric.Image.fromURL(cameraActiveImg, (cImg) => {
+      cImg.set({
+        left: 0,
+        top: 0,
+        width: 100,
+        height: 100,
+        imageName: 'cameraImage',
+      });
+      console.log('cameraActiveImg', cImg);
+      this.cameraImg = cImg;
+      fabric.Image.fromURL(favoritesImg, (favImg) => {
+        favImg.set({
+          width: 50,
+          height: 50,
+          left: 50,
+          top: 0,
+          imageName: 'favImage',
+        });
+        this.favImg = favImg as CameraImage;
+        this.g = new fabric.Group([cImg, favImg]);
+      });
+    });
+  }
+
+  /** 提供copy功能,每次新建的时候执行copy就行了 */
+  clone(): Promise<CameraGroup> {
+    console.log('clone');
+    console.log('this', this);
+    return new Promise((resolve) => {
+      this.g.clone((e) => {
+        console.log('clone', e);
+        const newG = e as fabric.Group;
+        const newGroup = new CameraGroup();
+        const cameraImg = newG.getObjects().find((x) => x.imageName === 'cameraImage');
+        const favImage = newG.getObjects().find((x) => x.imageName === 'favImage');
+        newGroup.cameraImg =                            ;
+        newGroup.favImg = favImage;
+        newGroup.g = e;
+        resolve(newGroup as CameraGroup);
+      });
+    });
+  }
+
+  setSelected() {
+    
+    this.cameraImg?.setSrc(cameraActiveImg);
+  }
+
+  setUnSelected() {
+    this.cameraImg?.setSrc(cameraImg);
+  }
+  /** 设为默认摄像头 */
+  setDefault() {
+    this.favImg?.set('visible', true);
+  }
+  /** 取消默认摄像头 */
+  cancelDefault() {
+    this.favImg?.set('visible', false);
+  }
+
+  setAttr(attr: { cameraId: string; left: number; top: number }) {
+    if (attr.cameraId) {
+      this.cameraId = attr.cameraId;
+    }
+    this.g?.set(attr);
+    return this.g;
+  }
+}
+
+export default new CameraGroup();

+ 48 - 38
src/views/map-config/mini-map/MapBase/CameraMap.ts

@@ -1,27 +1,20 @@
 import { fabric } from 'fabric';
 import cameraActiveImg from '@/assets/camera/camera-active.png';
 import cameraImg from '@/assets/camera/camera.png';
-import { MapData } from './types';
+import favoritesImg from '@/assets/camera/favorites.png';
+import { CameraImage, MapData, OnRightClick, OnSelect, isCanvas } from './types';
 import { fabricSetting } from './fabricSetting';
+import { getRandomPosition } from './utils';
+// import templateGroup from './CameraGroup';
+import { createGroup, toggleGroupSelected, toggleCameraDefault } from './CameraStarGroup';
 
-export interface CameraImage extends fabric.Image {
-  cameraId: string;
-}
-
-type Canvas = fabric.Canvas;
-
-const isCanvas = (canvas: Canvas | null): canvas is Canvas => {
-  return Boolean(canvas);
-};
-
-type OnSelect = (image: CameraImage | null) => unknown;
-type OnRightClick = (e: fabric.IEvent<MouseEvent>) => unknown;
-fabricSetting(fabric);
+fabricSetting();
 
 class CameraMap {
   public canvas: fabric.Canvas | null = null;
   private onSelect: OnSelect;
   private onRightClick: OnRightClick;
+  private templateGroup: fabric.Group | null = null;
 
   constructor(param: { canvasId: string; onSelect: OnSelect; onRightClick: OnRightClick }) {
     this.canvas = new fabric.Canvas(param.canvasId, {
@@ -31,7 +24,10 @@ class CameraMap {
     this.addListener();
     this.onSelect = param.onSelect;
     this.onRightClick = param.onRightClick;
-    // window.canvas = this.canvas;
+    createGroup().then((res) => {
+      this.templateGroup = res;
+    });
+    window.canvas = this.canvas;
   }
 
   /** 监听点击事件 */
@@ -43,6 +39,7 @@ class CameraMap {
       const target = options.target as CameraImage;
       const cameraId = target?.cameraId;
       // console.log('当前选中的id是', cameraId);
+      console.log('mouse:down');
       console.log(options);
 
       // 判断:右键,且在元素上右键
@@ -53,24 +50,29 @@ class CameraMap {
         return;
       }
 
-      canvas.forEachObject((object) => {
-        if (object === options.target) return;
-        (object as CameraImage).setSrc(cameraImg, () => {
-          canvas.renderAll();
-        });
-      });
+      this.setAllGroupsUnselected();
       if (!cameraId || !target) {
         this.onSelect(null);
         return;
       }
-      target.setSrc(cameraActiveImg, () => {
+      toggleGroupSelected(target, true).then(() => {
         canvas.renderAll();
       });
-
       this.onSelect(target);
     });
   }
 
+  private setAllGroupsUnselected() {
+    const canvas = this.canvas;
+    if (!isCanvas(canvas)) return;
+    canvas.getObjects('group').forEach((object) => {
+      // if (object === options.target) return;
+      toggleGroupSelected(object, false).then((res) => {
+        canvas.renderAll();
+      });
+    });
+  }
+
   /** 上传背景图 */
   public uploadBg(imgUrl: string) {
     const canvas = this.canvas;
@@ -97,25 +99,18 @@ class CameraMap {
     });
   }
 
-  private getRandomPosition() {
-    return 100 + Math.floor(Math.random() * 30);
-  }
-
   /** 增加一个摄像头 */
   public addCamera(cameraId: string): Promise<CameraImage> {
     const canvas = this.canvas;
-    if (!isCanvas(canvas)) return Promise.reject();
+    if (!isCanvas(canvas) || !this.templateGroup) return Promise.reject();
+
     return new Promise((resolve) => {
-      fabric.Image.fromURL(cameraActiveImg, (cImg) => {
-        const cameraImg: CameraImage = cImg as unknown as CameraImage;
-        this.setAllCameraUnActive();
-        cameraImg.set({
-          left: this.getRandomPosition(),
-          top: this.getRandomPosition(),
-          cameraId,
-        });
-        canvas.add(cameraImg);
-        resolve(cameraImg);
+      this.setAllGroupsUnselected();
+      createGroup().then((newGroup) => {
+        console.log('templateGroup.clone result', newGroup);
+        newGroup.set({ left: getRandomPosition(), top: getRandomPosition(), cameraId });
+        canvas.add(newGroup);
+        resolve(newGroup);
       });
     });
   }
@@ -196,6 +191,21 @@ class CameraMap {
       .objects.map((item) => (item as CameraImage).cameraId);
     return cameraIds.includes(cameraId);
   }
+
+  /** 根据cameraId查找某个元素 */
+  public getCameraById(cameraId: string) {
+    return this.canvas?.getObjects().find((x) => (x as CameraImage).cameraId === cameraId);
+  }
+
+  public setDefaultCamera(camera: fabric.Group) {
+    const canvas = this.canvas;
+    if (!isCanvas(canvas)) return;
+    canvas.getObjects('group').forEach((object) => {
+      toggleCameraDefault(object, false);
+    });
+    toggleCameraDefault(camera, true);
+    canvas.renderAll();
+  }
 }
 
 export default CameraMap;

+ 68 - 0
src/views/map-config/mini-map/MapBase/CameraStarGroup.ts

@@ -0,0 +1,68 @@
+import { fabric } from 'fabric';
+import cameraActiveImg from '@/assets/camera/camera-active.png';
+import cameraImg from '@/assets/camera/camera.png';
+import favoritesImg from '@/assets/camera/favorites.png';
+import { CameraImage } from './types';
+
+const cameraImageName = 'cameraImage';
+const favImageName = 'favImageImage';
+
+const cameraInfo = { width: 60, height: 40 };
+const favInfo = { width: 10, height: 10 };
+
+export function createGroup(): Promise<fabric.Group> {
+  return new Promise((resolve) => {
+    fabric.Image.fromURL(cameraActiveImg, (cImg) => {
+      cImg.set({
+        left: 0,
+        top: 0,
+        width: cameraInfo.width,
+        height: cameraInfo.height,
+        imageName: cameraImageName,
+      });
+      console.log('cameraActiveImg', cImg);
+
+      fabric.Image.fromURL(favoritesImg, (favImg) => {
+        favImg.set({
+          width: favInfo.width,
+          height: favInfo.height,
+          left: 40,
+          top: -10,
+          visible: false,
+          imageName: favImageName,
+        });
+        resolve(
+          new fabric.Group([cImg, favImg], {
+            width: cameraInfo.width,
+            height: cameraInfo.height,
+            // 不要缓存,否则无法修改图片地址
+            objectCaching: false,
+          }),
+        );
+      });
+    });
+  });
+}
+
+/** 设置是否是选中后的效果 */
+export function toggleGroupSelected(group: fabric.Group, isSelected: boolean) {
+  return new Promise((resolve, reject) => {
+    const groupCamera = group.getObjects()[0] as fabric.Image;
+    // .find((item) => item.imageName === cameraImageName) as fabric.Image;
+    if (!groupCamera) {
+      reject();
+      return;
+    }
+    const src = isSelected ? cameraActiveImg : cameraImg;
+    groupCamera.setSrc(src, () => {
+      resolve();
+    });
+  });
+}
+
+/** 设置是否为默认摄像头 */
+export function toggleCameraDefault(group: fabric.Group, visible: boolean) {
+  const star = group.getObjects()[1];
+  if (!star) return;
+  star.set({ visible });
+}

+ 21 - 0
src/views/map-config/mini-map/MapBase/DefaultCameraIcon.vue

@@ -0,0 +1,21 @@
+<template>
+  <!-- 默认选中图片的icon -->
+  <img
+    v-if="props.position"
+    :src="favIcon"
+    class="defaultCameraImg"
+    :style="{ left: props.position?.left + 'px', top: props.position?.top + 'px' }"
+  />
+</template>
+<script lang="ts" setup>
+  import favIcon from '@/assets/camera/favorites.png';
+
+  const props = defineProps<{ position: { left: number; top: number } | null }>();
+</script>
+<style scoped>
+  .defaultCameraImg {
+    position: absolute;
+    width: 15px;
+    /* height: 50px; */
+  }
+</style>

+ 31 - 1
src/views/map-config/mini-map/MapBase/fabricSetting.ts

@@ -1,4 +1,7 @@
-export function fabricSetting(fabric) {
+import { fabric } from 'fabric';
+// import favoritesImg from '@/assets/camera/favorites.png';
+
+export function fabricSetting() {
   fabric.Object.prototype.padding = 10;
 
   // 修改控制点的形状,默认为`rect`矩形,可选的值还有`circle`圆形
@@ -26,3 +29,30 @@ export function fabricSetting(fabric) {
 
   window.fabric = fabric;
 }
+
+// // 渲染元素的icon按钮
+// function renderIcon(icon) {
+//   return function (ctx, left, top, styleOverride, fabricObject) {
+//     const size = this.cornerSize;
+//     ctx.save();
+//     ctx.translate(left, top);
+//     ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
+//     ctx.drawImage(icon, -size / 2, -size / 2, size, size);
+//     ctx.restore();
+//   };
+// }
+// function setControlIcon() {
+//   const favImg = document.createElement('img');
+//   favImg.src = favoritesImg;
+//   // 删除按钮控件
+//   fabric.Object.prototype.controls.favIcon = new fabric.Control({
+//     x: 0.5,
+//     y: -0.5,
+//     offsetY: -16,
+//     offsetX: 26,
+//     cursorStyle: 'pointer',
+//     // mouseUpHandler: deleteObject,
+//     render: renderIcon(favImg),
+//     cornerSize: 24,
+//   });
+// }

+ 13 - 0
src/views/map-config/mini-map/MapBase/types.ts

@@ -21,3 +21,16 @@ export interface CameraImgObject {
   angle: number;
   cameraId: string;
 }
+
+export interface CameraImage extends fabric.Image {
+  cameraId?: string;
+}
+
+export type Canvas = fabric.Canvas;
+
+export const isCanvas = (canvas: Canvas | null): canvas is Canvas => {
+  return Boolean(canvas);
+};
+
+export type OnSelect = (image: CameraImage | null) => unknown;
+export type OnRightClick = (e: fabric.IEvent<MouseEvent>) => unknown;

+ 3 - 0
src/views/map-config/mini-map/MapBase/utils.ts

@@ -0,0 +1,3 @@
+export function getRandomPosition() {
+  return 100 + Math.floor(Math.random() * 30);
+}

+ 25 - 3
src/views/map-config/mini-map/MiniMapConfig.vue

@@ -93,6 +93,7 @@
             :position="mousePosition"
             :set-default="handleSetDefault"
           />
+          <!-- <DefaultCameraIcon :position="defaultCameraPosition" /> -->
         </div>
       </div>
     </div>
@@ -105,14 +106,18 @@
   import { ElMessage, ElInput } from 'element-plus';
   import urlJoin from 'url-join';
   import { onMounted, ref, toRaw } from 'vue';
-  import CameraMap, { CameraImage } from './MapBase/CameraMap';
+  import CameraMap from './MapBase/CameraMap';
   import { ElSelect, ElOption } from 'element-plus';
   import { updateMinMapViewLayoutApi } from '@/api/scene/scene';
   import { onUnmounted } from 'vue';
   import { useGlobSetting } from '@/hooks/setting';
-  import { computed } from 'vue';
+  import { computed, watch } from 'vue';
   import { Search } from '@element-plus/icons-vue';
   import ContextMenu from './MapBase/ContextMenu.vue';
+  import DefaultCameraIcon from './MapBase/DefaultCameraIcon.vue';
+  import { CameraImage } from './MapBase/types';
+  import { toggleCameraDefault } from './MapBase/CameraStarGroup';
+  import { Canvas } from 'fabric/fabric-impl';
 
   const miniMap = useMiniMap();
   const globSetting = useGlobSetting();
@@ -129,6 +134,7 @@
 
   const mousePosition = ref<{ left: number; top: number }>({ left: 0, top: 0 });
   const menuVisible = ref(false);
+  const defaultCameraPosition = ref<{ left: number; top: number } | null>(null);
 
   const handleAvatarSuccess = (e) => {
     const imgPath = e.data;
@@ -210,7 +216,8 @@
       onSelectCamera(cameraImg);
       mapJSONToOptions();
       if (!defaultCameraId.value) {
-        defaultCameraId.value = cameraOptions.value[0]?.value;
+        defaultCameraId.value = cameraId;
+        map.setDefaultCamera(cameraImg);
       }
     });
   };
@@ -264,10 +271,25 @@
   const handleSetDefault = () => {
     const cameraId = rightSelectedCamera.value?.cameraId;
     if (!cameraId) return;
+    map.setDefaultCamera(rightSelectedCamera.value);
     defaultCameraId.value = cameraId;
     /** 选择完成后隐藏 */
     menuVisible.value = false;
   };
+
+  watch(defaultCameraId, (newVal) => {
+    console.log('newVal', newVal);
+    const defaultCameraObject = map?.getCameraById(defaultCameraId.value);
+    console.log('defaultCameraObject', defaultCameraObject);
+    if (!defaultCameraObject) {
+      defaultCameraPosition.value = null;
+      return;
+    }
+    defaultCameraPosition.value = {
+      left: defaultCameraObject.left || 0,
+      top: defaultCameraObject.top || 0,
+    };
+  });
 </script>
 
 <style scoped>