<script setup lang="ts">
|
import eventBus from '@/utils/eventBus'
|
import { getComponentRotatedStyle } from '@/utils/style'
|
import { getCurrentInstance, onMounted, ref } from 'vue'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import { storeToRefs } from 'pinia'
|
|
const lines = ref(['xt', 'xc', 'xb', 'yl', 'yc', 'yr']) // 分别对应三条横线和三条竖线
|
const diff = ref(3) // 相距 dff 像素将自动吸附
|
const lineStatus = ref({
|
xt: false,
|
xc: false,
|
xb: false,
|
yl: false,
|
yc: false,
|
yr: false
|
})
|
|
const dvMainStore = dvMainStoreWithOut()
|
const { curComponent, componentData } = storeToRefs(dvMainStore)
|
let currentInstance
|
const hideLine = () => {
|
Object.keys(lineStatus.value).forEach(line => {
|
lineStatus.value[line] = false
|
})
|
}
|
|
const showLine = (isDownward, isRightward) => {
|
const linesRef = currentInstance.proxy.$refs
|
const components = componentData.value
|
const curComponentStyle = getComponentRotatedStyle(curComponent.value.style)
|
const curComponentHalfWidth = curComponentStyle.width / 2
|
const curComponentHalfHeight = curComponentStyle.height / 2
|
|
hideLine()
|
components.forEach(component => {
|
try {
|
if (component === curComponent.value) return
|
const componentStyle = getComponentRotatedStyle(component.style)
|
const { top, left, bottom, right } = componentStyle
|
const componentHalfWidth = componentStyle.width / 2
|
const componentHalfHeight = componentStyle.height / 2
|
const conditions = {
|
top: [
|
{
|
isNearly: isNearly(curComponentStyle.top, top),
|
lineNode: linesRef.xt[0], // xt
|
line: 'xt',
|
dragShift: top,
|
lineShift: top
|
},
|
{
|
isNearly: isNearly(curComponentStyle.bottom, top),
|
lineNode: linesRef.xt[0], // xt
|
line: 'xt',
|
dragShift: top - curComponentStyle.height,
|
lineShift: top
|
},
|
{
|
// 组件与拖拽节点的中间是否对齐
|
isNearly: isNearly(
|
curComponentStyle.top + curComponentHalfHeight,
|
top + componentHalfHeight
|
),
|
lineNode: linesRef.xc[0], // xc
|
line: 'xc',
|
dragShift: top + componentHalfHeight - curComponentHalfHeight,
|
lineShift: top + componentHalfHeight
|
},
|
{
|
isNearly: isNearly(curComponentStyle.top, bottom),
|
lineNode: linesRef.xb[0], // xb
|
line: 'xb',
|
dragShift: bottom,
|
lineShift: bottom
|
},
|
{
|
isNearly: isNearly(curComponentStyle.bottom, bottom),
|
lineNode: linesRef.xb[0], // xb
|
line: 'xb',
|
dragShift: bottom - curComponentStyle.height,
|
lineShift: bottom
|
}
|
],
|
left: [
|
{
|
isNearly: isNearly(curComponentStyle.left, left),
|
lineNode: linesRef.yl[0], // yl
|
line: 'yl',
|
dragShift: left,
|
lineShift: left
|
},
|
{
|
isNearly: isNearly(curComponentStyle.right, left),
|
lineNode: linesRef.yl[0], // yl
|
line: 'yl',
|
dragShift: left - curComponentStyle.width,
|
lineShift: left
|
},
|
{
|
// 组件与拖拽节点的中间是否对齐
|
isNearly: isNearly(
|
curComponentStyle.left + curComponentHalfWidth,
|
left + componentHalfWidth
|
),
|
lineNode: linesRef.yc[0], // yc
|
line: 'yc',
|
dragShift: left + componentHalfWidth - curComponentHalfWidth,
|
lineShift: left + componentHalfWidth
|
},
|
{
|
isNearly: isNearly(curComponentStyle.left, right),
|
lineNode: linesRef.yr[0], // yr
|
line: 'yr',
|
dragShift: right,
|
lineShift: right
|
},
|
{
|
isNearly: isNearly(curComponentStyle.right, right),
|
lineNode: linesRef.yr[0], // yr
|
line: 'yr',
|
dragShift: right - curComponentStyle.width,
|
lineShift: right
|
}
|
]
|
}
|
|
const needToShow = []
|
const { rotate } = curComponent.value.style
|
if (conditions) {
|
Object.keys(conditions).forEach(key => {
|
// 遍历符合的条件并处理
|
if (conditions[key]) {
|
conditions[key].forEach(condition => {
|
if (!condition.isNearly) return
|
// 修改当前组件位移
|
dvMainStore.setShapeSingleStyle({
|
key,
|
value:
|
rotate != 0
|
? translateCurComponentShift(key, condition, curComponentStyle)
|
: condition.dragShift
|
})
|
if (condition.lineNode) {
|
condition.lineNode.style[key] = `${condition.lineShift}px`
|
}
|
needToShow.push(condition.line)
|
})
|
}
|
})
|
}
|
if (needToShow.length) {
|
chooseTheTrueLine(needToShow, isDownward, isRightward)
|
}
|
} catch (e) {
|
console.warn('markLine disabled')
|
}
|
})
|
}
|
|
const translateCurComponentShift = (key, condition, curComponentStyle) => {
|
const { width, height } = curComponent.value.style
|
if (key == 'top') {
|
return Math.round(condition.dragShift - (height - curComponentStyle.height) / 2)
|
}
|
|
return Math.round(condition.dragShift - (width - curComponentStyle.width) / 2)
|
}
|
|
const chooseTheTrueLine = (needToShow, isDownward, isRightward) => {
|
// 如果鼠标向右移动 则按从右到左的顺序显示竖线 否则按相反顺序显示
|
// 如果鼠标向下移动 则按从下到上的顺序显示横线 否则按相反顺序显示
|
if (isRightward) {
|
if (needToShow.includes('yr')) {
|
lineStatus.value.yr = true
|
} else if (needToShow.includes('yc')) {
|
lineStatus.value.yc = true
|
} else if (needToShow.includes('yl')) {
|
lineStatus.value.yl = true
|
}
|
} else {
|
// eslint-disable-next-line no-lonely-if
|
if (needToShow.includes('yl')) {
|
lineStatus.value.yl = true
|
} else if (needToShow.includes('yc')) {
|
lineStatus.value.yc = true
|
} else if (needToShow.includes('yr')) {
|
lineStatus.value.yr = true
|
}
|
}
|
|
if (isDownward) {
|
if (needToShow.includes('xb')) {
|
lineStatus.value.xb = true
|
} else if (needToShow.includes('xc')) {
|
lineStatus.value.xc = true
|
} else if (needToShow.includes('xt')) {
|
lineStatus.value.xt = true
|
}
|
} else {
|
// eslint-disable-next-line no-lonely-if
|
if (needToShow.includes('xt')) {
|
lineStatus.value.xt = true
|
} else if (needToShow.includes('xc')) {
|
lineStatus.value.xc = true
|
} else if (needToShow.includes('xb')) {
|
lineStatus.value.xb = true
|
}
|
}
|
}
|
|
const isNearly = (dragValue, targetValue) => {
|
return Math.abs(dragValue - targetValue) <= diff.value
|
}
|
|
onMounted(() => {
|
currentInstance = getCurrentInstance()
|
// 监听元素移动和不移动的事件
|
eventBus.on('move', ({ isDownward, isRightward }) => {
|
showLine(isDownward, isRightward)
|
})
|
|
eventBus.on('unMove', () => {
|
hideLine()
|
})
|
})
|
</script>
|
<template>
|
<div class="mark-line" id="canvas-mark-line">
|
<div
|
v-for="line in lines"
|
v-show="lineStatus[line] || false"
|
:key="line"
|
:ref="line"
|
class="line"
|
:class="line.includes('x') ? 'xLine' : 'yLine'"
|
></div>
|
</div>
|
</template>
|
|
<style lang="less" scoped>
|
.mark-line {
|
height: 100%;
|
}
|
|
.line {
|
background: #59c7f9;
|
position: absolute;
|
z-index: 1000;
|
}
|
|
.xLine {
|
width: 100%;
|
height: 1px;
|
}
|
|
.yLine {
|
width: 1px;
|
height: 100%;
|
}
|
</style>
|