mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
200 lines
5.2 KiB
Vue
200 lines
5.2 KiB
Vue
<template>
|
|
<div
|
|
class="element-create-selection"
|
|
ref="selectionRef"
|
|
@mousedown.stop="$event => createSelection($event)"
|
|
>
|
|
<div :class="['selection', creatingElement.type]" v-if="start && end" :style="position">
|
|
|
|
<!-- 绘制线条专用 -->
|
|
<SvgWrapper
|
|
v-if="creatingElement.type === 'line' && lineData"
|
|
overflow="visible"
|
|
:width="lineData.svgWidth"
|
|
:height="lineData.svgHeight"
|
|
>
|
|
<path
|
|
:d="lineData.path"
|
|
stroke="#888"
|
|
fill="none"
|
|
stroke-width="1"
|
|
stroke-linecap
|
|
stroke-linejoin
|
|
stroke-miterlimit
|
|
></path>
|
|
</SvgWrapper>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { computed, defineComponent, onMounted, reactive, ref } from 'vue'
|
|
import { MutationTypes, useStore } from '@/store'
|
|
|
|
export default defineComponent({
|
|
name: 'element-create-selection',
|
|
setup(props, { emit }) {
|
|
const store = useStore()
|
|
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
|
const creatingElement = computed(() => store.state.creatingElement)
|
|
|
|
const start = ref<[number, number] | null>(null)
|
|
const end = ref<[number, number] | null>(null)
|
|
|
|
const selectionRef = ref<HTMLElement>()
|
|
const offset = reactive({
|
|
x: 0,
|
|
y: 0,
|
|
})
|
|
onMounted(() => {
|
|
if(!selectionRef.value) return
|
|
const { x, y } = selectionRef.value.getBoundingClientRect()
|
|
offset.x = x
|
|
offset.y = y
|
|
})
|
|
|
|
const createSelection = (e: MouseEvent) => {
|
|
let isMouseDown = true
|
|
|
|
const startPageX = e.pageX
|
|
const startPageY = e.pageY
|
|
start.value = [startPageX, startPageY]
|
|
|
|
document.onmousemove = e => {
|
|
if(!creatingElement.value || !isMouseDown) return
|
|
|
|
let currentPageX = e.pageX
|
|
let currentPageY = e.pageY
|
|
|
|
if(ctrlOrShiftKeyActive.value) {
|
|
const moveX = currentPageX - startPageX
|
|
const moveY = currentPageY - startPageY
|
|
|
|
const absX = Math.abs(moveX)
|
|
const absY = Math.abs(moveY)
|
|
|
|
if(creatingElement.value.type === 'shape') {
|
|
// moveX和moveY一正一负
|
|
const isOpposite = (moveY > 0 && moveX < 0) || (moveY < 0 && moveX > 0)
|
|
|
|
if(absX > absY) {
|
|
currentPageY = isOpposite ? startPageY - moveX : startPageY + moveX
|
|
}
|
|
else {
|
|
currentPageX = isOpposite ? startPageX - moveY : startPageX + moveY
|
|
}
|
|
}
|
|
|
|
else if(creatingElement.value.type === 'line') {
|
|
if(absX > absY) currentPageY = startPageY
|
|
else currentPageX = startPageX
|
|
}
|
|
}
|
|
|
|
end.value = [currentPageX, currentPageY]
|
|
}
|
|
|
|
document.onmouseup = e => {
|
|
document.onmousemove = null
|
|
document.onmouseup = null
|
|
isMouseDown = false
|
|
|
|
const endPageX = e.pageX
|
|
const endPageY = e.pageY
|
|
|
|
const minSize = 30
|
|
|
|
if(Math.abs(endPageX - startPageX) >= minSize || Math.abs(endPageY - startPageY) >= minSize) {
|
|
emit('created', {
|
|
start: start.value,
|
|
end: end.value,
|
|
})
|
|
}
|
|
else store.commit(MutationTypes.SET_CREATING_ELEMENT, null)
|
|
}
|
|
}
|
|
|
|
const lineData = computed(() => {
|
|
if(!start.value || !end.value) return null
|
|
if(!creatingElement.value || creatingElement.value.type !== 'line') return null
|
|
|
|
const [_startX, _startY] = start.value
|
|
const [_endX, _endY] = end.value
|
|
const minX = Math.min(_startX, _endX)
|
|
const maxX = Math.max(_startX, _endX)
|
|
const minY = Math.min(_startY, _endY)
|
|
const maxY = Math.max(_startY, _endY)
|
|
|
|
const svgWidth = maxX - minX >= 24 ? maxX - minX : 24
|
|
const svgHeight = maxY - minY >= 24 ? maxY - minY : 24
|
|
|
|
const startX = _startX === minX ? 0 : maxX - minX
|
|
const startY = _startY === minY ? 0 : maxY - minY
|
|
const endX = _endX === minX ? 0 : maxX - minX
|
|
const endY = _endY === minY ? 0 : maxY - minY
|
|
|
|
const path = `M${startX}, ${startY} L${endX}, ${endY}`
|
|
|
|
return {
|
|
svgWidth,
|
|
svgHeight,
|
|
startX,
|
|
startY,
|
|
endX,
|
|
endY,
|
|
path,
|
|
}
|
|
})
|
|
|
|
const position = computed(() => {
|
|
if(!start.value || !end.value) return {}
|
|
|
|
const [startX, startY] = start.value
|
|
const [endX, endY] = end.value
|
|
const minX = Math.min(startX, endX)
|
|
const maxX = Math.max(startX, endX)
|
|
const minY = Math.min(startY, endY)
|
|
const maxY = Math.max(startY, endY)
|
|
|
|
const width = maxX - minX
|
|
const height = maxY - minY
|
|
|
|
return {
|
|
left: minX - offset.x + 'px',
|
|
top: minY - offset.y + 'px',
|
|
width: width + 'px',
|
|
height: height + 'px',
|
|
}
|
|
})
|
|
|
|
return {
|
|
selectionRef,
|
|
start,
|
|
end,
|
|
creatingElement,
|
|
createSelection,
|
|
lineData,
|
|
position,
|
|
}
|
|
},
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.element-create-selection {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 2;
|
|
cursor: crosshair;
|
|
}
|
|
.selection {
|
|
position: absolute;
|
|
|
|
&:not(.line) {
|
|
border: 1px solid #888;
|
|
}
|
|
}
|
|
</style> |