aldehyde 0.2.472 → 0.2.474

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 (116) hide show
  1. package/lib/controls/entity-select/entity-select.js +1 -1
  2. package/lib/controls/entity-select/entity-select.js.map +1 -1
  3. package/lib/controls/entry-control.js +2 -2
  4. package/lib/controls/entry-control.js.map +1 -1
  5. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.css +47 -3
  6. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js +12 -12
  7. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js.map +1 -1
  8. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.json +77 -0
  9. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.ttf +0 -0
  10. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff +0 -0
  11. package/lib/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff2 +0 -0
  12. package/lib/draw-canvas/edit/components/asset-bar/index.d.ts +5 -0
  13. package/lib/draw-canvas/edit/components/asset-bar/index.d.ts.map +1 -0
  14. package/lib/draw-canvas/edit/components/asset-bar/index.js +78 -0
  15. package/lib/draw-canvas/edit/components/asset-bar/index.js.map +1 -0
  16. package/lib/draw-canvas/edit/components/asset-bar/index.less +36 -0
  17. package/lib/draw-canvas/edit/components/main-header/index.d.ts +14 -0
  18. package/lib/draw-canvas/edit/components/main-header/index.d.ts.map +1 -0
  19. package/lib/draw-canvas/edit/components/main-header/index.js +163 -0
  20. package/lib/draw-canvas/edit/components/main-header/index.js.map +1 -0
  21. package/lib/draw-canvas/edit/components/main-header/index.less +21 -0
  22. package/lib/draw-canvas/edit/components/render/index.d.ts +86 -0
  23. package/lib/draw-canvas/edit/components/render/index.d.ts.map +1 -0
  24. package/lib/draw-canvas/edit/components/render/index.js +686 -0
  25. package/lib/draw-canvas/edit/components/render/index.js.map +1 -0
  26. package/lib/draw-canvas/edit/components/render/types.d.ts +243 -0
  27. package/lib/draw-canvas/edit/components/render/types.d.ts.map +1 -0
  28. package/lib/draw-canvas/edit/components/render/types.js +66 -0
  29. package/lib/draw-canvas/edit/components/render/types.js.map +1 -0
  30. package/lib/draw-canvas/edit/components/setting-form/index.d.ts +19 -0
  31. package/lib/draw-canvas/edit/components/setting-form/index.d.ts.map +1 -0
  32. package/lib/draw-canvas/edit/components/setting-form/index.js +164 -0
  33. package/lib/draw-canvas/edit/components/setting-form/index.js.map +1 -0
  34. package/lib/draw-canvas/edit/index.d.ts +5 -0
  35. package/lib/draw-canvas/edit/index.d.ts.map +1 -0
  36. package/lib/draw-canvas/edit/index.js +112 -0
  37. package/lib/draw-canvas/edit/index.js.map +1 -0
  38. package/lib/draw-canvas/edit/index.less +34 -0
  39. package/lib/form/form-Item-group.d.ts.map +1 -1
  40. package/lib/form/form-Item-group.js +1 -1
  41. package/lib/form/form-Item-group.js.map +1 -1
  42. package/lib/icon/local-aliIcon/iconfont.js +5 -5
  43. package/lib/icon/local-aliIcon/iconfont.js.map +1 -1
  44. package/lib/table/relation-table.d.ts +4 -0
  45. package/lib/table/relation-table.d.ts.map +1 -1
  46. package/lib/tmpl/hcservice-v3.d.ts +1 -0
  47. package/lib/tmpl/hcservice-v3.d.ts.map +1 -1
  48. package/lib/tmpl/hcservice-v3.js +27 -0
  49. package/lib/tmpl/hcservice-v3.js.map +1 -1
  50. package/lib/tmpl/interface.d.ts +4 -0
  51. package/lib/tmpl/interface.d.ts.map +1 -1
  52. package/lib/tmpl/interface.js.map +1 -1
  53. package/lib/units/index.d.ts +1 -0
  54. package/lib/units/index.d.ts.map +1 -1
  55. package/lib/units/index.js +16 -0
  56. package/lib/units/index.js.map +1 -1
  57. package/package.json +1 -1
  58. package/src/aldehyde/controls/entity-select/entity-select.tsx +1 -1
  59. package/src/aldehyde/controls/entry-control.tsx +2 -2
  60. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.css +47 -3
  61. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.js +1 -1
  62. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.json +77 -0
  63. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.ttf +0 -0
  64. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff +0 -0
  65. package/src/aldehyde/controls/icon-selector/icon/phonenode-menu-icon/iconfont.woff2 +0 -0
  66. package/src/aldehyde/draw-canvas/edit/components/asset-bar/index.less +36 -0
  67. package/src/aldehyde/draw-canvas/edit/components/asset-bar/index.tsx +93 -0
  68. package/src/aldehyde/draw-canvas/edit/components/main-header/index.less +21 -0
  69. package/src/aldehyde/draw-canvas/edit/components/main-header/index.tsx +187 -0
  70. package/src/aldehyde/draw-canvas/edit/components/render/draws/bg-draw.ts +98 -0
  71. package/src/aldehyde/draw-canvas/edit/components/render/draws/contextmenu-draw.ts +307 -0
  72. package/src/aldehyde/draw-canvas/edit/components/render/draws/graph-draw.ts +251 -0
  73. package/src/aldehyde/draw-canvas/edit/components/render/draws/index.ts +7 -0
  74. package/src/aldehyde/draw-canvas/edit/components/render/draws/link-draw.ts +1416 -0
  75. package/src/aldehyde/draw-canvas/edit/components/render/draws/preview-draw.ts +257 -0
  76. package/src/aldehyde/draw-canvas/edit/components/render/draws/ref-line-draw.ts +72 -0
  77. package/src/aldehyde/draw-canvas/edit/components/render/draws/ruler-draw.ts +167 -0
  78. package/src/aldehyde/draw-canvas/edit/components/render/graphs/base-graph.ts +241 -0
  79. package/src/aldehyde/draw-canvas/edit/components/render/graphs/bezier.ts +542 -0
  80. package/src/aldehyde/draw-canvas/edit/components/render/graphs/circle.ts +700 -0
  81. package/src/aldehyde/draw-canvas/edit/components/render/graphs/curve.ts +501 -0
  82. package/src/aldehyde/draw-canvas/edit/components/render/graphs/index.ts +6 -0
  83. package/src/aldehyde/draw-canvas/edit/components/render/graphs/line.ts +494 -0
  84. package/src/aldehyde/draw-canvas/edit/components/render/graphs/rect.ts +681 -0
  85. package/src/aldehyde/draw-canvas/edit/components/render/handlers/drag-handlers.ts +69 -0
  86. package/src/aldehyde/draw-canvas/edit/components/render/handlers/drag-outside-handlers.ts +162 -0
  87. package/src/aldehyde/draw-canvas/edit/components/render/handlers/graph-handlers.ts +108 -0
  88. package/src/aldehyde/draw-canvas/edit/components/render/handlers/index.ts +9 -0
  89. package/src/aldehyde/draw-canvas/edit/components/render/handlers/key-move-handlers.ts +50 -0
  90. package/src/aldehyde/draw-canvas/edit/components/render/handlers/link-handlers.ts +46 -0
  91. package/src/aldehyde/draw-canvas/edit/components/render/handlers/selection-handlers.ts +385 -0
  92. package/src/aldehyde/draw-canvas/edit/components/render/handlers/shutcut-handlers.ts +46 -0
  93. package/src/aldehyde/draw-canvas/edit/components/render/handlers/text-handlers.ts +82 -0
  94. package/src/aldehyde/draw-canvas/edit/components/render/handlers/zoom-handlers.ts +60 -0
  95. package/src/aldehyde/draw-canvas/edit/components/render/index.ts +768 -0
  96. package/src/aldehyde/draw-canvas/edit/components/render/tools/align-tool.ts +91 -0
  97. package/src/aldehyde/draw-canvas/edit/components/render/tools/asset-tool.ts +142 -0
  98. package/src/aldehyde/draw-canvas/edit/components/render/tools/attract-tool.ts +440 -0
  99. package/src/aldehyde/draw-canvas/edit/components/render/tools/copy-tool.ts +269 -0
  100. package/src/aldehyde/draw-canvas/edit/components/render/tools/import-export-tool.ts +603 -0
  101. package/src/aldehyde/draw-canvas/edit/components/render/tools/index.ts +9 -0
  102. package/src/aldehyde/draw-canvas/edit/components/render/tools/link-tool.ts +225 -0
  103. package/src/aldehyde/draw-canvas/edit/components/render/tools/position-tool.ts +212 -0
  104. package/src/aldehyde/draw-canvas/edit/components/render/tools/selection-tool.ts +132 -0
  105. package/src/aldehyde/draw-canvas/edit/components/render/tools/z-index-tool.ts +227 -0
  106. package/src/aldehyde/draw-canvas/edit/components/render/types.ts +287 -0
  107. package/src/aldehyde/draw-canvas/edit/components/render/utils/a-star.ts +116 -0
  108. package/src/aldehyde/draw-canvas/edit/components/render/utils/bezier-scene-func.ts +73 -0
  109. package/src/aldehyde/draw-canvas/edit/components/setting-form/index.tsx +200 -0
  110. package/src/aldehyde/draw-canvas/edit/index.less +34 -0
  111. package/src/aldehyde/draw-canvas/edit/index.tsx +138 -0
  112. package/src/aldehyde/form/form-Item-group.tsx +1 -0
  113. package/src/aldehyde/icon/local-aliIcon/iconfont.js +1 -1
  114. package/src/aldehyde/tmpl/hcservice-v3.tsx +14 -0
  115. package/src/aldehyde/tmpl/interface.tsx +2 -0
  116. package/src/aldehyde/units/index.tsx +15 -0
@@ -0,0 +1,385 @@
1
+ import Konva from 'konva';
2
+ import { Render } from '../index';
3
+ import { Handler, LinkDrawPoint, LinkDrawPair, ManualPointsMap, MouseButton, ManualPoint } from '../types';
4
+ import { GraphDraw, LinkDraw, PreviewDraw, RulerDraw } from '../draws';
5
+
6
+ export class SelectionHandlers implements Handler {
7
+ // @ts-ignore
8
+ static readonly name = 'Selection';
9
+ private render: Render;
10
+ constructor(render: Render) {
11
+ this.render = render;
12
+ }
13
+ // selectRect 拉动的开始和结束坐标
14
+ selectRectStartX = 0;
15
+ selectRectStartY = 0;
16
+ selectRectEndX = 0;
17
+ selectRectEndY = 0;
18
+ selecting = false; // 是否正在使用 selectRect
19
+ transformerMousedownPos: Konva.Vector2d = { x: 0, y: 0 }; // 拖动前的位置
20
+ alignLines: Konva.Line[] = []; // 对齐线
21
+ alignLinesClear() { // 对齐线清除
22
+ for (const line of this.alignLines) {
23
+ line.destroy();
24
+ }
25
+ this.alignLines = [];
26
+ }
27
+ // 通过偏移量移动【目标节点】
28
+ selectingNodesPositionByOffset(offset: Konva.Vector2d) {
29
+ for (const node of this.render.selectionTool.selectingNodes) {
30
+ if (node.attrs.nodeMousedownPos) {
31
+ const x = node.attrs.nodeMousedownPos.x + offset.x;
32
+ const y = node.attrs.nodeMousedownPos.y + offset.y;
33
+ node.x(x);
34
+ node.y(y);
35
+ }
36
+ }
37
+ }
38
+ // 重置【目标节点】的 nodeMousedownPos
39
+ selectingNodesPositionReset() {
40
+ for (const node of this.render.selectionTool.selectingNodes) {
41
+ if (node.attrs.nodeMousedownPos) {
42
+ node.attrs.nodeMousedownPos.x = node.x();
43
+ node.attrs.nodeMousedownPos.y = node.y();
44
+ }
45
+ }
46
+ }
47
+ // 重置 transformer 状态
48
+ transformerStateReset() {
49
+ // 记录 transformer pos
50
+ const rect = this.render.transformer.findOne('.back')!.getClientRect();
51
+ this.transformerMousedownPos = { x: rect.x, y: rect.y };
52
+ const groups = this.render.transformer.nodes(); // 记录 拐点 移动之前的 坐标
53
+ const points = groups.reduce((ps, group) => ps.concat(Array.isArray(group.getAttr('points')) ? group.getAttr('points') : []), [] as LinkDrawPoint[]);
54
+ const pairs = points.reduce((ps, point) => ps.concat(point.pairs ? point.pairs.filter((o) => !o.disabled) : []), [] as LinkDrawPair[]);
55
+ for (const pair of pairs) {
56
+ const fromGroup = groups.find((o) => o.id() === pair.from.groupId);
57
+ const toGroup = groups.find((o) => o.id() === pair.to.groupId);
58
+ if (fromGroup && toGroup) { // 必须成对移动才记录
59
+ // 移动之前的 坐标
60
+ fromGroup.setAttr('manualPointsMapBefore', fromGroup.getAttr('manualPointsMap') ?? ({} as ManualPointsMap));
61
+ }
62
+ }
63
+ }
64
+
65
+ reset() { // 重置
66
+ this.render.attractTool.alignLinesClear(); // 对齐线清除
67
+ this.transformerStateReset();
68
+ this.selectingNodesPositionReset();
69
+ }
70
+
71
+ /**
72
+ * 矩阵变换:坐标系中的一个点,围绕着另外一个点进行旋转
73
+ * - - - - - - - -
74
+ * |x`| |cos -sin| |x-a| |a|
75
+ * | | = | | | | +
76
+ * |y`| |sin cos| |y-b| |b|
77
+ * - - - - - - - -
78
+ * @param x 目标节点坐标 x
79
+ * @param y 目标节点坐标 y
80
+ * @param centerX 围绕的点坐标 x
81
+ * @param centerY 围绕的点坐标 y
82
+ * @param angle 旋转角度
83
+ * @returns
84
+ */
85
+ rotatePoint(x: number, y: number, centerX: number, centerY: number, angle: number) {
86
+ const radians = (angle * Math.PI) / 180; // 将角度转换为弧度
87
+ // 计算旋转后的坐标
88
+ const newX = Math.cos(radians) * (x - centerX) - Math.sin(radians) * (y - centerY) + centerX;
89
+ const newY = Math.sin(radians) * (x - centerX) + Math.cos(radians) * (y - centerY) + centerY;
90
+ return { x: newX, y: newY };
91
+ }
92
+
93
+ lastRotation = 0;
94
+
95
+ handlers = { // 选择相关
96
+ stage: {
97
+ mousedown: (e: Konva.KonvaEventObject<GlobalEventHandlersEventMap['mousedown']>) => {
98
+ if (!this.render.graphType) { // 并非在新建并拖动图形
99
+ const parent = e.target.getParent();
100
+ if (e.target === this.render.stage) {
101
+ // 点击空白处 清除选择
102
+ this.render.selectionTool.selectingClear();
103
+ this.render.linkTool.selectingClear();
104
+ // 选择框(判断 ctrlKey 为了排查 mac 拖动快捷键)
105
+ if (e.evt.button === MouseButton["左键"] && !e.evt.ctrlKey) {
106
+ const pos = this.render.stage.getPointerPosition();
107
+ if (pos) { // 初始化状态值
108
+ this.selectRectStartX = pos.x;
109
+ this.selectRectStartY = pos.y;
110
+ this.selectRectEndX = pos.x;
111
+ this.selectRectEndY = pos.y;
112
+ }
113
+ // 初始化大小
114
+ this.render.selectRect.width(0);
115
+ this.render.selectRect.height(0);
116
+ this.selecting = true; // 开始选择
117
+ }
118
+ this.render.linkTool.pointsVisible(false); // 隐藏连接点
119
+ } else if (parent instanceof Konva.Transformer) {
120
+ // transformer 点击事件交给 transformer 自己的 handler
121
+ } else if (parent instanceof Konva.Group) {
122
+ // (判断 ctrlKey 为了排查 mac 拖动快捷键)
123
+ if (e.evt.button === MouseButton["左键"] && !e.evt.ctrlKey) {
124
+ if (!this.render.ignore(parent) && !this.render.ignoreDraw(e.target)) {
125
+ if (e.evt.ctrlKey || e.evt.metaKey) { // 新增多选
126
+ this.render.selectionTool.select([...this.render.selectionTool.selectingNodes, parent]);
127
+ } else { // 单选
128
+ this.render.selectionTool.select([parent]);
129
+ // 单选时无法通过 transformer 获取拖动初始位置 transformerMousedownPos
130
+ // 此时直接取目标的 getClientRect 位置
131
+ const rect = parent.getClientRect();
132
+ this.transformerMousedownPos = { x: rect.x, y: rect.y };
133
+ }
134
+ }
135
+ } else {
136
+ this.render.selectionTool.selectingClear();
137
+ }
138
+ }
139
+ }
140
+ },
141
+ mousemove: () => {
142
+ const stageState = this.render.getStageState();
143
+ if (this.selecting) { // 选择框
144
+ // 选择区域中
145
+ const pos = this.render.stage.getPointerPosition();
146
+ if (pos) { // 选择移动后的坐标
147
+ this.selectRectEndX = pos.x;
148
+ this.selectRectEndY = pos.y;
149
+ }
150
+ // 调整【选择框】的位置和大小
151
+ this.render.selectRect.setAttrs({
152
+ visible: true,
153
+ x: this.render.toStageValue(Math.min(this.selectRectStartX, this.selectRectEndX) - stageState.x),
154
+ y: this.render.toStageValue(Math.min(this.selectRectStartY, this.selectRectEndY) - stageState.y),
155
+ width: this.render.toStageValue(Math.abs(this.selectRectEndX - this.selectRectStartX)),
156
+ height: this.render.toStageValue(Math.abs(this.selectRectEndY - this.selectRectStartY))
157
+ });
158
+ }
159
+ },
160
+ mouseup: () => { // 选择框 重叠计算
161
+ const box = this.render.selectRect.getClientRect();
162
+ if (box.width > 0 && box.height > 0) {
163
+ // 区域有面积 获取所有图形
164
+ const shapes = this.render.layer.getChildren((node) => !this.render.ignore(node));
165
+ // 提取重叠部分
166
+ const selected = shapes.filter((shape) => Konva.Util.haveIntersection(box, shape.getClientRect()));
167
+ this.render.selectionTool.select(selected); // 多选
168
+ }
169
+ // 重置
170
+ this.render.selectRect.setAttrs({ visible: false, x: 0, y: 0, width: 0, height: 0 });
171
+ this.selecting = false; // 选择区域结束
172
+ }
173
+ },
174
+ transformer: { // 记录初始状态
175
+ mousedown: (e: Konva.KonvaEventObject<GlobalEventHandlersEventMap['mousedown']>) => {
176
+ const anchor = this.render.transformer.getActiveAnchor();
177
+ if (!anchor) { // 非变换
178
+ if (e.evt.ctrlKey || e.evt.metaKey) { // 选择
179
+ if (this.render.selectionTool.selectingNodes.length > 0) {
180
+ const pos = this.render.stage.getPointerPosition();
181
+ if (pos) {
182
+ const keeps: Konva.Node[] = [];
183
+ const removes: Konva.Node[] = [];
184
+ // 从高到低,逐个判断 已选节点 和 鼠标点击位置 是否重叠
185
+ let finded = false;
186
+ for (const node of this.render.selectionTool.selectingNodes.sort((a, b) => b.zIndex() - a.zIndex())) {
187
+ if (!finded && Konva.Util.haveIntersection(node.getClientRect(), { ...pos, width: 1, height: 1 })) {
188
+ // 记录需要移除选择的节点
189
+ removes.unshift(node);
190
+ finded = true;
191
+ } else {
192
+ keeps.unshift(node);
193
+ }
194
+ }
195
+ if (removes.length > 0) { // 取消选择
196
+ this.render.selectionTool.select(keeps);
197
+ } else {
198
+ // 从高到低,逐个判断 未选节点 和 鼠标点击位置 是否重叠
199
+ let finded = false;
200
+ const adds: Konva.Node[] = [];
201
+ for (const node of this.render.layer.getChildren().filter((node) => !this.render.ignore(node)).sort((a, b) => b.zIndex() - a.zIndex())) {
202
+ if (!finded && Konva.Util.haveIntersection(node.getClientRect(), { ...pos, width: 1, height: 1 })) {
203
+ // 记录需要增加选择的节点
204
+ adds.unshift(node);
205
+ finded = true;
206
+ }
207
+ }
208
+ if (adds.length > 0) { // 新增选择
209
+ this.render.selectionTool.select([...this.render.selectionTool.selectingNodes, ...adds]);
210
+ }
211
+ }
212
+ }
213
+ }
214
+ } else {
215
+ if (this.render.selectionTool.selectingNodes.length > 0) {
216
+ // 拖动前 重置状态
217
+ this.reset();
218
+ }
219
+ }
220
+ } else {
221
+ // 变换前 重置状态
222
+ this.reset();
223
+ }
224
+ },
225
+ transformstart: () => {
226
+ const back = this.render.transformer.findOne('.back');
227
+ if (back) {
228
+ this.lastRotation = back.getAbsoluteRotation();
229
+ }
230
+ },
231
+ transform: () => { // 旋转时,拐点也要跟着动
232
+ const back = this.render.transformer.findOne('.back');
233
+ if (back) {
234
+ const stageState = this.render.getStageState();
235
+ const { x, y, width, height } = back.getClientRect();
236
+ const rotation = back.getAbsoluteRotation() - this.lastRotation;
237
+ const centerX = x + width / 2;
238
+ const centerY = y + height / 2;
239
+ const groups = this.render.transformer.nodes();
240
+ const points = groups.reduce((ps, group) => ps.concat(Array.isArray(group.getAttr('points')) ? group.getAttr('points') : []), [] as LinkDrawPoint[]);
241
+ const pairs = points.reduce((ps, point) => ps.concat(point.pairs ? point.pairs.filter((o) => !o.disabled) : []), [] as LinkDrawPair[]);
242
+ for (const pair of pairs) {
243
+ const fromGroup = groups.find((o) => o.id() === pair.from.groupId);
244
+ const toGroup = groups.find((o) => o.id() === pair.to.groupId);
245
+ if (fromGroup && toGroup) { // 必须成对移动才记录
246
+ if (fromGroup.attrs.manualPointsMap && fromGroup.attrs.manualPointsMapBefore) {
247
+ let manualPoints = fromGroup.attrs.manualPointsMap[pair.id];
248
+ const manualPointsBefore = fromGroup.attrs.manualPointsMapBefore[pair.id];
249
+ if (Array.isArray(manualPoints) && Array.isArray(manualPointsBefore)) {
250
+ manualPoints = manualPointsBefore.map((o: ManualPoint) => {
251
+ const { x, y } = this.rotatePoint(this.render.toBoardValue(o.x) + stageState.x, this.render.toBoardValue(o.y) + stageState.y, centerX, centerY, rotation);
252
+ return { x: this.render.toStageValue(x - stageState.x), y: this.render.toStageValue(y - stageState.y) };
253
+ });
254
+ fromGroup.setAttr('manualPointsMap', { ...fromGroup.attrs.manualPointsMap, [pair.id]: manualPoints });
255
+ }
256
+ }
257
+ }
258
+ }
259
+ // 更新坐标记录
260
+ for (const group of groups) {
261
+ this.render.setAssetSettings(group, this.render.getAssetSettings(group), false);
262
+ }
263
+ this.render.emit('asset-position-change', groups);
264
+ this.render.emit('asset-rotation-change', groups);
265
+ }
266
+ this.render.redraw([GraphDraw.name, LinkDraw.name, PreviewDraw.name]);
267
+ },
268
+ transformend: () => {
269
+ this.reset(); // 变换结束 重置状态
270
+ this.render.updateHistory(); // 更新历史
271
+ this.render.redraw([GraphDraw.name, LinkDraw.name, PreviewDraw.name]);
272
+ },
273
+ dragstart: () => {
274
+ },
275
+ dragmove: () => { // 拖动
276
+ const rect = this.render.transformer.findOne('.back')!.getClientRect();
277
+ const { pos: transformerPos, isAttract } = this.render.attractTool.attractTransformer(rect);
278
+ if (isAttract) { // 磁吸偏移
279
+ this.selectingNodesPositionByOffset({
280
+ x: this.render.toStageValue(transformerPos.x - this.transformerMousedownPos.x),
281
+ y: this.render.toStageValue(transformerPos.y - this.transformerMousedownPos.y)
282
+ });
283
+ }
284
+ const groups = this.render.transformer.nodes(); // 拐点也需要移动
285
+ const points = groups.reduce((ps, group) => ps.concat(Array.isArray(group.getAttr('points')) ? group.getAttr('points') : []), [] as LinkDrawPoint[]);
286
+ const pairs = points.reduce((ps, point) => ps.concat(point.pairs ? point.pairs.filter((o) => !o.disabled) : []), [] as LinkDrawPair[]);
287
+ for (const pair of pairs) {
288
+ const fromGroup = groups.find((o) => o.id() === pair.from.groupId);
289
+ const toGroup = groups.find((o) => o.id() === pair.to.groupId);
290
+ if (fromGroup && toGroup) { // 必须成对移动才记录
291
+ if (fromGroup.attrs.manualPointsMap && fromGroup.attrs.manualPointsMapBefore) {
292
+ let manualPoints = fromGroup.attrs.manualPointsMap[pair.id];
293
+ const manualPointsBefore = fromGroup.attrs.manualPointsMapBefore[pair.id];
294
+ if (Array.isArray(manualPoints) && Array.isArray(manualPointsBefore)) {
295
+ manualPoints = isAttract
296
+ ? manualPointsBefore.map((o: ManualPoint) => ({
297
+ x: o.x + this.render.toStageValue(transformerPos.x - this.transformerMousedownPos.x),
298
+ y: o.y + this.render.toStageValue(transformerPos.y - this.transformerMousedownPos.y)
299
+ }))
300
+ : manualPointsBefore.map((o: ManualPoint) => ({
301
+ x: o.x + this.render.toStageValue(rect.x - this.transformerMousedownPos.x),
302
+ y: o.y + this.render.toStageValue(rect.y - this.transformerMousedownPos.y)
303
+ }));
304
+ fromGroup.setAttr('manualPointsMap', { ...fromGroup.attrs.manualPointsMap, [pair.id]: manualPoints });
305
+ }
306
+ }
307
+ }
308
+ }
309
+ for (const group of groups) { // 更新坐标记录
310
+ this.render.setAssetSettings(group, this.render.getAssetSettings(group), false);
311
+ }
312
+ this.render.emit('asset-position-change', groups);
313
+ this.render.redraw([GraphDraw.name, LinkDraw.name, RulerDraw.name, PreviewDraw.name]);
314
+ },
315
+ dragend: () => {
316
+ this.reset(); // 拖动结束 重置状态
317
+ this.render.updateHistory();
318
+ this.render.redraw([GraphDraw.name, LinkDraw.name, RulerDraw.name, PreviewDraw.name]);
319
+ },
320
+ mousemove: () => { // 子节点 hover
321
+ const pos = this.render.stage.getPointerPosition();
322
+ if (pos) {
323
+ // 获取所有图形
324
+ const shapes = this.render.transformer.nodes();
325
+ // 隐藏 hover 框
326
+ for (const shape of shapes) {
327
+ if (shape instanceof Konva.Group) {
328
+ shape.findOne('#hoverRect')?.visible(false);
329
+ }
330
+ }
331
+ if (shapes.length > 1) { // 多选
332
+ // zIndex 倒序(大的优先)
333
+ shapes.sort((a, b) => b.zIndex() - a.zIndex());
334
+ // 提取重叠目标
335
+ const selected = shapes.find((shape) => Konva.Util.haveIntersection({ ...pos, width: 1, height: 1 }, shape.getClientRect()));
336
+ if (selected) { // 显示 hover 框
337
+ if (selected instanceof Konva.Group) {
338
+ selected.findOne('#hoverRect')?.visible(true);
339
+ }
340
+ }
341
+ }
342
+ }
343
+ },
344
+ mouseleave: () => { // 隐藏 hover 框
345
+ for (const shape of this.render.transformer.nodes()) {
346
+ if (shape instanceof Konva.Group) {
347
+ shape.findOne('#hoverRect')?.visible(false);
348
+ }
349
+ }
350
+ }
351
+ }
352
+ };
353
+
354
+ transformerConfig = { // transformer config
355
+ // 变换中
356
+ anchorDragBoundFunc: (oldPos: Konva.Vector2d, newPos: Konva.Vector2d) => {
357
+ // 磁贴逻辑
358
+ if (!this.render.config.readonly && this.render.config.attractResize) {
359
+ // transformer 锚点按钮
360
+ const anchor = this.render.transformer.getActiveAnchor();
361
+ // 非旋转(就是放大缩小时)
362
+ if (anchor && anchor !== 'rotater') {
363
+ const stageState = this.render.getStageState();
364
+ const logicX = this.render.toStageValue(newPos.x - stageState.x); // x坐标
365
+ const logicNumX = Math.round(logicX / this.render.bgSize); // x单元格个数
366
+ const logicClosestX = logicNumX * this.render.bgSize; // x磁贴目标坐标
367
+ const logicDiffX = Math.abs(logicX - logicClosestX); // x磁贴偏移量
368
+ const snappedX = logicDiffX < 5; // x磁贴阈值
369
+ const logicY = this.render.toStageValue(newPos.y - stageState.y); // y坐标
370
+ const logicNumY = Math.round(logicY / this.render.bgSize); // y单元格个数
371
+ const logicClosestY = logicNumY * this.render.bgSize; // y磁贴目标坐标
372
+ const logicDiffY = Math.abs(logicY - logicClosestY); // y磁贴偏移量
373
+ const snappedY = logicDiffY < 5; // y磁贴阈值
374
+ if (snappedX || snappedY) { // xy磁贴
375
+ return {
376
+ x: snappedX ? this.render.toBoardValue(logicClosestX) + stageState.x : newPos.x,
377
+ y: snappedY ? this.render.toBoardValue(logicClosestY) + stageState.y : newPos.y
378
+ };
379
+ }
380
+ }
381
+ }
382
+ return newPos; // 不磁贴
383
+ }
384
+ };
385
+ }
@@ -0,0 +1,46 @@
1
+ import { Render } from '../index';
2
+ import { Handler, ShutcutKey } from '../types';
3
+
4
+ export class ShutcutHandlers implements Handler {
5
+ // @ts-ignore
6
+ static readonly name = 'Shutcut';
7
+ private render: Render;
8
+ constructor(render: Render) {
9
+ this.render = render;
10
+ }
11
+ handlers = {
12
+ dom: {
13
+ keydown: (e: GlobalEventHandlersEventMap['keydown']) => {
14
+ if (!this.render.config.readonly) {
15
+ if (e.ctrlKey || e.metaKey) {
16
+ if (e.code === ShutcutKey.C) {
17
+ this.render.copyTool.pasteStart();
18
+ } else if (e.code === ShutcutKey.V) {
19
+ this.render.copyTool.pasteEnd();
20
+ } else if (e.code === ShutcutKey.Z) {
21
+ if (e.shiftKey) {
22
+ this.render.nextHistory();
23
+ } else {
24
+ this.render.prevHistory();
25
+ }
26
+ } else if (e.code === ShutcutKey.A) {
27
+ this.render.selectionTool.selectAll();
28
+ }
29
+ } else if (e.code === ShutcutKey["删除"] || e.code === ShutcutKey.Backspace) {
30
+ this.render.remove(this.render.selectionTool.selectingNodes);
31
+ // 删除 连接线
32
+ this.render.linkTool.remove();
33
+ } else if (e.code === ShutcutKey.Esc) {
34
+ this.render.selectionTool.selectingClear();
35
+ this.render.linkTool.selectingClear();
36
+ }
37
+ }
38
+ if (e.code === ShutcutKey.R) {
39
+ if (e.ctrlKey || e.metaKey) {
40
+ window.location.reload();
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,82 @@
1
+ import Konva from 'konva';
2
+ import { Render } from '../index';
3
+ import { Handler } from '../types';
4
+
5
+ // 文本创建操作
6
+
7
+ export class TextHandlers implements Handler {
8
+ // @ts-ignore
9
+ static readonly name = 'Text';
10
+ private render: Render;
11
+ constructor(render: Render) {
12
+ this.render = render;
13
+ }
14
+ // 获取鼠标位置,并处理为相对大小
15
+ getStagePoint(attract = false) {
16
+ const pos = this.render.stage.getPointerPosition();
17
+ if (pos) {
18
+ const stageState = this.render.getStageState();
19
+ if (attract) {
20
+ const { pos: transformerPos } = this.render.attractTool.attractPoint(pos);
21
+ return {
22
+ x: this.render.toStageValue(transformerPos.x - stageState.x),
23
+ y: this.render.toStageValue(transformerPos.y - stageState.y)
24
+ };
25
+ } else {
26
+ return {
27
+ x: this.render.toStageValue(pos.x - stageState.x),
28
+ y: this.render.toStageValue(pos.y - stageState.y)
29
+ };
30
+ }
31
+ }
32
+ return null;
33
+ }
34
+ group: Konva.Group | null = null;
35
+ handlers = {
36
+ stage: {
37
+ mousedown: (e: Konva.KonvaEventObject<MouseEvent>) => {
38
+ // 只有在 texting 模式且点击空白区域时才创建文本
39
+ if (!this.render.texting) return;
40
+ const target = e.target;
41
+ // 检查是否点击在 stage 背景上(不是其他元素)
42
+ const isBackground = target === this.render.stage ||
43
+ (target.attrs && target.attrs.name && target.attrs.name.includes('background'));
44
+ if (!isBackground) return;
45
+ try {
46
+ // 清除当前选择
47
+ this.render.selectionTool.selectingClear();
48
+ this.render.linkTool.selectingClear();
49
+ const point = this.getStagePoint();
50
+ if (point) {
51
+ this.group = this.render.importExportTool.addTextAsset(point);
52
+ if (this.group) {
53
+ // 创建成功后立即选中文本
54
+ this.render.selectionTool.select([this.group]);
55
+ }
56
+ }
57
+ } catch (err) {
58
+ console.error('Failed to create text asset:', err);
59
+ this.group = null;
60
+ }
61
+ },
62
+ mouseup: () => { // 重置 texting 状态
63
+ this.render.changeTexting(false);
64
+ this.group = null;
65
+ },
66
+ click: (e: Konva.KonvaEventObject<MouseEvent>) => { // 点击空白区域时,如果有文本创建了一半,也取消
67
+ if (!this.render.texting) return;
68
+ const target = e.target;
69
+ const isBackground = target === this.render.stage ||
70
+ (target.attrs && target.attrs.name && target.attrs.name.includes('background'));
71
+ if (isBackground) {
72
+ this.render.changeTexting(false);
73
+ }
74
+ }
75
+ },
76
+ transformer: {
77
+ dblclick: () => {
78
+ // 双击文本时显示编辑面板
79
+ }
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,60 @@
1
+ import Konva from 'konva';
2
+ import { Render } from '../index';
3
+ import { Handler } from '../types';
4
+ import { GraphDraw, LinkDraw, RulerDraw, PreviewDraw, RefLineDraw, BgDraw } from '../draws';
5
+
6
+ // 缩放
7
+
8
+ export class ZoomHandlers implements Handler {
9
+ // @ts-ignore
10
+ static readonly name = 'Zoom';
11
+ private render: Render;
12
+ constructor(render: Render) {
13
+ this.render = render;
14
+ }
15
+ scaleBy = 0.1; // zoom 速度
16
+ // zoom 范围
17
+ scaleMin = 0.2;
18
+ scaleMax = 5;
19
+
20
+ handlers = {
21
+ stage: {
22
+ wheel: (e: Konva.KonvaEventObject<GlobalEventHandlersEventMap['wheel']>) => {
23
+ const { scale: oldScale } = this.render.getStageState();
24
+ const isPinchToZoom = e.evt.ctrlKey;
25
+ const newScale = isPinchToZoom ? oldScale + (e.evt.deltaY < 0 ? this.scaleBy : -this.scaleBy) : oldScale;
26
+ const finalScale = Math.max(this.scaleMin, Math.min(this.scaleMax, newScale));
27
+ if (finalScale !== oldScale) {
28
+ const position = this.render.stage.getPosition();
29
+ const point = { x: e.evt.offsetX, y: e.evt.offsetY };
30
+ const mousePointTo = {
31
+ x: (point.x - position.x) / oldScale,
32
+ y: (point.y - position.y) / oldScale
33
+ };
34
+ const newPosition = {
35
+ x: -(mousePointTo.x * finalScale - point.x),
36
+ y: -(mousePointTo.y * finalScale - point.y)
37
+ };
38
+ this.render.emit('scale-change', finalScale);
39
+ this.render.stage.scale({ x: finalScale, y: finalScale });
40
+ this.render.stage.position(newPosition);
41
+ } else if (!isPinchToZoom) {
42
+ const position = this.render.stage.getPosition();
43
+ this.render.stage.position({
44
+ x: position.x - e.evt.deltaX,
45
+ y: position.y - e.evt.deltaY
46
+ });
47
+ }
48
+ // 重绘
49
+ this.render.redraw([
50
+ BgDraw.name,
51
+ GraphDraw.name,
52
+ LinkDraw.name,
53
+ RulerDraw.name,
54
+ RefLineDraw.name,
55
+ PreviewDraw.name
56
+ ]);
57
+ }
58
+ }
59
+ }
60
+ }