@logicflow/core 2.0.0-beta.2 → 2.0.0-beta.4

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.
Files changed (275) hide show
  1. package/.turbo/turbo-build$colon$dev.log +2 -2
  2. package/.turbo/turbo-build.log +14 -8
  3. package/dist/index.min.js +9 -3
  4. package/es/LogicFlow.d.ts +8 -3
  5. package/es/LogicFlow.js +5 -4
  6. package/es/LogicFlow.js.map +1 -1
  7. package/es/common/drag.d.ts +51 -0
  8. package/es/common/drag.js +145 -0
  9. package/es/common/drag.js.map +1 -0
  10. package/es/common/history.d.ts +28 -0
  11. package/es/common/history.js +92 -0
  12. package/es/common/history.js.map +1 -0
  13. package/es/common/index.d.ts +5 -0
  14. package/es/common/index.js +6 -0
  15. package/es/common/index.js.map +1 -0
  16. package/es/common/keyboard.d.ts +34 -0
  17. package/es/common/keyboard.js +80 -0
  18. package/es/common/keyboard.js.map +1 -0
  19. package/es/common/matrix.d.ts +30 -0
  20. package/es/common/matrix.js +155 -0
  21. package/es/common/matrix.js.map +1 -0
  22. package/es/common/vector.d.ts +23 -0
  23. package/es/common/vector.js +97 -0
  24. package/es/common/vector.js.map +1 -0
  25. package/es/constant/index.d.ts +2 -1
  26. package/es/constant/index.js +1 -0
  27. package/es/constant/index.js.map +1 -1
  28. package/es/event/eventArgs.d.ts +6 -0
  29. package/es/event/eventEmitter.js +0 -1
  30. package/es/event/eventEmitter.js.map +1 -1
  31. package/es/index.d.ts +1 -1
  32. package/es/index.js +1 -1
  33. package/es/index.js.map +1 -1
  34. package/es/model/GraphModel.d.ts +12 -1
  35. package/es/model/GraphModel.js +21 -2
  36. package/es/model/GraphModel.js.map +1 -1
  37. package/es/model/SnaplineModel.d.ts +2 -0
  38. package/es/model/edge/BaseEdgeModel.d.ts +5 -9
  39. package/es/model/edge/BaseEdgeModel.js +26 -23
  40. package/es/model/edge/BaseEdgeModel.js.map +1 -1
  41. package/es/model/edge/BezierEdgeModel.d.ts +2 -0
  42. package/es/model/edge/LineEdgeModel.d.ts +2 -0
  43. package/es/model/edge/PolylineEdgeModel.d.ts +2 -0
  44. package/es/model/node/BaseNodeModel.js +22 -21
  45. package/es/model/node/BaseNodeModel.js.map +1 -1
  46. package/es/model/node/CircleNodeModel.d.ts +2 -0
  47. package/es/model/node/CircleNodeModel.js +2 -2
  48. package/es/model/node/CircleNodeModel.js.map +1 -1
  49. package/es/model/node/DiamondNodeModel.d.ts +2 -0
  50. package/es/model/node/DiamondNodeModel.js +2 -1
  51. package/es/model/node/DiamondNodeModel.js.map +1 -1
  52. package/es/model/node/EllipseNodeModel.d.ts +2 -0
  53. package/es/model/node/EllipseNodeModel.js +2 -1
  54. package/es/model/node/EllipseNodeModel.js.map +1 -1
  55. package/es/model/node/HtmlNodeModel.d.ts +2 -2
  56. package/es/model/node/HtmlNodeModel.js.map +1 -1
  57. package/es/model/node/PolygonNodeModel.d.ts +2 -0
  58. package/es/model/node/PolygonNodeModel.js +2 -2
  59. package/es/model/node/PolygonNodeModel.js.map +1 -1
  60. package/es/model/node/RectNodeModel.d.ts +3 -0
  61. package/es/model/node/RectNodeModel.js +8 -2
  62. package/es/model/node/RectNodeModel.js.map +1 -1
  63. package/es/model/node/TextNodeModel.d.ts +4 -2
  64. package/es/options.js +2 -11
  65. package/es/options.js.map +1 -1
  66. package/es/tool/tool.js.map +1 -1
  67. package/es/util/edge.d.ts +6 -0
  68. package/es/util/edge.js +15 -1
  69. package/es/util/edge.js.map +1 -1
  70. package/es/util/node.d.ts +6 -2
  71. package/es/util/node.js +22 -7
  72. package/es/util/node.js.map +1 -1
  73. package/es/view/Anchor.d.ts +1 -1
  74. package/es/view/Anchor.js +3 -3
  75. package/es/view/Anchor.js.map +1 -1
  76. package/es/view/Control.js +14 -2
  77. package/es/view/Control.js.map +1 -1
  78. package/es/view/Graph.d.ts +4 -0
  79. package/es/view/Graph.js +42 -3
  80. package/es/view/Graph.js.map +1 -1
  81. package/es/view/edge/AdjustPoint.js +3 -3
  82. package/es/view/edge/AdjustPoint.js.map +1 -1
  83. package/es/view/edge/BaseEdge.d.ts +2 -2
  84. package/es/view/edge/BaseEdge.js +5 -5
  85. package/es/view/node/BaseNode.d.ts +2 -2
  86. package/es/view/node/BaseNode.js +5 -5
  87. package/es/view/node/TextNode.js +1 -1
  88. package/es/view/node/TextNode.js.map +1 -1
  89. package/es/view/shape/Circle.d.ts +9 -1
  90. package/es/view/shape/Circle.js +5 -5
  91. package/es/view/shape/Circle.js.map +1 -1
  92. package/es/view/shape/Ellipse.d.ts +10 -1
  93. package/es/view/shape/Ellipse.js +5 -5
  94. package/es/view/shape/Ellipse.js.map +1 -1
  95. package/es/view/shape/Line.d.ts +14 -1
  96. package/es/view/shape/Line.js +5 -7
  97. package/es/view/shape/Line.js.map +1 -1
  98. package/es/view/shape/Path.d.ts +3 -2
  99. package/es/view/shape/Path.js +3 -3
  100. package/es/view/shape/Path.js.map +1 -1
  101. package/es/view/shape/Polygon.d.ts +5 -3
  102. package/es/view/shape/Polygon.js +6 -6
  103. package/es/view/shape/Polygon.js.map +1 -1
  104. package/es/view/shape/Polyline.d.ts +7 -1
  105. package/es/view/shape/Polyline.js +8 -6
  106. package/es/view/shape/Polyline.js.map +1 -1
  107. package/es/view/shape/Rect.d.ts +11 -13
  108. package/es/view/shape/Rect.js +6 -9
  109. package/es/view/shape/Rect.js.map +1 -1
  110. package/es/view/shape/Text.d.ts +19 -1
  111. package/es/view/shape/Text.js +28 -21
  112. package/es/view/shape/Text.js.map +1 -1
  113. package/es/view/text/BaseText.d.ts +12 -15
  114. package/es/view/text/BaseText.js +37 -27
  115. package/es/view/text/BaseText.js.map +1 -1
  116. package/es/view/text/LineText.d.ts +19 -7
  117. package/es/view/text/LineText.js +62 -54
  118. package/es/view/text/LineText.js.map +1 -1
  119. package/lib/LogicFlow.d.ts +8 -3
  120. package/lib/LogicFlow.js +5 -4
  121. package/lib/LogicFlow.js.map +1 -1
  122. package/lib/common/drag.d.ts +51 -0
  123. package/lib/common/drag.js +148 -0
  124. package/lib/common/drag.js.map +1 -0
  125. package/lib/common/history.d.ts +28 -0
  126. package/lib/common/history.js +95 -0
  127. package/lib/common/history.js.map +1 -0
  128. package/lib/common/index.d.ts +5 -0
  129. package/lib/common/index.js +22 -0
  130. package/lib/common/index.js.map +1 -0
  131. package/lib/common/keyboard.d.ts +34 -0
  132. package/lib/common/keyboard.js +86 -0
  133. package/lib/common/keyboard.js.map +1 -0
  134. package/lib/common/matrix.d.ts +30 -0
  135. package/lib/common/matrix.js +158 -0
  136. package/lib/common/matrix.js.map +1 -0
  137. package/lib/common/vector.d.ts +23 -0
  138. package/lib/common/vector.js +101 -0
  139. package/lib/common/vector.js.map +1 -0
  140. package/lib/constant/index.d.ts +2 -1
  141. package/lib/constant/index.js +1 -0
  142. package/lib/constant/index.js.map +1 -1
  143. package/lib/event/eventArgs.d.ts +6 -0
  144. package/lib/event/eventEmitter.js +0 -1
  145. package/lib/event/eventEmitter.js.map +1 -1
  146. package/lib/index.d.ts +1 -1
  147. package/lib/index.js +2 -2
  148. package/lib/index.js.map +1 -1
  149. package/lib/model/GraphModel.d.ts +12 -1
  150. package/lib/model/GraphModel.js +21 -2
  151. package/lib/model/GraphModel.js.map +1 -1
  152. package/lib/model/SnaplineModel.d.ts +2 -0
  153. package/lib/model/edge/BaseEdgeModel.d.ts +5 -9
  154. package/lib/model/edge/BaseEdgeModel.js +25 -22
  155. package/lib/model/edge/BaseEdgeModel.js.map +1 -1
  156. package/lib/model/edge/BezierEdgeModel.d.ts +2 -0
  157. package/lib/model/edge/LineEdgeModel.d.ts +2 -0
  158. package/lib/model/edge/PolylineEdgeModel.d.ts +2 -0
  159. package/lib/model/node/BaseNodeModel.js +21 -20
  160. package/lib/model/node/BaseNodeModel.js.map +1 -1
  161. package/lib/model/node/CircleNodeModel.d.ts +2 -0
  162. package/lib/model/node/CircleNodeModel.js +2 -2
  163. package/lib/model/node/CircleNodeModel.js.map +1 -1
  164. package/lib/model/node/DiamondNodeModel.d.ts +2 -0
  165. package/lib/model/node/DiamondNodeModel.js +2 -1
  166. package/lib/model/node/DiamondNodeModel.js.map +1 -1
  167. package/lib/model/node/EllipseNodeModel.d.ts +2 -0
  168. package/lib/model/node/EllipseNodeModel.js +2 -1
  169. package/lib/model/node/EllipseNodeModel.js.map +1 -1
  170. package/lib/model/node/HtmlNodeModel.d.ts +2 -2
  171. package/lib/model/node/HtmlNodeModel.js.map +1 -1
  172. package/lib/model/node/PolygonNodeModel.d.ts +2 -0
  173. package/lib/model/node/PolygonNodeModel.js +2 -2
  174. package/lib/model/node/PolygonNodeModel.js.map +1 -1
  175. package/lib/model/node/RectNodeModel.d.ts +3 -0
  176. package/lib/model/node/RectNodeModel.js +8 -2
  177. package/lib/model/node/RectNodeModel.js.map +1 -1
  178. package/lib/model/node/TextNodeModel.d.ts +4 -2
  179. package/lib/options.js +2 -11
  180. package/lib/options.js.map +1 -1
  181. package/lib/tool/tool.js.map +1 -1
  182. package/lib/util/edge.d.ts +6 -0
  183. package/lib/util/edge.js +16 -1
  184. package/lib/util/edge.js.map +1 -1
  185. package/lib/util/node.d.ts +6 -2
  186. package/lib/util/node.js +24 -9
  187. package/lib/util/node.js.map +1 -1
  188. package/lib/view/Anchor.d.ts +1 -1
  189. package/lib/view/Anchor.js +2 -2
  190. package/lib/view/Anchor.js.map +1 -1
  191. package/lib/view/Control.js +14 -2
  192. package/lib/view/Control.js.map +1 -1
  193. package/lib/view/Graph.d.ts +4 -0
  194. package/lib/view/Graph.js +41 -2
  195. package/lib/view/Graph.js.map +1 -1
  196. package/lib/view/edge/AdjustPoint.js +2 -2
  197. package/lib/view/edge/AdjustPoint.js.map +1 -1
  198. package/lib/view/edge/BaseEdge.d.ts +2 -2
  199. package/lib/view/edge/BaseEdge.js +5 -5
  200. package/lib/view/node/BaseNode.d.ts +2 -2
  201. package/lib/view/node/BaseNode.js +5 -5
  202. package/lib/view/node/TextNode.js +1 -1
  203. package/lib/view/node/TextNode.js.map +1 -1
  204. package/lib/view/shape/Circle.d.ts +9 -1
  205. package/lib/view/shape/Circle.js +5 -5
  206. package/lib/view/shape/Circle.js.map +1 -1
  207. package/lib/view/shape/Ellipse.d.ts +10 -1
  208. package/lib/view/shape/Ellipse.js +5 -5
  209. package/lib/view/shape/Ellipse.js.map +1 -1
  210. package/lib/view/shape/Line.d.ts +14 -1
  211. package/lib/view/shape/Line.js +5 -7
  212. package/lib/view/shape/Line.js.map +1 -1
  213. package/lib/view/shape/Path.d.ts +3 -2
  214. package/lib/view/shape/Path.js +3 -3
  215. package/lib/view/shape/Path.js.map +1 -1
  216. package/lib/view/shape/Polygon.d.ts +5 -3
  217. package/lib/view/shape/Polygon.js +6 -6
  218. package/lib/view/shape/Polygon.js.map +1 -1
  219. package/lib/view/shape/Polyline.d.ts +7 -1
  220. package/lib/view/shape/Polyline.js +8 -6
  221. package/lib/view/shape/Polyline.js.map +1 -1
  222. package/lib/view/shape/Rect.d.ts +11 -13
  223. package/lib/view/shape/Rect.js +6 -9
  224. package/lib/view/shape/Rect.js.map +1 -1
  225. package/lib/view/shape/Text.d.ts +19 -1
  226. package/lib/view/shape/Text.js +29 -21
  227. package/lib/view/shape/Text.js.map +1 -1
  228. package/lib/view/text/BaseText.d.ts +12 -15
  229. package/lib/view/text/BaseText.js +40 -27
  230. package/lib/view/text/BaseText.js.map +1 -1
  231. package/lib/view/text/LineText.d.ts +19 -7
  232. package/lib/view/text/LineText.js +62 -57
  233. package/lib/view/text/LineText.js.map +1 -1
  234. package/package.json +2 -1
  235. package/src/LogicFlow.tsx +19 -7
  236. package/src/common/drag.ts +205 -0
  237. package/src/common/history.ts +108 -0
  238. package/src/common/index.ts +6 -0
  239. package/src/common/keyboard.ts +108 -0
  240. package/src/common/matrix.ts +122 -0
  241. package/src/common/vector.ts +93 -0
  242. package/src/constant/index.ts +1 -0
  243. package/src/event/eventArgs.ts +6 -0
  244. package/src/event/eventEmitter.ts +1 -2
  245. package/src/index.ts +1 -1
  246. package/src/model/GraphModel.ts +22 -2
  247. package/src/model/edge/BaseEdgeModel.ts +31 -21
  248. package/src/model/node/BaseNodeModel.ts +27 -19
  249. package/src/model/node/CircleNodeModel.ts +2 -2
  250. package/src/model/node/DiamondNodeModel.ts +2 -0
  251. package/src/model/node/EllipseNodeModel.ts +2 -0
  252. package/src/model/node/HtmlNodeModel.ts +2 -2
  253. package/src/model/node/PolygonNodeModel.ts +2 -2
  254. package/src/model/node/RectNodeModel.ts +9 -2
  255. package/src/options.ts +3 -12
  256. package/src/tool/tool.ts +1 -1
  257. package/src/util/edge.ts +26 -1
  258. package/src/util/node.ts +29 -8
  259. package/src/view/Anchor.tsx +4 -4
  260. package/src/view/Control.tsx +5 -2
  261. package/src/view/Graph.tsx +19 -3
  262. package/src/view/edge/AdjustPoint.tsx +3 -3
  263. package/src/view/edge/BaseEdge.tsx +7 -7
  264. package/src/view/node/BaseNode.tsx +7 -7
  265. package/src/view/node/TextNode.tsx +1 -1
  266. package/src/view/shape/Circle.tsx +21 -7
  267. package/src/view/shape/Ellipse.tsx +20 -6
  268. package/src/view/shape/Line.tsx +24 -9
  269. package/src/view/shape/Path.tsx +9 -6
  270. package/src/view/shape/Polygon.tsx +13 -10
  271. package/src/view/shape/Polyline.tsx +20 -8
  272. package/src/view/shape/Rect.tsx +19 -19
  273. package/src/view/shape/Text.tsx +64 -33
  274. package/src/view/text/BaseText.tsx +67 -41
  275. package/src/view/text/LineText.tsx +94 -80
@@ -0,0 +1,205 @@
1
+ import { noop } from 'lodash-es'
2
+ import { Model } from '../model'
3
+ import { EventType } from '../constant'
4
+ import EventEmitter from '../event/eventEmitter'
5
+
6
+ // TODO:这种方式在同构项目中,会报错,该如何解决(是否要求用户控制在浏览器环境时才初始化)
7
+ // const DOC: any = window?.document
8
+ const LEFT_MOUSE_BUTTON_CODE = 0
9
+
10
+ export type IDragParams = {
11
+ deltaX: number
12
+ deltaY: number
13
+ event: MouseEvent | null
14
+ [key: string]: unknown
15
+ }
16
+
17
+ export type ICreateDragParams = {
18
+ onDragStart?: (params: Partial<IDragParams>) => void
19
+ onDragging?: (param: IDragParams) => void
20
+ onDragEnd?: (param: Partial<IDragParams>) => void
21
+ step?: number
22
+ isStopPropagation?: boolean
23
+ }
24
+
25
+ export type IStepperDragProps = {
26
+ eventType?: 'NODE' | 'BLANK' | 'SELECTION' | 'ADJUST_POINT' | ''
27
+ eventCenter?: EventEmitter
28
+ model?: Model.BaseModel
29
+ data?: Record<string, unknown>
30
+ [key: string]: unknown
31
+ } & Partial<ICreateDragParams>
32
+ /**
33
+ * 支持拖拽时按步长进行移动
34
+ * REMIND:在绘制的过程中因为放大缩小,移动的真实 step 是变化的
35
+ */
36
+ export class StepperDrag {
37
+ // 初始化
38
+ onDragStart: (params: Partial<IDragParams>) => void
39
+ onDragging: (params: IDragParams) => void
40
+ onDragEnd: (params: Partial<IDragParams>) => void
41
+
42
+ step: number
43
+ isStopPropagation: boolean
44
+ eventType: 'NODE' | 'BLANK' | 'SELECTION' | 'ADJUST_POINT' | ''
45
+ eventCenter?: EventEmitter
46
+ model?: Model.BaseModel
47
+ data?: Record<string, unknown>
48
+
49
+ // 运行时
50
+ isDragging: boolean = false
51
+ isStartDrag: boolean = false
52
+
53
+ startX: number = 0
54
+ startY: number = 0
55
+ totalDeltaX: number = 0
56
+ totalDeltaY: number = 0
57
+
58
+ startTime?: number
59
+ constructor({
60
+ onDragStart = noop,
61
+ onDragging = noop,
62
+ onDragEnd = noop,
63
+ step = 1,
64
+ eventType = '',
65
+ isStopPropagation = true,
66
+ eventCenter,
67
+ model,
68
+ data,
69
+ }: IStepperDragProps) {
70
+ this.onDragStart = onDragStart
71
+ this.onDragging = onDragging
72
+ this.onDragEnd = onDragEnd
73
+ this.step = step
74
+ this.eventType = eventType
75
+ this.isStopPropagation = isStopPropagation
76
+ this.eventCenter = eventCenter
77
+ this.model = model
78
+ this.data = data
79
+ }
80
+
81
+ setStep(step: number) {
82
+ this.step = step
83
+ }
84
+
85
+ handleMouseMove = (e: MouseEvent) => {
86
+ if (this.isStopPropagation) e.stopPropagation()
87
+ if (!this.isStartDrag) return
88
+
89
+ this.totalDeltaX += e.clientX - this.startX
90
+ this.totalDeltaY += e.clientY - this.startY
91
+ this.startX = e.clientX
92
+ this.startY = e.clientY
93
+
94
+ if (
95
+ this.step <= 1 ||
96
+ Math.abs(this.totalDeltaX) > this.step ||
97
+ Math.abs(this.totalDeltaY) > this.step
98
+ ) {
99
+ const remainderX = this.totalDeltaX % this.step
100
+ const remainderY = this.totalDeltaY % this.step
101
+
102
+ const deltaX = this.totalDeltaX - remainderX
103
+ const deltaY = this.totalDeltaY - remainderY
104
+
105
+ this.totalDeltaX = remainderX
106
+ this.totalDeltaY = remainderY
107
+
108
+ const elementData = this.model?.getData()
109
+ // REMIND: 为了区分点击和拖动,在鼠标没有拖动时,不触发 dragstart。
110
+ if (!this.isDragging) {
111
+ if (this.eventType) {
112
+ this.eventCenter?.emit(EventType[`${this.eventType}_DRAGSTART`], {
113
+ e,
114
+ data: this.data || elementData,
115
+ })
116
+ }
117
+ this.onDragStart({ event: e })
118
+ }
119
+
120
+ this.isDragging = true
121
+ // REMIND: 为了让 dragstart 和 drag 不在同一个事件循环中,将 drag 事件放在下一个任务队列中。
122
+ // TODO: 测试用例是否可覆盖???
123
+ Promise.resolve().then(() => {
124
+ this.onDragging({ deltaX, deltaY, event: e })
125
+ if (this.eventType) {
126
+ this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEMOVE`], {
127
+ e,
128
+ data: this.data || elementData,
129
+ })
130
+ this.eventCenter?.emit(EventType[`${this.eventType}_DRAG`], {
131
+ e,
132
+ data: this.data || elementData,
133
+ })
134
+ }
135
+ })
136
+ }
137
+ }
138
+
139
+ handleMouseUp = (e: MouseEvent) => {
140
+ const DOC: any = window?.document
141
+
142
+ this.isStartDrag = false
143
+ if (this.isStopPropagation) e.stopPropagation()
144
+
145
+ // fix: issue#568, 如果 onDragging 在下一个时间循环中触发,而 drop 在当前事件循环,会出现问题
146
+ Promise.resolve().then(() => {
147
+ DOC?.removeEventListener('mousemove', this.handleMouseMove, true)
148
+ DOC?.removeEventListener('mouseup', this.handleMouseUp, true)
149
+
150
+ const elementData = this.model?.getData()
151
+ if (this.eventType) {
152
+ this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEUP`], {
153
+ e,
154
+ data: this.data || elementData,
155
+ })
156
+ }
157
+
158
+ if (!this.isDragging) return
159
+ this.isDragging = false
160
+ this.onDragEnd({ event: e })
161
+ if (this.eventType) {
162
+ this.eventCenter?.emit(EventType[`${this.eventType}_DROP`], {
163
+ e,
164
+ data: this.data || elementData,
165
+ })
166
+ }
167
+ })
168
+ }
169
+
170
+ handleMouseDown = (e: MouseEvent) => {
171
+ const DOC: any = window?.document
172
+
173
+ // issue: LogicFlow交流群-3群 8.10 号抛出的事件相关的问题,是否是这引起的???
174
+ if (e.button !== LEFT_MOUSE_BUTTON_CODE) return
175
+ if (this.isStopPropagation) e.stopPropagation()
176
+
177
+ this.isStartDrag = true
178
+ this.startX = e.clientX
179
+ this.startY = e.clientY
180
+
181
+ DOC?.addEventListener('mousemove', this.handleMouseMove, true)
182
+ DOC?.addEventListener('mouseup', this.handleMouseUp, true)
183
+
184
+ const elementData = this.model?.getData()
185
+ if (this.eventType) {
186
+ this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEDOWN`], {
187
+ e,
188
+ data: this.data || elementData,
189
+ })
190
+ }
191
+ this.startTime = new Date().getTime()
192
+ }
193
+
194
+ cancelDrag = () => {
195
+ const DOC: any = window?.document
196
+
197
+ DOC?.removeEventListener('mousemove', this.handleMouseMove, true)
198
+ DOC?.removeEventListener('mouseup', this.handleMouseUp, true)
199
+
200
+ this.onDragEnd({ event: null })
201
+ this.isDragging = false
202
+ }
203
+ }
204
+
205
+ export default StepperDrag
@@ -0,0 +1,108 @@
1
+ import { cloneDeep, debounce, isEqual, last } from 'lodash-es'
2
+ import { deepObserve, IDisposer } from 'mobx-utils'
3
+ import { LogicFlow } from '../LogicFlow'
4
+ // import { EventType } from '../constant'
5
+ import { GraphModel } from '../model'
6
+ import EventEmitter from '../event/eventEmitter'
7
+
8
+ export type HistoryData = LogicFlow.GraphConfigData
9
+
10
+ export class History {
11
+ undos: HistoryData[] = []
12
+ redos: HistoryData[] = []
13
+ stopWatch: IDisposer | null = null
14
+ curData: HistoryData | null = null
15
+ maxSize: number = 50
16
+ // 发生数据变化后,最多再等 500ms,把距离上次的数据变更存储起来。
17
+ // 所以 waitTime 值越小,History 对数据变化越敏感,存的 undos 数据就越细
18
+ waitTime: number = 100
19
+ eventCenter: EventEmitter
20
+
21
+ constructor(eventCenter: EventEmitter) {
22
+ this.eventCenter = eventCenter
23
+ }
24
+
25
+ add(data: HistoryData) {
26
+ if (isEqual(last(this.undos), data)) return
27
+ this.undos.push(data)
28
+
29
+ // 因为 undo 的时候会触发 add.
30
+ // 所以需要区分这个 add 是 undo 触发的还是用户正常操作触发的
31
+ // 如果是用户正常操作触发的,需要清空 redos
32
+ if (!isEqual(this.curData, data)) {
33
+ this.redos = []
34
+ }
35
+ // this.eventCenter.emit(EventType.HISTORY_CHANGE, {
36
+ // data: {
37
+ // undos: this.undos,
38
+ // redos: this.redos,
39
+ // undoAble: this.undos.length > 1,
40
+ // redoAble: this.redos.length > 0,
41
+ // },
42
+ // })
43
+
44
+ if (this.undos.length > this.maxSize) {
45
+ this.undos.shift()
46
+ }
47
+ }
48
+
49
+ undoAble() {
50
+ return this.undos.length > 1
51
+ }
52
+
53
+ /**
54
+ * undo 方法触发:
55
+ * graphModel 重新渲染 nodes 和 edges
56
+ * graphModel 发生变化,触发 watch
57
+ * watch 触发 add
58
+ */
59
+ undo() {
60
+ if (!this.undoAble()) return
61
+ const preData = this.undos.pop()
62
+ if (preData) {
63
+ this.redos.push(preData)
64
+ }
65
+ const curData = this.undos.pop()
66
+ if (curData) {
67
+ this.curData = cloneDeep(curData)
68
+ }
69
+ return curData
70
+ }
71
+
72
+ redoAble() {
73
+ return this.redos.length > 0
74
+ }
75
+
76
+ redo() {
77
+ if (!this.redoAble()) return
78
+ const curData = this.redos.pop()
79
+ if (curData) {
80
+ this.curData = cloneDeep(curData)
81
+ }
82
+ return curData
83
+ }
84
+
85
+ watch(model: GraphModel) {
86
+ this.stopWatch && this.stopWatch()
87
+
88
+ // 把当前 watch 的 model 转换一下数据存起来,无需清空 redos
89
+ const historyData = model.modelToHistoryData()
90
+ if (historyData) {
91
+ this.undos.push(historyData)
92
+ }
93
+
94
+ this.stopWatch = deepObserve(
95
+ model,
96
+ debounce(() => {
97
+ // 数据变更后,把最新的当前 model 数据存起来,并清空 redos
98
+ // 因为这个回调函数的触发,一般是用户交互而引起的,所以按照正常逻辑需要清空 redos
99
+ const data = model.modelToHistoryData()
100
+ if (data) {
101
+ this.add(data)
102
+ }
103
+ }, this.waitTime),
104
+ )
105
+ }
106
+ }
107
+
108
+ export default History
@@ -0,0 +1,6 @@
1
+ export * from './drag'
2
+ export * from './history'
3
+ export * from './keyboard'
4
+
5
+ export * from './matrix'
6
+ export * from './vector'
@@ -0,0 +1,108 @@
1
+ import Mousetrap, { MousetrapInstance } from 'mousetrap'
2
+ import { forEach, isArray } from 'lodash-es'
3
+ import LogicFlow from '..'
4
+
5
+ export class Keyboard {
6
+ private target: HTMLElement
7
+ readonly mousetrap: MousetrapInstance
8
+ options: Required<Keyboard.Options>
9
+
10
+ constructor(options: Keyboard.Options) {
11
+ const { lf } = options
12
+ if (!options.keyboard) {
13
+ options.keyboard = { enabled: false }
14
+ }
15
+ this.options = options as Required<Keyboard.Options>
16
+ this.target = lf.container
17
+ this.mousetrap = new Mousetrap(this.target)
18
+
19
+ if (options.keyboard?.enabled) {
20
+ this.enable(true)
21
+ }
22
+ }
23
+
24
+ protected formatKey(key: string) {
25
+ return key
26
+ .toLowerCase()
27
+ .replace(/\s/g, '')
28
+ .replace('delete', 'del')
29
+ .replace('cmd', 'command')
30
+ }
31
+
32
+ private getKeys(keys: string | string[]) {
33
+ return (isArray(keys) ? keys : [keys]).map((key) => this.formatKey(key))
34
+ }
35
+
36
+ get disabled() {
37
+ return this.options.keyboard?.enabled !== true
38
+ }
39
+
40
+ on(
41
+ keys: string | string[],
42
+ callback: Keyboard.HandlerFunc,
43
+ action?: Keyboard.ActionType,
44
+ ) {
45
+ this.mousetrap.bind(this.getKeys(keys), callback, action)
46
+ }
47
+
48
+ off(keys: string | string[], action?: Keyboard.ActionType) {
49
+ this.mousetrap.unbind(this.getKeys(keys), action)
50
+ }
51
+
52
+ enable(force: boolean) {
53
+ if (this.disabled || force) {
54
+ this.options.keyboard.enabled = true
55
+ if (this.target instanceof HTMLElement) {
56
+ this.target.setAttribute('tabindex', '-1')
57
+ // 去掉节点被选中时 container 出现的边框
58
+ this.target.style.outline = 'none'
59
+ }
60
+ }
61
+ }
62
+
63
+ disable() {
64
+ if (!this.disabled) {
65
+ this.options.keyboard.enabled = false
66
+ if (this.target instanceof HTMLElement) {
67
+ this.target.removeAttribute('tabindex')
68
+ }
69
+ }
70
+ }
71
+
72
+ initShortcuts() {
73
+ const { shortcuts } = this.options.keyboard
74
+ if (shortcuts) {
75
+ if (isArray(shortcuts)) {
76
+ forEach(shortcuts, ({ keys, callback, action }) => {
77
+ this.on(keys, callback, action)
78
+ })
79
+ } else {
80
+ const { keys, callback, action } = shortcuts
81
+ this.on(keys, callback, action)
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ export namespace Keyboard {
88
+ export type ActionType = 'keypress' | 'keydown' | 'keyup'
89
+ export type HandlerFunc = (e: KeyboardEvent) => void
90
+
91
+ export interface Shortcut {
92
+ keys: string | string[]
93
+ callback: HandlerFunc
94
+ action?: ActionType
95
+ }
96
+
97
+ export interface KeyboardDef {
98
+ enabled: boolean
99
+ shortcuts?: Shortcut | Shortcut[]
100
+ }
101
+
102
+ export interface Options {
103
+ lf: LogicFlow
104
+ keyboard?: KeyboardDef
105
+ }
106
+ }
107
+
108
+ export default Keyboard
@@ -0,0 +1,122 @@
1
+ import { Vector } from './vector'
2
+
3
+ export class Matrix extends Array {
4
+ rows: number
5
+ columns: number
6
+
7
+ constructor(...vectors: any[]) {
8
+ super(vectors.length)
9
+ this.fill(new Array(3))
10
+ vectors.forEach((v: any, index: number) => {
11
+ this[index] = v
12
+ })
13
+ this.columns = vectors[0].length
14
+ this.rows = vectors.length
15
+ Object.setPrototypeOf(this, Matrix.prototype)
16
+ }
17
+
18
+ getRow(index: number) {
19
+ return this[index]
20
+ }
21
+
22
+ getColumn(index: number) {
23
+ return [...this.map((row: number[]) => row[index])]
24
+ }
25
+
26
+ // 转置
27
+ transpose() {
28
+ const rows: any[] = []
29
+ for (let i = 0; i < this.columns; i++) {
30
+ rows.push(this.getColumn(i))
31
+ }
32
+ return new Matrix(...rows)
33
+ }
34
+
35
+ // 叉乘
36
+ cross(m1: Matrix) {
37
+ const arr = new Array(this.rows).fill('').map((): any => [])
38
+ if (this.columns === m1.rows) {
39
+ for (let i = 0; i < this.rows; i++) {
40
+ const row = this.getRow(i)
41
+ for (let j = 0; j < m1.columns; j++) {
42
+ const column = m1.getColumn(j)
43
+ arr[i][j] = row.reduce(
44
+ (prev: number, r: number, index: number) =>
45
+ prev + r * column[index],
46
+ 0,
47
+ )
48
+ }
49
+ }
50
+ }
51
+ return new Matrix(...arr)
52
+ }
53
+
54
+ // 返回二维坐标(降维)
55
+ to2D() {
56
+ return this.map((item: any) => [item[0], item[1]])
57
+ }
58
+
59
+ toString(): string {
60
+ const [[a, b], [c, d], [e, f]] = this
61
+ return `matrix(${a} ${b} ${c} ${d} ${e} ${f})`
62
+ }
63
+
64
+ translate(tx: number, ty: number): Matrix {
65
+ return this.cross(new TranslateMatrix(tx, ty))
66
+ }
67
+
68
+ rotate(angle: number): Matrix {
69
+ return this.cross(new RotateMatrix(angle))
70
+ }
71
+
72
+ scale(sx: number, sy: number): Matrix {
73
+ return this.cross(new ScaleMatrix(sx, sy))
74
+ }
75
+ }
76
+
77
+ export class RotateMatrix extends Matrix {
78
+ constructor(theta: number) {
79
+ super(
80
+ new Vector(+Math.cos(theta).toFixed(2), +Math.sin(theta).toFixed(2), 0),
81
+ new Vector(-Math.sin(theta).toFixed(2), +Math.cos(theta).toFixed(2), 0),
82
+ new Vector(0, 0, 1),
83
+ )
84
+ Object.setPrototypeOf(this, RotateMatrix.prototype)
85
+ }
86
+
87
+ inverse() {
88
+ return this.transpose()
89
+ }
90
+ }
91
+
92
+ export class ScaleMatrix extends Matrix {
93
+ private readonly sx: number
94
+ private readonly sy: number
95
+
96
+ constructor(sx: number, sy: number) {
97
+ super(new Vector(sx, 0, 0), new Vector(0, sy, 0), new Vector(0, 0, 1))
98
+ this.sx = sx
99
+ this.sy = sy
100
+ Object.setPrototypeOf(this, ScaleMatrix.prototype)
101
+ }
102
+
103
+ inverse() {
104
+ return new ScaleMatrix(1 / this.sx, 1 / this.sy)
105
+ }
106
+ }
107
+
108
+ export class TranslateMatrix extends Matrix {
109
+ private readonly tx: number
110
+ private readonly ty: number
111
+
112
+ constructor(tx: number, ty: number) {
113
+ super(new Vector(1, 0, 0), new Vector(0, 1, 0), new Vector(tx, ty, 1))
114
+ this.tx = tx
115
+ this.ty = ty
116
+ Object.setPrototypeOf(this, TranslateMatrix.prototype)
117
+ }
118
+
119
+ inverse() {
120
+ return new TranslateMatrix(-this.tx, -this.ty)
121
+ }
122
+ }
@@ -0,0 +1,93 @@
1
+ function isVector(a1: any, a2: any): boolean {
2
+ return a1 instanceof Vector && a2 instanceof Vector
3
+ }
4
+
5
+ class Base extends Array {
6
+ x: number
7
+ y: number
8
+ z: number
9
+
10
+ constructor(x: number, y: number, z: number) {
11
+ super(3)
12
+ this[0] = x
13
+ this[1] = y
14
+ this[2] = z
15
+ this.x = x
16
+ this.y = y
17
+ this.z = z
18
+ Object.setPrototypeOf(this, Base.prototype)
19
+ }
20
+
21
+ add(v1: Vector | Point): Vector | Point {
22
+ if (isVector(this, v1)) {
23
+ return new Vector(this.x + v1.x, this.y + v1.y)
24
+ }
25
+ const z = this.z + v1.z
26
+ return new Point((this.x + v1.x) / z, (this.y + v1.y) / z)
27
+ }
28
+
29
+ subtract(v1: Vector | Point): Vector | Point {
30
+ if (isVector(this, v1)) {
31
+ return new Vector(this.x - v1.x, this.y - v1.y)
32
+ }
33
+ const z = this.z - v1.z
34
+ return z === 0
35
+ ? new Vector(this.x - v1.x, this.y - v1.y)
36
+ : new Point((this.x - v1.x) / z, (this.y - v1.y) / z)
37
+ }
38
+ }
39
+
40
+ class Vector extends Base {
41
+ constructor(x: number, y: number, z?: number) {
42
+ super(x, y, z ?? 0)
43
+ Object.setPrototypeOf(this, Vector.prototype)
44
+ }
45
+
46
+ toString(): string {
47
+ return 'Vector'
48
+ }
49
+
50
+ dot(v1: Vector) {
51
+ return v1.reduce((prev, cur, index) => prev + cur * this[index])
52
+ }
53
+
54
+ cross(v1: Vector) {
55
+ return new Vector(
56
+ this.y * v1.z - this.z * v1.y,
57
+ this.z * v1.x - this.x * v1.z,
58
+ this.x * v1.y - this.y * v1.x,
59
+ )
60
+ }
61
+
62
+ getLength() {
63
+ return Math.hypot(this.x, this.y)
64
+ }
65
+
66
+ normalize() {
67
+ const len = this.getLength()
68
+ return new Vector(this.x / len, this.y / len)
69
+ }
70
+
71
+ crossZ(v1: Vector) {
72
+ return this.x * v1.y - this.y * v1.x
73
+ }
74
+
75
+ angle(v1: Vector) {
76
+ const negative = this.crossZ(v1)
77
+ const r = Math.acos(this.normalize().dot(v1.normalize()))
78
+ return negative >= 0 ? r : -r
79
+ }
80
+ }
81
+
82
+ class Point extends Base {
83
+ constructor(x: number, y: number) {
84
+ super(x, y, 1)
85
+ Object.setPrototypeOf(this, Point.prototype)
86
+ }
87
+
88
+ toString(): string {
89
+ return 'Point'
90
+ }
91
+ }
92
+
93
+ export { Vector, Point }
@@ -114,6 +114,7 @@ export enum EventType {
114
114
  TEXT_UPDATE = 'text:update',
115
115
  GRAPH_TRANSFORM = 'graph:transform',
116
116
  GRAPH_RENDERED = 'graph:rendered',
117
+ GRAPH_UPDATED = 'graph:updated',
117
118
  }
118
119
 
119
120
  export enum OverlapMode {
@@ -282,6 +282,12 @@ interface CommonEventArgs {
282
282
  */
283
283
  data: GraphData
284
284
  }
285
+ /**
286
+ * 画布重新更新后触发. 即 lf.render(graphData)方法被调用后或者改变画布(garphModel)上的属性后触发。
287
+ * 如果是主动修改某个特定属性导致画布更新,想要在画布更新后做一些操作,建议注册事件后在回调函数中及时注销该事件,或者使用once事件代替on事件。
288
+ * 因为其他属性也可能导致画布更新,触发该事件。
289
+ */
290
+ 'graph:updated': Record<string, undefined>
285
291
  }
286
292
 
287
293
  type AnchorEventArgsPick<T extends 'data' | 'e' | 'nodeModel' | 'edgeModel'> =
@@ -74,10 +74,9 @@ export default class EventEmitter {
74
74
  */
75
75
  emit<T extends keyof EventArgs>(evts: T, eventArgs: CallbackArgs<T>): void
76
76
  emit<T extends string>(evts: T, eventArgs: CallbackArgs<T>): void
77
- emit(evts: string, eventArgs: EventCallback) {
77
+ emit(evts: string, eventArgs?: EventCallback) {
78
78
  evts?.split(',').forEach((evt) => {
79
79
  const events = this._events[evt] || []
80
- // TODO: 这是什么???
81
80
  const wildcardEvents = this._events[WILDCARD] || []
82
81
  // 实际的处理 emit 方法
83
82
  const doEmit = (es: EventType[]) => {
package/src/index.ts CHANGED
@@ -16,6 +16,6 @@ export * from './options'
16
16
  export * from './keyboard'
17
17
  export { ElementState, ModelType, ElementType, EventType } from './constant'
18
18
 
19
- export { formateAnchorConnectValidateData } from './util/node'
19
+ export { formatAnchorConnectValidateData } from './util/node'
20
20
 
21
21
  export default LogicFlow