Explorar o código

[v5.0.230512.1] Undo:刪除 - 筆畫、圖形、圖片、文字、複合物 的 Undo 行為

Louise lin %!s(int64=2) %!d(string=hai) anos
pai
achega
8a73042166

+ 17 - 20
HiTeachCC/ClientApp/src/components/AddImgBox.vue

@@ -229,6 +229,7 @@ export default {
               that.$q.loading.hide()
               console.log(res, '上传Resource且變更檔名成功后的返回')
               let fileUrl = res.url
+              let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
               // console.log(fileUrl)
               // console.log(stage)
               Konva.Image.fromURL(fileUrl + '?' + blobUrl.sas_read, function(image) {
@@ -241,7 +242,8 @@ export default {
                   height: image.height() * scaleRatio,
                   draggable: true,
                   src: fileUrl,
-                  uuid:that.$jsFn.getUUID()
+                  uuid:that.$jsFn.getUUID(),
+                  index: currentIndex
                 })
 
                 // stage.find('Transformer').destroy()
@@ -257,11 +259,7 @@ export default {
                   padding: 10,
                   name: 'default'
                 })
-                stage.find('Transformer').forEach(function(ele, i) {
-                  if (ele.attrs.name == 'default') {
-                    ele.destroy()
-                  }
-                })
+                that.$toolbox.removeTransformer()
                 
 
                 layer.add(image)
@@ -321,6 +319,7 @@ export default {
           this.$q.loading.hide()
           console.log(res, '上传Resource且變更檔名成功后的返回')
           let fileUrl = res.url
+          let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
           // console.log(fileUrl)
           // console.log(stage)
           Konva.Image.fromURL(fileUrl + '?' + blobUrl.sas_read, function(image) {
@@ -333,7 +332,8 @@ export default {
               height: image.height() * scaleRatio,
               draggable: true,
               src: fileUrl,
-              uuid:that.$jsFn.getUUID()
+              uuid:that.$jsFn.getUUID(),
+              index:currentIndex
             })
 
             // stage.find('Transformer').destroy()
@@ -349,11 +349,7 @@ export default {
               padding: 10,
               name: 'default'
             })
-            stage.find('Transformer').forEach(function(ele, i) {
-              if (ele.attrs.name == 'default') {
-                ele.destroy()
-              }
-            })
+            that.$toolbox.removeTransformer()
             layer.add(image)
             that.$toolbox.saveUndoHistory('add',image)//儲存undo記錄
             layer.add(tr)
@@ -438,6 +434,7 @@ export default {
     //剪貼簿文字
     addTextBox(target) {
       let that=this
+      let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
       this.$store.state.showtextInuptCard = false
       let layer = this.$store.state.layer
       document.body.classList.remove('cursor-fdj')
@@ -453,7 +450,8 @@ export default {
         lineHeight: 1,
         height: 'auto',
         name: 'text',
-        uuid:that.$jsFn.getUUID()
+        uuid:that.$jsFn.getUUID(),
+        index:currentIndex
       })
 
       this.$store.state.mode = 'check'
@@ -626,6 +624,7 @@ export default {
       let layer = this.$store.state.layer
       let imageObj = new Image()
       let finallink = Imgurl.slice(0, 14) != 'data:image/png' ? window.location.origin + Imgurl : Imgurl
+      let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
 
       imageObj.onload = function() {
         // console.log(imageObj)
@@ -637,7 +636,8 @@ export default {
           height: imageObj.height * 0.4,
           draggable: true,
           src: finallink,
-          uuid:that.$jsFn.getUUID()
+          uuid:that.$jsFn.getUUID(),
+          index:currentIndex
         })
         // stage.find('Transformer').destroy()
         let tr = new Konva.Transformer({
@@ -652,11 +652,7 @@ export default {
           padding: 10,
           name: 'default'
         })
-        stage.find('Transformer').forEach(function(ele, i) {
-          if (ele.attrs.name == 'default') {
-            ele.destroy()
-          }
-        })
+        that.$toolbox.removeTransformer()
        
         layer.add(image)
         that.$toolbox.saveUndoHistory('add',image)//儲存undo記錄
@@ -778,7 +774,8 @@ export default {
           height: image.height() * ratio,
           // image: imageObj,
           src: finallink,
-          name: 'boardPdfBg'
+          name: 'boardPdfBg',
+          index:0,
         })
 
         layer.add(image)

+ 1 - 5
HiTeachCC/ClientApp/src/components/Chart/OptionView.vue

@@ -1444,11 +1444,7 @@ export default {
               padding: 10,
               name: 'default'
             })
-            stage.find('Transformer').forEach(function (ele, i) {
-              if (ele.attrs.name == 'default') {
-                ele.destroy()
-              }
-            })
+            that.$toolbox.removeTransformer()
             layer.add(image)
             layer.add(tr)
             tr.nodes([image])

+ 102 - 16
HiTeachCC/ClientApp/src/components/ToolBox.vue

@@ -334,21 +334,25 @@ export default {
       console.log(mode,element)
       //加入物件的undo
       switch(mode){
-        case 'add':{
-        this.undoHistory.push({ action: 'delete', item: JSON.parse(JSON.stringify(element)) })
-        //新增前一動應提供該物件的初始化Attr
-        console.log(JSON.parse(JSON.stringify(element)),'add-update')
-        this.undoHistory.push({ action: 'update', item: JSON.parse(JSON.stringify(element)) })
-        break;
+        case 'add': {
+          this.undoHistory.push({ action: 'delete', item: JSON.parse(JSON.stringify(element)) })
+          //新增前一動應提供該物件的初始化Attr
+          this.undoHistory.push({ action: 'update', item: JSON.parse(JSON.stringify(element)) })
+          break;
         }
-        case 'update':{
-        this.undoHistory.push({ action: 'update', item: JSON.parse(JSON.stringify(element)) })
-         break;
+        case 'update': {
+          this.undoHistory.push({ action: 'update', item: JSON.parse(JSON.stringify(element)) })
+          break;
+        }
+        case 'delete': {
+          if(element.attrs.name!='selectionRectangle') //針對圈選刪除,不存圈選框
+          this.undoHistory.push({ action: 'add', item: JSON.parse(JSON.stringify(element)) })
+          break;
         }
       }
     },
     undo() {
-      this.setMode('undo')
+      // this.setMode('undo')
       if (this.undoHistory == '') {
         alert(this.$t('toolbox["目前沒有動作可復原"]'))
         return
@@ -370,11 +374,13 @@ export default {
     },
 
     //接收到單一物件針對uuid與動作去更新
-    updateStageObj(targetAction) {
+    async updateStageObj(targetAction) {
       console.log('單一物件渲染!', targetAction)
       let that = this
       let layer = this.$store.state.layer
+      let objectIndex
       if (targetAction.action == 'add') {
+        
         let normalClassName = ['Line', 'Circle', 'Rect', 'Star', 'Text', 'Path', 'Ellipse', 'RegularPolygon']
         if (normalClassName.includes(JSON.parse(targetAction.item).className)) {
           let KonvaItem = new Konva[JSON.parse(targetAction.item).className](JSON.parse(targetAction.item).attrs)
@@ -382,9 +388,56 @@ export default {
           if (JSON.parse(targetAction.item).className == 'Rect' && KonvaItem.attrs.name == 'bgRect') {
             KonvaItem.moveToBottom()
           }
-          KonvaItem.zIndex(KonvaItem.attrs.index)
-          layer.draw()
+          objectIndex=KonvaItem.attrs?.index?KonvaItem.attrs?.index:KonvaItem.index
+          KonvaItem.zIndex(objectIndex)
+        }else if (JSON.parse(targetAction.item).className == 'Label') {
+          //文字便利貼
+          let label = new Konva.Label(JSON.parse(targetAction.item).attrs)
+          JSON.parse(targetAction.item).children.forEach(item => {
+            if (item.className == 'Tag') {
+              let tag = new Konva.Tag(item.attrs)
+              label.add(tag)
+            }
+            if (item.className == 'Text') {
+              let text = new Konva.Text(item.attrs)
+              label.add(text)
+            }
+          })
+          layer.add(label)
+          objectIndex=JSON.parse(targetAction.item).attrs?.index?JSON.parse(targetAction.item).attrs?.index:JSON.parse(targetAction.item)?.index
+          label.zIndex(objectIndex)
+        } else if (JSON.parse(targetAction.item).className == 'Image') {
+          await this.addUndoSingleImg(JSON.parse(targetAction.item), layer)
+        } else if (JSON.parse(targetAction.item).className == 'Group') {
+          let KonvaGroup = new Konva[JSON.parse(targetAction.item).className](JSON.parse(targetAction.item).attrs)
+
+          JSON.parse(targetAction.item).children.forEach(async child => {
+            let normalClassName = ['Line', 'Circle', 'Rect', 'Star', 'Text', 'Path', 'Ellipse', 'RegularPolygon']
+            if (normalClassName.includes(child.className)) {
+              KonvaGroup.add(
+                new Konva[child.className]({
+                  parent: KonvaGroup,
+                  ...child.attrs
+                })
+              )
+            }
+            if (child.className == 'Image') {
+             await this.addUndoSingleImg(child, KonvaGroup)
+            }
+
+            layer.add(KonvaGroup)
+            objectIndex=KonvaGroup.attrs?.index?KonvaGroup.attrs?.index:KonvaGroup.index
+            KonvaGroup.zIndex(objectIndex)
+            
+          })
         }
+         layer.children.forEach(child => {
+            if (child.attrs.name == 'boardPdfBg') child.moveToBottom()
+          })
+
+         layer.batchDraw()
+
+        console.log(layer)
       } else if (targetAction.action == 'update') {
         // console.log('更新物件', targetAction)
         let targetItem = typeof targetAction.item === 'object' ? targetAction.item : JSON.parse(targetAction.item)
@@ -428,10 +481,43 @@ export default {
       } else if (targetAction.action == 'delete') {
         let childrenIndex = layer.children.findIndex(x => x.attrs.uuid == JSON.parse(targetAction.item).attrs.uuid)
         if (childrenIndex != -1) {
-         layer.children[childrenIndex].destroy()
-         layer.draw()
+          layer.children[childrenIndex].destroy()
+          layer.draw()
         }
-      } 
+      }
+    },
+
+     addUndoSingleImg(target, parent) {
+      return new Promise(async(r,j)=>{
+       let layer = this.$store.state.layer
+      let blobUrl = this.classInfo.blob
+      let finallink = target.attrs.src.includes(blobUrl.sas_read) ? target.attrs.src : target.attrs.src + '?' + blobUrl.sas_read
+
+      let imageObj = new Image()
+      imageObj.setAttribute('crossOrigin', 'Anonymous')
+      imageObj.src = finallink
+      imageObj.onload = await function() {
+        Konva.Image.fromURL(finallink, function(image) {
+          image.setAttrs({
+            ...target.attrs,
+            parent: parent
+          })
+          parent.add(image)
+          image.zIndex(target.attrs.index >= parent.children.length ? parent.children.length - 1 : target.attrs.index)
+          if (target.attrs.name == 'boardPdfBg') {
+            image.moveToBottom()
+          } else {
+            if (image.zIndex() == 0) image.zIndex(1)
+          }
+          layer.batchDraw()
+          r(200)
+        })
+      }
+      imageObj.onerror =function(){
+        j('err')
+      }
+      })
+      
     },
 
     //紀錄Undo位移行為

+ 5 - 11
HiTeachCC/ClientApp/src/components/Tools/turnTable.vue

@@ -126,11 +126,7 @@ export default {
               padding: 10,
               name: 'default'
             })
-            stage.find('Transformer').forEach(function(ele, i) {
-              if (ele.attrs.name == 'default') {
-                ele.destroy()
-              }
-            })
+            that.$toolbox.removeTransformer()
             layer.add(tr)
             tr.nodes([image])
             that.$parent.addMenuBtnToTr(tr, image) 
@@ -148,6 +144,7 @@ export default {
     pasteTargetByKonvaObj() {
       let stage = this.$store.state.stage
       let layer = this.$store.state.layer
+      let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
       this.$store.state.textColor = 'black'
       let text = this.pickTarget.sort + '\t\t\t' + this.pickTarget.name
       let uuid= this.$jsFn.getUUID()
@@ -179,7 +176,8 @@ export default {
         draggable: true,
         listening: true,
         text: text,
-         uuid:uuid
+        uuid:uuid,
+        index:currentIndex,
       })
 
       group.add(rect)
@@ -221,11 +219,7 @@ export default {
         padding: 10,
         name: 'default'
       })
-      stage.find('Transformer').forEach(function(ele, i) {
-        if (ele.attrs.name == 'default') {
-          ele.destroy()
-        }
-      })
+      this.$toolbox.removeTransformer()
       layer.add(tr)
       tr.nodes([group])
       this.$parent.addMenuBtnToTr(tr, group) 

+ 1 - 1
HiTeachCC/ClientApp/src/locale/lang/zh-CN/index.js

@@ -232,7 +232,7 @@ export default {
     'Uploading': '上传中',
     'ssoError': '您的帐户已在另一台设备上登录。如果不是您操作,请及时修改密码。',
     objMenu:{
-      刪除物件:'删除物件',
+      刪除物件:'删除',
       複製:'复制',
       移到最上層:'移到最上层',
       移到最下層:'移到最下层',

+ 1 - 1
HiTeachCC/ClientApp/src/locale/lang/zh-TW/index.js

@@ -231,7 +231,7 @@ export default {
     'Uploading': '上傳中',
     'ssoError': '您的帳號在其他設備登入,如果不是您的操作,請及時修改您的密碼。',
     objMenu:{
-      刪除物件:'刪除物件',
+      刪除物件:'刪除',
       複製:'複製',
       移到最上層:'移到最上層',
       移到最下層:'移到最下層',

+ 1 - 1
HiTeachCC/ClientApp/src/store/index.js

@@ -199,7 +199,7 @@ export default new Vuex.Store({
     startTime: 0,
     elapsedTime: 0,
     timeLineEvents: [],
-    version: 'v5.0.230509.1'
+    version: 'v5.0.230512.1'
   },
   mutations: {},
   actions: {

+ 47 - 32
HiTeachCC/ClientApp/src/views/Board.vue

@@ -788,12 +788,14 @@ export default {
       this.currentStickerColor = item;
     },
     addSticker(mode) {
+      let layer = this.$store.state.layer;
       //新增便利貼物件
       let x, y;
       let textNode = this.$store.state.currentEditTextNode;
       x = mode == "new" ? this.stage.width() * 0.1 + Math.floor(Math.random() * 200) : textNode.attrs.x;
       y = mode == "new" ? this.stage.height() * 0.2 + Math.floor(Math.random() * 200) : textNode.attrs.y;
       let uuid=this.$jsFn.getUUID()
+      let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
       let pastText = new Konva.Label({
         x: x,
         y: y,
@@ -801,7 +803,8 @@ export default {
         draggable: true,
         listening: true,
         text: this.currentAddTextValue,
-        uuid:uuid
+        uuid:uuid,
+        index:currentIndex
       });
       pastText.add(
         new Konva.Tag({
@@ -861,9 +864,11 @@ export default {
       this.addMenuBtnToTr(tr, pastText);
     },
     addPureText(mode) {
+      let layer = this.$store.state.layer;
       //新增便利貼物件
       let x, y;
       let pastText = this.$store.state.currentEditTextNode;
+      let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
       x = mode == "new" ? window.innerWidth / 2 - 100 : pastText.attrs.x;
       y = mode == "new" ? window.innerHeight / 2 - 100 : pastText.attrs.y;
       //新增純文字物件
@@ -877,7 +882,8 @@ export default {
         width: 300,
         height: "auto",
         name: "text",
-        uuid:this.$jsFn.getUUID()
+        uuid:this.$jsFn.getUUID(),
+        index:currentIndex
       });
 
       let tr = new Konva.Transformer({
@@ -1116,6 +1122,7 @@ export default {
     pasteTargetByKonvaObj(item, index) {
       let stage = this.$store.state.stage;
       let layer = this.$store.state.layer;
+      let currentIndex=layer?.children ? JSON.parse(JSON.stringify(layer?.children)).length : 1
       this.$store.state.textColor = "black";
       let text = item.seat + "\t\t\t" + (this.$store.state.hideStudentName == false ? item.name : "");
 
@@ -1168,7 +1175,8 @@ export default {
           text: text,
           draggable: true,
           listening: true,
-          uuid:uuid 
+          uuid:uuid ,
+          index:currentIndex
         });
 
         group.add(image);
@@ -1928,6 +1936,7 @@ export default {
                   // image: imageObj,
                   src: pdfSrc,
                   name: "boardPdfBg",
+                  index: 0,
                 });
 
                 that.layer.add(image);
@@ -1989,6 +1998,7 @@ export default {
                       // image: imageObj,
                       src: finallink,
                       name: "boardPdfBg",
+                      index: 0,
                     });
 
                     that.layer.add(image);
@@ -2157,6 +2167,7 @@ export default {
                 // image: imageObj,
                 src: targetUrl,
                 name: "boardPdfBg",
+                index: 0,
               });
 
               that.layer.add(image);
@@ -2522,8 +2533,7 @@ export default {
           if(mode=='shape'|| mode=='pencil-alt'){
             let addElement= layer.children[layer.children.length - 1]
             that.$toolbox.saveUndoHistory('add', addElement )//儲存undo記錄
-          }
-          else if(mode == 'check'){
+          }else if(mode == 'check'){
             that.$toolbox.saveUndoUpdate()
           } 
 
@@ -2582,7 +2592,7 @@ export default {
           let textSize = that.$store.state.textSize;
           let textColor = that.$store.state.textColor;
           let pos = stage.getPointerPosition();
-
+         
           if (mode == "check") {
             // 选择工具
             document.body.classList.remove("cursor-fdj");
@@ -2802,7 +2812,8 @@ export default {
               shadowBlur: 1,
               shadowColor: strokeColor,
               tension: 0.5,
-              uuid:that.$jsFn.getUUID()
+              uuid:that.$jsFn.getUUID(),
+              index: layer?.children ? layer?.children.length : 1
             });
             layer.add(lastLine);
           } else if (mode == "shape") {
@@ -2821,7 +2832,8 @@ export default {
                 name: "line",
                 lineCap: "round",
                 lineJoin: "round",
-                uuid:that.$jsFn.getUUID()
+                uuid:that.$jsFn.getUUID(),
+                index: layer?.children ? layer?.children.length : 1
               });
               layer.add(rect);
             } else if (shapeType == "long-arrow-alt-right") {
@@ -2842,7 +2854,8 @@ export default {
                 lineCap: "round",
                 lineJoin: "round",
                 draggable: true,
-                uuid:that.$jsFn.getUUID()
+                uuid:that.$jsFn.getUUID(),
+                index: layer?.children ? layer?.children.length : 1
               });
             } else {
               if (shapeType == "square") {
@@ -2856,7 +2869,8 @@ export default {
                   stroke: shapeBorderColor,
                   strokeWidth: 4,
                   name: "rect",
-                  uuid:that.$jsFn.getUUID()
+                  uuid:that.$jsFn.getUUID(),
+                  index: layer?.children ? layer?.children.length : 1
                 });
               } else if (shapeType == "circle") {
                 // 正圆
@@ -2869,7 +2883,8 @@ export default {
                   stroke: shapeBorderColor,
                   strokeWidth: 4,
                   name: "circle",
-                  uuid:that.$jsFn.getUUID()
+                  uuid:that.$jsFn.getUUID(),
+                  index: layer?.children ? layer?.children.length : 1
                 });
               } else if (shapeType == "ellipse") {
                 // 椭圆
@@ -2883,7 +2898,8 @@ export default {
                   stroke: shapeBorderColor,
                   strokeWidth: 4,
                   name: "ellipse",
-                  uuid:that.$jsFn.getUUID()
+                  uuid:that.$jsFn.getUUID(),
+                  index: layer?.children ? layer?.children.length : 1
                 });
               } else if (shapeType == "campground") {
                 // 三角形
@@ -2896,7 +2912,8 @@ export default {
                   stroke: shapeBorderColor,
                   strokeWidth: 4,
                   name: "campground",
-                  uuid:that.$jsFn.getUUID()
+                  uuid:that.$jsFn.getUUID(),
+                  index: layer?.children ? layer?.children.length : 1
                 });
               } else if (shapeType == "star") {
                 // 五角星
@@ -2910,7 +2927,8 @@ export default {
                   stroke: shapeBorderColor,
                   strokeWidth: 4,
                   name: "star",
-                  uuid:that.$jsFn.getUUID()
+                  uuid:that.$jsFn.getUUID(),
+                  index: layer?.children ? layer?.children.length : 1
                 });
               }
               console.log(rect);
@@ -2927,6 +2945,7 @@ export default {
             //trs.nodes();
             var selectionRectangle = new Konva.Rect({
               fill: "rgba(180,180,180,0.5)",
+              name: "selectionRectangle",
             });
             console.log(selectionRectangle);
             layer.add(selectionRectangle);
@@ -2988,25 +3007,26 @@ export default {
               //console.log(selected, '内容')
               //console.log(stage.eventListeners,'点击过后的')
               selected.forEach((i) => {
-                console.log(i);
+                that.$toolbox.saveUndoHistory("delete", i);
                 i.destroy();
               });
               //trs.nodes(selected);
               //layer.batchDraw();
             });
+            let currentDeleteObj;
             document.body.classList.remove("cursor-fdj");
             if (e.target != stage && e.target.attrs.name != "boardPdfBg") {
-              // stage.find('Transformer').destroy()
-              stage.find("Transformer").forEach(function (ele, i) {
-                if (ele.attrs.name == "default") {
-                  ele.destroy();
-                }
-              });
+             
+              that.$toolbox.removeTransformer()
               //刪除便利貼,點到文字就殺整個
-              if (e.target.className == "Text" && e.target.parent?.className == "Label") {
-                e.target.parent.destroy();
+              if (e.target.className == "Text" && e.target.parent?.className == "Label"||e.target.attrs.name=='pastTextPickName'||e.target.attrs.name=='pastImgContent') {
+                currentDeleteObj = e.target.parent;
+                
+              }else{
+                currentDeleteObj= e.target
               }
-              e.target.destroy();
+              that.$toolbox.saveUndoHistory("delete",  currentDeleteObj); 
+              currentDeleteObj.destroy();
               layer.draw();
             }
           }
@@ -3229,15 +3249,9 @@ export default {
             //that.$store.state.checkvalue='checkbtn'
             document.body.style.cursor = "default";
             //stage.find('Transformer').destroy()
-            if(val!='undo'){
-            stage.find("Transformer").forEach(function (ele, i) {
-              console.log(ele, i, "查看执行的内容");
-              if (ele.attrs.name == "default") {
-                ele.destroy();
-              }
-            });
+            that.$toolbox.removeTransformer()
             layer.draw();
-            }
+           
           }
           if (val == "zooms") {
             // console.log('点击了缩放工具!')
@@ -7591,6 +7605,7 @@ export default {
                       x: stageX,
                       y: locationY ? parseInt(locationY) : 0,
                       image: imageObj,
+                      index: 0,
                     },
                     className: "Image",
                   },