pipipi-pikachu 5 tahun lalu
induk
melakukan
7246f89bc0

+ 1 - 1
src/views/Editor/Canvas/MouseSelection.vue

@@ -43,7 +43,7 @@ export default {
 <style lang="scss" scoped>
 .mouse-selection {
   position: absolute;
-  background-color: rgba($themeColor, 0.25);
+  background: rgba(150, 150, 150, 0.25);
   z-index: 200;
 
   &.quadrant-1 {

+ 47 - 0
src/views/Editor/Canvas/hooks/useSetViewportSize.ts

@@ -0,0 +1,47 @@
+import { ref, computed, onMounted, onUnmounted, Ref } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store/state'
+import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
+
+export default (canvasRef: Ref<HTMLElement | null>) => {
+  const canvasScale = ref(1)
+  const viewportLeft = ref(0)
+  const viewportTop = ref(0)
+
+  const store = useStore<State>()
+  const editorAreaShowScale = computed(() => store.state.editorAreaShowScale)
+
+  const setViewportSize = () => {
+    if(!canvasRef.value) return
+    const canvasWidth = canvasRef.value.clientWidth
+    const canvasHeight = canvasRef.value.clientHeight
+
+    if(canvasHeight / canvasWidth > VIEWPORT_ASPECT_RATIO) {
+      const viewportActualWidth = canvasWidth * (editorAreaShowScale.value / 100)
+      canvasScale.value = viewportActualWidth / VIEWPORT_SIZE
+      viewportLeft.value = (canvasWidth - viewportActualWidth) / 2
+      viewportTop.value = (canvasHeight - viewportActualWidth * VIEWPORT_ASPECT_RATIO) / 2
+    }
+    else {
+      const viewportActualHeight = canvasHeight * (editorAreaShowScale.value / 100)
+      canvasScale.value = viewportActualHeight / (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO)
+      viewportLeft.value = (canvasWidth - viewportActualHeight / VIEWPORT_ASPECT_RATIO) / 2
+      viewportTop.value = (canvasHeight - viewportActualHeight) / 2
+    }
+  }
+
+  const resizeObserver = new ResizeObserver(setViewportSize)
+
+  onMounted(() => {
+    if(canvasRef.value) resizeObserver.observe(canvasRef.value)
+  })
+  onUnmounted(() => {
+    if(canvasRef.value) resizeObserver.unobserve(canvasRef.value)
+  })
+
+  return {
+    canvasScale,
+    viewportLeft,
+    viewportTop,
+  }
+}

+ 68 - 0
src/views/Editor/Canvas/hooks/useUpdateMouseSelection.ts

@@ -0,0 +1,68 @@
+import { ref, reactive, Ref, toRefs } from 'vue'
+
+export default (e: MouseEvent, viewportRef: Ref<HTMLElement | null>, canvasScale: number) => {
+  const isMouseDown = ref(false)
+  const mouseSelectionState = reactive({
+    isShow: false,
+    top: 0,
+    left: 0,
+    width: 0,
+    height: 0,
+    quadrant: 4,
+  })
+  const startMousePosition = reactive({
+    x: 0,
+    y: 0,
+  })
+
+  const minSelectionRange = 5
+
+  if(!viewportRef.value) return
+
+  isMouseDown.value = true
+  const viewportRect = viewportRef.value.getBoundingClientRect()
+
+  startMousePosition.x = e.pageX
+  startMousePosition.y = e.pageY
+
+  mouseSelectionState.top = (startMousePosition.x - viewportRect.y) / canvasScale
+  mouseSelectionState.left = (startMousePosition.y - viewportRect.x) / canvasScale
+
+  const mousemoveListener = (e: MouseEvent) => {
+    if(!isMouseDown.value) return
+
+    const currentPageX = e.pageX
+    const currentPageY = e.pageY
+
+    const offsetWidth = (currentPageX - startMousePosition.x) / canvasScale
+    const offsetHeight = (currentPageY - startMousePosition.y) / canvasScale
+
+    const width = Math.abs(offsetWidth)
+    const height = Math.abs(offsetHeight)
+
+    if(width < minSelectionRange || height < minSelectionRange) return
+    
+    let quadrant = 0
+    if(offsetWidth > 0 && offsetHeight > 0) quadrant = 4
+    else if(offsetWidth < 0 && offsetHeight < 0) quadrant = 1
+    else if(offsetWidth > 0 && offsetHeight < 0) quadrant = 2
+    else if(offsetWidth < 0 && offsetHeight > 0) quadrant = 3
+
+    mouseSelectionState.isShow = true
+    mouseSelectionState.quadrant = quadrant
+    mouseSelectionState.width = width
+    mouseSelectionState.height = height
+  }
+  const mouseupListener = () => {
+    isMouseDown.value = false
+    mouseSelectionState.isShow = false
+
+    document.removeEventListener('mousemove', mousemoveListener)
+    document.removeEventListener('mouseup', mouseupListener)
+  }
+
+  document.addEventListener('mousemove', mousemoveListener)
+  document.addEventListener('mouseup', mouseupListener)
+
+  return { ...toRefs(mouseSelectionState) }
+}

+ 11 - 63
src/views/Editor/Canvas/index.vue

@@ -14,7 +14,7 @@
         height: viewportStyles.height + 'px',
         left: viewportStyles.left + 'px',
         top: viewportStyles.top + 'px',
-        transform: `scale(${viewportStyles.scale})`,
+        transform: `scale(${canvasScale})`,
       }"
     >
       <MouseSelection 
@@ -49,6 +49,7 @@ import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
 import { getImageDataURL } from '@/utils/image'
 
 import useDropImage from '@/hooks/useDropImage'
+import useSetViewportSize from './hooks/useSetViewportSize'
 
 import MouseSelection from './MouseSelection.vue'
 import SlideBackground from './SlideBackground.vue'
@@ -62,9 +63,11 @@ export default defineComponent({
     AlignmentLine,
   },
   setup() {
+    const store = useStore<State>()
     const viewportRef = ref<HTMLElement | null>(null)
     const isShowGridLines = ref(false)
     const alignmentLines = ref<AlignmentLineProps[]>([])
+    const currentSlide = computed(() => store.getters.currentSlide)
 
     const dropImageFile = useDropImage(viewportRef)
     watch(dropImageFile, () => {
@@ -75,51 +78,15 @@ export default defineComponent({
       }
     })
 
-    const viewportStyles = reactive({
+    const canvasRef = ref<HTMLElement | null>(null)
+    const { canvasScale, viewportLeft, viewportTop } = useSetViewportSize(canvasRef)
+    const viewportStyles = computed(() => ({
       width: VIEWPORT_SIZE,
       height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
-      left: 0,
-      top: 0,
-      scale: 1,
-    })
-
-    const canvasRef = ref<Element | null>(null)
-    const canvasScale = ref(1)
-
-    const store = useStore<State>()
-    const currentSlide = computed(() => store.getters.currentSlide)
-
-    const editorAreaShowScale = computed(() => store.state.editorAreaShowScale)
-    const setViewportSize = () => {
-      if(!canvasRef.value) return
-      const canvasWidth = canvasRef.value.clientWidth
-      const canvasHeight = canvasRef.value.clientHeight
+      left: viewportLeft.value,
+      top: viewportTop.value,
+    }))
 
-      if(canvasHeight / canvasWidth > VIEWPORT_ASPECT_RATIO) {
-        const viewportActualWidth = canvasWidth * (editorAreaShowScale.value / 100)
-        canvasScale.value = viewportActualWidth / VIEWPORT_SIZE
-        viewportStyles.scale = canvasScale.value
-        viewportStyles.left = (canvasWidth - viewportActualWidth) / 2
-        viewportStyles.top = (canvasHeight - viewportActualWidth * VIEWPORT_ASPECT_RATIO) / 2
-      }
-      else {
-        const viewportActualHeight = canvasHeight * (editorAreaShowScale.value / 100)
-        canvasScale.value = viewportActualHeight / (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO)
-        viewportStyles.scale = canvasScale.value
-        viewportStyles.left = (canvasWidth - viewportActualHeight / VIEWPORT_ASPECT_RATIO) / 2
-        viewportStyles.top = (canvasHeight - viewportActualHeight) / 2
-      }
-    }
-
-    const resizeObserver = new ResizeObserver(setViewportSize)
-
-    onMounted(() => {
-      if(canvasRef.value) resizeObserver.observe(canvasRef.value)
-    })
-    onUnmounted(() => {
-      if(canvasRef.value) resizeObserver.unobserve(canvasRef.value)
-    })
-    
     const mouseSelectionState = reactive({
       isShow: false,
       top: 0,
@@ -205,26 +172,6 @@ export default defineComponent({
           text: '粘贴',
           subText: 'Ctrl + V',
         },
-        { divider: true },
-        {
-          text: '参考线',
-          children: [
-            {
-              text: '打开',
-              disable: isShowGridLines.value,
-              icon: isShowGridLines.value ? 'icon-check' : '',
-              iconPlacehoder: true,
-              action: () => isShowGridLines.value = true,
-            },
-            {
-              text: '关闭',
-              disable: !isShowGridLines.value,
-              icon: !isShowGridLines.value ? 'icon-check' : '',
-              iconPlacehoder: true,
-              action: () => isShowGridLines.value = false,
-            },
-          ],
-        },
         {
           text: '清空页面',
         },
@@ -235,6 +182,7 @@ export default defineComponent({
       canvasRef,
       viewportRef,
       viewportStyles,
+      canvasScale,
       mouseSelectionState,
       handleClickBlankArea,
       removeEditorAreaFocus,