Bladeren bron

feat(map): update

gemercheung 1 jaar geleden
bovenliggende
commit
9cae455c26
5 gewijzigde bestanden met toevoegingen van 253 en 79 verwijderingen
  1. 5 2
      src/core/Scene.js
  2. 20 14
      src/core/box/object/PureTextLabel.js
  3. 28 4
      src/core/player/Player.js
  4. 149 0
      src/view/case/photos/edit.vue
  5. 51 59
      src/view/case/photos/index.vue

+ 5 - 2
src/core/Scene.js

@@ -57,6 +57,7 @@ export default class Scene extends Mitt {
       domElement.parentNode.appendChild(stats.dom);
       stats.dom.style.pointerEvents = "none";
       stats.dom.style.left = "15%";
+      stats.dom.style.display = "none";
 
       this.onBindEvent();
 
@@ -101,7 +102,7 @@ export default class Scene extends Mitt {
     }
   }
 
-  deleteItemById(uuid) {
+  deleteItemById(uuid, type) {
     for (var i = this.scene.children.length - 1; i >= 0; i--) {
       let obj = this.scene.children[i];
       if (obj.uuid === uuid) {
@@ -153,7 +154,9 @@ export default class Scene extends Mitt {
     stats.end();
     requestAnimationFrame(this.animate);
   };
-
+  editing(item) {
+    this.player.editing(item);
+  }
   onBindEvent = () => {
     //window.addEventListener('resize', this.onResize)
   };

+ 20 - 14
src/core/box/object/PureTextLabel.js

@@ -1,32 +1,33 @@
 import * as THREE from "three";
 
 export default class PureTextLabel extends THREE.Mesh {
-  constructor(text, outline) {
-    let res = 5;
-    const width = 150 * res;
-    const height = 15 * res;
+  constructor(text, point, fontsize = 12, color = "#000000", id) {
+    let res = 2;
+    const width = 168 * res;
+    const height = 50 * res;
     var canvas = document.createElement("canvas");
     canvas.width = width;
     canvas.height = height;
+
     let fontFamily = "Arial";
-    let fontSize = 7 * res;
-    let offsetX = 75 * res;
-    let offsetY = 10 * res;
+    let fontSize = fontsize * res;
     var context = canvas.getContext("2d");
-
     context.fillStyle = "transparent";
     context.rect(0, 0, width, height);
     context.fill();
-    context.font = "normal " + fontSize + "px " + fontFamily;
-    context.fillStyle = "#000000";
+    let fontStyle = "normal " + fontSize + "px " + fontFamily;
+    // console.log("fontStyle", fontStyle);
+    context.font = fontStyle;
+    context.fillStyle = color;
     context.textAlign = "center";
-    context.fillText(text, offsetX, offsetY);
+    context.textBaseline = "middle";
+    context.fillText(text, width / 2, height / 2);
     const canvas_map = new THREE.Texture(canvas);
     canvas_map.colorSpace = THREE.SRGBColorSpace;
     canvas_map.needsUpdate = true;
     canvas_map.anisotropy = 4;
 
-    const g = new THREE.PlaneGeometry(1.5, 0.15);
+    const g = new THREE.PlaneGeometry(1.5, 0.44);
     g.rotateX(-Math.PI / 2);
 
     // const texture = new THREE.CanvasTexture(canvas_map);
@@ -36,7 +37,12 @@ export default class PureTextLabel extends THREE.Mesh {
       transparent: true, // 允许材质透明
     });
     super(g, m);
-
-    this.name = "textlabel_" + text;
+    if (id) {
+      this.uuid = id;
+    }
+    const p = new THREE.Vector3().copy(point);
+    this.userData = p.toArray();
+    this.position.copy(p);
+    this.name = "pureText_" + text;
   }
 }

+ 28 - 4
src/core/player/Player.js

@@ -57,7 +57,8 @@ export default class Player {
 
   setMode(mode) {
     this.mode = mode;
-    if (mode === 1 || mode === 2) {
+
+    if (mode !== 0) {
       this.reset();
       this.setEditMode();
     }
@@ -89,7 +90,7 @@ export default class Player {
       let pos = new THREE.Vector3(0, 0, -1);
       pos.unproject(this.orthCamera);
       pos.y = 5;
-      this.text = new PureTextLabel(this.showText, true);
+      this.text = new PureTextLabel(this.showText, pos);
       this.text.visible = false;
       this.scene.scene.add(this.text);
       this.drawing = true;
@@ -228,6 +229,7 @@ export default class Player {
         pos.unproject(this.orthCamera);
         pos.y = 5;
         this.text.position.copy(pos);
+        this.text.userData = pos.toArray();
       }
     }
   };
@@ -327,8 +329,13 @@ export default class Player {
           this.pointerdown.y,
           -1
         );
-        this.scene.emit("lockText");
-        this.drawing = false;
+        this.scene.emit("edit", {
+          type: 4,
+          text: this.showText,
+          id: this.text.uuid,
+          pos: this.text.userData,
+        });
+        this.drawing = true;
         // const activeSymbolItem = {
         //   id: this.symbolIndex,
         //   point: lasPos.toArray(),
@@ -366,6 +373,9 @@ export default class Player {
     if (this.mode === 2) {
       // this.drawing = false;
     }
+    if (this.mode === 4) {
+      this.drawing = false;
+    }
     this.syncDrawData();
   };
 
@@ -512,6 +522,20 @@ export default class Player {
       }
     }
   }
+
+  editing(item) {
+    if (item.type === 4) {
+      console.log("editing", item);
+      const lastPos = this.text.userData;
+      const newP = new THREE.Vector3().fromArray(lastPos);
+      this.scene.scene.remove(this.text);
+      this.text = null;
+      this.showText = item.text;
+      console.log("this.text", lastPos, newP, item);
+      this.text = new PureTextLabel(item.text, newP, item.fontsize, item.color);
+      this.scene.scene.add(this.text);
+    }
+  }
   getDrawData() {
     let data;
     if (this.scene.sceneType === 1) {

+ 149 - 0
src/view/case/photos/edit.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="layout" v-if="isShow">
+    <el-icon class="close" @click="handleClose">
+      <Close />
+    </el-icon>
+    <el-form :inline="true" :model="form" label-width="auto">
+      <el-form-item label="内容">
+        <el-input type="input" :maxlength="40" v-model="form.text" />
+      </el-form-item>
+
+      <el-form-item label="字号:">
+        <el-select
+          v-model="form.fontsize"
+          placeholder="选择字号"
+          style="width: 200px"
+        >
+          <el-option
+            v-for="item in fontSizeOptions"
+            v-bind="item"
+            :key="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="颜色:">
+        <el-color-picker
+          v-model="form.color"
+          color-format="rgba"
+          show-alpha
+          :predefine="predefineColors"
+        />
+      </el-form-item>
+      <el-form-item label="删除:">
+        <el-button type="primary" @handle="handleClick">删除</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+<script setup>
+import { reactive, ref, watch } from "vue";
+
+const isShow = ref(false);
+const props = defineProps({ show: Boolean, data: Object });
+const emit = defineEmits(["update", "del", "close"]);
+
+const predefineColors = [
+  "#ff0f00",
+  "#ffbe00",
+  "#1a9bff",
+  "#1aad19",
+  "#000000",
+  "#ffffff",
+  "#666666",
+];
+
+watch(
+  props,
+  ({ show, data }) => {
+    isShow.value = show;
+    form.text = data.text;
+    form.id = data.id;
+    form.type = data.type;
+    form.pos = data.pos;
+    form.fontsize = data.fontsize || 12;
+    console.log("data", data);
+  },
+  {
+    deep: true,
+  }
+);
+
+// do not use same name with ref
+const form = reactive({
+  id: "",
+  text: "",
+  fontsize: 12,
+  type: null,
+  pos: null,
+  color: "#000000",
+});
+
+watch(
+  form,
+  () => {
+    handleUpdate();
+  },
+  {
+    deep: true,
+  }
+);
+
+const fontSizeRange = [8, 30];
+const fontSizeOptions = [];
+for (let i = fontSizeRange[0]; i <= fontSizeRange[1]; i++) {
+  fontSizeOptions.push({ value: i, label: i.toString() });
+}
+
+const handleClose = () => {
+  isShow.value = false;
+};
+const handleUpdate = () => {
+  emit("update", form);
+};
+
+const handleClick = () => {
+  emit("del", form.id, form.type);
+};
+</script>
+
+<style>
+.layout {
+  position: absolute;
+  top: 0;
+  left: 50%;
+  transform: translateX(-50%);
+  right: 0;
+  background: #fff;
+  box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
+  z-index: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 15px 25px 0 10px;
+  width: fit-content;
+  /* width: 300px; */
+}
+.layout .el-form {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  justify-content: flex-start;
+  max-width: 300px;
+}
+.layout .el-form-item {
+  margin-left: 10px;
+  margin-right: 10px;
+  flex: 0 0 auto;
+  display: flex;
+  align-items: center;
+}
+.close {
+  align-self: start;
+  font-size: 14px;
+  color: rgba(0, 0, 0, 0.85);
+  position: absolute !important;
+  right: 10px;
+  top: 10px;
+  cursor: pointer;
+}
+</style>

+ 51 - 59
src/view/case/photos/index.vue

@@ -1,8 +1,8 @@
 <template>
-  <div class="photo ">
+  <div class="photo">
     <div class="left">
       <div class="upload my-photo-upload">
-          <!-- <el-upload
+        <!-- <el-upload
           v-model:file-list="fileList"
           class="upload-demo"
           multiple
@@ -47,45 +47,20 @@
           >退出编辑</el-button
         >
       </div>
-      <swiper
-        class="swiper"
-        v-if="false"
-        slides-per-view="auto"
-        :space-between="24"
-        :centeredSlides="true"
-        @swiper="onSwiper"
-        style="height: 100%"
-        @slideChange="onSlideChange"
-      >
-        <swiper-slide
-          class="swiperItem"
-          v-for="(item, index) in newlist"
-          :key="index"
-        >
-          <div class="swiperList">
-            <div
-              class="itemper"
-              :class="{ oneItemper: sortType }"
-              v-for="eleItem in item"
-              :key="eleItem"
-            >
-              <img class="itemImg" :src="eleItem.imgUrl" alt="" />
-              <div class="text">{{ eleItem.imgInfo }}</div>
-            </div>
-            <div class="page">
-              <span style="margin-right: 16px">第 {{ index + 1 }} 页</span>
-              <span>共 {{ newlist.length }} 页</span>
-            </div>
-          </div>
-        </swiper-slide>
-      </swiper>
+
       <canvas id="canvas" v-show="true"></canvas>
+      <edit
+        :show="editing.show"
+        :data="editing.data"
+        @update="handleEditingUpdate"
+        @del="handleEditingDel"
+      />
     </div>
   </div>
 </template>
 
 <script setup>
-import { onMounted, ref, computed, onUnmounted } from "vue";
+import { onMounted, ref, computed, onUnmounted, reactive } from "vue";
 import { Menu, FullScreen } from "@element-plus/icons-vue";
 import { Swiper, SwiperSlide } from "swiper/vue";
 import "swiper/css";
@@ -94,9 +69,16 @@ import { addCaseImgFile, addCaseImgFileAll } from "../quisk";
 import { saveCaseImgTagData, getCaseImgTagData } from "@/store/case";
 import Scene from "@/core/Scene.js";
 import draggable from "./draggable.vue";
+import edit from "./edit.vue";
+
 import { ElMessage, ElMessageBox } from "element-plus";
 
 const props = defineProps({ caseId: Number });
+
+const editing = ref({
+  show: false,
+  data: {},
+});
 const newlist = ref([]);
 const fileList = ref([]);
 const swiperRef = ref(null);
@@ -216,6 +198,12 @@ const renderCanvas = () => {
     hasDrawData.value = hasData;
     console.log("sync", data, hasData);
   });
+  scene.on("edit", (editData) => {
+    console.log("editData", editData);
+    editing.value.show = true;
+    editing.value.data = editData;
+    // debugger;
+  });
 };
 const onSwiper = (swiper) => {
   console.log("onSwiper");
@@ -226,14 +214,14 @@ const onSlideChange = (swiper) => {
 };
 const handleChange = (val, list) => {
   fileList.value = list;
-  console.log('handleChange',val, list, fileList.value);
-}
+  console.log("handleChange", val, list, fileList.value);
+};
 const handleRequest = (val, list) => {
-  console.log('handleRequest',val, list);
-}
+  console.log("handleRequest", val, list);
+};
 const handleUpload = (val) => {
-  console.log('handleUpload', val);
-}
+  console.log("handleUpload", val);
+};
 const handleItem = (item) => {
   let active = sortType.value ? item : Math.floor(item / 2);
   // swiperRef.value.slideTo(active);
@@ -293,30 +281,35 @@ const handleClear = () => {
     window.scene.player.clear();
   }
 };
-onUnmounted(() => {});
+
+const handleEditingUpdate = (data) => {
+  // console.log("update", data);
+  if (window.scene) {
+    window.scene.editing(data);
+  }
+};
+const handleEditingDel = (id, type) => {
+  if (window.scene) {
+    window.deleteItemById(id, type);
+  }
+};
 
 onMounted(() => {
   renderCanvas();
   console.warn("renderCanvas");
-  // try {
-  //   const res = await getCaseImgTagData(caseId.value);
-  //   const { isHorizontal, data } = res.data;
-  //   sortType.value = !isHorizontal;
-  //   data && (loadedDrawData.value = data);
-  // } catch (error) {}
 });
 </script>
 <style lang="scss">
-.my-photo-upload{
-      .upload-demo{    
-        display: inline-block;
-        margin-right: 20px;
-        position: relative;
-        bottom: -1px;
-        .el-upload-list{
-          display: none;
-        }
-      }
+.my-photo-upload {
+  .upload-demo {
+    display: inline-block;
+    margin-right: 20px;
+    position: relative;
+    bottom: -1px;
+    .el-upload-list {
+      display: none;
+    }
+  }
 }
 </style>
 <style lang="scss" scoped>
@@ -337,7 +330,6 @@ onMounted(() => {
     background: #ffffff;
     box-shadow: 10px 0 10px -10px rgba(0, 0, 0, 0.15);
     // box-shadow: 0px 2px 8px 0px rgba(0,0,0,0.15);
-
   }
 
   .right {