|
@@ -1,31 +1,114 @@
|
|
|
+<!-- eslint-disable vue/no-unused-vars -->
|
|
|
+<!-- eslint-disable vue/valid-v-for -->
|
|
|
<template>
|
|
|
- <div class="flow-wrap">
|
|
|
- <!-- <svg
|
|
|
+ <div ref="wrapRef" class="svg-wrap" @mousemove="handleMouseMove">
|
|
|
+ <svg
|
|
|
version="1.1"
|
|
|
baseProfile="full"
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
|
xmlns:ev="http://www.w3.org/2001/xml-events"
|
|
|
+ :width="wrapSize.width"
|
|
|
+ :height="wrapSize.height"
|
|
|
>
|
|
|
- <rect x="0" y="0" width="10" height="10" fill="blue" />
|
|
|
- <text x="5" y="30">A nice rectangle</text>
|
|
|
- <circle cx="50" cy="50" r="50" fill="#529fca" />
|
|
|
- <polygon
|
|
|
- points="9.9, 2.2, 3.3, 21.78, 19.8, 8.58, 0, 8.58, 16.5, 21.78"
|
|
|
+ <SvgRect
|
|
|
+ v-for="i in children"
|
|
|
+ :key="i.id"
|
|
|
+ v-bind="i"
|
|
|
+ :draggingId="draggingId"
|
|
|
+ :mousePos="curPos"
|
|
|
+ @startLine="startLine"
|
|
|
+ @startDrag="startDrag"
|
|
|
+ @updatePos="updatePos"
|
|
|
/>
|
|
|
|
|
|
- <SvgRect />
|
|
|
- </svg> -->
|
|
|
+ <line v-if="lineStartPoint" v-bind="dashLineAttr"></line>
|
|
|
+ </svg>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
+import { reactive, ref, onBeforeUnmount, onMounted, computed } from "vue";
|
|
|
import SvgRect from "./components/svgRect.vue";
|
|
|
+import { findFromArray, getPosFromEvent } from "./utils/index";
|
|
|
+
|
|
|
+const wrapRef = ref(null);
|
|
|
+const childrenRefs = ref(null);
|
|
|
+let curPos = ref({ x: 0, y: 0 });
|
|
|
+const wrapSize = reactive({ width: 0, height: 0 });
|
|
|
+const draggingId = ref(0);
|
|
|
+const lineStartPoint = ref(null);
|
|
|
+const children = ref([
|
|
|
+ { id: 1, pos: { x: 10, y: 10 }, size: { width: 100, height: 100 } },
|
|
|
+ { id: 2, pos: { x: 20, y: 20 }, size: { width: 100, height: 100 } },
|
|
|
+ { id: 3, pos: { x: 30, y: 30 }, size: { width: 100, height: 100 } },
|
|
|
+]);
|
|
|
+
|
|
|
+const dashLineAttr = computed(() => {
|
|
|
+ if (lineStartPoint.value) {
|
|
|
+ return {
|
|
|
+ x1: lineStartPoint.value?.cx,
|
|
|
+ y1: lineStartPoint.value?.cy,
|
|
|
+ x2: curPos.value.x,
|
|
|
+ y2: curPos.value.y,
|
|
|
+ stroke: "black",
|
|
|
+ "stroke-dasharray": "3 4",
|
|
|
+ "stroke-width": "2",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+});
|
|
|
+
|
|
|
+function startDrag({ id, event }) {
|
|
|
+ draggingId.value = id;
|
|
|
+ lineStartPoint.value = null;
|
|
|
+ curPos.value = getPosFromEvent(event);
|
|
|
+ const { index, result } = findFromArray(children.value, (i) => i.id === id);
|
|
|
+ children.value.splice(index, 1);
|
|
|
+ children.value.push(result);
|
|
|
+}
|
|
|
+
|
|
|
+function startLine({ id, point }) {
|
|
|
+ draggingId.value = 0;
|
|
|
+ lineStartPoint.value = point;
|
|
|
+}
|
|
|
+
|
|
|
+function updatePos({ id, pos }) {
|
|
|
+ const { result } = findFromArray(children.value, (i) => i.id === id);
|
|
|
+ result.pos = pos;
|
|
|
+}
|
|
|
+
|
|
|
+function handleMouseMove(e) {
|
|
|
+ curPos.value = getPosFromEvent(e);
|
|
|
+}
|
|
|
+
|
|
|
+function handleMouseUp() {
|
|
|
+ draggingId.value = 0;
|
|
|
+ lineStartPoint.value = null;
|
|
|
+}
|
|
|
+
|
|
|
+function initSvgSize() {
|
|
|
+ // 避免因为转rem时有小数误差导致得滚动条
|
|
|
+ wrapSize.width = wrapRef.value.offsetWidth - 1;
|
|
|
+ wrapSize.height = wrapRef.value.offsetHeight - 1;
|
|
|
+}
|
|
|
+
|
|
|
+window.addEventListener("mouseup", handleMouseUp);
|
|
|
+window.addEventListener("resize", initSvgSize);
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ initSvgSize();
|
|
|
+});
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ window.removeEventListener("mouseup", handleMouseUp);
|
|
|
+ window.removeEventListener("resize", initSvgSize);
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
-.flow-wrap {
|
|
|
- height: 45px;
|
|
|
+.svg-wrap {
|
|
|
+ min-height: 400px;
|
|
|
background-color: blue;
|
|
|
background-image: linear-gradient(
|
|
|
transparent 0px,
|
|
@@ -33,7 +116,11 @@ import SvgRect from "./components/svgRect.vue";
|
|
|
#fff 2px,
|
|
|
#fff 15px
|
|
|
),
|
|
|
- linear-gradient(90deg, #999 0px, #999 2px, #fff 2px, #fff 15px);
|
|
|
+ linear-gradient(90deg, #ccc 0px, #ccc 2px, #fff 2px, #fff 15px);
|
|
|
background-size: 15px 15px, 15px 15px;
|
|
|
+ position: relative;
|
|
|
+ svg {
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|