浏览代码

拼图游戏投放地点更精准

任一存 2 年之前
父节点
当前提交
5bfa2906c0
共有 2 个文件被更改,包括 124 次插入43 次删除
  1. 17 11
      src/utils.js
  2. 107 32
      src/views/JigsawGame.vue

+ 17 - 11
src/utils.js

@@ -67,33 +67,39 @@ export default {
       return fn.apply(context, args)
     }
   },
-  mapPosFromDraftToWindow(posRaw, objectFit = 'cover', draftWidth = 1920, draftHeight = 1080) {
+  mapPosFromDraftToWindow(posRaw, objectFit = 'cover', draftWidth = 1920, draftHeight = 1080, windowWidth = null, windowHeight = null) {
+    if (!windowWidth) {
+      windowWidth = window.innerWidth
+    }
+    if (!windowHeight) {
+      windowHeight = window.innerHeight
+    }
     if (objectFit === 'cover') {
-      if (window.innerWidth / window.innerHeight > draftWidth / draftHeight) { // 实际窗口更宽扁,设计图与实际窗口等宽,上下被裁减
-        const scale = window.innerWidth / draftWidth
+      if (windowWidth / windowHeight > draftWidth / draftHeight) { // 实际窗口更宽扁,设计图与实际窗口等宽,上下被裁减
+        const scale = windowWidth / draftWidth
         return {
           x: posRaw.x * scale,
-          y: posRaw.y * scale - (draftHeight * scale - window.innerHeight) / 2,
+          y: posRaw.y * scale - (draftHeight * scale - windowHeight) / 2,
         }
       } else { // false: 实际窗口更窄高,设计图与实际窗口等高,左右被裁减
-        const scale = window.innerHeight / draftHeight
+        const scale = windowHeight / draftHeight
         return {
-          x: posRaw.x * scale - (draftWidth * scale - window.innerWidth) / 2,
+          x: posRaw.x * scale - (draftWidth * scale - windowWidth) / 2,
           y: posRaw.y * scale,
         }
       }
     } else if (objectFit === 'contain') {
-      if (window.innerWidth / window.innerHeight > draftWidth / draftHeight) { // true: 实际窗口更宽扁,设计图与实际窗口等高,左右留白
-        const scale = window.innerHeight / draftHeight
+      if (windowWidth / windowHeight > draftWidth / draftHeight) { // true: 实际窗口更宽扁,设计图与实际窗口等高,左右留白
+        const scale = windowHeight / draftHeight
         return {
-          x: posRaw.x * scale + (window.innerWidth - draftWidth * scale) / 2,
+          x: posRaw.x * scale + (windowWidth - draftWidth * scale) / 2,
           y: posRaw.y * scale
         }
       } else { // false: 实际窗口更窄高,设计图与实际窗口等宽,上下留白
-        const scale = window.innerWidth / draftWidth
+        const scale = windowWidth / draftWidth
         return {
           x: posRaw.x * scale,
-          y: posRaw.y * scale + (window.innerHeight - draftHeight * scale) / 2,
+          y: posRaw.y * scale + (windowHeight - draftHeight * scale) / 2,
         }
       }
     } else {

+ 107 - 32
src/views/JigsawGame.vue

@@ -3,16 +3,25 @@
     class="jigsaw-game"
   >
     <div class="left-wrapper">
-      <div
-        @dragover.prevent
-        @drop.prevent="onDrop"
-      >
+      <div class="object-wrapper">
         <object
           ref="svgContainer"
           :data="require(`@/assets/images/jigsaw-game-${$route.query.sceneL2Idx}/compound.svg`)"
           type=""
         />
       </div>
+      <div
+        ref="forDrop"
+        class="for-drop"
+        :style="{
+          left: leftForDrop + 'px',
+          top: topForDrop + 'px',
+          width: widthForDrop + 'px',
+          height: heightForDrop + 'px',
+        }"
+        @dragover.prevent
+        @drop.prevent="onDrop"
+      />
     </div>
 
     <div class="jigsaw-list">
@@ -53,10 +62,7 @@
 </template>
 
 <script>
-import { computed, onMounted, reactive, toRefs, ref } from 'vue'
 import useWindowSizeAdaptor from '@/useFunctions/useWindowSizeAdaptor.js'
-import { useRoute } from "vue-router"
-import { useStore } from "vuex"
 import { ElMessageBox } from 'element-plus'
 
 export default {
@@ -64,13 +70,6 @@ export default {
   setup () {
     const { windowSizeWhenDesign, unit } = useWindowSizeAdaptor()
 
-    // const route = useRoute()
-    // const store = useStore()
-
-    // const jigsawNameList = computed(() => {
-    //   config.sceneTree[route.query.sceneL2Idx]
-    // })
-
     return {
       windowSizeWhenDesign,
       unit
@@ -78,7 +77,11 @@ export default {
   },
   data() {
     return {
-      jigsawItemsFlatten: []
+      jigsawItemsFlatten: [],
+      leftForDrop: 0,
+      topForDrop: 0,
+      widthForDrop: 0,
+      heightForDrop: 0,
     }
   },
   computed: {
@@ -101,8 +104,8 @@ export default {
     }
     setTimeout(() => {
       if (!this.jigsawProgressSceneL2.isJigsawDone) {
-        const svgRoot = this.$refs.svgContainer.contentDocument
-        const gList = svgRoot.getElementsByTagName('g')
+        const objectDocument = this.$refs.svgContainer.contentDocument
+        const gList = objectDocument.getElementsByTagName('g')
         for (let index = 1; index < gList.length; index++) {
           const element = gList[index]
           element.setAttribute('visibility', 'hidden')
@@ -117,34 +120,96 @@ export default {
       'recordJigsawDone',
     ]),
     onDragStart(e, jigsawImgName, idx) {
-      console.log(jigsawImgName) // 1.马路.png
+      // 不知道为啥,在svg内部元素上无法触发drop事件,求助gpt也没用。只好用一个透明方块放在需要能drop的svg内部元素上面。
+
+      // reset for drop
+      this.leftForDrop = 0
+      this.topForDrop = 0
+      this.widthForDrop = 0
+      this.heightForDrop = 0
+
+      // get id
       let temp = jigsawImgName.split('.')
       temp.pop()
       const id = `_${temp.join('.')}-剪影_图像`
-      // console.log(id)
-      const svgRoot = this.$refs.svgContainer.contentDocument
-      svgRoot.getElementById(id).setAttribute('visibility', 'show')
+
+      // get elements
+      const objectDocument = this.$refs.svgContainer.contentDocument
+      const svgEl = objectDocument.getElementsByTagName('svg')[0]
+      const gTarget = objectDocument.getElementById(id)
+      const imgTarget = gTarget.getElementsByTagName('image')[0]
+
+      // get svg original size from viewBox attribute
+      const svgWidth = Number(svgEl.getAttribute('viewBox').split(' ')[2])
+      const svgHeight = Number(svgEl.getAttribute('viewBox').split(' ')[3])
+      console.log('svg original size by viewBox attribute: ', svgWidth, svgHeight)
+
+      // show g element
+      gTarget.setAttribute('visibility', 'show')
+
+      // save drag info
       e.dataTransfer.setData('text/plain', jigsawImgName)
-      e.dataTransfer.setData('text/html', String(idx))
+      e.dataTransfer.setData('text/html', String(idx)) // 并非真的html类型,只是为了传输数据
+
+      // get image's original size
+      const imageWidthOriginal = Number(imgTarget.getAttribute('width'))
+      const imageHeightOriginal = Number(imgTarget.getAttribute('height'))
+      console.log("image's original size: ", imageWidthOriginal, imageHeightOriginal)
+
+      // get image's original top left from transform attribute
+      let imageLeftOriginal = 0
+      let imageTopOriginal = 0
+      const transformString = imgTarget.getAttribute('transform')
+      if (transformString) {
+        const regForTransform = /translate\((.+)\)/
+        const matchRes = transformString.match(regForTransform)
+        if (matchRes) {
+          imageLeftOriginal = Number(matchRes[1].split(' ')[0])
+          imageTopOriginal = Number(matchRes[1].split(' ')[1]) || 0
+        } else {
+          imageLeftOriginal = 0
+          imageTopOriginal = 0
+        }
+      } else {
+        imageLeftOriginal = 0
+        imageTopOriginal = 0
+      }
+      console.log("image's original top left: ", imageLeftOriginal, imageTopOriginal)
+
+      // compute image's actual left top
+      const topLeft = utils.mapPosFromDraftToWindow({
+        x: imageLeftOriginal,
+        y: imageTopOriginal,
+      }, 'cover', svgWidth, svgHeight, this.$refs.svgContainer.clientWidth, this.$refs.svgContainer.clientHeight)
+      console.log("image's actual left top: ", topLeft.x, topLeft.y)
+
+      const rightBottom = utils.mapPosFromDraftToWindow({
+        x: imageLeftOriginal + imageWidthOriginal,
+        y: imageTopOriginal + imageHeightOriginal,
+      }, 'cover', svgWidth, svgHeight, this.$refs.svgContainer.clientWidth, this.$refs.svgContainer.clientHeight)
+      console.log("image's actual right top: ", rightBottom.x, rightBottom.y)
+
+      this.leftForDrop = topLeft.x
+      this.topForDrop = topLeft.y
+      this.widthForDrop = rightBottom.x - topLeft.x
+      this.heightForDrop = rightBottom.y - topLeft.y
+      console.log("image's actual ltwh for render: ", this.leftForDrop, this.topForDrop, this.widthForDrop, this.heightForDrop)
     },
     onDragEnd(jigsawImgName) {
-      // console.log(jigsawImgName) // 1.马路.png
       let temp = jigsawImgName.split('.')
       temp.pop()
       const id = `_${temp.join('.')}-剪影_图像`
-      // console.log(id)
-      const svgRoot = this.$refs.svgContainer.contentDocument
-      svgRoot.getElementById(id).setAttribute('visibility', 'hidden')
+      const objectDocument = this.$refs.svgContainer.contentDocument
+      objectDocument.getElementById(id).setAttribute('visibility', 'hidden')
     },
     onDrop(e) {
+      e.preventDefault()
       let jigsawImgName = e.dataTransfer.getData('text/plain')
-      console.log(jigsawImgName)
       let temp = jigsawImgName.split('.')
       temp.pop()
       const id = `_${temp.join('.')}_图像`
-      // console.log(id)
-      const svgRoot = this.$refs.svgContainer.contentDocument
-      svgRoot.getElementById(id).setAttribute('visibility', 'show')
+      const objectDocument = this.$refs.svgContainer.contentDocument
+      objectDocument.getElementById(id).setAttribute('visibility', 'show')
 
       const idx = Number(e.dataTransfer.getData('text/html'))
       this.jigsawItemsFlatten[idx].hasPut = true
@@ -160,7 +225,10 @@ export default {
         })
         this.recordJigsawDone(Number(this.$route.query.sceneL2Idx))
       }
-    }
+    },
+    onDragOver(e) {
+      e.preventDefault()
+    },
   },
 }
 </script>
@@ -188,7 +256,8 @@ export default {
     background-position: center center;
     margin-right: calc(83 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
     padding: calc(15 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
-    >div {
+    position: relative;
+    >.object-wrapper {
       width: 100%;
       height: 100%;
       overflow: hidden;
@@ -197,6 +266,12 @@ export default {
         // width: 100%;
       }
     }
+    >.for-drop {
+      position: absolute;
+      // background-color: red;
+      // opacity: 0.2;
+      z-index: 1;
+    }
   }
   >.jigsaw-list {
     position: relative;