ChenYangfan 6 лет назад
Родитель
Сommit
f879714408

+ 1 - 1
src/components/Cards/QuizCard.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="quiz-card" :to="navPath">
     <div class="quiz-card-title" @click="showMore = !showMore"
-         :class="showMore ? 'quiz-card-title--active' : null">
+         :class="showMore ? 'quiz-card-title--pointerActive' : null">
       <c-icon :theme="stateAction.theme" :left="-2" :right="6" :size="18" bold>
         {{showMore ? 'expand_more' : 'keyboard_arrow_right'}}
       </c-icon>

+ 2 - 2
src/components/DiscussionTab/CMessage.vue

@@ -5,11 +5,11 @@
     </div>
     <div v-show="edit">
       <div class="left-content">
-        <icon-button v-if="!read" theme="blue" class="archive-button" :class="toArchive ? 'archive-button--active' : ''"
+        <icon-button v-if="!read" theme="blue" class="archive-button" :class="toArchive ? 'archive-button--pointerActive' : ''"
                      title="设置为已读" @click.native.stop="handleArchiveButtonClick" :size="32">
           archive
         </icon-button>
-        <icon-button class="delete-button" theme="red" :class="toDelete ? 'delete-button--active' : ''"
+        <icon-button class="delete-button" theme="red" :class="toDelete ? 'delete-button--pointerActive' : ''"
                      title="删除" @click.native.stop="handleDeleteButtonClick" :size="32">
           delete
         </icon-button>

+ 98 - 13
src/components/PDF/PointerCanvas.vue

@@ -4,13 +4,37 @@
 </template>
 
 <script>
+import { mapState } from 'vuex'
+
 export default {
   name: 'PointerCanvas',
+  props: {
+    noPointer: Boolean,
+    noBox: Boolean
+  },
   data () {
     return {
       points: [],
+      disablePointer: false,
       width: window.innerWidth,
-      height: window.innerHeight
+      height: window.innerHeight,
+      rects: [],
+      drawingRect: {}
+    }
+  },
+  computed: {
+    pointerActive () {
+      return this.width > 500 && !this.noPointer && !this.disablePointer
+    },
+    ...mapState({
+      currentPage: state => state.pdf.currentPage
+    })
+  },
+  watch: {
+    currentPage () {
+      this.rects = []
+      this.drawingRect = {}
+      this.renderer()
     }
   },
   mounted () {
@@ -19,48 +43,109 @@ export default {
 
     window.addEventListener('resize', this.handleResize)
     this._canvas.addEventListener('mousemove', this.handleMouseMove)
-    this._interval = setInterval(this.shiftPoints, 32)
+    this._canvas.addEventListener('mousedown', this.handleMouseDown)
+    this._canvas.addEventListener('mouseup', this.handleMouseUp)
+    this._interval = setInterval(this.shiftPoints, 36)
   },
   destroyed () {
     clearInterval(this._interval)
     window.removeEventListener('resize', this.handleResize)
     this._canvas.removeEventListener('mousemove', this.handleMouseMove)
+    this._canvas.removeEventListener('mousedown', this.handleMouseDown)
+    this._canvas.removeEventListener('mouseup', this.handleMouseUp)
   },
   methods: {
     handleResize () {
       this.width = window.innerWidth
       this.height = window.innerHeight
+      this.renderer()
     },
     handleMouseMove (e) {
-      const { x, y } = this.points[this.points.length - 1] ?? { x: 0, y: 0 }
-      console.log(x, e.clientX)
-      if (this.points.length === 0 || Math.abs(x - e.clientX) > 8 || Math.abs(y - e.clientY) > 8) {
-        this.points.unshift({ x: e.clientX, y: e.clientY })
-        if (this.points.length > 30) {
-          this.points.pop()
+      if (this.pointerActive) {
+        const { x, y } = this.points[this.points.length - 1] ?? { x: 0, y: 0 }
+        console.log(x, e.clientX)
+        if (this.points.length === 0 || Math.abs(x - e.clientX) > 8 || Math.abs(y - e.clientY) > 8) {
+          this.points.unshift({ x: e.clientX, y: e.clientY })
+          if (this.points.length > 30) {
+            this.points.pop()
+          }
         }
       }
     },
     shiftPoints () {
       if (this.points.length > 10) {
         this.points.pop()
-        this.points.pop()
       }
       if (this.points.length > 0) {
         this.points.pop()
+        requestAnimationFrame(() => {
+          this.renderer()
+        })
+      }
+    },
+    handleMouseDown (e) {
+      if (!this.noBox) {
+        this.disablePointer = true
+        this.drawingRect.begin = { x: e.clientX, y: e.clientY }
+
+        this._canvas.addEventListener('mousemove', this.handleBoxMouseMove)
+      }
+    },
+    handleBoxMouseMove (e) {
+      this.drawingRect.end = { x: e.clientX, y: e.clientY }
+      requestAnimationFrame(() => {
+        this.renderer()
+      })
+    },
+    handleMouseUp (e) {
+      if (!this.noBox) {
+        this.drawingRect.begin && this.drawingRect.end && this.rects.push(this.drawingRect)
+        this._canvas.removeEventListener('mousemove', this.handleBoxMouseMove)
+        this.disablePointer = false
+        requestAnimationFrame(() => {
+          this.renderer()
+        })
+        this.drawingRect = {}
       }
-      this.renderer()
     },
     renderer () {
+      this._ctx.clearRect(0, 0, 2000, 2000)
+
+      // 框选
+      this._ctx.lineWidth = 4
       this._ctx.lineJoin = 'round'
-      this._ctx.strokeStyle = `rgba(211, 47, 47, 0.3)`
+      this._ctx.strokeStyle = `rgba(211, 47, 47, 1)`
+      this._ctx.fillStyle = `rgba(211, 47, 47, .1)`
+      this.rects.forEach(rect => {
+        if (rect) {
+          this._ctx.beginPath()
+          this._ctx.rect(rect.begin.x, rect.begin.y, rect.end.x - rect.begin.x, rect.end.y - rect.begin.y)
+          this._ctx.closePath()
+          this._ctx.fill()
+          this._ctx.stroke()
+        }
+      })
+      if (this.drawingRect.begin && this.drawingRect.end) {
+        this._ctx.beginPath()
+        this._ctx.rect(
+          this.drawingRect.begin.x,
+          this.drawingRect.begin.y,
+          this.drawingRect.end.x - this.drawingRect.begin.x,
+          this.drawingRect.end.y - this.drawingRect.begin.y
+        )
+        this._ctx.closePath()
+        this._ctx.fill()
+        this._ctx.stroke()
+      }
+
+      // 线条
+      this._ctx.strokeStyle = `rgba(211, 47, 47, 0.25)`
       this._ctx.fillStyle = `rgba(211, 47, 47, 1)`
-      this._ctx.clearRect(0, 0, 2000, 2000)
       this._ctx.beginPath()
       const length = this.points.length
       this.points.forEach((point, index) => {
         this._ctx.lineTo(point.x, point.y)
-        this._ctx.lineWidth = (length - index + 6) / 1.5
+        this._ctx.lineWidth = (length - index + 8) / 2
         this._ctx.stroke()
       })
       this._ctx.closePath()

+ 15 - 2
src/views/reader/PdfReader.vue

@@ -2,7 +2,11 @@
   <div class="pdf-reader">
     <icon-button @click="$router.go(-1)" title="返回主页面">arrow_back</icon-button>
     <pdf-viewer></pdf-viewer>
-    <pointer-canvas></pointer-canvas>
+    <pointer-canvas :no-pointer="!pointer" :no-box="!box"></pointer-canvas>
+    <div class="pointer-actions">
+      <c-button icon="gesture" :theme="pointer ? 'red' : ''" @click="pointer = !pointer">指针</c-button>
+      <c-button icon="crop_square" :theme="box ? 'green' : ''" @click="box = !box" :left="12">框选</c-button>
+    </div>
     <discussion-area
       :class="showDiscussion ? 'show-discussion' : 'hide-discussion'"
     >
@@ -26,9 +30,10 @@ import {
 } from '@/store/types/pdf-types'
 import IconButton from '@/components/Basic/IconButton'
 import PointerCanvas from '@/components/PDF/PointerCanvas'
+import CButton from '@/components/Basic/CButton'
 
 export default {
-  components: { PointerCanvas, IconButton, DiscussionArea, PdfViewer },
+  components: { CButton, PointerCanvas, IconButton, DiscussionArea, PdfViewer },
   computed: {
     ...mapState({
       src: state => state.pdf.src,
@@ -38,6 +43,8 @@ export default {
   },
   data () {
     return {
+      pointer: false,
+      box: false,
       slide: {}
     }
   },
@@ -121,4 +128,10 @@ export default {
   transform: translateY(100%);
   opacity: 0;
 }
+
+.pointer-actions {
+  position: fixed;
+  left: 12px;
+  bottom: 12px;
+}
 </style>