File size: 5,813 Bytes
89ce340 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
import { type Ref, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store'
import type { PPTElement } from '@/types/slides'
import { getElementRange } from '@/utils/element'
export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | undefined>) => {
const mainStore = useMainStore()
const { canvasScale, hiddenElementIdList } = storeToRefs(mainStore)
const mouseSelectionVisible = ref(false)
const mouseSelectionQuadrant = ref(1)
const mouseSelection = ref({
top: 0,
left: 0,
width: 0,
height: 0,
})
// 更新鼠标框选范围
const updateMouseSelection = (e: MouseEvent) => {
if (!viewportRef.value) return
let isMouseDown = true
const viewportRect = viewportRef.value.getBoundingClientRect()
const minSelectionRange = 5
const startPageX = e.pageX
const startPageY = e.pageY
const left = (startPageX - viewportRect.x) / canvasScale.value
const top = (startPageY - viewportRect.y) / canvasScale.value
// 确定框选的起始位置和其他默认值初始化
mouseSelection.value = {
top: top,
left: left,
width: 0,
height: 0,
}
mouseSelectionVisible.value = false
mouseSelectionQuadrant.value = 4
document.onmousemove = e => {
if (!isMouseDown) return
const currentPageX = e.pageX
const currentPageY = e.pageY
const offsetWidth = (currentPageX - startPageX) / canvasScale.value
const offsetHeight = (currentPageY - startPageY) / canvasScale.value
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 = 2
else if ( offsetWidth > 0 && offsetHeight < 0 ) quadrant = 1
else if ( offsetWidth < 0 && offsetHeight > 0 ) quadrant = 3
// 更新框选范围
mouseSelection.value = {
...mouseSelection.value,
width: width,
height: height,
}
mouseSelectionVisible.value = true
mouseSelectionQuadrant.value = quadrant
}
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
isMouseDown = false
// 计算画布中的元素是否处在鼠标选择范围中,处在范围中的元素设置为被选中状态
let inRangeElementList: PPTElement[] = []
for (let i = 0; i < elementList.value.length; i++) {
const element = elementList.value[i]
const mouseSelectionLeft = mouseSelection.value.left
const mouseSelectionTop = mouseSelection.value.top
const mouseSelectionWidth = mouseSelection.value.width
const mouseSelectionHeight = mouseSelection.value.height
const { minX, maxX, minY, maxY } = getElementRange(element)
// 计算元素是否处在框选范围内时,四个框选方向的计算方式有差异
let isInclude = false
if (mouseSelectionQuadrant.value === 4) {
isInclude = minX > mouseSelectionLeft &&
maxX < mouseSelectionLeft + mouseSelectionWidth &&
minY > mouseSelectionTop &&
maxY < mouseSelectionTop + mouseSelectionHeight
}
else if (mouseSelectionQuadrant.value === 2) {
isInclude = minX > (mouseSelectionLeft - mouseSelectionWidth) &&
maxX < (mouseSelectionLeft - mouseSelectionWidth) + mouseSelectionWidth &&
minY > (mouseSelectionTop - mouseSelectionHeight) &&
maxY < (mouseSelectionTop - mouseSelectionHeight) + mouseSelectionHeight
}
else if (mouseSelectionQuadrant.value === 1) {
isInclude = minX > mouseSelectionLeft &&
maxX < mouseSelectionLeft + mouseSelectionWidth &&
minY > (mouseSelectionTop - mouseSelectionHeight) &&
maxY < (mouseSelectionTop - mouseSelectionHeight) + mouseSelectionHeight
}
else if (mouseSelectionQuadrant.value === 3) {
isInclude = minX > (mouseSelectionLeft - mouseSelectionWidth) &&
maxX < (mouseSelectionLeft - mouseSelectionWidth) + mouseSelectionWidth &&
minY > mouseSelectionTop &&
maxY < mouseSelectionTop + mouseSelectionHeight
}
// 被锁定或被隐藏的元素即使在范围内,也不需要设置为选中状态
if (isInclude && !element.lock && !hiddenElementIdList.value.includes(element.id)) inRangeElementList.push(element)
}
// 如果范围内有组合元素的成员,需要该组全部成员都处在范围内,才会被设置为选中状态
inRangeElementList = inRangeElementList.filter(inRangeElement => {
if (inRangeElement.groupId) {
const inRangeElementIdList = inRangeElementList.map(inRangeElement => inRangeElement.id)
const groupElementList = elementList.value.filter(element => element.groupId === inRangeElement.groupId)
return groupElementList.every(groupElement => inRangeElementIdList.includes(groupElement.id))
}
return true
})
const inRangeElementIdList = inRangeElementList.map(inRangeElement => inRangeElement.id)
mainStore.setActiveElementIdList(inRangeElementIdList)
mouseSelectionVisible.value = false
}
}
return {
mouseSelection,
mouseSelectionVisible,
mouseSelectionQuadrant,
updateMouseSelection,
}
} |