Merge branch 'xhf' of http://git.znkjfw.com/ak/zn-admin-vue3-wcs into xhf
This commit is contained in:
commit
4b54062344
@ -1,32 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 新增设备 -->
|
<!-- 新增设备 -->
|
||||||
<Dialog v-model="dialogFormVisible" title="编辑路线" width="750" class="map-edit-route-dialog">
|
<Dialog v-model="dialogFormVisible" title="编辑路线" width="780" class="map-edit-route-dialog">
|
||||||
<el-form :model="form" label-width="120" ref="ruleFormRef">
|
<el-form :model="form" label-width="120" ref="ruleFormRef">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="开始点位x轴" prop="startPointX" required>
|
<el-form-item label="开始点位x轴" prop="startPointX" required>
|
||||||
<el-input v-model="form.startPointX" placeholder="请输入开始点位x轴" type="number" />
|
<el-input
|
||||||
|
v-model="form.startPointX"
|
||||||
|
placeholder="请输入开始点位x轴"
|
||||||
|
type="number"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="开始点位y轴" prop="startPointY" required>
|
<el-form-item label="开始点位y轴" prop="startPointY" required>
|
||||||
<el-input v-model="form.startPointY" placeholder="请输入开始点位y轴" type="number" />
|
<el-input
|
||||||
|
v-model="form.startPointY"
|
||||||
|
placeholder="请输入开始点位y轴"
|
||||||
|
type="number"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="结束点位x轴" prop="endPointX" required>
|
<el-form-item label="结束点位x轴" prop="endPointX" required>
|
||||||
<el-input v-model="form.endPointX" placeholder="请输入结束点位x轴" type="number" />
|
<el-input
|
||||||
|
v-model="form.endPointX"
|
||||||
|
placeholder="请输入结束点位x轴"
|
||||||
|
type="number"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="结束点位y轴" prop="endPointY" required>
|
<el-form-item label="结束点位y轴" prop="endPointY" required>
|
||||||
<el-input v-model="form.endPointY" placeholder="请输入结束点位y轴" type="number" />
|
<el-input
|
||||||
|
v-model="form.endPointY"
|
||||||
|
placeholder="请输入结束点位y轴"
|
||||||
|
type="number"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="开始控制点x轴" prop="beginControlX" required>
|
<el-form-item label="开始控制点x轴" prop="beginControlX" required>
|
||||||
<el-input v-model="form.beginControlX" type="number" :disabled="true" />
|
<el-input v-model="form.beginControlX" type="number" :disabled="true" />
|
||||||
@ -38,7 +58,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="结束控制点x轴" prop="endControlX" required>
|
<el-form-item label="结束控制点x轴" prop="endControlX" required>
|
||||||
<el-input v-model="form.endControlX" type="number" :disabled="true" />
|
<el-input v-model="form.endControlX" type="number" :disabled="true" />
|
||||||
@ -50,7 +70,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="行走方法" prop="method" required>
|
<el-form-item label="行走方法" prop="method" required>
|
||||||
<el-select v-model="form.method" placeholder="请选择行走方法" @change="methodChange">
|
<el-select v-model="form.method" placeholder="请选择行走方法" @change="methodChange">
|
||||||
@ -68,81 +88,69 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="膨胀区域前" prop="expansionZoneFront" required>
|
<el-form-item label="膨胀区域前" prop="expansionZoneFront" required>
|
||||||
<div>
|
<el-input v-model="form.expansionZoneFront" type="number">
|
||||||
<el-input-number
|
<template #append>米</template>
|
||||||
v-model="form.expansionZoneFront"
|
</el-input>
|
||||||
placeholder="请输入膨胀区域前"
|
|
||||||
:precision="2"
|
|
||||||
class="!w-170px"
|
|
||||||
/>
|
|
||||||
<span class="ml-3">米</span>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="膨胀区域后" prop="expansionZoneAfter" required>
|
<el-form-item label="膨胀区域后" prop="expansionZoneAfter" required>
|
||||||
<div>
|
<el-input v-model="form.expansionZoneAfter" type="number">
|
||||||
<el-input-number
|
<template #append>米</template>
|
||||||
v-model="form.expansionZoneAfter"
|
</el-input>
|
||||||
placeholder="请输入膨胀区域后"
|
|
||||||
:precision="2"
|
|
||||||
class="!w-170px"
|
|
||||||
/>
|
|
||||||
<span class="ml-3">米</span>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="膨胀区域左" prop="expansionZoneLeft" required>
|
<el-form-item label="膨胀区域左" prop="expansionZoneLeft" required>
|
||||||
<div>
|
<el-input v-model="form.expansionZoneLeft" type="number">
|
||||||
<el-input-number
|
<template #append>米</template>
|
||||||
v-model="form.expansionZoneLeft"
|
</el-input>
|
||||||
placeholder="请输入膨胀区域左"
|
|
||||||
:precision="2"
|
|
||||||
class="!w-170px"
|
|
||||||
/>
|
|
||||||
<span class="ml-3">米</span>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="膨胀区域右" prop="expansionZoneRight" required>
|
<el-form-item label="膨胀区域右" prop="expansionZoneRight" required>
|
||||||
<div>
|
<el-input v-model="form.expansionZoneRight" type="number">
|
||||||
<el-input-number
|
<template #append>米</template>
|
||||||
v-model="form.expansionZoneRight"
|
</el-input>
|
||||||
placeholder="请输入膨胀区域右"
|
|
||||||
:precision="2"
|
|
||||||
class="!w-170px"
|
|
||||||
/>
|
|
||||||
<span class="ml-3">米</span>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="正向限速" prop="forwardSpeedLimit" required>
|
<el-form-item label="正向限速" prop="forwardSpeedLimit" required>
|
||||||
<el-input
|
<div class="flex-center">
|
||||||
v-model="form.forwardSpeedLimit"
|
<el-slider v-model="form.forwardSpeedLimit" :min="0.1" :max="10" :step="0.1" />
|
||||||
type="number"
|
<el-input
|
||||||
placeholder="请输入正向限速"
|
v-model="form.forwardSpeedLimit"
|
||||||
/> </el-form-item
|
style="width: 200px; margin-left: 6px"
|
||||||
></el-col>
|
type="number"
|
||||||
|
>
|
||||||
|
<template #append>m/s</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="反向限速" prop="reverseSpeedLimit" required>
|
<el-form-item label="反向限速" prop="reverseSpeedLimit" required>
|
||||||
<el-input
|
<div class="flex-center">
|
||||||
v-model="form.reverseSpeedLimit"
|
<el-slider v-model="form.reverseSpeedLimit" :min="0.1" :max="10" :step="0.1" />
|
||||||
type="number"
|
<el-input
|
||||||
placeholder="请输入反向限速"
|
v-model="form.reverseSpeedLimit"
|
||||||
/> </el-form-item
|
style="width: 200px; margin-left: 6px"
|
||||||
></el-col>
|
type="number"
|
||||||
|
>
|
||||||
|
<template #append>m/s</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</el-form-item></el-col
|
||||||
|
>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="30">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="车头朝向" prop="toward" required>
|
<el-form-item label="车头朝向" prop="toward" required>
|
||||||
<el-select v-model="form.toward" placeholder="请选择车头朝向">
|
<el-select v-model="form.toward" placeholder="请选择车头朝向">
|
||||||
@ -286,4 +294,15 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
|||||||
border-top: none !important;
|
border-top: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-input-group__append,
|
||||||
|
.el-input-group__prepend {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-center {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogFormVisible" title="节点属性" width="540" class="node-form-dialog">
|
<Dialog v-model="dialogFormVisible" title="节点属性" width="540" class="node-form-dialog">
|
||||||
<el-form :model="form" label-width="auto" ref="ruleFormRef">
|
<el-form :model="form" label-width="auto" ref="ruleFormRef">
|
||||||
<el-form-item label="X" prop="locationX" required>
|
<el-form-item
|
||||||
<el-input type="number" v-model="form.locationX" placeholder="请输入" />
|
label="X"
|
||||||
|
prop="locationX"
|
||||||
|
required
|
||||||
|
:rules="{ required: true, message: '请输入x轴坐标', trigger: 'change' }"
|
||||||
|
>
|
||||||
|
<el-input type="number" v-model="form.locationX" placeholder="请输入" :min="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Y" prop="locationY" required>
|
<el-form-item
|
||||||
<el-input type="number" v-model="form.locationY" placeholder="请输入" />
|
label="Y"
|
||||||
|
prop="locationY"
|
||||||
|
required
|
||||||
|
:rules="{ required: true, message: '请输入y轴坐标', trigger: 'change' }"
|
||||||
|
>
|
||||||
|
<el-input type="number" v-model="form.locationY" placeholder="请输入" :min="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="类型" prop="type" required>
|
<el-form-item label="类型" prop="type" required>
|
||||||
<el-select v-model="form.type" placeholder="请选择类型" @change="typeChange">
|
<el-select v-model="form.type" placeholder="请选择类型" @change="typeChange">
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<!-- 刻度尺 -->
|
<!-- 刻度尺 -->
|
||||||
<template>
|
<template>
|
||||||
<div :style="wrapperStyle" class="vue-ruler-wrapper" onselectstart="return false;" ref="el">
|
<div class="vue-ruler-wrapper" onselectstart="return false;">
|
||||||
<section>
|
<section>
|
||||||
<div
|
<div
|
||||||
ref="horizontalRuler"
|
|
||||||
class="vue-ruler-h"
|
class="vue-ruler-h"
|
||||||
@mousedown.stop="horizontalDragRuler"
|
@mousedown.stop="horizontalDragRuler"
|
||||||
:style="{ width: width + 'px' }"
|
:style="{ width: width + 'px' }"
|
||||||
@ -17,7 +16,6 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref="verticalRuler"
|
|
||||||
class="vue-ruler-v"
|
class="vue-ruler-v"
|
||||||
@mousedown.stop="verticalDragRuler"
|
@mousedown.stop="verticalDragRuler"
|
||||||
:style="{ height: height + 'px' }"
|
:style="{ height: height + 'px' }"
|
||||||
@ -30,21 +28,10 @@
|
|||||||
>{{ item.id }}</span
|
>{{ item.id }}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div :style="{ top: verticalDottedTop + 'px' }" class="vue-ruler-ref-dot-h"></div>
|
|
||||||
<div :style="{ left: horizontalDottedLeft + 'px' }" class="vue-ruler-ref-dot-v"></div>
|
|
||||||
<div
|
|
||||||
v-for="item in lineList"
|
|
||||||
:title="item.title"
|
|
||||||
:style="getLineStyle(item)"
|
|
||||||
:key="item.id"
|
|
||||||
:class="`vue-ruler-ref-line-${item.type}`"
|
|
||||||
@mousedown="handleDragLine(item)"
|
|
||||||
></div>
|
|
||||||
</section>
|
</section>
|
||||||
<div ref="content" class="vue-ruler-content" :style="contentStyle">
|
<div class="vue-ruler-content">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isDrag" class="vue-ruler-content-mask"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -53,40 +40,6 @@ import { computed, defineComponent, onBeforeUnmount, onMounted, ref } from 'vue'
|
|||||||
defineOptions({ name: 'V3RulerComponent' })
|
defineOptions({ name: 'V3RulerComponent' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
position: {
|
|
||||||
type: String,
|
|
||||||
default: 'relative',
|
|
||||||
validator: (val) => {
|
|
||||||
return ['absolute', 'fixed', 'relative', 'static', 'inherit'].indexOf(val) !== -1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 规定元素的定位类型
|
|
||||||
isHotKey: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 热键开关
|
|
||||||
isScaleRevise: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 刻度修正(根据content进行刻度重置)
|
|
||||||
value: {
|
|
||||||
type: Array,
|
|
||||||
default: () => {
|
|
||||||
return [
|
|
||||||
{ type: 'h', site: 50 },
|
|
||||||
{ type: 'v', site: 180 }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 预置参考线
|
|
||||||
contentLayout: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {
|
|
||||||
return { top: 0, left: 0 }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//步长
|
//步长
|
||||||
stepLength: {
|
stepLength: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -101,123 +54,11 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['input', 'update:visible'])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 绑定事件 on(element, event, handler)
|
|
||||||
*/
|
|
||||||
const on = (function () {
|
|
||||||
return function (element, event, handler) {
|
|
||||||
if (element && event && handler) {
|
|
||||||
element.addEventListener(event, handler, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 解绑事件 off(element, event, handler)
|
|
||||||
*/
|
|
||||||
const off = (function () {
|
|
||||||
return function (element, event, handler) {
|
|
||||||
if (element && event) {
|
|
||||||
element.removeEventListener(event, handler, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
const size = 17
|
|
||||||
let left_top = 18 // 内容左上填充
|
let left_top = 18 // 内容左上填充
|
||||||
let windowWidth = ref(0) // 窗口宽度
|
|
||||||
let windowHeight = ref(0) // 窗口高度
|
|
||||||
let xScale = ref([{ id: 0 }]) // 水平刻度
|
let xScale = ref([{ id: 0 }]) // 水平刻度
|
||||||
let yScale = ref([{ id: 0 }]) // 垂直刻度
|
let yScale = ref([{ id: 0 }]) // 垂直刻度
|
||||||
let topSpacing = 0 // 标尺与窗口上间距
|
|
||||||
let leftSpacing = 0 // 标尺与窗口左间距
|
|
||||||
let isDrag = ref(false)
|
|
||||||
let dragFlag = '' // 拖动开始标记,可能值x(从水平标尺开始拖动);y(从垂直标尺开始拖动)
|
|
||||||
let horizontalDottedLeft = ref(-999) // 水平虚线位置
|
|
||||||
let verticalDottedTop = ref(-999) // 垂直虚线位置
|
|
||||||
let rulerWidth = 0 // 垂直标尺的宽度
|
|
||||||
let rulerHeight = 0 // 水平标尺的高度
|
|
||||||
let dragLineId = '' // 被移动线的ID
|
|
||||||
//ref
|
|
||||||
const content = ref(null)
|
|
||||||
const el = ref(null)
|
|
||||||
const verticalRuler = ref(null)
|
|
||||||
const horizontalRuler = ref(null)
|
|
||||||
const wrapperStyle = computed(() => {
|
|
||||||
return {
|
|
||||||
width: windowWidth.value + 'px',
|
|
||||||
height: windowHeight.value + 'px',
|
|
||||||
position: props.position
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const contentStyle = computed(() => {
|
|
||||||
return {
|
|
||||||
left: props.contentLayout.left + 'px',
|
|
||||||
top: props.contentLayout.top + 'px',
|
|
||||||
padding: left_top + 'px 0px 0px ' + left_top + 'px'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const lineList = computed(() => {
|
|
||||||
let hCount = 0
|
|
||||||
let vCount = 0
|
|
||||||
return props.value.map((item) => {
|
|
||||||
const isH = item.type === 'h'
|
|
||||||
return {
|
|
||||||
id: `${item.type}_${isH ? hCount++ : vCount++}`,
|
|
||||||
type: item.type,
|
|
||||||
title: item.site.toFixed(2) + 'px',
|
|
||||||
[isH ? 'top' : 'left']: item.site / (props.stepLength / 50) + size
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
onMounted(() => {
|
|
||||||
on(document, 'mousemove', dottedLineMove)
|
|
||||||
on(document, 'mouseup', dottedLineUp)
|
|
||||||
init()
|
|
||||||
on(window, 'resize', windowResize)
|
|
||||||
})
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
off(document, 'mousemove', dottedLineMove)
|
|
||||||
off(document, 'mouseup', dottedLineUp)
|
|
||||||
off(window, 'resize', windowResize)
|
|
||||||
})
|
|
||||||
const init = () => {
|
|
||||||
box()
|
|
||||||
scaleCalc()
|
|
||||||
}
|
|
||||||
const windowResize = () => {
|
|
||||||
xScale.value = [{ id: 0 }]
|
|
||||||
yScale.value = [{ id: 0 }]
|
|
||||||
init()
|
|
||||||
}
|
|
||||||
const getLineStyle = ({ type, top, left }) => {
|
|
||||||
return type === 'h' ? { top: top + 'px' } : { left: left + 'px' }
|
|
||||||
}
|
|
||||||
const handleDragLine = ({ type, id }) => {
|
|
||||||
return type === 'h' ? dragHorizontalLine(id) : dragVerticalLine(id)
|
|
||||||
}
|
|
||||||
//获取窗口宽与高
|
|
||||||
const box = () => {
|
|
||||||
setSpacing()
|
|
||||||
if (props.isScaleRevise) {
|
|
||||||
// 根据内容部分进行刻度修正
|
|
||||||
const contentLeft = content.value.offsetLeft
|
|
||||||
const contentTop = content.value.offsetTop
|
|
||||||
getCalcRevise(xScale.value, contentLeft)
|
|
||||||
getCalcRevise(yScale.value, contentTop)
|
|
||||||
}
|
|
||||||
// windowWidth.value = document.documentElement.clientWidth - leftSpacing
|
|
||||||
// windowHeight.value = document.documentElement.clientHeight - topSpacing - 80
|
|
||||||
windowWidth.value = props.width + 18
|
|
||||||
windowHeight.value = props.height + 18
|
|
||||||
rulerWidth = verticalRuler.value.clientWidth
|
|
||||||
rulerHeight = horizontalRuler.value.clientHeight
|
|
||||||
}
|
|
||||||
const setSpacing = () => {
|
|
||||||
topSpacing = horizontalRuler.value.getBoundingClientRect().y //.offsetParent.offsetTop
|
|
||||||
leftSpacing = verticalRuler.value.getBoundingClientRect().x // .offsetParent.offsetLeft
|
|
||||||
}
|
|
||||||
// 计算刻度
|
// 计算刻度
|
||||||
const scaleCalc = () => {
|
const scaleCalc = () => {
|
||||||
getCalc(xScale.value, props.width)
|
getCalc(xScale.value, props.width)
|
||||||
@ -232,127 +73,10 @@ const getCalc = (array, length) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 获取矫正刻度方法
|
|
||||||
const getCalcRevise = (array, length) => {
|
onMounted(() => {
|
||||||
for (let i = 0; i < length; i += 1) {
|
scaleCalc()
|
||||||
if (i % props.stepLength === 0 && i + props.stepLength <= length) {
|
})
|
||||||
array.push({ id: i })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//生成一个参考线
|
|
||||||
const newLine = (val) => {
|
|
||||||
isDrag.value = true
|
|
||||||
dragFlag = val
|
|
||||||
}
|
|
||||||
//虚线移动
|
|
||||||
const dottedLineMove = ($event) => {
|
|
||||||
setSpacing()
|
|
||||||
switch (dragFlag) {
|
|
||||||
case 'x':
|
|
||||||
if (isDrag.value) {
|
|
||||||
verticalDottedTop.value = $event.pageY - topSpacing
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'y':
|
|
||||||
if (isDrag.value) {
|
|
||||||
horizontalDottedLeft.value = $event.pageX - leftSpacing
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'h':
|
|
||||||
if (isDrag.value) {
|
|
||||||
verticalDottedTop.value = $event.pageY - topSpacing
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'v':
|
|
||||||
if (isDrag.value) {
|
|
||||||
horizontalDottedLeft.value = $event.pageX - leftSpacing
|
|
||||||
}
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//虚线松开
|
|
||||||
const dottedLineUp = ($event) => {
|
|
||||||
setSpacing()
|
|
||||||
if (isDrag.value) {
|
|
||||||
isDrag.value = false
|
|
||||||
const cloneList = JSON.parse(JSON.stringify(props.value))
|
|
||||||
switch (dragFlag) {
|
|
||||||
case 'x':
|
|
||||||
cloneList.push({
|
|
||||||
type: 'h',
|
|
||||||
site: ($event.pageY - topSpacing - size) * (props.stepLength / 50)
|
|
||||||
})
|
|
||||||
emit('input', cloneList)
|
|
||||||
break
|
|
||||||
case 'y':
|
|
||||||
cloneList.push({
|
|
||||||
type: 'v',
|
|
||||||
site: ($event.pageX - leftSpacing - size) * (props.stepLength / 50)
|
|
||||||
})
|
|
||||||
emit('input', cloneList)
|
|
||||||
break
|
|
||||||
case 'h':
|
|
||||||
dragCalc(cloneList, $event.pageY, topSpacing, rulerHeight, 'h')
|
|
||||||
emit('input', cloneList)
|
|
||||||
break
|
|
||||||
case 'v':
|
|
||||||
dragCalc(cloneList, $event.pageX, leftSpacing, rulerWidth, 'v')
|
|
||||||
emit('input', cloneList)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
verticalDottedTop.value = horizontalDottedLeft.value = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const dragCalc = (list, page, spacing, ruler, type) => {
|
|
||||||
if (page - spacing < ruler) {
|
|
||||||
let Index
|
|
||||||
lineList.value.forEach((item, index) => {
|
|
||||||
if (item.id === dragLineId) {
|
|
||||||
Index = index
|
|
||||||
}
|
|
||||||
})
|
|
||||||
list.splice(Index, 1, {
|
|
||||||
type: type,
|
|
||||||
site: -600
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let Index
|
|
||||||
lineList.value.forEach((item, index) => {
|
|
||||||
if (item.id === dragLineId) {
|
|
||||||
Index = index
|
|
||||||
}
|
|
||||||
})
|
|
||||||
list.splice(Index, 1, {
|
|
||||||
type: type,
|
|
||||||
site: (page - spacing - size) * (props.stepLength / 50)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//水平标尺按下鼠标
|
|
||||||
const horizontalDragRuler = () => {
|
|
||||||
newLine('x')
|
|
||||||
}
|
|
||||||
//垂直标尺按下鼠标
|
|
||||||
const verticalDragRuler = () => {
|
|
||||||
newLine('y')
|
|
||||||
}
|
|
||||||
// 水平线处按下鼠标
|
|
||||||
const dragHorizontalLine = (id) => {
|
|
||||||
isDrag.value = true
|
|
||||||
dragFlag = 'h'
|
|
||||||
dragLineId = id
|
|
||||||
}
|
|
||||||
// 垂直线处按下鼠标
|
|
||||||
const dragVerticalLine = (id) => {
|
|
||||||
isDrag.value = true
|
|
||||||
dragFlag = 'v'
|
|
||||||
dragLineId = id
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.vue-ruler-wrapper {
|
.vue-ruler-wrapper {
|
||||||
@ -363,11 +87,7 @@ const dragVerticalLine = (id) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.vue-ruler-h,
|
.vue-ruler-h,
|
||||||
.vue-ruler-v,
|
.vue-ruler-v {
|
||||||
.vue-ruler-ref-line-v,
|
|
||||||
.vue-ruler-ref-line-h,
|
|
||||||
.vue-ruler-ref-dot-h,
|
|
||||||
.vue-ruler-ref-dot-v {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -412,69 +132,10 @@ const dragVerticalLine = (id) => {
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vue-ruler-ref-line-v,
|
|
||||||
.vue-ruler-ref-line-h,
|
|
||||||
.vue-ruler-ref-dot-h,
|
|
||||||
.vue-ruler-ref-dot-v {
|
|
||||||
z-index: 998;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-ruler-ref-line-h {
|
|
||||||
width: 100%;
|
|
||||||
height: 3px;
|
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAABCAMAAADU3h9xAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFSv//AAAAH8VRuAAAAA5JREFUeNpiYIACgAADAAAJAAE0lmO3AAAAAElFTkSuQmCC)
|
|
||||||
repeat-x left center;
|
|
||||||
/*./image/line_h.png*/
|
|
||||||
cursor: n-resize;
|
|
||||||
/*url(./image/cur_move_h.cur), move*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-ruler-ref-line-v {
|
|
||||||
width: 3px;
|
|
||||||
height: 100%;
|
|
||||||
_height: 9999px;
|
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAICAMAAAAPxGVzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFSv//AAAAH8VRuAAAAA5JREFUeNpiYEAFAAEGAAAQAAGePof9AAAAAElFTkSuQmCC)
|
|
||||||
repeat-y center top;
|
|
||||||
/*./image/line_v.png*/
|
|
||||||
cursor: w-resize;
|
|
||||||
/*url(./image/cur_move_v.cur), move*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-ruler-ref-dot-h {
|
|
||||||
width: 100%;
|
|
||||||
height: 3px;
|
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAMAAABFaP0WAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFf39/////F3PnHQAAAAJ0Uk5T/wDltzBKAAAAEElEQVR42mJgYGRgZAQIMAAADQAExkizYQAAAABJRU5ErkJggg==)
|
|
||||||
repeat-x left 1px;
|
|
||||||
/*./image/line_dot.png*/
|
|
||||||
cursor: n-resize;
|
|
||||||
/*url(./image/cur_move_h.cur), move*/
|
|
||||||
top: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-ruler-ref-dot-v {
|
|
||||||
width: 3px;
|
|
||||||
height: 100%;
|
|
||||||
_height: 9999px;
|
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAMAAABFaP0WAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFf39/////F3PnHQAAAAJ0Uk5T/wDltzBKAAAAEElEQVR42mJgYGRgZAQIMAAADQAExkizYQAAAABJRU5ErkJggg==)
|
|
||||||
repeat-y 1px top;
|
|
||||||
/*./image/line_dot.png*/
|
|
||||||
cursor: w-resize;
|
|
||||||
/*url(./image/cur_move_v.cur), move*/
|
|
||||||
left: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-ruler-content {
|
.vue-ruler-content {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 997;
|
z-index: 997;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vue-ruler-content-mask {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: transparent;
|
|
||||||
z-index: 998;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,190 +1,127 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="box">
|
||||||
<svg
|
<svg :width="boxWidth" :height="boxHeight">
|
||||||
ref="svgElement"
|
<path
|
||||||
:width="width"
|
v-for="(curve, index) in curves"
|
||||||
:height="height"
|
|
||||||
@mousedown="startDrawing"
|
|
||||||
@mousemove="drawLine"
|
|
||||||
@mouseup="stopDrawing"
|
|
||||||
@mouseleave="stopDrawing"
|
|
||||||
>
|
|
||||||
<!-- 渲染所有点 -->
|
|
||||||
<circle
|
|
||||||
v-for="(point, index) in points"
|
|
||||||
:key="index"
|
:key="index"
|
||||||
:cx="point.x"
|
:d="getCurvePath(curve)"
|
||||||
:cy="point.y"
|
:stroke="curve.isSelected ? 'red' : 'blue'"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="none"
|
||||||
|
@mousedown="selectCurve(index)"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
v-for="(curve, index) in curves"
|
||||||
|
:key="'start-' + index"
|
||||||
|
:cx="curve.startControlX"
|
||||||
|
:cy="curve.startControlY"
|
||||||
r="5"
|
r="5"
|
||||||
fill="red"
|
fill="green"
|
||||||
@mousedown="startFromPoint(index, $event)"
|
@mousedown="startDrag(index, 'start')"
|
||||||
/>
|
/>
|
||||||
|
<circle
|
||||||
<!-- 渲染所有直线 -->
|
v-for="(curve, index) in curves"
|
||||||
<path
|
:key="'end-' + index"
|
||||||
v-for="(line, index) in lines"
|
:cx="curve.endControlX"
|
||||||
:key="'line-' + index"
|
:cy="curve.endControlY"
|
||||||
:d="`M ${line.startPointX} ${line.startPointY} L ${line.endPointX} ${line.endPointY}`"
|
r="5"
|
||||||
stroke="black"
|
fill="green"
|
||||||
stroke-width="2"
|
@mousedown="startDrag(index, 'end')"
|
||||||
fill="none"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 实时绘制当前直线 -->
|
|
||||||
<path
|
|
||||||
v-if="isDrawing"
|
|
||||||
:d="`M ${startX} ${startY} L ${currentX} ${currentY}`"
|
|
||||||
stroke="blue"
|
|
||||||
stroke-width="2"
|
|
||||||
fill="none"
|
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<!-- 显示直线数据 -->
|
|
||||||
<div>
|
|
||||||
<h3>直线数据:</h3>
|
|
||||||
<pre>{{ lines }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
export default {
|
// 盒子的宽度和高度
|
||||||
setup() {
|
const boxWidth = ref(800)
|
||||||
const svgElement = ref(null) // SVG 元素的引用
|
const boxHeight = ref(600)
|
||||||
const width = 800 // SVG 宽度
|
|
||||||
const height = 600 // SVG 高度
|
|
||||||
|
|
||||||
// 点位数据
|
// 初始点位数据
|
||||||
const points = ref([
|
const curves = ref([
|
||||||
{ x: 10, y: 10 },
|
{
|
||||||
{ x: 30, y: 100 },
|
startX: 100,
|
||||||
{ x: 40, y: 40 },
|
startY: 100,
|
||||||
{ x: 230, y: 400 },
|
endX: 300,
|
||||||
{ x: 750, y: 640 }
|
endY: 100,
|
||||||
])
|
startControlX: 100,
|
||||||
|
startControlY: 100,
|
||||||
|
endControlX: 300,
|
||||||
|
endControlY: 100,
|
||||||
|
isSelected: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startX: 200,
|
||||||
|
startY: 200,
|
||||||
|
endX: 400,
|
||||||
|
endY: 200,
|
||||||
|
startControlX: 200,
|
||||||
|
startControlY: 200,
|
||||||
|
endControlX: 400,
|
||||||
|
endControlY: 400,
|
||||||
|
isSelected: false
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
// 直线数据
|
// 当前拖动的曲线索引和控制点类型
|
||||||
const lines = ref([])
|
const dragging = ref({
|
||||||
|
index: null,
|
||||||
|
type: null
|
||||||
|
})
|
||||||
|
|
||||||
// 当前绘制的直线状态
|
// 获取曲线的路径字符串
|
||||||
const isDrawing = ref(false)
|
const getCurvePath = (curve) => {
|
||||||
const startX = ref(0)
|
return `M${curve.startX},${curve.startY} C${curve.startControlX},${curve.startControlY} ${curve.endControlX},${curve.endControlY} ${curve.endX},${curve.endY}`
|
||||||
const startY = ref(0)
|
}
|
||||||
const currentX = ref(0)
|
|
||||||
const currentY = ref(0)
|
|
||||||
const startPointIndex = ref(null) // 起始点的索引
|
|
||||||
|
|
||||||
// 从点开始绘制
|
// 选中曲线
|
||||||
const startFromPoint = (index, event) => {
|
const selectCurve = (index) => {
|
||||||
const point = points.value[index]
|
curves.value.forEach((curve, i) => {
|
||||||
startX.value = point.x
|
curve.isSelected = i === index
|
||||||
startY.value = point.y
|
})
|
||||||
startPointIndex.value = index
|
console.log('Selected curve:', curves.value[index])
|
||||||
isDrawing.value = true
|
}
|
||||||
event.preventDefault() // 防止默认行为
|
|
||||||
}
|
|
||||||
|
|
||||||
// 实时绘制
|
// 开始拖动控制点
|
||||||
const drawLine = (event) => {
|
const startDrag = (index, type) => {
|
||||||
if (isDrawing.value) {
|
dragging.value = { index, type }
|
||||||
const rect = svgElement.value.getBoundingClientRect()
|
window.addEventListener('mousemove', handleDrag)
|
||||||
currentX.value = event.clientX - rect.left
|
window.addEventListener('mouseup', endDrag)
|
||||||
currentY.value = event.clientY - rect.top
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 结束绘制
|
// 处理拖动事件
|
||||||
const stopDrawing = () => {
|
const handleDrag = (event) => {
|
||||||
if (isDrawing.value) {
|
if (dragging.value.index !== null) {
|
||||||
// 找到最近的终点
|
const curve = curves.value[dragging.value.index]
|
||||||
const endPointIndex = findClosestPoint(currentX.value, currentY.value)
|
let newX = event.offsetX
|
||||||
|
let newY = event.offsetY
|
||||||
|
|
||||||
if (endPointIndex !== null && endPointIndex !== startPointIndex.value) {
|
// 确保控制点不超出盒子范围
|
||||||
const endPoint = points.value[endPointIndex]
|
newX = Math.max(0, Math.min(newX, boxWidth.value))
|
||||||
const newLine = {
|
newY = Math.max(0, Math.min(newY, boxHeight.value))
|
||||||
startPointX: startX.value,
|
|
||||||
startPointY: startY.value,
|
|
||||||
endPointX: endPoint.x,
|
|
||||||
endPointY: endPoint.y
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否已存在相同的直线
|
if (dragging.value.type === 'start') {
|
||||||
const isDuplicate = lines.value.some(
|
curve.startControlX = newX
|
||||||
(line) =>
|
curve.startControlY = newY
|
||||||
(line.startPointX === newLine.startPointX &&
|
} else {
|
||||||
line.startPointY === newLine.startPointY &&
|
curve.endControlX = newX
|
||||||
line.endPointX === newLine.endPointX &&
|
curve.endControlY = newY
|
||||||
line.endPointY === newLine.endPointY) ||
|
|
||||||
(line.startPointX === newLine.endPointX &&
|
|
||||||
line.startPointY === newLine.endPointY &&
|
|
||||||
line.endPointX === newLine.startPointX &&
|
|
||||||
line.endPointY === newLine.startPointY)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!isDuplicate) {
|
|
||||||
// 保存当前直线
|
|
||||||
lines.value.push(newLine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置状态
|
|
||||||
isDrawing.value = false
|
|
||||||
startX.value = 0
|
|
||||||
startY.value = 0
|
|
||||||
currentX.value = 0
|
|
||||||
currentY.value = 0
|
|
||||||
startPointIndex.value = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 找到最近的点
|
|
||||||
const findClosestPoint = (x, y) => {
|
|
||||||
let minDistance = Infinity
|
|
||||||
let closestIndex = null
|
|
||||||
|
|
||||||
points.value.forEach((point, index) => {
|
|
||||||
const distance = Math.sqrt((point.x - x) ** 2 + (point.y - y) ** 2)
|
|
||||||
if (distance < minDistance && distance < 10) {
|
|
||||||
// 10 是点的捕捉范围
|
|
||||||
minDistance = distance
|
|
||||||
closestIndex = index
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return closestIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
svgElement,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
points,
|
|
||||||
lines,
|
|
||||||
isDrawing,
|
|
||||||
startX,
|
|
||||||
startY,
|
|
||||||
currentX,
|
|
||||||
currentY,
|
|
||||||
startFromPoint,
|
|
||||||
drawLine,
|
|
||||||
stopDrawing
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 结束拖动
|
||||||
|
const endDrag = () => {
|
||||||
|
dragging.value = { index: null, type: null }
|
||||||
|
window.removeEventListener('mousemove', handleDrag)
|
||||||
|
window.removeEventListener('mouseup', endDrag)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
svg {
|
.box {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid black;
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user