|
@@ -2,6 +2,7 @@
|
|
<!-- eslint-disable vue/valid-v-for -->
|
|
<!-- eslint-disable vue/valid-v-for -->
|
|
<template>
|
|
<template>
|
|
<div ref="wrapRef" class="svg-wrap" @mousemove="handleMouseMove">
|
|
<div ref="wrapRef" class="svg-wrap" @mousemove="handleMouseMove">
|
|
|
|
+ <Bar />
|
|
<svg
|
|
<svg
|
|
version="1.1"
|
|
version="1.1"
|
|
baseProfile="full"
|
|
baseProfile="full"
|
|
@@ -11,27 +12,38 @@
|
|
:width="wrapSize.width"
|
|
:width="wrapSize.width"
|
|
:height="wrapSize.height"
|
|
:height="wrapSize.height"
|
|
>
|
|
>
|
|
|
|
+ <marker
|
|
|
|
+ id="markerArrow"
|
|
|
|
+ markerUnits="strokeWidth"
|
|
|
|
+ markerWidth="5"
|
|
|
|
+ markerHeight="4"
|
|
|
|
+ refX="6"
|
|
|
|
+ refY="2"
|
|
|
|
+ orient="auto"
|
|
|
|
+ >
|
|
|
|
+ <path d="M 0 0 L 5 2 L 0 4 z" class="trangle" />
|
|
|
|
+ </marker>
|
|
|
|
+ <line
|
|
|
|
+ v-for="i in linesAttr"
|
|
|
|
+ :key="i.id"
|
|
|
|
+ v-bind="i"
|
|
|
|
+ class="line"
|
|
|
|
+ marker-end="url(#markerArrow)"
|
|
|
|
+ />
|
|
<SvgRect
|
|
<SvgRect
|
|
v-for="i in children"
|
|
v-for="i in children"
|
|
:key="i.id"
|
|
:key="i.id"
|
|
v-bind="i"
|
|
v-bind="i"
|
|
:isDragging="isDragging"
|
|
:isDragging="isDragging"
|
|
- :draggingId="draggingId"
|
|
|
|
- :mousePos="curPos"
|
|
|
|
|
|
+ :curNodeId="curNodeId"
|
|
:startPoint="lineStartPoint"
|
|
:startPoint="lineStartPoint"
|
|
- :allItems="children"
|
|
|
|
|
|
+ @click="nodeClick"
|
|
@startLine="startLine"
|
|
@startLine="startLine"
|
|
@endLine="endLine"
|
|
@endLine="endLine"
|
|
@cancelEndLine="cancelEndLine"
|
|
@cancelEndLine="cancelEndLine"
|
|
@startDrag="startDrag"
|
|
@startDrag="startDrag"
|
|
- @hover="hover"
|
|
|
|
- @updatePos="updatePos"
|
|
|
|
/>
|
|
/>
|
|
- <line
|
|
|
|
- v-if="lineStartPoint"
|
|
|
|
- v-bind="dashLineAttr"
|
|
|
|
- class="dash-line"
|
|
|
|
- ></line>
|
|
|
|
|
|
+ <line v-if="lineStartPoint" v-bind="dashLineAttr" class="dash-line" />
|
|
</svg>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
@@ -39,77 +51,95 @@
|
|
<script setup>
|
|
<script setup>
|
|
import { reactive, ref, onBeforeUnmount, onMounted, computed } from "vue";
|
|
import { reactive, ref, onBeforeUnmount, onMounted, computed } from "vue";
|
|
import SvgRect from "./components/svgRect.vue";
|
|
import SvgRect from "./components/svgRect.vue";
|
|
-import { findFromArray, getPosFromEvent } from "./utils/index";
|
|
|
|
|
|
+import Bar from "./components/bar.vue";
|
|
|
|
+import {
|
|
|
|
+ findFromArray,
|
|
|
|
+ getPosFromEvent,
|
|
|
|
+ countPointByPos,
|
|
|
|
+ twoObjIsEqual,
|
|
|
|
+ sticky,
|
|
|
|
+} from "./utils/index";
|
|
|
|
|
|
const wrapRef = ref(null);
|
|
const wrapRef = ref(null);
|
|
const childrenRefs = ref(null);
|
|
const childrenRefs = ref(null);
|
|
-let curPos = ref({ x: 0, y: 0 });
|
|
|
|
|
|
+let curMousePos = ref({ x: 0, y: 0 });
|
|
const wrapSize = reactive({ width: 0, height: 0 });
|
|
const wrapSize = reactive({ width: 0, height: 0 });
|
|
-const draggingId = ref(0);
|
|
|
|
|
|
+const curNodeId = ref(0);
|
|
|
|
+const curNodeConfig = ref({});
|
|
const isDragging = ref(false);
|
|
const isDragging = ref(false);
|
|
const lineStartPoint = ref(null);
|
|
const lineStartPoint = ref(null);
|
|
const lineEndPoint = ref(null);
|
|
const lineEndPoint = ref(null);
|
|
|
|
+const lines = reactive([]);
|
|
const children = ref([
|
|
const children = ref([
|
|
{
|
|
{
|
|
id: 1,
|
|
id: 1,
|
|
- pos: { x: 10, y: 10 },
|
|
|
|
|
|
+ pos: { x: 160, y: 110 },
|
|
size: { width: 100, height: 100 },
|
|
size: { width: 100, height: 100 },
|
|
- lines: [],
|
|
|
|
},
|
|
},
|
|
{
|
|
{
|
|
id: 2,
|
|
id: 2,
|
|
- pos: { x: 20, y: 20 },
|
|
|
|
|
|
+ pos: { x: 170, y: 120 },
|
|
size: { width: 100, height: 100 },
|
|
size: { width: 100, height: 100 },
|
|
- lines: [
|
|
|
|
- {
|
|
|
|
- start: {
|
|
|
|
- pos: "right",
|
|
|
|
- },
|
|
|
|
- end: {
|
|
|
|
- targetId: 3,
|
|
|
|
- pos: "left",
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
},
|
|
},
|
|
{
|
|
{
|
|
id: 3,
|
|
id: 3,
|
|
- pos: { x: 30, y: 30 },
|
|
|
|
|
|
+ pos: { x: 180, y: 130 },
|
|
size: { width: 100, height: 100 },
|
|
size: { width: 100, height: 100 },
|
|
- lines: [],
|
|
|
|
},
|
|
},
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
+const curNode = computed(() => {
|
|
|
|
+ return curNodeId.value !== 0
|
|
|
|
+ ? children.value.find((i) => i.id === curNodeId.value)
|
|
|
|
+ : null;
|
|
|
|
+});
|
|
|
|
+
|
|
const dashLineAttr = computed(() => {
|
|
const dashLineAttr = computed(() => {
|
|
- if (lineStartPoint.value) {
|
|
|
|
|
|
+ return lineStartPoint.value
|
|
|
|
+ ? {
|
|
|
|
+ x1: lineStartPoint.value?.cx,
|
|
|
|
+ y1: lineStartPoint.value?.cy,
|
|
|
|
+ x2: lineEndPoint.value?.cx ?? curMousePos.value.x,
|
|
|
|
+ y2: lineEndPoint.value?.cy ?? curMousePos.value.y,
|
|
|
|
+ }
|
|
|
|
+ : {};
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+const linesAttr = computed(() =>
|
|
|
|
+ lines.map((line) => {
|
|
|
|
+ const { targetId: startTargetId, pos: startPos } = line.start;
|
|
|
|
+ const { targetId: endTargetId, pos: endPos } = line.end;
|
|
|
|
+ const startNode = children.value.find((i) => i.id === startTargetId);
|
|
|
|
+ const endNode = children.value.find((i) => i.id === endTargetId);
|
|
|
|
+ const endPoint = countPointByPos(endPos, endNode.pos, endNode.size);
|
|
|
|
+ const startPoint = countPointByPos(startPos, startNode.pos, startNode.size);
|
|
return {
|
|
return {
|
|
- x1: lineStartPoint.value?.cx,
|
|
|
|
- y1: lineStartPoint.value?.cy,
|
|
|
|
- x2: lineEndPoint.value?.cx ?? curPos.value.x,
|
|
|
|
- y2: lineEndPoint.value?.cy ?? curPos.value.y,
|
|
|
|
|
|
+ id: `${startTargetId}-${startPos}-${endTargetId}-${endPos}`,
|
|
|
|
+ x1: startPoint.cx,
|
|
|
|
+ y1: startPoint.cy,
|
|
|
|
+ x2: endPoint.cx,
|
|
|
|
+ y2: endPoint.cy,
|
|
};
|
|
};
|
|
- }
|
|
|
|
- return {};
|
|
|
|
-});
|
|
|
|
|
|
+ })
|
|
|
|
+);
|
|
|
|
|
|
-function startDrag({ id, event }) {
|
|
|
|
|
|
+function startDrag({ id, event, innerPos }) {
|
|
isDragging.value = true;
|
|
isDragging.value = true;
|
|
- draggingId.value = id;
|
|
|
|
|
|
+ curNodeId.value = id;
|
|
|
|
+ curNodeConfig.value = {
|
|
|
|
+ innerPos,
|
|
|
|
+ };
|
|
lineStartPoint.value = null;
|
|
lineStartPoint.value = null;
|
|
lineEndPoint.value = null;
|
|
lineEndPoint.value = null;
|
|
- curPos.value = getPosFromEvent(event);
|
|
|
|
|
|
+ // 移动当前的节点最后渲染
|
|
|
|
+ curMousePos.value = getPosFromEvent(event, wrapRef.value);
|
|
const { index, result } = findFromArray(children.value, (i) => i.id === id);
|
|
const { index, result } = findFromArray(children.value, (i) => i.id === id);
|
|
children.value.splice(index, 1);
|
|
children.value.splice(index, 1);
|
|
children.value.push(result);
|
|
children.value.push(result);
|
|
}
|
|
}
|
|
|
|
|
|
-function hover(id) {
|
|
|
|
- // const { index, result } = findFromArray(children.value, (i) => i.id === id);
|
|
|
|
- // children.value.splice(index, 1);
|
|
|
|
- // children.value.push(result);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
function startLine({ id, point }) {
|
|
function startLine({ id, point }) {
|
|
|
|
+ curNodeId.value = id;
|
|
isDragging.value = false;
|
|
isDragging.value = false;
|
|
lineStartPoint.value = {
|
|
lineStartPoint.value = {
|
|
targetId: id,
|
|
targetId: id,
|
|
@@ -132,39 +162,33 @@ function cancelEndLine() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-function updatePos({ id, pos }) {
|
|
|
|
- const { result } = findFromArray(children.value, (i) => i.id === id);
|
|
|
|
- result.pos = pos;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
function handleMouseMove(e) {
|
|
function handleMouseMove(e) {
|
|
- curPos.value = getPosFromEvent(e);
|
|
|
|
|
|
+ curMousePos.value = getPosFromEvent(e, wrapRef.value);
|
|
|
|
+ console.log(curMousePos.value);
|
|
|
|
+ if (curNode.value && isDragging.value) {
|
|
|
|
+ curNode.value.pos = {
|
|
|
|
+ x: sticky(curMousePos.value.x - curNodeConfig.value.innerPos.x),
|
|
|
|
+ y: sticky(curMousePos.value.y - curNodeConfig.value.innerPos.y),
|
|
|
|
+ };
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
function handleMouseUp() {
|
|
function handleMouseUp() {
|
|
- if (isDragging.value === false) {
|
|
|
|
- draggingId.value = 0;
|
|
|
|
- }
|
|
|
|
isDragging.value = false;
|
|
isDragging.value = false;
|
|
if (lineStartPoint.value && lineEndPoint.value) {
|
|
if (lineStartPoint.value && lineEndPoint.value) {
|
|
- const startId = lineStartPoint.value.targetId;
|
|
|
|
- const { result } = findFromArray(children.value, (i) => i.id === startId);
|
|
|
|
- const exist = result.lines.find(
|
|
|
|
- (line) =>
|
|
|
|
- line.start.pos === lineStartPoint.value.pos &&
|
|
|
|
- line.end.targetId === lineEndPoint.value.targetId &&
|
|
|
|
- line.end.pos === lineEndPoint.value.pos
|
|
|
|
- );
|
|
|
|
|
|
+ const line = {
|
|
|
|
+ start: {
|
|
|
|
+ targetId: lineStartPoint.value.targetId,
|
|
|
|
+ pos: lineStartPoint.value.pos,
|
|
|
|
+ },
|
|
|
|
+ end: {
|
|
|
|
+ targetId: lineEndPoint.value.targetId,
|
|
|
|
+ pos: lineEndPoint.value.pos,
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+ const exist = lines.find((_line) => twoObjIsEqual(_line, line));
|
|
if (!exist) {
|
|
if (!exist) {
|
|
- result.lines.push({
|
|
|
|
- start: {
|
|
|
|
- pos: lineStartPoint.value.pos,
|
|
|
|
- },
|
|
|
|
- end: {
|
|
|
|
- targetId: lineEndPoint.value.targetId,
|
|
|
|
- pos: lineEndPoint.value.pos,
|
|
|
|
- },
|
|
|
|
- });
|
|
|
|
|
|
+ lines.push(line);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lineStartPoint.value = null;
|
|
lineStartPoint.value = null;
|
|
@@ -177,8 +201,17 @@ function initSvgSize() {
|
|
wrapSize.height = wrapRef.value.offsetHeight - 1;
|
|
wrapSize.height = wrapRef.value.offsetHeight - 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+function catchClick() {
|
|
|
|
+ curNodeId.value = 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function nodeClick(e) {
|
|
|
|
+ e.stopPropagation();
|
|
|
|
+}
|
|
|
|
+
|
|
window.addEventListener("mouseup", handleMouseUp);
|
|
window.addEventListener("mouseup", handleMouseUp);
|
|
window.addEventListener("resize", initSvgSize);
|
|
window.addEventListener("resize", initSvgSize);
|
|
|
|
+window.addEventListener("click", catchClick);
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
initSvgSize();
|
|
initSvgSize();
|
|
@@ -187,6 +220,7 @@ onMounted(() => {
|
|
onBeforeUnmount(() => {
|
|
onBeforeUnmount(() => {
|
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
window.removeEventListener("resize", initSvgSize);
|
|
window.removeEventListener("resize", initSvgSize);
|
|
|
|
+ window.removeEventListener("click", catchClick);
|
|
});
|
|
});
|
|
</script>
|
|
</script>
|
|
|
|
|
|
@@ -212,5 +246,15 @@ onBeforeUnmount(() => {
|
|
stroke-dasharray: 3 4;
|
|
stroke-dasharray: 3 4;
|
|
stroke-width: 2;
|
|
stroke-width: 2;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ .line {
|
|
|
|
+ stroke: #5ba8ff;
|
|
|
|
+ stroke-width: 2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .trangle {
|
|
|
|
+ stroke: #5ba8ff;
|
|
|
|
+ fill: #5ba8ff;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
</style>
|
|
</style>
|