aldehyde 0.2.473 → 0.2.475

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 (203) hide show
  1. package/lib/controls/action/utils.d.ts +1 -1
  2. package/lib/controls/entity-select/entity-select.d.ts +2 -2
  3. package/lib/controls/entity-select/entity-select.d.ts.map +1 -1
  4. package/lib/controls/entity-select/entity-select.js +16 -7
  5. package/lib/controls/entity-select/entity-select.js.map +1 -1
  6. package/lib/controls/entry-control.d.ts.map +1 -1
  7. package/lib/controls/entry-control.js +3 -2
  8. package/lib/controls/entry-control.js.map +1 -1
  9. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.css +47 -3
  10. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js +12 -12
  11. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js.map +1 -1
  12. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.json +77 -0
  13. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.ttf +0 -0
  14. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff +0 -0
  15. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff2 +0 -0
  16. package/lib/controls/select/index.d.ts.map +1 -1
  17. package/lib/controls/select/index.js +13 -7
  18. package/lib/controls/select/index.js.map +1 -1
  19. package/lib/controls/text/index.less +1 -0
  20. package/lib/controls/view-control.d.ts.map +1 -1
  21. package/lib/controls/view-control.js +1 -0
  22. package/lib/controls/view-control.js.map +1 -1
  23. package/lib/detail/button/edit-button.d.ts.map +1 -1
  24. package/lib/detail/button/edit-button.js +23 -11
  25. package/lib/detail/button/edit-button.js.map +1 -1
  26. package/lib/detail/button/view-button.d.ts.map +1 -1
  27. package/lib/detail/button/view-button.js +21 -10
  28. package/lib/detail/button/view-button.js.map +1 -1
  29. package/lib/draw-canvas/edit/components/asset-bar/index.d.ts +5 -0
  30. package/lib/draw-canvas/edit/components/asset-bar/index.d.ts.map +1 -0
  31. package/lib/draw-canvas/edit/components/asset-bar/index.js +79 -0
  32. package/lib/draw-canvas/edit/components/asset-bar/index.js.map +1 -0
  33. package/lib/draw-canvas/edit/components/asset-bar/index.less +36 -0
  34. package/lib/draw-canvas/edit/components/main-header/index.d.ts +19 -0
  35. package/lib/draw-canvas/edit/components/main-header/index.d.ts.map +1 -0
  36. package/lib/draw-canvas/edit/components/main-header/index.js +203 -0
  37. package/lib/draw-canvas/edit/components/main-header/index.js.map +1 -0
  38. package/lib/draw-canvas/edit/components/main-header/index.less +21 -0
  39. package/lib/draw-canvas/edit/components/render/index.d.ts +90 -0
  40. package/lib/draw-canvas/edit/components/render/index.d.ts.map +1 -0
  41. package/lib/draw-canvas/edit/components/render/index.js +692 -0
  42. package/lib/draw-canvas/edit/components/render/index.js.map +1 -0
  43. package/lib/draw-canvas/edit/components/render/types.d.ts +247 -0
  44. package/lib/draw-canvas/edit/components/render/types.d.ts.map +1 -0
  45. package/lib/draw-canvas/edit/components/render/types.js +66 -0
  46. package/lib/draw-canvas/edit/components/render/types.js.map +1 -0
  47. package/lib/draw-canvas/edit/components/setting-form/imag-upload.d.ts +26 -0
  48. package/lib/draw-canvas/edit/components/setting-form/imag-upload.d.ts.map +1 -0
  49. package/lib/draw-canvas/edit/components/setting-form/imag-upload.js +83 -0
  50. package/lib/draw-canvas/edit/components/setting-form/imag-upload.js.map +1 -0
  51. package/lib/draw-canvas/edit/components/setting-form/index.d.ts +17 -0
  52. package/lib/draw-canvas/edit/components/setting-form/index.d.ts.map +1 -0
  53. package/lib/draw-canvas/edit/components/setting-form/index.js +243 -0
  54. package/lib/draw-canvas/edit/components/setting-form/index.js.map +1 -0
  55. package/lib/draw-canvas/edit/constant.d.ts +7 -0
  56. package/lib/draw-canvas/edit/constant.d.ts.map +1 -0
  57. package/lib/draw-canvas/edit/constant.js +7 -0
  58. package/lib/draw-canvas/edit/constant.js.map +1 -0
  59. package/lib/draw-canvas/edit/index.d.ts +8 -0
  60. package/lib/draw-canvas/edit/index.d.ts.map +1 -0
  61. package/lib/draw-canvas/edit/index.js +165 -0
  62. package/lib/draw-canvas/edit/index.js.map +1 -0
  63. package/lib/draw-canvas/edit/index.less +49 -0
  64. package/lib/draw-canvas/view/index.d.ts +8 -0
  65. package/lib/draw-canvas/view/index.d.ts.map +1 -0
  66. package/lib/draw-canvas/view/index.js +50 -0
  67. package/lib/draw-canvas/view/index.js.map +1 -0
  68. package/lib/draw-canvas/view/index.less +60 -0
  69. package/lib/draw-canvas/view/view.d.ts +10 -0
  70. package/lib/draw-canvas/view/view.d.ts.map +1 -0
  71. package/lib/draw-canvas/view/view.js +104 -0
  72. package/lib/draw-canvas/view/view.js.map +1 -0
  73. package/lib/form/form-Item-group.d.ts.map +1 -1
  74. package/lib/form/form-Item-group.js +4 -4
  75. package/lib/form/form-Item-group.js.map +1 -1
  76. package/lib/icon/local-aliIcon/iconfont.js +5 -5
  77. package/lib/icon/local-aliIcon/iconfont.js.map +1 -1
  78. package/lib/lowcode-components/index.d.ts +2 -0
  79. package/lib/lowcode-components/index.d.ts.map +1 -1
  80. package/lib/lowcode-components/index.js +2 -1
  81. package/lib/lowcode-components/index.js.map +1 -1
  82. package/lib/lowcode-components/lowcode-view/component/assets.d.ts.map +1 -1
  83. package/lib/lowcode-components/lowcode-view/component/assets.js +8 -0
  84. package/lib/lowcode-components/lowcode-view/component/assets.js.map +1 -1
  85. package/lib/lowcode-components/radar-chart/index.d.ts +51 -0
  86. package/lib/lowcode-components/radar-chart/index.d.ts.map +1 -0
  87. package/lib/lowcode-components/radar-chart/index.js +276 -0
  88. package/lib/lowcode-components/radar-chart/index.js.map +1 -0
  89. package/lib/module/dtmpl-edit-card.d.ts.map +1 -1
  90. package/lib/module/dtmpl-edit-card.js +18 -1
  91. package/lib/module/dtmpl-edit-card.js.map +1 -1
  92. package/lib/module/dtmpl-edit-page.d.ts.map +1 -1
  93. package/lib/module/dtmpl-edit-page.js +19 -2
  94. package/lib/module/dtmpl-edit-page.js.map +1 -1
  95. package/lib/routable/ltmpl-route.d.ts +2 -0
  96. package/lib/routable/ltmpl-route.d.ts.map +1 -1
  97. package/lib/routable/ltmpl-route.js +20 -4
  98. package/lib/routable/ltmpl-route.js.map +1 -1
  99. package/lib/table/act-table.d.ts +2 -0
  100. package/lib/table/act-table.d.ts.map +1 -1
  101. package/lib/table/act-table.js +4 -4
  102. package/lib/table/act-table.js.map +1 -1
  103. package/lib/table/column/column-builder.d.ts.map +1 -1
  104. package/lib/table/column/column-builder.js +23 -8
  105. package/lib/table/column/column-builder.js.map +1 -1
  106. package/lib/table/relation-table.d.ts +7 -0
  107. package/lib/table/relation-table.d.ts.map +1 -1
  108. package/lib/tmpl/control-type-supportor.d.ts.map +1 -1
  109. package/lib/tmpl/control-type-supportor.js +1 -0
  110. package/lib/tmpl/control-type-supportor.js.map +1 -1
  111. package/lib/tmpl/hcservice-v3.d.ts +3 -0
  112. package/lib/tmpl/hcservice-v3.d.ts.map +1 -1
  113. package/lib/tmpl/hcservice-v3.js +61 -0
  114. package/lib/tmpl/hcservice-v3.js.map +1 -1
  115. package/lib/tmpl/interface.d.ts +17 -1
  116. package/lib/tmpl/interface.d.ts.map +1 -1
  117. package/lib/tmpl/interface.js.map +1 -1
  118. package/lib/tmpl/tmpl-config-analysis.js +1 -1
  119. package/lib/tmpl/tmpl-config-analysis.js.map +1 -1
  120. package/lib/units/index.d.ts +3 -1
  121. package/lib/units/index.d.ts.map +1 -1
  122. package/lib/units/index.js +33 -3
  123. package/lib/units/index.js.map +1 -1
  124. package/package.json +4 -1
  125. package/src/aldehyde/controls/entity-select/entity-select.tsx +18 -8
  126. package/src/aldehyde/controls/entry-control.tsx +3 -2
  127. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.css +47 -3
  128. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js +1 -1
  129. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.json +77 -0
  130. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.ttf +0 -0
  131. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff +0 -0
  132. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff2 +0 -0
  133. package/src/aldehyde/controls/select/index.tsx +7 -6
  134. package/src/aldehyde/controls/text/index.less +1 -0
  135. package/src/aldehyde/controls/view-control.tsx +1 -0
  136. package/src/aldehyde/detail/button/edit-button.tsx +21 -22
  137. package/src/aldehyde/detail/button/view-button.tsx +23 -21
  138. package/src/aldehyde/draw-canvas/edit/components/asset-bar/index.less +36 -0
  139. package/src/aldehyde/draw-canvas/edit/components/asset-bar/index.tsx +95 -0
  140. package/src/aldehyde/draw-canvas/edit/components/main-header/index.less +21 -0
  141. package/src/aldehyde/draw-canvas/edit/components/main-header/index.tsx +233 -0
  142. package/src/aldehyde/draw-canvas/edit/components/render/draws/bg-draw.ts +163 -0
  143. package/src/aldehyde/draw-canvas/edit/components/render/draws/contextmenu-draw.ts +307 -0
  144. package/src/aldehyde/draw-canvas/edit/components/render/draws/graph-draw.ts +251 -0
  145. package/src/aldehyde/draw-canvas/edit/components/render/draws/index.ts +7 -0
  146. package/src/aldehyde/draw-canvas/edit/components/render/draws/link-draw.ts +1416 -0
  147. package/src/aldehyde/draw-canvas/edit/components/render/draws/preview-draw.ts +275 -0
  148. package/src/aldehyde/draw-canvas/edit/components/render/draws/ref-line-draw.ts +72 -0
  149. package/src/aldehyde/draw-canvas/edit/components/render/draws/ruler-draw.ts +167 -0
  150. package/src/aldehyde/draw-canvas/edit/components/render/graphs/base-graph.ts +241 -0
  151. package/src/aldehyde/draw-canvas/edit/components/render/graphs/bezier.ts +542 -0
  152. package/src/aldehyde/draw-canvas/edit/components/render/graphs/circle.ts +700 -0
  153. package/src/aldehyde/draw-canvas/edit/components/render/graphs/curve.ts +501 -0
  154. package/src/aldehyde/draw-canvas/edit/components/render/graphs/index.ts +6 -0
  155. package/src/aldehyde/draw-canvas/edit/components/render/graphs/line.ts +494 -0
  156. package/src/aldehyde/draw-canvas/edit/components/render/graphs/rect.ts +681 -0
  157. package/src/aldehyde/draw-canvas/edit/components/render/handlers/drag-handlers.ts +69 -0
  158. package/src/aldehyde/draw-canvas/edit/components/render/handlers/drag-outside-handlers.ts +159 -0
  159. package/src/aldehyde/draw-canvas/edit/components/render/handlers/graph-handlers.ts +108 -0
  160. package/src/aldehyde/draw-canvas/edit/components/render/handlers/index.ts +9 -0
  161. package/src/aldehyde/draw-canvas/edit/components/render/handlers/key-move-handlers.ts +50 -0
  162. package/src/aldehyde/draw-canvas/edit/components/render/handlers/link-handlers.ts +46 -0
  163. package/src/aldehyde/draw-canvas/edit/components/render/handlers/selection-handlers.ts +393 -0
  164. package/src/aldehyde/draw-canvas/edit/components/render/handlers/shutcut-handlers.ts +46 -0
  165. package/src/aldehyde/draw-canvas/edit/components/render/handlers/text-handlers.ts +82 -0
  166. package/src/aldehyde/draw-canvas/edit/components/render/handlers/zoom-handlers.ts +60 -0
  167. package/src/aldehyde/draw-canvas/edit/components/render/index.ts +776 -0
  168. package/src/aldehyde/draw-canvas/edit/components/render/tools/align-tool.ts +91 -0
  169. package/src/aldehyde/draw-canvas/edit/components/render/tools/asset-tool.ts +142 -0
  170. package/src/aldehyde/draw-canvas/edit/components/render/tools/attract-tool.ts +440 -0
  171. package/src/aldehyde/draw-canvas/edit/components/render/tools/copy-tool.ts +269 -0
  172. package/src/aldehyde/draw-canvas/edit/components/render/tools/import-export-tool.ts +603 -0
  173. package/src/aldehyde/draw-canvas/edit/components/render/tools/index.ts +9 -0
  174. package/src/aldehyde/draw-canvas/edit/components/render/tools/link-tool.ts +225 -0
  175. package/src/aldehyde/draw-canvas/edit/components/render/tools/position-tool.ts +194 -0
  176. package/src/aldehyde/draw-canvas/edit/components/render/tools/selection-tool.ts +132 -0
  177. package/src/aldehyde/draw-canvas/edit/components/render/tools/z-index-tool.ts +227 -0
  178. package/src/aldehyde/draw-canvas/edit/components/render/types.ts +291 -0
  179. package/src/aldehyde/draw-canvas/edit/components/render/utils/a-star.ts +116 -0
  180. package/src/aldehyde/draw-canvas/edit/components/render/utils/bezier-scene-func.ts +73 -0
  181. package/src/aldehyde/draw-canvas/edit/components/setting-form/imag-upload.tsx +118 -0
  182. package/src/aldehyde/draw-canvas/edit/components/setting-form/index.tsx +295 -0
  183. package/src/aldehyde/draw-canvas/edit/constant.ts +6 -0
  184. package/src/aldehyde/draw-canvas/edit/index.less +49 -0
  185. package/src/aldehyde/draw-canvas/edit/index.tsx +197 -0
  186. package/src/aldehyde/draw-canvas/view/index.less +60 -0
  187. package/src/aldehyde/draw-canvas/view/index.tsx +48 -0
  188. package/src/aldehyde/draw-canvas/view/view.tsx +114 -0
  189. package/src/aldehyde/form/form-Item-group.tsx +5 -5
  190. package/src/aldehyde/icon/local-aliIcon/iconfont.js +1 -1
  191. package/src/aldehyde/lowcode-components/index.ts +4 -2
  192. package/src/aldehyde/lowcode-components/lowcode-view/component/assets.ts +8 -0
  193. package/src/aldehyde/lowcode-components/radar-chart/index.tsx +323 -0
  194. package/src/aldehyde/module/dtmpl-edit-card.tsx +18 -1
  195. package/src/aldehyde/module/dtmpl-edit-page.tsx +19 -2
  196. package/src/aldehyde/routable/ltmpl-route.tsx +39 -3
  197. package/src/aldehyde/table/act-table.tsx +7 -4
  198. package/src/aldehyde/table/column/column-builder.tsx +29 -9
  199. package/src/aldehyde/tmpl/control-type-supportor.tsx +1 -0
  200. package/src/aldehyde/tmpl/hcservice-v3.tsx +44 -0
  201. package/src/aldehyde/tmpl/interface.tsx +15 -1
  202. package/src/aldehyde/tmpl/tmpl-config-analysis.tsx +1 -1
  203. package/src/aldehyde/units/index.tsx +31 -3
@@ -0,0 +1,1416 @@
1
+ import Konva from 'konva';
2
+ import { LinkType, BaseDraw, Draw, Render, LinkDrawPoint, LinkDrawPair, ManualPointsMap, ManualPoint } from '../types';
3
+ import * as Draws from '../draws';
4
+ import { nanoid } from 'nanoid';
5
+ import aStar from '../utils/a-star';
6
+ import { BezierSceneFunc } from '../utils/bezier-scene-func';
7
+
8
+ // 绘制连线
9
+
10
+ export interface LinkDrawOption {
11
+ size: number
12
+ }
13
+
14
+ // 连接线(临时)
15
+ export interface LinkDrawState {
16
+ linkingLine: {
17
+ group: Konva.Group;
18
+ circle: Konva.Circle;
19
+ line: Konva.Line
20
+ } | null;
21
+ linkType: LinkType; // 连接线类型
22
+ linkManualing: boolean // 是否 正在操作拐点
23
+ }
24
+
25
+ type Area = {
26
+ x1: number;
27
+ y1: number;
28
+ x2: number;
29
+ y2: number;
30
+ }
31
+
32
+ export class LinkDraw extends BaseDraw implements Draw {
33
+ // @ts-ignore
34
+ static override readonly name = 'Link';
35
+ option: LinkDrawOption;
36
+
37
+ state: LinkDrawState = {
38
+ linkingLine: null,
39
+ linkType: "curve",
40
+ linkManualing: false
41
+ }
42
+
43
+ constructor(render: Render, layer: Konva.Layer, option: LinkDrawOption) {
44
+ super(render, layer);
45
+ this.option = option;
46
+ this.group.name(this.constructor.name);
47
+ }
48
+
49
+ // 元素(连接点们)最小区域(绝对值)
50
+ getGroupLinkArea(group?: Konva.Group): Area {
51
+ let area: Area = { x1: 0, y1: 0, x2: 0, y2: 0 };
52
+ if (group) {
53
+ const stageState = this.render.getStageState(); // stage 状态
54
+ const anchors = group.find('.link-anchor');
55
+ const positions = anchors.map((o) => o.absolutePosition());
56
+ area = {
57
+ x1: Math.min(...positions.map((o) => o.x)) - stageState.x,
58
+ y1: Math.min(...positions.map((o) => o.y)) - stageState.y,
59
+ x2: Math.max(...positions.map((o) => o.x)) - stageState.x,
60
+ y2: Math.max(...positions.map((o) => o.y)) - stageState.y
61
+ };
62
+ }
63
+ return area;
64
+ }
65
+
66
+ // 连线不可通过区域
67
+ getGroupForbiddenArea(groupArea: Area, gap: number): Area {
68
+ const area: Area = {
69
+ x1: groupArea.x1 - gap,
70
+ y1: groupArea.y1 - gap,
71
+ x2: groupArea.x2 + gap,
72
+ y2: groupArea.y2 + gap
73
+ };
74
+ return area;
75
+ }
76
+
77
+ // 连线通过区域
78
+ getGroupAccessArea(groupArea: Area, gap: number): Area {
79
+ const area: Area = {
80
+ x1: groupArea.x1 - gap,
81
+ y1: groupArea.y1 - gap,
82
+ x2: groupArea.x2 + gap,
83
+ y2: groupArea.y2 + gap
84
+ };
85
+ return area;
86
+ }
87
+
88
+ // 两区域扩展
89
+ getGroupPairArea(groupArea1: Area, groupArea2: Area): Area {
90
+ const area: Area = {
91
+ x1: Math.min(groupArea1.x1, groupArea2.x1),
92
+ y1: Math.min(groupArea1.y1, groupArea2.y1),
93
+ x2: Math.max(groupArea1.x2, groupArea2.x2),
94
+ y2: Math.max(groupArea1.y2, groupArea2.y2)
95
+ };
96
+ return area;
97
+ }
98
+
99
+ // 两区域最短距离
100
+ getGroupPairDistance(groupArea1: Area, groupArea2: Area): number {
101
+ const xs = [groupArea1.x1, groupArea1.x2, groupArea2.x1, groupArea2.x2];
102
+ const maxX = Math.max(...xs);
103
+ const minX = Math.min(...xs);
104
+ const dx = maxX - minX - (groupArea1.x2 - groupArea1.x1 + (groupArea2.x2 - groupArea2.x1));
105
+ const ys = [groupArea1.y1, groupArea1.y2, groupArea2.y1, groupArea2.y2];
106
+ const maxY = Math.max(...ys);
107
+ const minY = Math.min(...ys);
108
+ const dy = maxY - minY - (groupArea1.y2 - groupArea1.y1 + (groupArea2.y2 - groupArea2.y1));
109
+ return this.render.toBoardValue(Math.min(this.render.bgSize * 0.5, Math.max(dx < 6 ? 6 : dx, dy < 6 ? 6 : dy) * 0.5));
110
+ }
111
+
112
+ // 两区域空隙中点
113
+ getGroupPairCenter(groupArea1: Area, groupArea2: Area): Konva.Vector2d {
114
+ return { x: (groupArea2.x1 + groupArea1.x2) * 0.5, y: (groupArea2.y1 + groupArea1.y2) * 0.5 };
115
+ }
116
+
117
+ // 连接出入口
118
+ getEntry(anchor: Konva.Node, groupForbiddenArea: Area, gap: number): Konva.Vector2d {
119
+ const stageState = this.render.getStageState();
120
+ const fromPos = anchor.absolutePosition();
121
+ // 默认为 起点/终点 位置(无 direction 时的值)
122
+ let x = fromPos.x - stageState.x;
123
+ let y = fromPos.y - stageState.y;
124
+ const direction = anchor.attrs.direction;
125
+ // 定义了 direction 的时候
126
+ if (direction) {
127
+ // 取整 连接点 锚点 旋转角度(保留 1 位小数点)
128
+ const rotate = Math.round(anchor.getAbsoluteRotation() * 10) / 10;
129
+ if (rotate === -45) {
130
+ if (direction === 'top') {
131
+ x = groupForbiddenArea.x1;
132
+ y = groupForbiddenArea.y1;
133
+ } else if (direction === 'bottom') {
134
+ x = groupForbiddenArea.x2;
135
+ y = groupForbiddenArea.y2;
136
+ } else if (direction === 'left') {
137
+ x = groupForbiddenArea.x1;
138
+ y = groupForbiddenArea.y2;
139
+ } else if (direction === 'right') {
140
+ x = groupForbiddenArea.x2;
141
+ y = groupForbiddenArea.y1;
142
+ }
143
+ } else if (rotate === 45) {
144
+ if (direction === 'top') {
145
+ x = groupForbiddenArea.x2;
146
+ y = groupForbiddenArea.y1;
147
+ } else if (direction === 'bottom') {
148
+ x = groupForbiddenArea.x1;
149
+ y = groupForbiddenArea.y2;
150
+ } else if (direction === 'left') {
151
+ x = groupForbiddenArea.x1;
152
+ y = groupForbiddenArea.y1;
153
+ } else if (direction === 'right') {
154
+ x = groupForbiddenArea.x2;
155
+ y = groupForbiddenArea.y2;
156
+ }
157
+ } else if (rotate === 135) {
158
+ if (direction === 'top') {
159
+ x = groupForbiddenArea.x2;
160
+ y = groupForbiddenArea.y2;
161
+ } else if (direction === 'bottom') {
162
+ x = groupForbiddenArea.x1;
163
+ y = groupForbiddenArea.y1;
164
+ } else if (direction === 'left') {
165
+ x = groupForbiddenArea.x2;
166
+ y = groupForbiddenArea.y1;
167
+ } else if (direction === 'right') {
168
+ x = groupForbiddenArea.x1;
169
+ y = groupForbiddenArea.y2;
170
+ }
171
+ } else if (rotate === -135) {
172
+ if (direction === 'top') {
173
+ x = groupForbiddenArea.x1;
174
+ y = groupForbiddenArea.y2;
175
+ } else if (direction === 'bottom') {
176
+ x = groupForbiddenArea.x2;
177
+ y = groupForbiddenArea.y1;
178
+ } else if (direction === 'left') {
179
+ x = groupForbiddenArea.x2;
180
+ y = groupForbiddenArea.y2;
181
+ } else if (direction === 'right') {
182
+ x = groupForbiddenArea.x1;
183
+ y = groupForbiddenArea.y1;
184
+ }
185
+ } else if (rotate > -45 && rotate < 45) {
186
+ const offset = gap * Math.tan((rotate * Math.PI) / 180);
187
+ if (direction === 'top') {
188
+ x = fromPos.x - stageState.x + offset;
189
+ y = groupForbiddenArea.y1;
190
+ } else if (direction === 'bottom') {
191
+ x = fromPos.x - stageState.x - offset;
192
+ y = groupForbiddenArea.y2;
193
+ } else if (direction === 'left') {
194
+ x = groupForbiddenArea.x1;
195
+ y = fromPos.y - stageState.y - offset;
196
+ } else if (direction === 'right') {
197
+ x = groupForbiddenArea.x2;
198
+ y = fromPos.y - stageState.y + offset;
199
+ }
200
+ } else if (rotate > 45 && rotate < 135) {
201
+ const offset = gap * Math.atan(((90 - rotate) * Math.PI) / 180);
202
+ if (direction === 'top') {
203
+ x = groupForbiddenArea.x2;
204
+ y = fromPos.y - stageState.y - offset;
205
+ } else if (direction === 'bottom') {
206
+ x = groupForbiddenArea.x1;
207
+ y = fromPos.y - stageState.y + offset;
208
+ } else if (direction === 'left') {
209
+ x = fromPos.x - stageState.x - offset;
210
+ y = groupForbiddenArea.y1;
211
+ } else if (direction === 'right') {
212
+ x = fromPos.x - stageState.x + offset;
213
+ y = groupForbiddenArea.y2;
214
+ }
215
+ } else if ((rotate > 135 && rotate <= 180) || (rotate >= -180 && rotate < -135)) {
216
+ const offset = gap * Math.tan((rotate * Math.PI) / 180);
217
+ if (direction === 'top') {
218
+ x = fromPos.x - stageState.x - offset;
219
+ y = groupForbiddenArea.y2;
220
+ } else if (direction === 'bottom') {
221
+ x = fromPos.x - stageState.x + offset;
222
+ y = groupForbiddenArea.y1;
223
+ } else if (direction === 'left') {
224
+ x = groupForbiddenArea.x2;
225
+ y = fromPos.y - stageState.y + offset;
226
+ } else if (direction === 'right') {
227
+ x = groupForbiddenArea.x1;
228
+ y = fromPos.y - stageState.y - offset;
229
+ }
230
+ } else if (rotate > -135 && rotate < -45) {
231
+ const offset = gap * Math.atan(((90 + rotate) * Math.PI) / 180);
232
+ if (direction === 'top') {
233
+ x = groupForbiddenArea.x1;
234
+ y = fromPos.y - stageState.y - offset;
235
+ } else if (direction === 'bottom') {
236
+ x = groupForbiddenArea.x2;
237
+ y = fromPos.y - stageState.y + offset;
238
+ } else if (direction === 'left') {
239
+ x = fromPos.x - stageState.x - offset;
240
+ y = groupForbiddenArea.y2;
241
+ } else if (direction === 'right') {
242
+ x = fromPos.x - stageState.x + offset;
243
+ y = groupForbiddenArea.y1;
244
+ }
245
+ }
246
+ }
247
+ return { x, y } as Konva.Vector2d;
248
+ }
249
+
250
+ // 连接点信息
251
+ getAnchorPos(anchor?: Konva.Node): Konva.Vector2d {
252
+ const stageState = this.render.getStageState();
253
+ return anchor ? { x: anchor.absolutePosition().x - stageState.x, y: anchor.absolutePosition().y - stageState.y } : { x: 0, y: 0 };
254
+ }
255
+
256
+ /**
257
+ * 修改当前连接线类型
258
+ * @param linkType LinkType
259
+ */
260
+ changeLinkType(linkType: LinkType) {
261
+ this.state.linkType = linkType;
262
+ this.render.emit('link-type-change', this.state.linkType);
263
+ }
264
+
265
+ override draw() {
266
+ this.clear();
267
+ const stageState = this.render.getStageState();
268
+
269
+ // 所有层级的素材
270
+ const groups = [
271
+ ...(this.render.layer.find('.asset') as Konva.Group[]),
272
+ ...(this.render.layer.find('.sub-asset') as Konva.Group[])
273
+ ];
274
+ const points = groups.reduce((ps, group) => ps.concat(Array.isArray(group.getAttr('points')) ? group.getAttr('points') : []), [] as LinkDrawPoint[]);
275
+ const pairs = points.reduce((ps, point) => ps.concat(point.pairs ? point.pairs.filter((o) => !o.disabled) : []), [] as LinkDrawPair[]);
276
+
277
+ // 连接线
278
+ for (const pair of pairs) {
279
+ // 多层素材,需要排除内部 pair 对
280
+ // pair 也不能为 disabled
281
+ if (pair.from.groupId !== pair.to.groupId && !pair.disabled) {
282
+ const fromGroup = groups.find((o) => o.id() === pair.from.groupId);
283
+ const fromPoint = points.find((o) => o.id === pair.from.pointId);
284
+ const toGroup = groups.find((o) => o.id() === pair.to.groupId);
285
+ const toPoint = points.find((o) => o.id === pair.to.pointId);
286
+ if (pair.linkType === "manual") {
287
+ // 折线
288
+ if (fromGroup && toGroup && fromPoint && toPoint) {
289
+ const fromAnchor = fromGroup.findOne(`#${fromPoint.id}`);
290
+ const toAnchor = toGroup.findOne(`#${toPoint.id}`);
291
+ // 锚点信息
292
+ const fromAnchorPos = this.getAnchorPos(fromAnchor);
293
+ const toAnchorPos = this.getAnchorPos(toAnchor);
294
+ // 拐点(已拐)记录
295
+ const manualPointsMap: ManualPointsMap = fromGroup.getAttr('manualPointsMap') ?? ({} as ManualPointsMap);
296
+ const manualPoints = manualPointsMap[pair.id] ?? ([] as ManualPoint[]);
297
+ // 连接点 + 拐点
298
+ const linkPoints = [
299
+ [this.render.toStageValue(fromAnchorPos.x), this.render.toStageValue(fromAnchorPos.y)],
300
+ ...manualPoints.map((o) => [o.x, o.y]),
301
+ [this.render.toStageValue(toAnchorPos.x), this.render.toStageValue(toAnchorPos.y)]
302
+ ];
303
+
304
+ // 连接线
305
+ const linkLine = new Konva.Arrow({
306
+ name: 'link-line',
307
+ // 用于删除连接线
308
+ groupId: fromGroup.id(),
309
+ pointId: fromPoint.id,
310
+ pairId: pair.id,
311
+ linkType: pair.linkType,
312
+ points: linkPoints.flat(),
313
+ pointerAtBeginning: false,
314
+ pointerAtEnding: false
315
+ });
316
+ linkLine.stroke(this.render.getLinkSettings(linkLine).stroke);
317
+ linkLine.strokeWidth(this.render.getLinkSettings(linkLine).strokeWidth);
318
+ linkLine.hitStrokeWidth(Math.max(this.render.getLinkSettings().strokeWidth, 10));
319
+ linkLine.dash(this.render.linkTool.linkCurrent?.attrs.pairId === pair.id ? [1, 1] : []);
320
+ linkLine.fill(this.render.getLinkSettings(linkLine).stroke);
321
+ linkLine.pointerAtBeginning(this.render.getLinkSettings(linkLine).arrowStart);
322
+ linkLine.pointerAtEnding(this.render.getLinkSettings(linkLine).arrowEnd);
323
+ if (!this.render.config.readonly) {
324
+ linkLine.on('pointerclick', () => this.render.linkTool.select(linkLine));
325
+ linkLine.on('mouseenter', () => {
326
+ linkLine.opacity(0.5);
327
+ document.body.style.cursor = 'pointer';
328
+ });
329
+ linkLine.on('mouseleave', () => {
330
+ linkLine.opacity(1);
331
+ document.body.style.cursor = 'default';
332
+ });
333
+ }
334
+ this.group.add(linkLine);
335
+ if (!this.render.config.readonly) {
336
+ // 正在拖动效果
337
+ const manualingLine = new Konva.Line({
338
+ name: 'manualing-line',
339
+ stroke: '#ff0000',
340
+ strokeWidth: 2,
341
+ points: [],
342
+ dash: [4, 4]
343
+ });
344
+ this.group.add(manualingLine);
345
+ for (let i = 0; i < linkPoints.length - 1; i++) {
346
+ const circle = new Konva.Circle({
347
+ name: 'link-manual-point',
348
+ id: nanoid(),
349
+ pairId: pair.id,
350
+ x: (linkPoints[i][0] + linkPoints[i + 1][0]) / 2,
351
+ y: (linkPoints[i][1] + linkPoints[i + 1][1]) / 2,
352
+ radius: this.render.toStageValue(this.render.bgSize / 2),
353
+ stroke: 'rgba(0,0,255,0.2)',
354
+ strokeWidth: this.render.toStageValue(1),
355
+ linkManualIndex: i // 当前拐点位置
356
+ });
357
+ // hover 效果
358
+ circle.on('mouseenter', () => {
359
+ circle.stroke('rgba(0,0,255,0.8)');
360
+ document.body.style.cursor = 'pointer';
361
+ });
362
+ circle.on('mouseleave', () => {
363
+ if (!circle.attrs.dragStart) {
364
+ circle.stroke('rgba(0,0,255,0.1)');
365
+ document.body.style.cursor = 'default';
366
+ }
367
+ });
368
+
369
+ // 拐点操作
370
+ circle.on('mousedown', () => {
371
+ const pos = circle.getAbsolutePosition();
372
+ // 记录操作开始状态
373
+ circle.setAttrs({
374
+ // 开始坐标
375
+ dragStartX: pos.x,
376
+ dragStartY: pos.y,
377
+ // 正在操作
378
+ dragStart: true
379
+ });
380
+ // 标记状态 - 正在操作拐点
381
+ this.state.linkManualing = true;
382
+ });
383
+ this.render.stage.on('mousemove', () => {
384
+ if (circle.attrs.dragStart) {
385
+ // 正在操作
386
+ const pos = this.render.stage.getPointerPosition();
387
+ if (pos) {
388
+ // 磁贴
389
+ const { pos: transformerPos } = this.render.attractTool.attractPoint(pos);
390
+ // 移动拐点
391
+ circle.setAbsolutePosition(transformerPos);
392
+ // 正在拖动效果
393
+ const tempPoints = [...linkPoints];
394
+ tempPoints.splice(circle.attrs.linkManualIndex + 1, 0, [
395
+ this.render.toStageValue(transformerPos.x - stageState.x),
396
+ this.render.toStageValue(transformerPos.y - stageState.y)
397
+ ]);
398
+ manualingLine.points(tempPoints.flat());
399
+ }
400
+ }
401
+ });
402
+ circle.on('mouseup', () => {
403
+ const pos = circle.getAbsolutePosition();
404
+ if (
405
+ Math.abs(pos.x - circle.attrs.dragStartX) > this.option.size ||
406
+ Math.abs(pos.y - circle.attrs.dragStartY) > this.option.size
407
+ ) {
408
+ // 操作移动距离达到阈值
409
+ const stageState = this.render.getStageState();
410
+ // 记录(插入)拐点
411
+ manualPoints.splice(circle.attrs.linkManualIndex, 0, {
412
+ x: this.render.toStageValue(pos.x - stageState.x),
413
+ y: this.render.toStageValue(pos.y - stageState.y)
414
+ });
415
+ manualPointsMap[pair.id] = manualPoints;
416
+ fromGroup.setAttr('manualPointsMap', manualPointsMap);
417
+ }
418
+
419
+ // 操作结束
420
+ circle.setAttrs({ dragStart: false });
421
+
422
+ // state 操作结束
423
+ this.state.linkManualing = false;
424
+
425
+ // 销毁
426
+ circle.destroy();
427
+ manualingLine.destroy();
428
+
429
+ // 更新历史
430
+ this.render.updateHistory();
431
+
432
+ // 对齐线清除
433
+ this.render.attractTool.alignLinesClear();
434
+
435
+ // 重绘
436
+ this.render.redraw([
437
+ Draws.LinkDraw.name,
438
+ Draws.RulerDraw.name,
439
+ Draws.PreviewDraw.name
440
+ ]);
441
+ })
442
+
443
+ this.group.add(circle);
444
+ }
445
+
446
+ // 拐点(已拐)
447
+ for (let i = 1; i < linkPoints.length - 1; i++) {
448
+ const circle = new Konva.Circle({
449
+ name: 'link-manual-point',
450
+ id: nanoid(),
451
+ pairId: pair.id,
452
+ x: linkPoints[i][0],
453
+ y: linkPoints[i][1],
454
+ radius: this.render.toStageValue(this.render.bgSize / 2),
455
+ stroke: 'rgba(0,100,0,0.2)',
456
+ strokeWidth: this.render.toStageValue(1),
457
+ linkManualIndex: i // 当前拐点位置
458
+ });
459
+
460
+ // hover 效果
461
+ circle.on('mouseenter', () => {
462
+ circle.stroke('rgba(0,100,0,1)');
463
+ document.body.style.cursor = 'pointer';
464
+ });
465
+ circle.on('mouseleave', () => {
466
+ if (!circle.attrs.dragStart) {
467
+ circle.stroke('rgba(0,100,0,0.1)');
468
+ document.body.style.cursor = 'default';
469
+ }
470
+ });
471
+
472
+ // 拐点操作
473
+ circle.on('mousedown', () => {
474
+ const pos = circle.getAbsolutePosition();
475
+ // 记录操作开始状态
476
+ circle.setAttrs({
477
+ dragStartX: pos.x,
478
+ dragStartY: pos.y,
479
+ dragStart: true
480
+ });
481
+
482
+ // 标记状态 - 正在操作拐点
483
+ this.state.linkManualing = true;
484
+ })
485
+ this.render.stage.on('mousemove', () => {
486
+ if (circle.attrs.dragStart) {
487
+ // 正在操作
488
+ const pos = this.render.stage.getPointerPosition();
489
+ if (pos) {
490
+ // 磁贴
491
+ const { pos: transformerPos } = this.render.attractTool.attractPoint(pos);
492
+ // 移动拐点
493
+ circle.setAbsolutePosition(transformerPos);
494
+ // 正在拖动效果
495
+ const tempPoints = [...linkPoints];
496
+ tempPoints[circle.attrs.linkManualIndex] = [
497
+ this.render.toStageValue(transformerPos.x - stageState.x),
498
+ this.render.toStageValue(transformerPos.y - stageState.y)
499
+ ];
500
+ manualingLine.points(tempPoints.flat());
501
+ }
502
+ }
503
+ });
504
+ circle.on('mouseup', () => {
505
+ const pos = circle.getAbsolutePosition();
506
+ if (
507
+ Math.abs(pos.x - circle.attrs.dragStartX) > this.option.size ||
508
+ Math.abs(pos.y - circle.attrs.dragStartY) > this.option.size
509
+ ) {
510
+ // 操作移动距离达到阈值
511
+ const stageState = this.render.getStageState();
512
+ // 记录(更新)拐点
513
+ manualPoints[circle.attrs.linkManualIndex - 1] = {
514
+ x: this.render.toStageValue(pos.x - stageState.x),
515
+ y: this.render.toStageValue(pos.y - stageState.y)
516
+ };
517
+ manualPointsMap[pair.id] = manualPoints;
518
+ fromGroup.setAttr('manualPointsMap', manualPointsMap);
519
+ }
520
+ // 操作结束
521
+ circle.setAttrs({ dragStart: false });
522
+ // state 操作结束
523
+ this.state.linkManualing = false;
524
+ // 销毁
525
+ circle.destroy();
526
+ manualingLine.destroy();
527
+ // 更新历史
528
+ this.render.updateHistory();
529
+ // 对齐线清除
530
+ this.render.attractTool.alignLinesClear();
531
+ // 重绘
532
+ this.render.redraw([
533
+ Draws.LinkDraw.name,
534
+ Draws.RulerDraw.name,
535
+ Draws.PreviewDraw.name
536
+ ]);
537
+ })
538
+ this.group.add(circle);
539
+ }
540
+ }
541
+ }
542
+ } else if (pair.linkType === "curve") {
543
+ // 曲线
544
+ if (fromGroup && toGroup && fromPoint && toPoint) {
545
+ const fromAnchor = fromGroup.findOne(`#${fromPoint.id}`);
546
+ const toAnchor = toGroup.findOne(`#${toPoint.id}`);
547
+ // 锚点信息
548
+ const fromAnchorPos = this.getAnchorPos(fromAnchor);
549
+ const toAnchorPos = this.getAnchorPos(toAnchor);
550
+ // 拐点(已拐)记录
551
+ const manualPointsMap: ManualPointsMap = fromGroup.getAttr('manualPointsMap') ?? ({} as ManualPointsMap);
552
+ const manualPoints = manualPointsMap[pair.id] ?? ([] as ManualPoint[]);
553
+ // 连接点 + 拐点
554
+ const linkPoints = [
555
+ [
556
+ this.render.toStageValue(fromAnchorPos.x),
557
+ this.render.toStageValue(fromAnchorPos.y)
558
+ ],
559
+ ...manualPoints.map((o) => [o.x, o.y]),
560
+ [this.render.toStageValue(toAnchorPos.x), this.render.toStageValue(toAnchorPos.y)]
561
+ ];
562
+
563
+ // 连接线
564
+ const linkLine = new Konva.Arrow({
565
+ name: 'link-line',
566
+ // 用于删除连接线
567
+ groupId: fromGroup.id(),
568
+ pointId: fromPoint.id,
569
+ pairId: pair.id,
570
+ linkType: pair.linkType,
571
+ points: linkPoints.flat(),
572
+ pointerAtBeginning: false,
573
+ pointerAtEnding: false
574
+ });
575
+ linkLine.stroke(this.render.getLinkSettings(linkLine).stroke);
576
+ linkLine.strokeWidth(this.render.getLinkSettings(linkLine).strokeWidth);
577
+ linkLine.hitStrokeWidth(Math.max(this.render.getLinkSettings().strokeWidth, 10));
578
+ linkLine.dash(this.render.linkTool.linkCurrent?.attrs.pairId === pair.id ? [1, 1] : []);
579
+ linkLine.fill(this.render.getLinkSettings(linkLine).stroke);
580
+ linkLine.pointerAtBeginning(this.render.getLinkSettings(linkLine).arrowStart);
581
+ linkLine.pointerAtEnding(this.render.getLinkSettings(linkLine).arrowEnd);
582
+ linkLine.tension(this.render.getLinkSettings(linkLine).tension || 0);
583
+ if (!this.render.config.readonly) {
584
+ linkLine.on('pointerclick', () => this.render.linkTool.select(linkLine));
585
+ linkLine.on('mouseenter', () => {
586
+ linkLine.opacity(0.5);
587
+ document.body.style.cursor = 'pointer';
588
+ });
589
+ linkLine.on('mouseleave', () => {
590
+ linkLine.opacity(1);
591
+ document.body.style.cursor = 'default';
592
+ });
593
+ }
594
+ this.group.add(linkLine);
595
+ if (!this.render.config.readonly) {
596
+ // 正在拖动效果
597
+ const manualingLine = new Konva.Arrow({
598
+ name: 'manualing-line',
599
+ stroke: '#ff0000',
600
+ strokeWidth: 2,
601
+ points: [],
602
+ dash: [4, 4],
603
+ pointerAtBeginning: false,
604
+ pointerAtEnding: false,
605
+ tension: this.render.getLinkSettings(linkLine).tension
606
+ });
607
+ this.group.add(manualingLine);
608
+ // 拐点(待拐)
609
+ for (let i = 0; i < linkPoints.length - 1; i++) {
610
+ const circle = new Konva.Circle({
611
+ name: 'link-manual-point',
612
+ id: nanoid(),
613
+ pairId: pair.id,
614
+ x: (linkPoints[i][0] + linkPoints[i + 1][0]) / 2,
615
+ y: (linkPoints[i][1] + linkPoints[i + 1][1]) / 2,
616
+ radius: this.render.toStageValue(this.render.bgSize / 2),
617
+ stroke: 'rgba(0,0,255,0.2)',
618
+ strokeWidth: this.render.toStageValue(1),
619
+ linkManualIndex: i // 当前拐点位置
620
+ });
621
+ // hover 效果
622
+ circle.on('mouseenter', () => {
623
+ circle.stroke('rgba(0,0,255,0.8)');
624
+ document.body.style.cursor = 'pointer';
625
+ });
626
+ circle.on('mouseleave', () => {
627
+ if (!circle.attrs.dragStart) {
628
+ circle.stroke('rgba(0,0,255,0.1)');
629
+ document.body.style.cursor = 'default';
630
+ }
631
+ });
632
+ // 拐点操作
633
+ circle.on('mousedown', () => {
634
+ const pos = circle.getAbsolutePosition();
635
+ // 记录操作开始状态
636
+ circle.setAttrs({
637
+ // 开始坐标
638
+ dragStartX: pos.x,
639
+ dragStartY: pos.y,
640
+ // 正在操作
641
+ dragStart: true
642
+ });
643
+ // 标记状态 - 正在操作拐点
644
+ this.state.linkManualing = true;
645
+ });
646
+ this.render.stage.on('mousemove', () => {
647
+ if (circle.attrs.dragStart) {
648
+ // 正在操作
649
+ const pos = this.render.stage.getPointerPosition();
650
+ if (pos) {
651
+ // 磁贴
652
+ const { pos: transformerPos } = this.render.attractTool.attractPoint(pos);
653
+ // 移动拐点
654
+ circle.setAbsolutePosition(transformerPos);
655
+ // 正在拖动效果
656
+ const tempPoints = [...linkPoints];
657
+ tempPoints.splice(circle.attrs.linkManualIndex + 1, 0, [
658
+ this.render.toStageValue(transformerPos.x - stageState.x),
659
+ this.render.toStageValue(transformerPos.y - stageState.y)
660
+ ]);
661
+ manualingLine.points(tempPoints.flat());
662
+ }
663
+ }
664
+ });
665
+ circle.on('mouseup', () => {
666
+ const pos = circle.getAbsolutePosition();
667
+ if (
668
+ Math.abs(pos.x - circle.attrs.dragStartX) > this.option.size ||
669
+ Math.abs(pos.y - circle.attrs.dragStartY) > this.option.size
670
+ ) {
671
+ // 操作移动距离达到阈值
672
+ const stageState = this.render.getStageState();
673
+ // 记录(插入)拐点
674
+ manualPoints.splice(circle.attrs.linkManualIndex, 0, {
675
+ x: this.render.toStageValue(pos.x - stageState.x),
676
+ y: this.render.toStageValue(pos.y - stageState.y)
677
+ });
678
+ manualPointsMap[pair.id] = manualPoints;
679
+ fromGroup.setAttr('manualPointsMap', manualPointsMap);
680
+ }
681
+ // 操作结束
682
+ circle.setAttrs({ dragStart: false });
683
+ // state 操作结束
684
+ this.state.linkManualing = false;
685
+ // 销毁
686
+ circle.destroy();
687
+ manualingLine.destroy();
688
+ // 更新历史
689
+ this.render.updateHistory();
690
+ // 对齐线清除
691
+ this.render.attractTool.alignLinesClear();
692
+ // 重绘
693
+ this.render.redraw([
694
+ Draws.LinkDraw.name,
695
+ Draws.RulerDraw.name,
696
+ Draws.PreviewDraw.name
697
+ ]);
698
+ });
699
+ this.group.add(circle);
700
+ }
701
+ // 拐点(已拐)
702
+ for (let i = 1; i < linkPoints.length - 1; i++) {
703
+ const circle = new Konva.Circle({
704
+ name: 'link-manual-point',
705
+ id: nanoid(),
706
+ pairId: pair.id,
707
+ x: linkPoints[i][0],
708
+ y: linkPoints[i][1],
709
+ radius: this.render.toStageValue(this.render.bgSize / 2),
710
+ stroke: 'rgba(0,100,0,0.2)',
711
+ strokeWidth: this.render.toStageValue(1),
712
+ linkManualIndex: i // 当前拐点位置
713
+ });
714
+ // hover 效果
715
+ circle.on('mouseenter', () => {
716
+ circle.stroke('rgba(0,100,0,1)');
717
+ document.body.style.cursor = 'pointer';
718
+ });
719
+ circle.on('mouseleave', () => {
720
+ if (!circle.attrs.dragStart) {
721
+ circle.stroke('rgba(0,100,0,0.1)');
722
+ document.body.style.cursor = 'default';
723
+ }
724
+ });
725
+ // 拐点操作
726
+ circle.on('mousedown', () => {
727
+ const pos = circle.getAbsolutePosition();
728
+ // 记录操作开始状态
729
+ circle.setAttrs({
730
+ dragStartX: pos.x,
731
+ dragStartY: pos.y,
732
+ dragStart: true
733
+ });
734
+ // 标记状态 - 正在操作拐点
735
+ this.state.linkManualing = true;
736
+ });
737
+ this.render.stage.on('mousemove', () => {
738
+ if (circle.attrs.dragStart) {
739
+ // 正在操作
740
+ const pos = this.render.stage.getPointerPosition();
741
+ if (pos) {
742
+ // 磁贴
743
+ const { pos: transformerPos } = this.render.attractTool.attractPoint(pos);
744
+ // 移动拐点
745
+ circle.setAbsolutePosition(transformerPos);
746
+ // 正在拖动效果
747
+ const tempPoints = [...linkPoints];
748
+ tempPoints[circle.attrs.linkManualIndex] = [
749
+ this.render.toStageValue(transformerPos.x - stageState.x),
750
+ this.render.toStageValue(transformerPos.y - stageState.y)
751
+ ];
752
+ manualingLine.points(tempPoints.flat());
753
+ }
754
+ }
755
+ });
756
+ circle.on('mouseup', () => {
757
+ const pos = circle.getAbsolutePosition();
758
+ if (
759
+ Math.abs(pos.x - circle.attrs.dragStartX) > this.option.size ||
760
+ Math.abs(pos.y - circle.attrs.dragStartY) > this.option.size
761
+ ) {
762
+ // 操作移动距离达到阈值
763
+ const stageState = this.render.getStageState();
764
+ // 记录(更新)拐点
765
+ manualPoints[circle.attrs.linkManualIndex - 1] = {
766
+ x: this.render.toStageValue(pos.x - stageState.x),
767
+ y: this.render.toStageValue(pos.y - stageState.y)
768
+ };
769
+ manualPointsMap[pair.id] = manualPoints;
770
+ fromGroup.setAttr('manualPointsMap', manualPointsMap);
771
+ }
772
+ // 操作结束
773
+ circle.setAttrs({ dragStart: false });
774
+ // state 操作结束
775
+ this.state.linkManualing = false;
776
+ // 销毁
777
+ circle.destroy();
778
+ manualingLine.destroy();
779
+ // 更新历史
780
+ this.render.updateHistory();
781
+ // 对齐线清除
782
+ this.render.attractTool.alignLinesClear();
783
+ // 重绘
784
+ this.render.redraw([
785
+ Draws.LinkDraw.name,
786
+ Draws.RulerDraw.name,
787
+ Draws.PreviewDraw.name
788
+ ]);
789
+ })
790
+ this.group.add(circle);
791
+ }
792
+ }
793
+ }
794
+ } else if (pair.linkType === "bezier") {
795
+ if (fromGroup && toGroup && fromPoint && toPoint) {
796
+ const fromAnchor = fromGroup.findOne(`#${fromPoint.id}`);
797
+ const toAnchor = toGroup.findOne(`#${toPoint.id}`);
798
+ // 锚点信息
799
+ const fromAnchorPos = this.getAnchorPos(fromAnchor);
800
+ const toAnchorPos = this.getAnchorPos(toAnchor);
801
+ // 拐点(已拐)记录
802
+ const manualPointsMap: ManualPointsMap = fromGroup.getAttr('manualPointsMap') ?? ({} as ManualPointsMap);
803
+ const manualPoints = manualPointsMap[pair.id] ?? ([] as ManualPoint[]);
804
+ // 连接点 + 拐点
805
+ const linkPoints = [
806
+ [this.render.toStageValue(fromAnchorPos.x), this.render.toStageValue(fromAnchorPos.y)],
807
+ ...manualPoints.map((o) => [o.x, o.y]),
808
+ [this.render.toStageValue(toAnchorPos.x), this.render.toStageValue(toAnchorPos.y)]
809
+ ];
810
+ // 连接线
811
+ const linkLine = new Konva.Arrow({
812
+ name: 'link-line',
813
+ // 用于删除连接线
814
+ groupId: fromGroup.id(),
815
+ pointId: fromPoint.id,
816
+ pairId: pair.id,
817
+ linkType: pair.linkType,
818
+ points: linkPoints.flat(),
819
+ pointerAtBeginning: false,
820
+ pointerAtEnding: false,
821
+ sceneFunc: BezierSceneFunc
822
+ });
823
+ linkLine.stroke(this.render.getLinkSettings(linkLine).stroke);
824
+ linkLine.strokeWidth(this.render.getLinkSettings(linkLine).strokeWidth);
825
+ linkLine.hitStrokeWidth(Math.max(this.render.getLinkSettings().strokeWidth, 10));
826
+ linkLine.dash(this.render.linkTool.linkCurrent?.attrs.pairId === pair.id ? [1, 1] : []);
827
+ linkLine.fill(this.render.getLinkSettings(linkLine).stroke);
828
+ linkLine.pointerAtBeginning(this.render.getLinkSettings(linkLine).arrowStart);
829
+ linkLine.pointerAtEnding(this.render.getLinkSettings(linkLine).arrowEnd);
830
+ if (!this.render.config.readonly) {
831
+ linkLine.on('pointerclick', () => this.render.linkTool.select(linkLine));
832
+ linkLine.on('mouseenter', () => {
833
+ linkLine.opacity(0.5);
834
+ document.body.style.cursor = 'pointer';
835
+ });
836
+ linkLine.on('mouseleave', () => {
837
+ linkLine.opacity(1);
838
+ document.body.style.cursor = 'default';
839
+ });
840
+ }
841
+ this.group.add(linkLine);
842
+ if (!this.render.config.readonly) {
843
+ // 正在拖动效果
844
+ const manualingLine = new Konva.Arrow({
845
+ name: 'manualing-line',
846
+ stroke: '#ff0000',
847
+ strokeWidth: 2,
848
+ points: [],
849
+ dash: [4, 4],
850
+ pointerAtBeginning: false,
851
+ pointerAtEnding: false,
852
+ sceneFunc: BezierSceneFunc
853
+ });
854
+ this.group.add(manualingLine);
855
+ // 拐点
856
+ if (linkPoints.length <= 3) {
857
+ // 拐点(待拐)
858
+ for (let i = 0; i < linkPoints.length - 1; i++) {
859
+ const circle = new Konva.Circle({
860
+ name: 'link-manual-point',
861
+ id: nanoid(),
862
+ pairId: pair.id,
863
+ x: (linkPoints[i][0] + linkPoints[i + 1][0]) / 2,
864
+ y: (linkPoints[i][1] + linkPoints[i + 1][1]) / 2,
865
+ radius: this.render.toStageValue(this.render.bgSize / 2),
866
+ stroke: 'rgba(0,0,255,0.2)',
867
+ strokeWidth: this.render.toStageValue(1),
868
+ linkManualIndex: i // 当前拐点位置
869
+ });
870
+ // hover 效果
871
+ circle.on('mouseenter', () => {
872
+ circle.stroke('rgba(0,0,255,0.8)');
873
+ document.body.style.cursor = 'pointer';
874
+ });
875
+ circle.on('mouseleave', () => {
876
+ if (!circle.attrs.dragStart) {
877
+ circle.stroke('rgba(0,0,255,0.1)');
878
+ document.body.style.cursor = 'default';
879
+ }
880
+ });
881
+ // 拐点操作
882
+ circle.on('mousedown', () => {
883
+ const pos = circle.getAbsolutePosition();
884
+ // 记录操作开始状态
885
+ circle.setAttrs({
886
+ // 开始坐标
887
+ dragStartX: pos.x,
888
+ dragStartY: pos.y,
889
+ // 正在操作
890
+ dragStart: true
891
+ });
892
+ // 标记状态 - 正在操作拐点
893
+ this.state.linkManualing = true;
894
+ });
895
+ this.render.stage.on('mousemove', () => {
896
+ if (circle.attrs.dragStart) {
897
+ // 正在操作
898
+ const pos = this.render.stage.getPointerPosition();
899
+ if (pos) {
900
+ // 磁贴
901
+ const { pos: transformerPos } = this.render.attractTool.attractPoint(pos);
902
+ // 移动拐点
903
+ circle.setAbsolutePosition(transformerPos);
904
+ // 正在拖动效果
905
+ const tempPoints = [...linkPoints];
906
+ tempPoints.splice(circle.attrs.linkManualIndex + 1, 0, [
907
+ this.render.toStageValue(transformerPos.x - stageState.x),
908
+ this.render.toStageValue(transformerPos.y - stageState.y)
909
+ ]);
910
+ manualingLine.points(tempPoints.flat());
911
+ }
912
+ }
913
+ });
914
+ circle.on('mouseup', () => {
915
+ const pos = circle.getAbsolutePosition();
916
+ if (
917
+ Math.abs(pos.x - circle.attrs.dragStartX) > this.option.size ||
918
+ Math.abs(pos.y - circle.attrs.dragStartY) > this.option.size
919
+ ) {
920
+ // 操作移动距离达到阈值
921
+ const stageState = this.render.getStageState();
922
+ // 记录(插入)拐点
923
+ manualPoints.splice(circle.attrs.linkManualIndex, 0, {
924
+ x: this.render.toStageValue(pos.x - stageState.x),
925
+ y: this.render.toStageValue(pos.y - stageState.y)
926
+ });
927
+ manualPointsMap[pair.id] = manualPoints;
928
+ fromGroup.setAttr('manualPointsMap', manualPointsMap);
929
+ }
930
+ // 操作结束
931
+ circle.setAttrs({ dragStart: false });
932
+ // state 操作结束
933
+ this.state.linkManualing = false;
934
+ // 销毁
935
+ circle.destroy();
936
+ manualingLine.destroy();
937
+ // 更新历史
938
+ this.render.updateHistory();
939
+ // 对齐线清除
940
+ this.render.attractTool.alignLinesClear();
941
+ // 重绘
942
+ this.render.redraw([
943
+ Draws.LinkDraw.name,
944
+ Draws.RulerDraw.name,
945
+ Draws.PreviewDraw.name
946
+ ]);
947
+ });
948
+ this.group.add(circle);
949
+ }
950
+ }
951
+ // 拐点(已拐)
952
+ for (let i = 1; i < linkPoints.length - 1; i++) {
953
+ const circle = new Konva.Circle({
954
+ name: 'link-manual-point',
955
+ id: nanoid(),
956
+ pairId: pair.id,
957
+ x: linkPoints[i][0],
958
+ y: linkPoints[i][1],
959
+ radius: this.render.toStageValue(this.render.bgSize / 2),
960
+ stroke: 'rgba(0,100,0,0.2)',
961
+ strokeWidth: this.render.toStageValue(1),
962
+ linkManualIndex: i // 当前拐点位置
963
+ });
964
+ // hover 效果
965
+ circle.on('mouseenter', () => {
966
+ circle.stroke('rgba(0,100,0,1)');
967
+ document.body.style.cursor = 'pointer';
968
+ });
969
+ circle.on('mouseleave', () => {
970
+ if (!circle.attrs.dragStart) {
971
+ circle.stroke('rgba(0,100,0,0.1)');
972
+ document.body.style.cursor = 'default';
973
+ }
974
+ });
975
+ // 拐点操作
976
+ circle.on('mousedown', () => {
977
+ const pos = circle.getAbsolutePosition();
978
+ // 记录操作开始状态
979
+ circle.setAttrs({
980
+ dragStartX: pos.x,
981
+ dragStartY: pos.y,
982
+ dragStart: true
983
+ });
984
+ // 标记状态 - 正在操作拐点
985
+ this.state.linkManualing = true;
986
+ });
987
+ this.render.stage.on('mousemove', () => {
988
+ if (circle.attrs.dragStart) {
989
+ // 正在操作
990
+ const pos = this.render.stage.getPointerPosition();
991
+ if (pos) {
992
+ // 磁贴
993
+ const { pos: transformerPos } = this.render.attractTool.attractPoint(pos);
994
+ // 移动拐点
995
+ circle.setAbsolutePosition(transformerPos);
996
+ // 正在拖动效果
997
+ const tempPoints = [...linkPoints]
998
+ tempPoints[circle.attrs.linkManualIndex] = [
999
+ this.render.toStageValue(transformerPos.x - stageState.x),
1000
+ this.render.toStageValue(transformerPos.y - stageState.y)
1001
+ ];
1002
+ manualingLine.points(tempPoints.flat());
1003
+ }
1004
+ }
1005
+ });
1006
+ circle.on('mouseup', () => {
1007
+ const pos = circle.getAbsolutePosition();
1008
+ if (
1009
+ Math.abs(pos.x - circle.attrs.dragStartX) > this.option.size ||
1010
+ Math.abs(pos.y - circle.attrs.dragStartY) > this.option.size
1011
+ ) {
1012
+ // 操作移动距离达到阈值
1013
+ const stageState = this.render.getStageState();
1014
+ // 记录(更新)拐点
1015
+ manualPoints[circle.attrs.linkManualIndex - 1] = {
1016
+ x: this.render.toStageValue(pos.x - stageState.x),
1017
+ y: this.render.toStageValue(pos.y - stageState.y)
1018
+ };
1019
+ manualPointsMap[pair.id] = manualPoints;
1020
+ fromGroup.setAttr('manualPointsMap', manualPointsMap);
1021
+ }
1022
+ // 操作结束
1023
+ circle.setAttrs({ dragStart: false });
1024
+ // state 操作结束
1025
+ this.state.linkManualing = false;
1026
+ // 销毁
1027
+ circle.destroy();
1028
+ manualingLine.destroy();
1029
+ // 更新历史
1030
+ this.render.updateHistory();
1031
+ // 对齐线清除
1032
+ this.render.attractTool.alignLinesClear();
1033
+ // 重绘
1034
+ this.render.redraw([
1035
+ Draws.LinkDraw.name,
1036
+ Draws.RulerDraw.name,
1037
+ Draws.PreviewDraw.name
1038
+ ]);
1039
+ });
1040
+ this.group.add(circle);
1041
+ }
1042
+ }
1043
+ }
1044
+ } else if (pair.linkType === "straight") {
1045
+ // 直线
1046
+ if (fromGroup && toGroup && fromPoint && toPoint) {
1047
+ const fromAnchor = fromGroup.findOne(`#${fromPoint.id}`);
1048
+ const toAnchor = toGroup.findOne(`#${toPoint.id}`);
1049
+ // 锚点信息
1050
+ const fromAnchorPos = this.getAnchorPos(fromAnchor);
1051
+ const toAnchorPos = this.getAnchorPos(toAnchor);
1052
+ const linkLine = new Konva.Arrow({
1053
+ name: 'link-line',
1054
+ // 用于删除连接线
1055
+ groupId: fromGroup.id(),
1056
+ pointId: fromPoint.id,
1057
+ pairId: pair.id,
1058
+ linkType: pair.linkType,
1059
+ points: [
1060
+ [this.render.toStageValue(fromAnchorPos.x), this.render.toStageValue(fromAnchorPos.y)],
1061
+ [this.render.toStageValue(toAnchorPos.x), this.render.toStageValue(toAnchorPos.y)]
1062
+ ].flat(),
1063
+ pointerAtBeginning: false,
1064
+ pointerAtEnding: false
1065
+ });
1066
+ linkLine.stroke(this.render.getLinkSettings(linkLine).stroke);
1067
+ linkLine.strokeWidth(this.render.getLinkSettings(linkLine).strokeWidth);
1068
+ linkLine.hitStrokeWidth(Math.max(this.render.getLinkSettings().strokeWidth, 10));
1069
+ linkLine.dash(this.render.linkTool.linkCurrent?.attrs.pairId === pair.id ? [1, 1] : []);
1070
+ linkLine.fill(this.render.getLinkSettings(linkLine).stroke);
1071
+ linkLine.pointerAtBeginning(this.render.getLinkSettings(linkLine).arrowStart);
1072
+ linkLine.pointerAtEnding(this.render.getLinkSettings(linkLine).arrowEnd);
1073
+
1074
+ if (!this.render.config.readonly) {
1075
+ linkLine.on('pointerclick', () => this.render.linkTool.select(linkLine));
1076
+ linkLine.on('mouseenter', () => {
1077
+ linkLine.opacity(0.5);
1078
+ document.body.style.cursor = 'pointer';
1079
+ });
1080
+ linkLine.on('mouseleave', () => {
1081
+ linkLine.opacity(1);
1082
+ document.body.style.cursor = 'default';
1083
+ });
1084
+ }
1085
+ this.group.add(linkLine);
1086
+ }
1087
+ } else {
1088
+ // 自动
1089
+ // 最小区域
1090
+ const fromGroupLinkArea = this.getGroupLinkArea(fromGroup);
1091
+ const toGroupLinkArea = this.getGroupLinkArea(toGroup);
1092
+ // 两区域的最短距离
1093
+ const groupDistance = this.getGroupPairDistance(fromGroupLinkArea, toGroupLinkArea);
1094
+ // 不可通过区域
1095
+ const fromGroupForbiddenArea = this.getGroupForbiddenArea(fromGroupLinkArea, groupDistance - 2);
1096
+ const toGroupForbiddenArea = this.getGroupForbiddenArea(toGroupLinkArea, groupDistance - 2);
1097
+ // 两区域扩展
1098
+ const groupForbiddenArea = this.getGroupPairArea(fromGroupForbiddenArea, toGroupForbiddenArea);
1099
+ // 连线通过区域
1100
+ const groupAccessArea = this.getGroupPairArea(this.getGroupAccessArea(fromGroupForbiddenArea, groupDistance), this.getGroupAccessArea(toGroupForbiddenArea, groupDistance));
1101
+ if (fromGroup && toGroup && fromPoint && toPoint) {
1102
+ const fromAnchor = fromGroup.findOne(`#${fromPoint.id}`);
1103
+ const toAnchor = toGroup.findOne(`#${toPoint.id}`);
1104
+ // 锚点信息
1105
+ const fromAnchorPos = this.getAnchorPos(fromAnchor);
1106
+ const toAnchorPos = this.getAnchorPos(toAnchor);
1107
+ if (fromAnchor && toAnchor) {
1108
+ // 连接出入口
1109
+ const fromEntry: Konva.Vector2d = this.getEntry(fromAnchor, fromGroupForbiddenArea, groupDistance);
1110
+ const toEntry: Konva.Vector2d = this.getEntry(toAnchor, toGroupForbiddenArea, groupDistance);
1111
+ type matrixPoint = { x: number, y: number, type?: 'from' | 'to' | 'from-entry' | 'to-entry' };
1112
+ // 可能点
1113
+ let matrixPoints: matrixPoint[] = [];
1114
+ // 通过区域 四角
1115
+ matrixPoints.push({ x: groupAccessArea.x1, y: groupAccessArea.y1 });
1116
+ matrixPoints.push({ x: groupAccessArea.x2, y: groupAccessArea.y2 });
1117
+ matrixPoints.push({ x: groupAccessArea.x1, y: groupAccessArea.y2 });
1118
+ matrixPoints.push({ x: groupAccessArea.x2, y: groupAccessArea.y1 });
1119
+ // 最小区域 四角
1120
+ matrixPoints.push({ x: groupForbiddenArea.x1, y: groupForbiddenArea.y1 });
1121
+ matrixPoints.push({ x: groupForbiddenArea.x2, y: groupForbiddenArea.y2 });
1122
+ matrixPoints.push({ x: groupForbiddenArea.x1, y: groupForbiddenArea.y2 });
1123
+ matrixPoints.push({ x: groupForbiddenArea.x2, y: groupForbiddenArea.y1 });
1124
+ // 起点
1125
+ matrixPoints.push({ ...fromAnchorPos, type: 'from' });
1126
+ // 起点 出口
1127
+ matrixPoints.push({ ...fromEntry, type: 'from-entry' });
1128
+ // 终点
1129
+ matrixPoints.push({ ...toAnchorPos, type: 'to' });
1130
+ // 终点 入口
1131
+ matrixPoints.push({ ...toEntry, type: 'to-entry' });
1132
+ // 通过区域 中点
1133
+ matrixPoints.push(this.getGroupPairCenter(fromGroupForbiddenArea, toGroupForbiddenArea));
1134
+ // 去重
1135
+ matrixPoints = matrixPoints.reduce(
1136
+ (arr, item) => {
1137
+ if (item.type === void 0) {
1138
+ if (arr.findIndex((o) => o.x === item.x && o.y === item.y) < 0) {
1139
+ arr.push(item);
1140
+ }
1141
+ } else {
1142
+ const idx = arr.findIndex((o) => o.x === item.x && o.y === item.y)
1143
+ if (idx > -1) {
1144
+ arr.splice(idx, 1);
1145
+ }
1146
+ arr.push(item);
1147
+ }
1148
+ return arr;
1149
+ },
1150
+ [] as typeof matrixPoints
1151
+ );
1152
+ const columns = [
1153
+ ...matrixPoints.map((o) => o.x),
1154
+ // 增加列
1155
+ fromGroupForbiddenArea.x1,
1156
+ fromGroupForbiddenArea.x2,
1157
+ toGroupForbiddenArea.x1,
1158
+ toGroupForbiddenArea.x2
1159
+ ].sort((a, b) => a - b);
1160
+ // 去重
1161
+ for (let x = columns.length - 1; x > 0; x--) {
1162
+ if (columns[x] === columns[x - 1]) {
1163
+ columns.splice(x, 1);
1164
+ }
1165
+ }
1166
+ const rows = [
1167
+ ...matrixPoints.map((o) => o.y),
1168
+ // 增加行
1169
+ fromGroupForbiddenArea.y1,
1170
+ fromGroupForbiddenArea.y2,
1171
+ toGroupForbiddenArea.y1,
1172
+ toGroupForbiddenArea.y2
1173
+ ].sort((a, b) => a - b);
1174
+ // 去重
1175
+ for (let y = rows.length - 1; y > 0; y--) {
1176
+ if (rows[y] === rows[y - 1]) {
1177
+ rows.splice(y, 1);
1178
+ }
1179
+ }
1180
+ // 屏蔽区域(序号)
1181
+ const columnFromStart = columns.findIndex((o) => o === fromGroupForbiddenArea.x1);
1182
+ const columnFromEnd = columns.findIndex((o) => o === fromGroupForbiddenArea.x2);
1183
+ const rowFromStart = rows.findIndex((o) => o === fromGroupForbiddenArea.y1);
1184
+ const rowFromEnd = rows.findIndex((o) => o === fromGroupForbiddenArea.y2);
1185
+ const columnToStart = columns.findIndex((o) => o === toGroupForbiddenArea.x1);
1186
+ const columnToEnd = columns.findIndex((o) => o === toGroupForbiddenArea.x2);
1187
+ const rowToStart = rows.findIndex((o) => o === toGroupForbiddenArea.y1);
1188
+ const rowToEnd = rows.findIndex((o) => o === toGroupForbiddenArea.y2);
1189
+ // 算法矩阵起点、终点
1190
+ let matrixStart: Konva.Vector2d | null = null;
1191
+ let matrixEnd: Konva.Vector2d | null = null;
1192
+ // 算法地图矩阵
1193
+ const matrix: Array<number[]> = [];
1194
+ for (let y = 0; y < rows.length; y++) {
1195
+ // 新增行
1196
+ if (matrix[y] === void 0) {
1197
+ matrix[y] = [];
1198
+ }
1199
+ for (let x = 0; x < columns.length; x++) {
1200
+ // 不可通过区域
1201
+ if (
1202
+ x >= columnFromStart &&
1203
+ x <= columnFromEnd &&
1204
+ y >= rowFromStart &&
1205
+ y <= rowFromEnd
1206
+ ) {
1207
+ matrix[y][x] = 2;
1208
+ } else if (
1209
+ x >= columnToStart &&
1210
+ x <= columnToEnd &&
1211
+ y >= rowToStart &&
1212
+ y <= rowToEnd
1213
+ ) {
1214
+ matrix[y][x] = 2;
1215
+ } else {
1216
+ // 可通过区域
1217
+ matrix[y][x] = 0;
1218
+ }
1219
+ // 出口、入口 -> 算法 起点、终点
1220
+ if (columns[x] === fromEntry.x && rows[y] === fromEntry.y) {
1221
+ matrix[y][x] = 1;
1222
+ matrixStart = { x, y };
1223
+ }
1224
+ if (columns[x] === toEntry.x && rows[y] === toEntry.y) {
1225
+ matrix[y][x] = 1;
1226
+ matrixEnd = { x, y };
1227
+ }
1228
+ // 没有定义方向(给于十字可通过区域)
1229
+ // 如,从:
1230
+ // 1 1 1
1231
+ // 1 0 1
1232
+ // 1 1 1
1233
+ // 变成:
1234
+ // 1 0 1
1235
+ // 0 0 0
1236
+ // 1 0 1
1237
+ if (!fromAnchor.attrs.direction) {
1238
+ if (columns[x] === fromEntry.x || rows[y] === fromEntry.y) {
1239
+ if (
1240
+ x >= columnFromStart &&
1241
+ x <= columnFromEnd &&
1242
+ y >= rowFromStart &&
1243
+ y <= rowFromEnd
1244
+ ) {
1245
+ matrix[y][x] = 1;
1246
+ }
1247
+ }
1248
+ }
1249
+ if (!toAnchor.attrs.direction) {
1250
+ if (columns[x] === toEntry.x || rows[y] === toEntry.y) {
1251
+ if (
1252
+ x >= columnToStart &&
1253
+ x <= columnToEnd &&
1254
+ y >= rowToStart &&
1255
+ y <= rowToEnd
1256
+ ) {
1257
+ matrix[y][x] = 1;
1258
+ }
1259
+ }
1260
+ }
1261
+ }
1262
+ }
1263
+
1264
+ if (matrixStart && matrixEnd) {
1265
+ const way = aStar({ from: matrixStart, to: matrixEnd, matrix, maxCost: 2 });
1266
+ const linkLine = new Konva.Arrow({
1267
+ name: 'link-line',
1268
+ // 用于删除连接线
1269
+ groupId: fromGroup.id(),
1270
+ pointId: fromPoint.id,
1271
+ pairId: pair.id,
1272
+ linkType: pair.linkType, // 记录 连接线 类型
1273
+ points: [
1274
+ [this.render.toStageValue(fromAnchorPos.x), this.render.toStageValue(fromAnchorPos.y)], // 补充 起点
1275
+ ...way.map((o) => [this.render.toStageValue(columns[o.x]), this.render.toStageValue(rows[o.y])]),
1276
+ [this.render.toStageValue(toAnchorPos.x), this.render.toStageValue(toAnchorPos.y)] // 补充 终点
1277
+ ].flat(),
1278
+ pointerAtBeginning: false,
1279
+ pointerAtEnding: false
1280
+ });
1281
+ linkLine.stroke(this.render.getLinkSettings(linkLine).stroke);
1282
+ linkLine.strokeWidth(this.render.getLinkSettings(linkLine).strokeWidth);
1283
+ linkLine.hitStrokeWidth(Math.max(this.render.getLinkSettings().strokeWidth, 10));
1284
+ linkLine.dash(this.render.linkTool.linkCurrent?.attrs.pairId === pair.id ? [1, 1] : []);
1285
+ linkLine.fill(this.render.getLinkSettings(linkLine).stroke);
1286
+ linkLine.pointerAtBeginning(this.render.getLinkSettings(linkLine).arrowStart);
1287
+ linkLine.pointerAtEnding(this.render.getLinkSettings(linkLine).arrowEnd);
1288
+ if (!this.render.config.readonly) {
1289
+ linkLine.on('pointerclick', () => this.render.linkTool.select(linkLine));
1290
+ linkLine.on('mouseenter', () => {
1291
+ linkLine.opacity(0.5);
1292
+ document.body.style.cursor = 'pointer';
1293
+ });
1294
+ linkLine.on('mouseleave', () => {
1295
+ linkLine.opacity(1);
1296
+ document.body.style.cursor = 'default';
1297
+ });
1298
+ }
1299
+ this.group.add(linkLine);
1300
+ }
1301
+ }
1302
+ }
1303
+ }
1304
+ }
1305
+ }
1306
+
1307
+ if (!this.render.config.readonly) {
1308
+ // 连接点
1309
+ for (const point of points) {
1310
+ const group = groups.find((o) => o.id() === point.groupId);
1311
+ // 非 选择中
1312
+ if (group && !group.getAttr('selected')) {
1313
+ const anchor = this.render.layer.findOne(`#${point.id}`);
1314
+ if (anchor) {
1315
+ const circle = new Konva.Circle({
1316
+ name: 'link-point',
1317
+ id: point.id,
1318
+ groupId: group.id(),
1319
+ x: this.render.toStageValue(anchor.absolutePosition().x - stageState.x),
1320
+ y: this.render.toStageValue(anchor.absolutePosition().y - stageState.y),
1321
+ radius: this.render.toStageValue(this.option.size),
1322
+ stroke: 'rgba(255,0,0,0.2)',
1323
+ strokeWidth: this.render.toStageValue(1),
1324
+ // 调整中,不显示连接点
1325
+ opacity: point.visible && !(this.render.draws[Draws.GraphDraw.name] as Draws.GraphDraw).state.adjusting ? 1 : 0
1326
+ });
1327
+ // hover 效果
1328
+ circle.on('mouseenter', () => {
1329
+ circle.stroke('rgba(255,0,0,0.5)');
1330
+ circle.opacity(1);
1331
+ document.body.style.cursor = 'pointer';
1332
+ });
1333
+ circle.on('mouseleave', () => {
1334
+ circle.stroke('rgba(255,0,0,0.2)');
1335
+ circle.opacity(0);
1336
+ document.body.style.cursor = 'default';
1337
+ });
1338
+ circle.on('mousedown', () => {
1339
+ this.render.selectionTool.selectingClear();
1340
+ this.render.linkTool.selectingClear();
1341
+ const pos = this.render.stage.getPointerPosition();
1342
+ if (pos) {
1343
+ // 临时 连接线 画
1344
+ this.state.linkingLine = {
1345
+ group: group,
1346
+ circle: circle,
1347
+ line: new Konva.Line({
1348
+ name: 'linking-line',
1349
+ points: [
1350
+ [circle.x(), circle.y()],
1351
+ [
1352
+ this.render.toStageValue(pos.x - stageState.x),
1353
+ this.render.toStageValue(pos.y - stageState.y)
1354
+ ]
1355
+ ].flat(),
1356
+ stroke: 'blue',
1357
+ strokeWidth: 1
1358
+ })
1359
+ };
1360
+ this.layer.add(this.state.linkingLine.line);
1361
+ }
1362
+ });
1363
+ circle.on('mouseup', () => {
1364
+ if (this.state.linkingLine) {
1365
+ const line = this.state.linkingLine;
1366
+ // 不同连接点
1367
+ if (line.circle.id() !== circle.id()) {
1368
+ const toGroup = groups.find((o) => o.id() === circle.getAttr('groupId'));
1369
+ if (toGroup) {
1370
+ const fromPoint = points.find((o) => o.id === line.circle.id());
1371
+ if (fromPoint) {
1372
+ const toPoint = points.find((o) => o.id === line.circle.id());
1373
+ if (toPoint) {
1374
+ if (Array.isArray(fromPoint.pairs)) {
1375
+ fromPoint.pairs = [
1376
+ ...fromPoint.pairs,
1377
+ {
1378
+ id: nanoid(),
1379
+ from: {
1380
+ groupId: line.group.id(),
1381
+ pointId: line.circle.id()
1382
+ },
1383
+ to: {
1384
+ groupId: circle.getAttr('groupId'),
1385
+ pointId: circle.id()
1386
+ },
1387
+ linkType: this.state.linkType // 记录 连接线 类型
1388
+ }
1389
+ ];
1390
+ }
1391
+ // 更新历史
1392
+ this.render.updateHistory();
1393
+ // 对齐线清除
1394
+ this.render.attractTool.alignLinesClear();
1395
+ // 重绘
1396
+ this.render.redraw([
1397
+ Draws.LinkDraw.name,
1398
+ Draws.RulerDraw.name,
1399
+ Draws.PreviewDraw.name
1400
+ ]);
1401
+ }
1402
+ }
1403
+ }
1404
+ }
1405
+ // 临时 连接线 移除
1406
+ this.state.linkingLine?.line.destroy();
1407
+ this.state.linkingLine = null;
1408
+ }
1409
+ });
1410
+ this.group.add(circle);
1411
+ }
1412
+ }
1413
+ }
1414
+ }
1415
+ }
1416
+ }