workflow-editor 0.0.90-up → 0.0.91-up

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "workflow-editor",
3
3
  "private": false,
4
- "version": "0.0.90-up",
4
+ "version": "0.0.91-up",
5
5
  "type": "module",
6
6
  "main": "./lib/workflow-editor.js",
7
7
  "scripts": {
@@ -438,6 +438,10 @@ export default {
438
438
  const controlPoints = transition.lineInfo.controlPoint
439
439
  controlPoints[pointIndex] = this.currentPosition
440
440
  // this.$set(controlPoints, pointIndex, this.currentPosition)
441
+ } else if (transition.lineInfo && transition.lineInfo.type === 'RightAngleLine') {
442
+ const pointIndex = this.controlPointToMove.pointIndex
443
+ const controlPoints = transition.lineInfo.controlPoint
444
+ controlPoints[pointIndex] = this.currentPosition
441
445
  }
442
446
  },
443
447
  endDrag(event) {
@@ -9,6 +9,7 @@
9
9
  <script>
10
10
  import { mapGetters, mapMutations } from 'vuex'
11
11
  import IconSvg from './icon-svg'
12
+ import { getJoint, createRightAngleControlPoints } from '../util'
12
13
  export default {
13
14
  name: 'ContextMenu',
14
15
  components: {
@@ -20,6 +21,7 @@ export default {
20
21
  { name: 'switch-line-type-StraightLine', label: this.$t('workflowEditor.main.straightLine'), icon: 'switch' },
21
22
  { name: 'switch-line-type-CurveLine', label: this.$t('workflowEditor.main.curveLine'), icon: 'switch' },
22
23
  { name: 'switch-line-type-BrokenLine', label: this.$t('workflowEditor.main.brokenLine'), icon: 'switch' },
24
+ { name: 'switch-line-type-RightAngleLine', label: this.$t('workflowEditor.main.rightAngleLine'), icon: 'switch' },
23
25
  { name: 'remove', label: this.$t('workflowEditor.common.remove'), icon: 'delete' },
24
26
  { name: 'properties', label: this.$t('workflowEditor.common.attribute'), icon: 'properties' }
25
27
  ],
@@ -78,6 +80,12 @@ export default {
78
80
  switchLineType(lineType) {
79
81
  this.selectedTransition.lineInfo.controlPoint = null
80
82
  this.selectedTransition.lineInfo.type = lineType
83
+ // 直角折线:切换后(包括再次点击同一个线型,此时组件不会重建、created钩子不会执行)立即生成默认折点
84
+ if (lineType === 'RightAngleLine') {
85
+ const startPoint = getJoint(this.selectedTransition.startJoint.parent, this.selectedTransition.startJoint.position)
86
+ const endPoint = getJoint(this.selectedTransition.endJoint.parent, this.selectedTransition.endJoint.position)
87
+ this.selectedTransition.lineInfo.controlPoint = createRightAngleControlPoints(startPoint, endPoint)
88
+ }
81
89
  },
82
90
  execute(menu) {
83
91
  console.log('menu:' + menu)
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <g>
3
+ <path
4
+ :d="path"
5
+ marker-end="url(#arrow)"
6
+ @dblclick.stop="addBreakPoint"
7
+ />
8
+ <template v-if="owner.isSelected">
9
+ <template v-if="controlPoint">
10
+ <circle
11
+ v-for="(point,index) in controlPoint"
12
+ :key="index"
13
+ :cx="point.x"
14
+ :cy="point.y"
15
+ r="3"
16
+ class="control-point"
17
+ @mousedown.stop="startDrag(index, $event)"
18
+ @mouseup.stop="endDrag"
19
+ @dblclick.stop="removeBreakPoint(index)"
20
+ />
21
+ </template>
22
+ </template>
23
+ </g>
24
+ </template>
25
+ <script>
26
+ import { getJoint, getMousePosition, createRightAngleControlPoints } from '../util'
27
+ import { mapMutations } from 'vuex'
28
+ export default {
29
+ name: 'RightAngleLine',
30
+ props: {
31
+ owner: {
32
+ type: Object,
33
+ default: null
34
+ }
35
+ },
36
+ computed: {
37
+ startPoint() {
38
+ return getJoint(this.owner.startJoint.parent, this.owner.startJoint.position)
39
+ },
40
+ endPoint() {
41
+ return getJoint(this.owner.endJoint.parent, this.owner.endJoint.position)
42
+ },
43
+ controlPoint() {
44
+ return this.owner.lineInfo.controlPoint
45
+ },
46
+ // 直角折线由两个折点、三段组成,默认形成 Z 字形
47
+ path() {
48
+ let myPath = 'M ' + this.startPoint.x + ' ' + this.startPoint.y + ' '
49
+ if (this.controlPoint) {
50
+ this.controlPoint.forEach(point => {
51
+ myPath += 'L ' + point.x + ' ' + point.y
52
+ })
53
+ }
54
+ myPath += 'L ' + this.endPoint.x + ' ' + this.endPoint.y
55
+ return myPath
56
+ }
57
+ },
58
+ created: function() {
59
+ // controlPoint没有值时需要给一个初始值:默认生成两个折点(保证不重合),形成 Z 字形直角折线
60
+ if (!this.owner.lineInfo.controlPoint || this.owner.lineInfo.controlPoint.length === 0) {
61
+ this.initDefaultControlPoints()
62
+ }
63
+ },
64
+ methods: {
65
+ ...mapMutations('wfEditor', [
66
+ 'setControlPointToMove'
67
+ ]),
68
+ // 生成默认的两个折点,保证两个点不重合、不会都堆在中间
69
+ initDefaultControlPoints() {
70
+ this.owner.lineInfo.controlPoint = createRightAngleControlPoints(this.startPoint, this.endPoint)
71
+ },
72
+ // 所有顶点(起点、折点、终点)
73
+ allPoints() {
74
+ const points = [{ x: this.startPoint.x, y: this.startPoint.y }]
75
+ if (this.controlPoint) {
76
+ this.controlPoint.forEach(p => points.push({ x: parseFloat(p.x), y: parseFloat(p.y) }))
77
+ }
78
+ points.push({ x: this.endPoint.x, y: this.endPoint.y })
79
+ return points
80
+ },
81
+ // 双击线段:在该线段上新增一个折点(吸附到线段,保持整条线横平竖直)
82
+ addBreakPoint($event) {
83
+ if (!$event) return
84
+ // 防御:折点为空时(例如切换线型后未初始化)先补上默认折点
85
+ if (!this.controlPoint || this.controlPoint.length === 0) {
86
+ this.initDefaultControlPoints()
87
+ }
88
+ const pos = getMousePosition($event)
89
+ const points = this.allPoints()
90
+ // 点击位置离某个已有顶点太近时不做处理,避免产生多余的微小线段
91
+ for (const p of points) {
92
+ if (Math.hypot(pos.x - p.x, pos.y - p.y) < 8) {
93
+ return
94
+ }
95
+ }
96
+ let bestIndex = -1
97
+ let bestDist = Infinity
98
+ let newPoint = null
99
+ for (let i = 0; i < points.length - 1; i++) {
100
+ const p1 = points[i]
101
+ const p2 = points[i + 1]
102
+ // 把点击点投影到线段所在的水平/垂直线上
103
+ const isHorizontal = Math.abs(p1.y - p2.y) < Math.abs(p1.x - p2.x)
104
+ const proj = isHorizontal ? { x: pos.x, y: p1.y } : { x: p1.x, y: pos.y }
105
+ const dist = Math.hypot(pos.x - proj.x, pos.y - proj.y)
106
+ if (dist < bestDist) {
107
+ bestDist = dist
108
+ bestIndex = i
109
+ newPoint = proj
110
+ }
111
+ }
112
+ if (bestIndex >= 0 && newPoint) {
113
+ this.controlPoint.splice(bestIndex, 0, newPoint)
114
+ }
115
+ },
116
+ // 双击折点:删除该折点(至少保留一个折点)
117
+ removeBreakPoint(index) {
118
+ if (this.controlPoint && this.controlPoint.length > 1) {
119
+ this.controlPoint.splice(index, 1)
120
+ }
121
+ },
122
+ startDrag(pointIndex, $event) {
123
+ this.setControlPointToMove({
124
+ owner: this.owner,
125
+ pointIndex: pointIndex
126
+ })
127
+ },
128
+ endDrag() {
129
+ this.setControlPointToMove(null)
130
+ }
131
+ }
132
+ }
133
+ </script>
134
+ <style scoped>
135
+ .control-point{
136
+ fill: #fff;
137
+ cursor: move;
138
+ }
139
+ </style>
@@ -39,12 +39,14 @@ import { mapGetters, mapMutations } from 'vuex'
39
39
  import StraightLine from './straight-line'
40
40
  import CurveLine from './curve-line'
41
41
  import BrokenLine from './broken-line'
42
+ import RightAngleLine from './right-angle-line'
42
43
  export default {
43
44
  name: 'Transition',
44
45
  components: {
45
46
  StraightLine,
46
47
  CurveLine,
47
- BrokenLine
48
+ BrokenLine,
49
+ RightAngleLine
48
50
  },
49
51
  props: {
50
52
  model: {
@@ -102,7 +104,7 @@ export default {
102
104
  const point = this.getTextPoint()
103
105
  this.text.x = point.x
104
106
  this.text.y = point.y
105
- })
107
+ }, { deep: true })
106
108
  // 水平拖动起点节点
107
109
  this.$watch('model.startJoint.parent.x', function (newVal) {
108
110
  // 计算文本框的x、y坐标
@@ -165,6 +167,24 @@ export default {
165
167
  textY = minY + Math.abs(startPoint.y - point.y) / 2 - 10
166
168
  }
167
169
  }
170
+ } else if (this.model.lineInfo.type === 'RightAngleLine') {
171
+ // 直角折线:文字放在所有折点(含端点)包围盒的中心
172
+ if (this.model.lineInfo.controlPoint && this.model.lineInfo.controlPoint.length > 0) {
173
+ let minX = Math.min(startPoint.x, endPoint.x)
174
+ let minY = Math.min(startPoint.y, endPoint.y)
175
+ let maxX = Math.max(startPoint.x, endPoint.x)
176
+ let maxY = Math.max(startPoint.y, endPoint.y)
177
+ this.model.lineInfo.controlPoint.forEach(p => {
178
+ const px = parseFloat(p.x)
179
+ const py = parseFloat(p.y)
180
+ minX = Math.min(minX, px)
181
+ minY = Math.min(minY, py)
182
+ maxX = Math.max(maxX, px)
183
+ maxY = Math.max(maxY, py)
184
+ })
185
+ textX = (minX + maxX) / 2
186
+ textY = (minY + maxY) / 2
187
+ }
168
188
  }
169
189
  return { x: textX, y: textY }
170
190
  },
@@ -175,6 +175,36 @@ function getJoint(parent, position) {
175
175
  return { position: '', x: parent.x, y: parent.y }
176
176
  }
177
177
  }
178
+
179
+ // 生成直角折线的默认折点(两个),保证两个点不重合、有间距
180
+ function createRightAngleControlPoints(startPoint, endPoint) {
181
+ const dx = Math.abs(endPoint.x - startPoint.x)
182
+ const dy = Math.abs(endPoint.y - startPoint.y)
183
+ if (dy < 20) {
184
+ // 两个节点横向排列:两个折点沿水平线错开(约 1/3、2/3 处),不做纵向凸起
185
+ const x1 = startPoint.x + (endPoint.x - startPoint.x) / 3
186
+ const x2 = startPoint.x + 2 * (endPoint.x - startPoint.x) / 3
187
+ return [
188
+ { x: x1, y: startPoint.y },
189
+ { x: x2, y: endPoint.y }
190
+ ]
191
+ } else if (dx < 20) {
192
+ // 两个节点纵向排列:两个折点沿垂直线错开(约 1/3、2/3 处),不做横向凸起
193
+ const y1 = startPoint.y + (endPoint.y - startPoint.y) / 3
194
+ const y2 = startPoint.y + 2 * (endPoint.y - startPoint.y) / 3
195
+ return [
196
+ { x: startPoint.x, y: y1 },
197
+ { x: endPoint.x, y: y2 }
198
+ ]
199
+ } else {
200
+ // 一般斜向:经典 Z 字形,中间竖段位于水平中点,两个折点一上一下
201
+ const midX = startPoint.x + (endPoint.x - startPoint.x) / 2
202
+ return [
203
+ { x: midX, y: startPoint.y },
204
+ { x: midX, y: endPoint.y }
205
+ ]
206
+ }
207
+ }
178
208
  // 根据鼠标的位置clientX,clientY算出对应的SVG中的坐标
179
209
  function getMousePosition(evt) {
180
210
  const CTM = document.getElementById('svg').getScreenCTM()
@@ -371,7 +401,7 @@ function generateTransitions(type, arr) {
371
401
  x: point[0],
372
402
  y: point[1]
373
403
  }
374
- } else if (transition.g.lineType === 'BrokenLine' && transition.g.coordinate) {
404
+ } else if ((transition.g.lineType === 'BrokenLine' || transition.g.lineType === 'RightAngleLine') && transition.g.coordinate) {
375
405
  const points = transition.g.coordinate.split(';')
376
406
  const controlPoints = []
377
407
  points.forEach(pointXY => {
@@ -476,7 +506,7 @@ function watchShowName(vm, newVal) {
476
506
  return showName
477
507
  }
478
508
  export {
479
- clearAllSelectedComponents, deepCopy, endDragTache, findIncomingTransitionsByTacheId, findOutgoingTransitionsByTacheId, findTacheById, getClientMousePosition, getComponentInfo, getI18n, getJoint, getMouseOffset, getMousePosition, getRealRegion, getVirtualRegion, initializeProcessData, removeTextProperty, startDragTache, updateTransitionsWhenTacheIdChanged,
509
+ clearAllSelectedComponents, createRightAngleControlPoints, deepCopy, endDragTache, findIncomingTransitionsByTacheId, findOutgoingTransitionsByTacheId, findTacheById, getClientMousePosition, getComponentInfo, getI18n, getJoint, getMouseOffset, getMousePosition, getRealRegion, getVirtualRegion, initializeProcessData, removeTextProperty, startDragTache, updateTransitionsWhenTacheIdChanged,
480
510
  validateTacheCode, watchShowName
481
511
  }
482
512
 
@@ -432,7 +432,7 @@ export default {
432
432
  }
433
433
  if (transition.lineInfo.type === 'CurveLine' && transition.lineInfo.controlPoint) {
434
434
  transition.ref.g.coordinate = transition.lineInfo.controlPoint.x + ',' + transition.lineInfo.controlPoint.y
435
- } else if (transition.lineInfo.type === 'BrokenLine' && transition.lineInfo.controlPoint) {
435
+ } else if ((transition.lineInfo.type === 'BrokenLine' || transition.lineInfo.type === 'RightAngleLine') && transition.lineInfo.controlPoint) {
436
436
  let coordinate = ''
437
437
  transition.lineInfo.controlPoint.forEach((point) => {
438
438
  coordinate += point.x + ',' + point.y + ';'
@@ -108,7 +108,8 @@ const cn = {
108
108
  tacheType: '环节类型',
109
109
  straightLine: '直线',
110
110
  curveLine: '曲线',
111
- brokenLine: '折线'
111
+ brokenLine: '折线',
112
+ rightAngleLine: '直角线'
112
113
  },
113
114
  // 公共属性
114
115
  common: {
@@ -108,7 +108,8 @@ const en = {
108
108
  tacheType: 'Tache Type',
109
109
  straightLine: 'Straight Line',
110
110
  curveLine: 'Curve Line',
111
- brokenLine: 'Broken Line'
111
+ brokenLine: 'Broken Line',
112
+ rightAngleLine: 'Right Angle Line'
112
113
  },
113
114
  // 公共属性
114
115
  common: {