vue3-sketch-ruler
Version:
> In using vue3, the zoom operation used for page presentation
140 lines (127 loc) • 4.23 kB
text/typescript
import { computed, ref } from 'vue'
import type { PaletteType, LineType } from '../index-types'
import { debounce } from '../canvas-ruler/utils.ts'
interface Props {
palette: PaletteType
lockLine: boolean
scale: number
snapThreshold: number
snapsObj: LineType
lines: LineType
canvasHeight: number
canvasWidth: number
rate: number
index?: number
}
export default function useLine(props: Props, vertical: boolean) {
const offsetLine = ref(0)
const startValue = ref(0)
const showLabel = ref(false)
const actionStyle = computed(() => ({
backgroundColor: props.palette.hoverBg,
color: props.palette.hoverColor,
[vertical ? 'top' : 'left']: `-8px`,
[vertical ? 'left' : 'top']: `${offsetLine.value + 10}px`
}))
const handleMouseMove = ({ offsetX, offsetY }: { offsetX: number; offsetY: number }) => {
offsetLine.value = vertical ? offsetX : offsetY
}
const handleMouseDown = (e: MouseEvent, propValue?: number) => {
return new Promise<void>((resolve) => {
if (props.lockLine) return
const startPosition = vertical ? e.clientY : e.clientX
handleMouseMove(e)
const initialValue = propValue || startValue.value
let tempStartValue = initialValue
const moveHandler = (e: MouseEvent) => {
const currentPosition = vertical ? e.clientY : e.clientX
const delta = (currentPosition - startPosition) / props.scale
let nextPos = delta + initialValue
let guidePos = nextPos
const snaps = vertical ? props.snapsObj.h : props.snapsObj.v
const guideSnaps = snaps!.slice().sort((a: number, b: number) => {
return Math.abs(guidePos - a) - Math.abs(guidePos - b)
})
// 吸附效果跟scale有关, 缩放后吸附效果会变差,所以要除props.scale
if (
guideSnaps.length &&
Math.abs(guideSnaps[0] - nextPos) < props.snapThreshold / props.scale
) {
guidePos = guideSnaps[0]
nextPos = guidePos
}
tempStartValue = Math.round(nextPos)
startValue.value = tempStartValue
}
const mouseUpHandler = () => {
document.removeEventListener('mousemove', moveHandler)
handleLineRelease(tempStartValue, props.index)
resolve()
}
document.addEventListener('mousemove', moveHandler)
document.addEventListener('mouseup', mouseUpHandler, { once: true })
})
}
/**
* @description: 放开线条处理
* @param {*} value 距离边框的位置
* @param {*} index 选的哪条线
*/
const handleLineRelease = (value: number, index?: number) => {
const linesArrs = vertical ? props.lines?.h : props.lines?.v
const isOutOfRange = checkBoundary(value)
if (!linesArrs) {
return
}
if (isOutOfRange) {
if (typeof index === 'number') {
linesArrs.splice(index, 1)
} else {
return // 新增越界,什么也不做
}
} else {
if (typeof index !== 'number') {
linesArrs.push(value)
} else {
linesArrs[index] = value
}
}
}
/**
* @desc:检查越界
* @param {number} value
*/
const checkBoundary = (value: number) => {
const maxOffset = vertical ? props.canvasHeight : props.canvasWidth
return value < 0 || value > maxOffset
}
const labelContent = computed(() => {
if (checkBoundary(startValue.value)) return '放开删除'
return `${vertical ? 'Y' : 'X'}:${startValue.value * props.rate}`
})
const debouncedHandleMouseLeave = debounce(() => {
showLabel.value = false
}, 200)
const debouncedHandleMouseEnter = debounce(() => {
showLabel.value = true
}, 200)
const handleMouseenter = (e: MouseEvent) => {
if (!props.lockLine) {
handleMouseMove(e)
debouncedHandleMouseEnter()
debouncedHandleMouseLeave.cancel()
}
}
const handleMouseLeave = () => {
debouncedHandleMouseLeave()
}
return {
showLabel,
startValue,
actionStyle,
labelContent,
handleMouseDown,
handleMouseenter,
handleMouseLeave
}
}