|
@@ -124,8 +124,8 @@
|
|
|
@click.stop="selectNode(node)"
|
|
@click.stop="selectNode(node)"
|
|
|
>
|
|
>
|
|
|
<rect
|
|
<rect
|
|
|
- :width="getNodeWidth(node)"
|
|
|
|
|
- :height="node.height || 40"
|
|
|
|
|
|
|
+ :width="nodeWidth"
|
|
|
|
|
+ :height="node.height || 36"
|
|
|
rx="6"
|
|
rx="6"
|
|
|
ry="6"
|
|
ry="6"
|
|
|
:fill="getNodeBgColor(node)"
|
|
:fill="getNodeBgColor(node)"
|
|
@@ -133,27 +133,20 @@
|
|
|
stroke-width="2"
|
|
stroke-width="2"
|
|
|
:class="{ selected: selectedNode === node }"
|
|
:class="{ selected: selectedNode === node }"
|
|
|
/>
|
|
/>
|
|
|
- <foreignObject :width="getNodeWidth(node)" :height="node.height || 40">
|
|
|
|
|
- <div class="node-content" xmlns="http://www.w3.org/1999/xhtml">
|
|
|
|
|
|
|
+ <foreignObject :width="nodeWidth" :height="node.height || 36">
|
|
|
|
|
+ <div class="node-content" xmlns="http://www.w3.org/1999/xhtml" :title="node.nodeName">
|
|
|
<i :class="node.nodeIcon" :style="{ color: node.nodeColor }"></i>
|
|
<i :class="node.nodeIcon" :style="{ color: node.nodeColor }"></i>
|
|
|
- <input
|
|
|
|
|
- type="text"
|
|
|
|
|
- class="node-name-input"
|
|
|
|
|
- v-model="node.nodeName"
|
|
|
|
|
- @mousedown.stop
|
|
|
|
|
- @input="onNodeNameInput(node)"
|
|
|
|
|
- :style="{ width: getInputWidth(node) + 'px' }"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <span class="node-name">{{ node.nodeName }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</foreignObject>
|
|
</foreignObject>
|
|
|
<!-- 连接点 -->
|
|
<!-- 连接点 -->
|
|
|
- <circle :cx="getNodeWidth(node) / 2" cy="0" r="6" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
|
|
|
|
+ <circle :cx="nodeWidth / 2" cy="0" r="5" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
class="anchor top" @mousedown.stop="startConnect($event, node, 'top')" />
|
|
class="anchor top" @mousedown.stop="startConnect($event, node, 'top')" />
|
|
|
- <circle :cx="getNodeWidth(node) / 2" :cy="node.height || 40" r="6" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
|
|
|
|
+ <circle :cx="nodeWidth / 2" :cy="node.height || 36" r="5" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
class="anchor bottom" @mousedown.stop="startConnect($event, node, 'bottom')" />
|
|
class="anchor bottom" @mousedown.stop="startConnect($event, node, 'bottom')" />
|
|
|
- <circle cx="0" :cy="(node.height || 40) / 2" r="6" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
|
|
|
|
+ <circle cx="0" :cy="(node.height || 36) / 2" r="5" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
class="anchor left" @mousedown.stop="startConnect($event, node, 'left')" />
|
|
class="anchor left" @mousedown.stop="startConnect($event, node, 'left')" />
|
|
|
- <circle :cx="getNodeWidth(node)" :cy="(node.height || 40) / 2" r="6" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
|
|
|
|
+ <circle :cx="nodeWidth" :cy="(node.height || 36) / 2" r="5" fill="#fff" stroke="#1890ff" stroke-width="2"
|
|
|
class="anchor right" @mousedown.stop="startConnect($event, node, 'right')" />
|
|
class="anchor right" @mousedown.stop="startConnect($event, node, 'right')" />
|
|
|
</g>
|
|
</g>
|
|
|
</g>
|
|
</g>
|
|
@@ -170,7 +163,11 @@
|
|
|
<!-- 节点属性 -->
|
|
<!-- 节点属性 -->
|
|
|
<el-form v-if="selectedNode" label-width="80px" size="small">
|
|
<el-form v-if="selectedNode" label-width="80px" size="small">
|
|
|
<el-form-item label="节点内容">
|
|
<el-form-item label="节点内容">
|
|
|
- <el-input v-model="selectedNode.nodeName" />
|
|
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="selectedNode.nodeName"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :autosize="{ minRows: 1, maxRows: 6 }"
|
|
|
|
|
+ />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
<el-form-item label="节点类型">
|
|
<el-form-item label="节点类型">
|
|
|
<el-input :value="getNodeTypeName(selectedNode.nodeType)" disabled />
|
|
<el-input :value="getNodeTypeName(selectedNode.nodeType)" disabled />
|
|
@@ -253,6 +250,8 @@ export default {
|
|
|
tempEdge: null,
|
|
tempEdge: null,
|
|
|
// 画布尺寸
|
|
// 画布尺寸
|
|
|
canvasSize: { width: 2000, height: 2000 },
|
|
canvasSize: { width: 2000, height: 2000 },
|
|
|
|
|
+ // 节点固定宽度
|
|
|
|
|
+ nodeWidth: 120,
|
|
|
// 是否正在拖动画布
|
|
// 是否正在拖动画布
|
|
|
isDraggingCanvas: false,
|
|
isDraggingCanvas: false,
|
|
|
// 画布拖动起始点
|
|
// 画布拖动起始点
|
|
@@ -551,12 +550,11 @@ export default {
|
|
|
},
|
|
},
|
|
|
/** 检测并扩展画布 */
|
|
/** 检测并扩展画布 */
|
|
|
checkAndExpandCanvas(node) {
|
|
checkAndExpandCanvas(node) {
|
|
|
- const nodeWidth = this.getNodeWidth(node)
|
|
|
|
|
- const nodeHeight = node.height || 40
|
|
|
|
|
|
|
+ const nodeHeight = node.height || 36
|
|
|
const padding = 200 // 边缘预留空间
|
|
const padding = 200 // 边缘预留空间
|
|
|
const expandStep = 500 // 每次扩展的大小
|
|
const expandStep = 500 // 每次扩展的大小
|
|
|
|
|
|
|
|
- const nodeRight = node.posX + nodeWidth
|
|
|
|
|
|
|
+ const nodeRight = node.posX + this.nodeWidth
|
|
|
const nodeBottom = node.posY + nodeHeight
|
|
const nodeBottom = node.posY + nodeHeight
|
|
|
|
|
|
|
|
// 检测右边缘
|
|
// 检测右边缘
|
|
@@ -603,8 +601,8 @@ export default {
|
|
|
},
|
|
},
|
|
|
/** 获取锚点位置 */
|
|
/** 获取锚点位置 */
|
|
|
getAnchorPos(node, anchor) {
|
|
getAnchorPos(node, anchor) {
|
|
|
- const w = this.getNodeWidth(node)
|
|
|
|
|
- const h = node.height || 40
|
|
|
|
|
|
|
+ const w = this.nodeWidth
|
|
|
|
|
+ const h = node.height || 36
|
|
|
switch (anchor) {
|
|
switch (anchor) {
|
|
|
case 'top': return { x: node.posX + w / 2, y: node.posY }
|
|
case 'top': return { x: node.posX + w / 2, y: node.posY }
|
|
|
case 'bottom': return { x: node.posX + w / 2, y: node.posY + h }
|
|
case 'bottom': return { x: node.posX + w / 2, y: node.posY + h }
|
|
@@ -621,8 +619,8 @@ export default {
|
|
|
const x = (clientX - rect.left + scrollLeft - this.canvasOffset.x) / this.scale
|
|
const x = (clientX - rect.left + scrollLeft - this.canvasOffset.x) / this.scale
|
|
|
const y = (clientY - rect.top + scrollTop - this.canvasOffset.y) / this.scale
|
|
const y = (clientY - rect.top + scrollTop - this.canvasOffset.y) / this.scale
|
|
|
return this.nodes.find(n => {
|
|
return this.nodes.find(n => {
|
|
|
- const w = this.getNodeWidth(n)
|
|
|
|
|
- const h = n.height || 40
|
|
|
|
|
|
|
+ const w = this.nodeWidth
|
|
|
|
|
+ const h = n.height || 36
|
|
|
return x >= n.posX && x <= n.posX + w && y >= n.posY && y <= n.posY + h
|
|
return x >= n.posX && x <= n.posX + w && y >= n.posY && y <= n.posY + h
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
@@ -671,26 +669,7 @@ export default {
|
|
|
const color = node.nodeColor || '#1890ff'
|
|
const color = node.nodeColor || '#1890ff'
|
|
|
return color + '15'
|
|
return color + '15'
|
|
|
},
|
|
},
|
|
|
- /** 计算节点宽度 */
|
|
|
|
|
- getNodeWidth(node) {
|
|
|
|
|
- const minWidth = 80
|
|
|
|
|
- const padding = 50 // 图标 + 左右padding
|
|
|
|
|
- const charWidth = 14 // 每个字符大约宽度
|
|
|
|
|
- const textWidth = (node.nodeName || '').length * charWidth
|
|
|
|
|
- return Math.max(minWidth, textWidth + padding)
|
|
|
|
|
- },
|
|
|
|
|
- /** 计算输入框宽度 */
|
|
|
|
|
- getInputWidth(node) {
|
|
|
|
|
- const minWidth = 40
|
|
|
|
|
- const charWidth = 14
|
|
|
|
|
- const textWidth = (node.nodeName || '').length * charWidth
|
|
|
|
|
- return Math.max(minWidth, textWidth + 10)
|
|
|
|
|
- },
|
|
|
|
|
- /** 节点名称输入事件 */
|
|
|
|
|
- onNodeNameInput(node) {
|
|
|
|
|
- // 触发视图更新
|
|
|
|
|
- this.$forceUpdate()
|
|
|
|
|
- },
|
|
|
|
|
|
|
+
|
|
|
/** 获取节点类型名称 */
|
|
/** 获取节点类型名称 */
|
|
|
getNodeTypeName(typeCode) {
|
|
getNodeTypeName(typeCode) {
|
|
|
const t = this.nodeTypes.find(n => n.typeCode === typeCode)
|
|
const t = this.nodeTypes.find(n => n.typeCode === typeCode)
|