fix
This commit is contained in:
217
src/views/canvas1/components/tools/offset-tool.vue
Normal file
217
src/views/canvas1/components/tools/offset-tool.vue
Normal file
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<div class="offset-tool">
|
||||
<div class="input" v-show="showInput">
|
||||
<my-input v-model="left" type="number" before="X" after="%" :min="-100" :max="100" />
|
||||
<my-input v-model="top" type="number" before="Y" after="%" :min="-100" :max="100" />
|
||||
</div>
|
||||
<div
|
||||
class="dish"
|
||||
@mousedown="mousedown"
|
||||
@touchstart="mousedown"
|
||||
ref="dishRef"
|
||||
v-show="showDish"
|
||||
>
|
||||
<img src="/src/assets/images/icon/xyz.png" />
|
||||
<span class="ball" :style="ballStyle"></span>
|
||||
<span class="tip x">X: {{ left }}%</span>
|
||||
<span class="tip y">Y: {{ top }}%</span>
|
||||
<span class="line x"></span>
|
||||
<span class="line y"></span>
|
||||
<span class="line z" :style="lineZStyle"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import MyInput from './my-input.vue'
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object as () => { x: number; y: number } },
|
||||
showInput: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showDish: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'change', 'input'])
|
||||
// 工具的实际坐标 -100 ~ 100
|
||||
const top = ref(Math.round(props.modelValue.y))
|
||||
const left = ref(Math.round(props.modelValue.x))
|
||||
|
||||
// 原点的坐标 0 ~ 100
|
||||
const ballStyle = computed(() => ({
|
||||
top: 50 + top.value / 2 + '%',
|
||||
left: 50 + left.value / 2 + '%'
|
||||
}))
|
||||
watch(
|
||||
() => props.modelValue.x,
|
||||
(v) => (left.value = v)
|
||||
)
|
||||
watch(
|
||||
() => props.modelValue.y,
|
||||
(v) => (top.value = v)
|
||||
)
|
||||
const dishRef = ref<HTMLDivElement>()
|
||||
const mousedown = (e: MouseEvent | TouchEvent) => {
|
||||
if (!dishRef.value) return
|
||||
const mousemove = (e: MouseEvent | TouchEvent) => {
|
||||
if (!dishRef.value) return
|
||||
const rect = dishRef.value.getBoundingClientRect()
|
||||
const X = e.clientX || (e as TouchEvent).touches[0].clientX
|
||||
const Y = e.clientY || (e as TouchEvent).touches[0].clientY
|
||||
var x = ((X - rect.left) / rect.width) * 100
|
||||
var y = ((Y - rect.top) / rect.height) * 100
|
||||
if (x < 0) x = 0
|
||||
if (x > 100) x = 100
|
||||
if (y < 0) y = 0
|
||||
if (y > 100) y = 100
|
||||
left.value = Math.round((x - 50) * 2)
|
||||
top.value = Math.round((y - 50) * 2)
|
||||
onInput()
|
||||
}
|
||||
mousemove(e)
|
||||
const mouseup = () => {
|
||||
onChange()
|
||||
document.removeEventListener('mousemove', mousemove)
|
||||
document.removeEventListener('touchmove', mousemove)
|
||||
document.removeEventListener('mouseup', mouseup)
|
||||
document.removeEventListener('touchend', mouseup)
|
||||
}
|
||||
document.addEventListener('mousemove', mousemove)
|
||||
document.addEventListener('touchmove', mousemove)
|
||||
document.addEventListener('mouseup', mouseup)
|
||||
document.addEventListener('touchend', mouseup)
|
||||
}
|
||||
const onInput = () => {
|
||||
const value = {
|
||||
x: left.value,
|
||||
y: top.value
|
||||
}
|
||||
emit('update:modelValue', value)
|
||||
emit('input', value)
|
||||
}
|
||||
var changeTime: any = null
|
||||
const onChange = () => {
|
||||
clearTimeout(changeTime)
|
||||
changeTime = setTimeout(() => {
|
||||
const value = {
|
||||
x: left.value,
|
||||
y: top.value
|
||||
}
|
||||
emit('update:modelValue', value)
|
||||
emit('change', value)
|
||||
}, 500)
|
||||
}
|
||||
const lineZStyle = computed(() => ({
|
||||
'--rotateZ': calculateAngle(0, 0, left.value, top.value) + 'deg',
|
||||
width: calculateDistance(0, 0, left.value, top.value) / 2 + '%'
|
||||
}))
|
||||
// 计算角度
|
||||
function calculateAngle(x1: number, y1: number, x2: number, y2: number) {
|
||||
const deltaX = x2 - x1
|
||||
const deltaY = y1 - y2
|
||||
let angle = Math.atan2(deltaX, deltaY) * (180 / Math.PI) - 90
|
||||
return angle
|
||||
}
|
||||
// 计算距离
|
||||
function calculateDistance(x1: number, y1: number, x2: number, y2: number) {
|
||||
const deltaX = x2 - x1
|
||||
const deltaY = y2 - y1
|
||||
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
|
||||
return distance
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.offset-tool {
|
||||
position: relative;
|
||||
> .input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
> * {
|
||||
flex: 1;
|
||||
margin-right: 1rem;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
> .dish {
|
||||
width: 11.5rem;
|
||||
height: 11.5rem;
|
||||
border: 0.1rem solid #eaeaea;
|
||||
border-radius: 0.34rem;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
background-color: #f6f6f6;
|
||||
margin-top: 2rem;
|
||||
> * {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
> img {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
bottom: 0.35rem;
|
||||
right: 0.35rem;
|
||||
}
|
||||
> .ball {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 0.85rem;
|
||||
height: 0.85rem;
|
||||
border: 0.1rem solid #fff;
|
||||
background-color: #333;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0px 0.068rem 0.17px 0px rgba(0, 0, 0, 0.26);
|
||||
}
|
||||
> .tip {
|
||||
font-size: 0.85rem;
|
||||
color: #000;
|
||||
line-height: 2.4rem;
|
||||
&.x {
|
||||
top: 50%;
|
||||
right: 0%;
|
||||
transform: translate(100%, -50%);
|
||||
padding-left: 6px;
|
||||
}
|
||||
&.y {
|
||||
top: 0%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
}
|
||||
}
|
||||
> .line {
|
||||
border-color: #d9d9d9;
|
||||
border-style: dashed;
|
||||
border-width: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
&.x {
|
||||
width: 100%;
|
||||
border-top-width: 0.1rem;
|
||||
}
|
||||
&.y {
|
||||
height: 100%;
|
||||
border-left-width: 0.1rem;
|
||||
}
|
||||
&.z {
|
||||
width: 50%;
|
||||
border-top-width: 0.1rem;
|
||||
border-color: #454754;
|
||||
transform: translate(0%, -50%) rotateZ(var(--rotateZ));
|
||||
transform-origin: left center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user