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,91 @@
1
+ import Konva from 'konva';
2
+ import { Render } from '../index';
3
+ import { AlignType } from '../types';
4
+ import { GraphDraw, LinkDraw, RulerDraw, PreviewDraw } from '../draws';
5
+
6
+ // 工具栏对齐
7
+
8
+ export class AlignTool {
9
+ // @ts-ignore
10
+ static readonly name = 'AlignTool';
11
+ private render: Render;
12
+ constructor(render: Render) {
13
+ this.render = render;
14
+ }
15
+
16
+ getAlignRect(node: Konva.Node | Konva.Transformer) {
17
+ const stageState = this.render.getStageState();
18
+ let width = 0, height = 0, x = 0, y = 0;
19
+ const result = node.getClientRect();
20
+ // 转为 逻辑觉尺寸
21
+ [width, height, x, y] = [
22
+ this.render.toStageValue(result.width),
23
+ this.render.toStageValue(result.height),
24
+ this.render.toStageValue(result.x - stageState.x),
25
+ this.render.toStageValue(result.y - stageState.y)
26
+ ];
27
+ return { width, height, x, y };
28
+ }
29
+
30
+ // 对齐参考点
31
+ getAlignPoints(node?: Konva.Node | Konva.Transformer): { [index: string]: number } {
32
+ let width = 0, height = 0, x = 0, y = 0;
33
+ if (node !== void 0) {
34
+ // 选择器 / 基于节点 逻辑觉尺寸
35
+ const rect = this.getAlignRect(node);
36
+ [width, height, x, y] = [rect.width, rect.height, rect.x, rect.y];
37
+ } else { // 默认为选择器
38
+ return this.getAlignPoints(this.render.transformer);
39
+ }
40
+ return {
41
+ Middle: x + width / 2,
42
+ Left: x,
43
+ Right: x + width,
44
+ Center: y + height / 2,
45
+ Top: y,
46
+ Bottom: y + height
47
+ };
48
+ }
49
+
50
+ align(type: AlignType, target?: Konva.Node) {
51
+ // 对齐参考点(所有)
52
+ const points = this.getAlignPoints(target);
53
+ // 对齐参考点
54
+ const point = points[type];
55
+ // 需要移动的节点
56
+ const nodes = this.render.transformer.nodes().filter((node) => node !== target);
57
+ // 移动逻辑
58
+ for (const node of nodes) {
59
+ // 逻辑觉尺寸
60
+ const rect = this.getAlignRect(node);
61
+ const [width, height, x, y] = [rect.width, rect.height, rect.x, rect.y];
62
+ switch (type) {
63
+ case "Middle":
64
+ case "Left":
65
+ case "Right":
66
+ {
67
+ const cx = type === "Middle" ? x + width / 2 : type === "Left" ? x : x + width;
68
+ node.x(node.x() + (point - cx));
69
+ }
70
+ break;
71
+ case "Center":
72
+ case "Top":
73
+ case "Bottom":
74
+ {
75
+ const cy = type === "Center" ? y + height / 2 : type === "Top" ? y : y + height;
76
+ node.y(node.y() + (point - cy));
77
+ }
78
+ break;
79
+ }
80
+ }
81
+ // 更新历史
82
+ this.render.updateHistory();
83
+ // 重绘
84
+ this.render.redraw([
85
+ GraphDraw.name,
86
+ LinkDraw.name,
87
+ RulerDraw.name,
88
+ PreviewDraw.name
89
+ ]);
90
+ }
91
+ }
@@ -0,0 +1,142 @@
1
+ import Konva from 'konva';
2
+ import { Render } from '../index';
3
+ import { PreviewDraw } from '../draws';
4
+
5
+ const gifler = (window as any).gifler;
6
+
7
+ export class AssetTool {
8
+ // @ts-ignore
9
+ static readonly name = 'AssetTool';
10
+ private render: Render;
11
+ constructor(render: Render) {
12
+ this.render = render;
13
+ }
14
+
15
+ // 加载 svg xml
16
+ async loadSvgXML(svgXML: string) {
17
+ const blob = new Blob([svgXML], { type: 'image/svg+xml' });
18
+ const url = URL.createObjectURL(blob);
19
+ return new Promise<Konva.Image>((resolve) => {
20
+ Konva.Image.fromURL(url, (imageNode) => {
21
+ imageNode.setAttrs({ svgXML } as any);
22
+ resolve(imageNode);
23
+ });
24
+ });
25
+ }
26
+
27
+ // 加载 svg
28
+ async loadSvg(src: string) {
29
+ const svgXML = await (await fetch(src)).text();
30
+ return this.loadSvgXML(this.render.setSvgXMLSettings(svgXML, this.render.getAssetSettings()));
31
+ }
32
+
33
+ // 加载 gif
34
+ async loadGif(src: string) {
35
+ return new Promise<Konva.Image>((resolve) => {
36
+ const img = document.createElement('img');
37
+ img.onload = () => {
38
+ const canvas = document.createElement('canvas');
39
+ canvas.width = img.naturalWidth;
40
+ canvas.height = img.naturalHeight;
41
+ const gif = gifler(src);
42
+ gif.frames(canvas, (ctx: CanvasRenderingContext2D, frame: any) => {
43
+ ctx.drawImage(frame.buffer, frame.x, frame.y);
44
+ this.render.layer.draw();
45
+ // 更新预览(layer)
46
+ this.render.draws[PreviewDraw.name]?.layer.draw();
47
+ });
48
+ img.remove();
49
+ // TODO: 拖动 gif 素材产生大量 JS event listeners
50
+ resolve(new Konva.Image({ image: canvas, gif: src }));
51
+ }
52
+ img.src = src;
53
+ });
54
+ }
55
+
56
+ // 加载图片
57
+ async loadImg(src: string) {
58
+ return new Promise<Konva.Image>((resolve) => {
59
+ Konva.Image.fromURL(src, (imageNode) => {
60
+ imageNode.setAttrs({ src } as any);
61
+ resolve(imageNode);
62
+ });
63
+ });
64
+ }
65
+
66
+ // 加载节点 json
67
+ async loadJson(src: string) {
68
+ try {
69
+ // 读取 json内容
70
+ const json = JSON.parse(await (await fetch(src)).text());
71
+ // 子素材
72
+ const assets = json.children;
73
+ // 刷新id
74
+ this.render.linkTool.jsonIdCover(assets);
75
+ // 生成空白 stage+layer
76
+ const stageEmpty = new Konva.Stage({ container: document.createElement('div') });
77
+ const layerEmpty = new Konva.Layer();
78
+ stageEmpty.add(layerEmpty);
79
+ // 空白 json 根
80
+ const jsonRoot = JSON.parse(stageEmpty.toJSON());
81
+ jsonRoot.children[0].children = [json];
82
+ // 重新加载 stage
83
+ const stageReload = Konva.Node.create(JSON.stringify(jsonRoot), document.createElement('div'));
84
+ // 目标 group(即 json 转化后的节点)
85
+ const groupTarget = stageReload.children[0].children[0] as Konva.Group;
86
+ // 释放内存
87
+ stageEmpty.destroy();
88
+ groupTarget.remove();
89
+ stageReload.destroy();
90
+ // 深度遍历加载子素材
91
+ const nodes: {
92
+ target: Konva.Stage | Konva.Layer | Konva.Group | Konva.Node
93
+ parent?: Konva.Stage | Konva.Layer | Konva.Group | Konva.Node
94
+ }[] = [{ target: groupTarget }];
95
+ while (nodes.length > 0) {
96
+ const item = nodes.shift();
97
+ if (item) {
98
+ const node = item.target;
99
+ if (node instanceof Konva.Image) {
100
+ if (node.attrs.svgXML) {
101
+ const n = await this.loadSvgXML(node.attrs.svgXML);
102
+ n.listening(false);
103
+ node.parent?.add(n);
104
+ node.remove();
105
+ } else if (node.attrs.gif) {
106
+ const n = await this.loadGif(node.attrs.gif);
107
+ n.listening(false);
108
+ node.parent?.add(n);
109
+ node.remove();
110
+ } else if (node.attrs.src) {
111
+ const n = await this.loadImg(node.attrs.src);
112
+ n.listening(false);
113
+ node.parent?.add(n);
114
+ node.remove();
115
+ }
116
+ }
117
+ if (node instanceof Konva.Stage || node instanceof Konva.Layer || node instanceof Konva.Group) {
118
+ nodes.push(
119
+ ...node.getChildren().map((o) => ({
120
+ target: o,
121
+ parent: node
122
+ }))
123
+ );
124
+ }
125
+ }
126
+ }
127
+
128
+ // 作用:点击空白区域可选择
129
+ const clickMask = new Konva.Rect({
130
+ id: 'click-mask',
131
+ width: groupTarget.width(),
132
+ height: groupTarget.height()
133
+ });
134
+ groupTarget.add(clickMask);
135
+ clickMask.zIndex(1)
136
+ return groupTarget;
137
+ } catch (e) {
138
+ console.error(e);
139
+ return new Konva.Group();
140
+ }
141
+ }
142
+ }
@@ -0,0 +1,440 @@
1
+ import Konva from 'konva';
2
+ import { Render } from '../index';
3
+ import { SortItem } from '../types';
4
+
5
+ interface AlignRect {
6
+ x: number;
7
+ y: number;
8
+ width: number;
9
+ height: number;
10
+ }
11
+
12
+ type SortItemPair = [SortItem, SortItem];
13
+
14
+ export class AttractTool {
15
+ // @ts-ignore
16
+ static readonly name = 'AttractTool';
17
+
18
+ private render: Render;
19
+ constructor(render: Render) {
20
+ this.render = render;
21
+ }
22
+ // 对齐线
23
+ alignLines: Konva.Line[] = [];
24
+
25
+ // 对齐线清除
26
+ alignLinesClear() {
27
+ for (const line of this.alignLines) {
28
+ line.destroy();
29
+ }
30
+ this.alignLines = [];
31
+ }
32
+
33
+ getSortItems(rect: AlignRect) {
34
+ const stageState = this.render.getStageState();
35
+ // 横向所有需要判断对齐的 x 坐标
36
+ const sortX: Array<SortItem> = [];
37
+ // 纵向向所有需要判断对齐的 y 坐标
38
+ const sortY: Array<SortItem> = [];
39
+ // 选择目标所有的对齐 x
40
+ sortX.push(
41
+ { value: this.render.toStageValue(rect.x - stageState.x) },
42
+ { value: this.render.toStageValue(rect.x - stageState.x + rect.width / 2) },
43
+ { value: this.render.toStageValue(rect.x - stageState.x + rect.width) }
44
+ );
45
+ // 选择目标所有的对齐 y
46
+ sortY.push(
47
+ { value: this.render.toStageValue(rect.y - stageState.y) },
48
+ { value: this.render.toStageValue(rect.y - stageState.y + rect.height / 2) },
49
+ { value: this.render.toStageValue(rect.y - stageState.y + rect.height) }
50
+ );
51
+ // 拖动目标
52
+ const targetIds = this.render.selectionTool.selectingNodes.map((o) => o._id);
53
+ // 除拖动目标的其他
54
+ const otherNodes = this.render.layer.find('.asset').filter((node) => !targetIds.includes(node._id));
55
+ // 其他节点所有的 x / y 坐标
56
+ for (const node of otherNodes) {
57
+ const nodeRect = node.getClientRect();
58
+ sortX.push(
59
+ { id: node._id, value: this.render.toStageValue(nodeRect.x - stageState.x) },
60
+ { id: node._id, value: this.render.toStageValue(nodeRect.x - stageState.x + nodeRect.width / 2) },
61
+ { id: node._id, value: this.render.toStageValue(nodeRect.x - stageState.x + nodeRect.width) }
62
+ );
63
+ sortY.push(
64
+ { id: node._id, value: this.render.toStageValue(nodeRect.y - stageState.y) },
65
+ { id: node._id, value: this.render.toStageValue(nodeRect.y - stageState.y + nodeRect.height / 2) },
66
+ { id: node._id, value: this.render.toStageValue(nodeRect.y - stageState.y + nodeRect.height) }
67
+ );
68
+ }
69
+ sortX.sort((a, b) => a.value - b.value);
70
+ sortY.sort((a, b) => a.value - b.value);
71
+ return { sortX, sortY };
72
+ }
73
+
74
+ attractPoint = (pos: Konva.Vector2d) => {
75
+ this.alignLinesClear(); // 对齐线清除
76
+ const stageState = this.render.getStageState();
77
+ let newPosX = pos.x;
78
+ let newPosY = pos.y;
79
+ let isAttract = false;
80
+ let pairX: SortItemPair | null = null;
81
+ let pairY: SortItemPair | null = null;
82
+ // 对齐线 磁吸逻辑
83
+ if (!this.render.config.readonly && this.render.config.attractNode) {
84
+ const sortX = [{ value: this.render.toStageValue(newPosX - stageState.x) }] as SortItem[],
85
+ sortY = [{ value: this.render.toStageValue(newPosY - stageState.y) }] as SortItem[];
86
+ // x 最短距离
87
+ let XMin = Infinity;
88
+ // x 最短距离的【对】(多个)
89
+ let pairXMin: Array<SortItemPair> = [];
90
+ // y 最短距离
91
+ let YMin = Infinity;
92
+ // y 最短距离的【对】(多个)
93
+ let pairYMin: Array<SortItemPair> = [];
94
+ // 一对对比较距离,记录最短距离的【对】
95
+ // 必须是 选择目标 与 其他节点 成【对】
96
+ // 可能有多个这样的【对】
97
+ for (let i = 0; i < sortX.length - 1; i++) {
98
+ // 相邻两个点,必须为 目标节点 + 非目标节点
99
+ if ((sortX[i].id === void 0 && sortX[i + 1].id !== void 0) || (sortX[i].id !== void 0 && sortX[i + 1].id === void 0)) {
100
+ // 相邻两个点的 x 距离
101
+ const offset = Math.abs(sortX[i].value - sortX[i + 1].value);
102
+ if (offset < XMin) {
103
+ // 更新 x 最短距离 记录
104
+ XMin = offset;
105
+ // 更新 x 最短距离的【对】 记录
106
+ pairXMin = [[sortX[i], sortX[i + 1]]];
107
+ } else if (offset === XMin) {
108
+ // 存在多个 x 最短距离
109
+ pairXMin.push([sortX[i], sortX[i + 1]]);
110
+ }
111
+ }
112
+ }
113
+ for (let i = 0; i < sortY.length - 1; i++) {
114
+ // 相邻两个点,必须为 目标节点 + 非目标节点
115
+ if ((sortY[i].id === void 0 && sortY[i + 1].id !== void 0) || (sortY[i].id !== void 0 && sortY[i + 1].id === void 0)) {
116
+ // 相邻两个点的 y 距离
117
+ const offset = Math.abs(sortY[i].value - sortY[i + 1].value);
118
+ if (offset < YMin) {
119
+ // 更新 y 最短距离 记录
120
+ YMin = offset;
121
+ // 更新 y 最短距离的【对】 记录
122
+ pairYMin = [[sortY[i], sortY[i + 1]]];
123
+ } else if (offset === YMin) {
124
+ // 存在多个 y 最短距离
125
+ pairYMin.push([sortY[i], sortY[i + 1]]);
126
+ }
127
+ }
128
+ }
129
+ // 取第一【对】,用于判断距离是否在阈值内
130
+ if (pairXMin[0]) {
131
+ if (Math.abs(pairXMin[0][0].value - pairXMin[0][1].value) < this.render.bgSize / 2) {
132
+ pairX = pairXMin[0];
133
+ }
134
+ }
135
+ if (pairYMin[0]) {
136
+ if (Math.abs(pairYMin[0][0].value - pairYMin[0][1].value) < this.render.bgSize / 2) {
137
+ pairY = pairYMin[0];
138
+ }
139
+ }
140
+ // 优先对齐节点
141
+ // 存在 1或多个 x 最短距离 满足阈值
142
+ if (pairX?.length === 2) {
143
+ for (const pair of pairXMin) {
144
+ // 【对】里的那个非目标节点
145
+ const other = pair.find((o) => o.id !== void 0);
146
+ if (other) { // x 对齐线
147
+ const line = new Konva.Line({
148
+ points: [[other.value, this.render.toStageValue(-stageState.y)], [other.value, this.render.toStageValue(this.render.stage.height() - stageState.y)]].flat(),
149
+ stroke: 'blue',
150
+ strokeWidth: this.render.toStageValue(1),
151
+ dash: [4, 4],
152
+ listening: false
153
+ });
154
+ this.alignLines.push(line);
155
+ this.render.layerCover.add(line);
156
+ }
157
+ }
158
+ // 磁贴第一个【对】
159
+ const target = pairX.find((o) => o.id === void 0);
160
+ const other = pairX.find((o) => o.id !== void 0);
161
+ if (target && other) {
162
+ // 磁铁坐标值
163
+ newPosX = newPosX - this.render.toBoardValue(target.value - other.value);
164
+ isAttract = true;
165
+ }
166
+ }
167
+ // 存在 1或多个 y 最短距离 满足阈值
168
+ if (pairY?.length === 2) {
169
+ for (const pair of pairYMin) {
170
+ // 【对】里的那个非目标节点
171
+ const other = pair.find((o) => o.id !== void 0);
172
+ if (other) {
173
+ // y 对齐线
174
+ const line = new Konva.Line({
175
+ points: [[this.render.toStageValue(-stageState.x), other.value], [this.render.toStageValue(this.render.stage.width() - stageState.x), other.value]].flat(),
176
+ stroke: 'blue',
177
+ strokeWidth: this.render.toStageValue(1),
178
+ dash: [4, 4],
179
+ listening: false
180
+ });
181
+ this.alignLines.push(line);
182
+ this.render.layerCover.add(line);
183
+ }
184
+ }
185
+ // 磁贴第一个【对】
186
+ const target = pairY.find((o) => o.id === void 0);
187
+ const other = pairY.find((o) => o.id !== void 0);
188
+ if (target && other) {
189
+ // 磁铁坐标值
190
+ newPosY = newPosY - this.render.toBoardValue(target.value - other.value);
191
+ isAttract = true;
192
+ }
193
+ }
194
+ }
195
+ if (!this.render.config.readonly && this.render.config.attractBg) {
196
+ // 没有 x 对齐节点
197
+ if (pairX === null) {
198
+ const logicLeftX = this.render.toStageValue(newPosX - stageState.x); // x坐标
199
+ const logicNumLeftX = Math.round(logicLeftX / this.render.bgSize); // x单元格个数
200
+ const logicClosestLeftX = logicNumLeftX * this.render.bgSize; // x磁贴目标坐标
201
+ const logicDiffLeftX = Math.abs(logicLeftX - logicClosestLeftX); // x磁贴偏移量
202
+ const logicRightX = this.render.toStageValue(newPosX - stageState.x); // x坐标
203
+ const logicNumRightX = Math.round(logicRightX / this.render.bgSize); // x单元格个数
204
+ const logicClosestRightX = logicNumRightX * this.render.bgSize; // x磁贴目标坐标
205
+ const logicDiffRightX = Math.abs(logicRightX - logicClosestRightX); // x磁贴偏移量
206
+ // stage 逻辑边界磁贴
207
+ const logicStageRightX = stageState.width;
208
+ const logicDiffStageRightX = Math.abs(logicRightX - logicStageRightX);
209
+ // 距离近优先
210
+ for (const diff of [{ type: 'leftX', value: logicDiffLeftX }, { type: 'rightX', value: logicDiffRightX }, { type: 'stageRightX', value: logicDiffStageRightX }].sort((a, b) => a.value - b.value)) {
211
+ if (diff.value < 5) {
212
+ if (diff.type === 'stageRightX') {
213
+ newPosX = this.render.toBoardValue(logicStageRightX) + stageState.x;
214
+ } else if (diff.type === 'leftX') {
215
+ newPosX = this.render.toBoardValue(logicClosestLeftX) + stageState.x;
216
+ } else if (diff.type === 'rightX') {
217
+ newPosX = this.render.toBoardValue(logicClosestRightX) + stageState.x;
218
+ }
219
+ isAttract = true;
220
+ break;
221
+ }
222
+ }
223
+ }
224
+ // 没有 y 对齐节点
225
+ if (pairY === null) {
226
+ const logicTopY = this.render.toStageValue(newPosY - stageState.y); // y坐标
227
+ const logicNumTopY = Math.round(logicTopY / this.render.bgSize); // y单元格个数
228
+ const logicClosestTopY = logicNumTopY * this.render.bgSize; // y磁贴目标坐标
229
+ const logicDiffTopY = Math.abs(logicTopY - logicClosestTopY); // y磁贴偏移量
230
+ const logicBottomY = this.render.toStageValue(newPosY - stageState.y); // y坐标
231
+ const logicNumBottomY = Math.round(logicBottomY / this.render.bgSize); // y单元格个数
232
+ const logicClosestBottomY = logicNumBottomY * this.render.bgSize; // y磁贴目标坐标
233
+ const logicDiffBottomY = Math.abs(logicBottomY - logicClosestBottomY); // y磁贴偏移量
234
+ // stage 逻辑边界磁贴
235
+ const logicStageBottomY = stageState.height;
236
+ const logicDiffStageBottomY = Math.abs(logicBottomY - logicStageBottomY);
237
+ // 距离近优先
238
+ for (const diff of [{ type: 'topY', value: logicDiffTopY }, { type: 'bottomY', value: logicDiffBottomY }, { type: 'stageBottomY', value: logicDiffStageBottomY }].sort((a, b) => a.value - b.value)) {
239
+ if (diff.value < 5) {
240
+ if (diff.type === 'stageBottomY') {
241
+ newPosY = this.render.toBoardValue(logicStageBottomY) + stageState.y;
242
+ } else if (diff.type === 'topY') {
243
+ newPosY = this.render.toBoardValue(logicClosestTopY) + stageState.y;
244
+ } else if (diff.type === 'bottomY') {
245
+ newPosY = this.render.toBoardValue(logicClosestBottomY) + stageState.y;
246
+ }
247
+ isAttract = true;
248
+ break;
249
+ }
250
+ }
251
+ }
252
+ }
253
+ return { pos: { x: newPosX, y: newPosY }, isAttract };
254
+ }
255
+ // 磁吸逻辑
256
+ attractTransformer = (rect: AlignRect) => {
257
+ // 对齐线清除
258
+ this.alignLinesClear();
259
+ const stageState = this.render.getStageState();
260
+ const width = this.render.transformer.width();
261
+ const height = this.render.transformer.height();
262
+ let newPosX = rect.x;
263
+ let newPosY = rect.y;
264
+ let isAttract = false;
265
+ let pairX: SortItemPair | null = null;
266
+ let pairY: SortItemPair | null = null;
267
+ // 对齐线 磁吸逻辑
268
+ if (!this.render.config.readonly && this.render.config.attractNode) {
269
+ const { sortX, sortY } = this.getSortItems(rect);
270
+ // x 最短距离
271
+ let XMin = Infinity;
272
+ // x 最短距离的【对】(多个)
273
+ let pairXMin: Array<SortItemPair> = [];
274
+ // y 最短距离
275
+ let YMin = Infinity;
276
+ // y 最短距离的【对】(多个)
277
+ let pairYMin: Array<SortItemPair> = [];
278
+ // 一对对比较距离,记录最短距离的【对】
279
+ // 必须是 选择目标 与 其他节点 成【对】
280
+ // 可能有多个这样的【对】
281
+ for (let i = 0; i < sortX.length - 1; i++) {
282
+ // 相邻两个点,必须为 目标节点 + 非目标节点
283
+ if ((sortX[i].id === void 0 && sortX[i + 1].id !== void 0) || (sortX[i].id !== void 0 && sortX[i + 1].id === void 0)) {
284
+ // 相邻两个点的 x 距离
285
+ const offset = Math.abs(sortX[i].value - sortX[i + 1].value)
286
+ if (offset < XMin) {
287
+ // 更新 x 最短距离 记录
288
+ XMin = offset;
289
+ // 更新 x 最短距离的【对】 记录
290
+ pairXMin = [[sortX[i], sortX[i + 1]]];
291
+ } else if (offset === XMin) {
292
+ // 存在多个 x 最短距离
293
+ pairXMin.push([sortX[i], sortX[i + 1]]);
294
+ }
295
+ }
296
+ }
297
+ for (let i = 0; i < sortY.length - 1; i++) {
298
+ // 相邻两个点,必须为 目标节点 + 非目标节点
299
+ if ((sortY[i].id === void 0 && sortY[i + 1].id !== void 0) || (sortY[i].id !== void 0 && sortY[i + 1].id === void 0)) {
300
+ // 相邻两个点的 y 距离
301
+ const offset = Math.abs(sortY[i].value - sortY[i + 1].value);
302
+ if (offset < YMin) {
303
+ // 更新 y 最短距离 记录
304
+ YMin = offset;
305
+ // 更新 y 最短距离的【对】 记录
306
+ pairYMin = [[sortY[i], sortY[i + 1]]];
307
+ } else if (offset === YMin) {
308
+ // 存在多个 y 最短距离
309
+ pairYMin.push([sortY[i], sortY[i + 1]]);
310
+ }
311
+ }
312
+ }
313
+ // 取第一【对】,用于判断距离是否在阈值内
314
+ if (pairXMin[0]) {
315
+ if (Math.abs(pairXMin[0][0].value - pairXMin[0][1].value) < this.render.bgSize / 2) {
316
+ pairX = pairXMin[0];
317
+ }
318
+ }
319
+ if (pairYMin[0]) {
320
+ if (Math.abs(pairYMin[0][0].value - pairYMin[0][1].value) < this.render.bgSize / 2) {
321
+ pairY = pairYMin[0];
322
+ }
323
+ }
324
+ // 优先对齐节点
325
+ // 存在 1或多个 x 最短距离 满足阈值
326
+ if (pairX?.length === 2) {
327
+ for (const pair of pairXMin) {
328
+ // 【对】里的那个非目标节点
329
+ const other = pair.find((o) => o.id !== void 0);
330
+ if (other) {
331
+ // x 对齐线
332
+ const line = new Konva.Line({
333
+ points: [[other.value, this.render.toStageValue(-stageState.y)], [other.value, this.render.toStageValue(this.render.stage.height() - stageState.y)]].flat(),
334
+ stroke: 'blue',
335
+ strokeWidth: this.render.toStageValue(1),
336
+ dash: [4, 4],
337
+ listening: false
338
+ });
339
+ this.alignLines.push(line);
340
+ this.render.layerCover.add(line);
341
+ }
342
+ }
343
+ // 磁贴第一个【对】
344
+ const target = pairX.find((o) => o.id === void 0);
345
+ const other = pairX.find((o) => o.id !== void 0);
346
+ if (target && other) {
347
+ // 磁贴坐标值
348
+ newPosX = newPosX - this.render.toBoardValue(target.value - other.value);
349
+ isAttract = true;
350
+ }
351
+ }
352
+ // 存在 1或多个 y 最短距离 满足阈值
353
+ if (pairY?.length === 2) {
354
+ for (const pair of pairYMin) {
355
+ // 【对】里的那个非目标节点
356
+ const other = pair.find((o) => o.id !== void 0);
357
+ if (other) {
358
+ // y 对齐线
359
+ const line = new Konva.Line({
360
+ points: [[this.render.toStageValue(-stageState.x), other.value], [this.render.toStageValue(this.render.stage.width() - stageState.x), other.value]].flat(),
361
+ stroke: 'blue',
362
+ strokeWidth: this.render.toStageValue(1),
363
+ dash: [4, 4],
364
+ listening: false
365
+ });
366
+ this.alignLines.push(line);
367
+ this.render.layerCover.add(line);
368
+ }
369
+ }
370
+ // 磁贴第一个【对】
371
+ const target = pairY.find((o) => o.id === void 0);
372
+ const other = pairY.find((o) => o.id !== void 0);
373
+ if (target && other) {
374
+ // 磁贴坐标值
375
+ newPosY = newPosY - this.render.toBoardValue(target.value - other.value);
376
+ isAttract = true;
377
+ }
378
+ }
379
+ }
380
+ if (!this.render.config.readonly && this.render.config.attractBg) {
381
+ // 没有 x 对齐节点
382
+ if (pairX === null) {
383
+ const logicLeftX = this.render.toStageValue(newPosX - stageState.x); // x坐标
384
+ const logicNumLeftX = Math.round(logicLeftX / this.render.bgSize); // x单元格个数
385
+ const logicClosestLeftX = logicNumLeftX * this.render.bgSize; // x磁贴目标坐标
386
+ const logicDiffLeftX = Math.abs(logicLeftX - logicClosestLeftX); // x磁贴偏移量
387
+ const logicRightX = this.render.toStageValue(newPosX + width - stageState.x); // x坐标
388
+ const logicNumRightX = Math.round(logicRightX / this.render.bgSize); // x单元格个数
389
+ const logicClosestRightX = logicNumRightX * this.render.bgSize; // x磁贴目标坐标
390
+ const logicDiffRightX = Math.abs(logicRightX - logicClosestRightX); // x磁贴偏移量
391
+ // stage 逻辑边界磁贴
392
+ const logicStageRightX = stageState.width;
393
+ const logicDiffStageRightX = Math.abs(logicRightX - logicStageRightX);
394
+ // 距离近优先
395
+ for (const diff of [{ type: 'leftX', value: logicDiffLeftX }, { type: 'rightX', value: logicDiffRightX }, { type: 'stageRightX', value: logicDiffStageRightX }].sort((a, b) => a.value - b.value)) {
396
+ if (diff.value < 5) {
397
+ if (diff.type === 'stageRightX') {
398
+ newPosX = this.render.toBoardValue(logicStageRightX) + stageState.x - width;
399
+ } else if (diff.type === 'leftX') {
400
+ newPosX = this.render.toBoardValue(logicClosestLeftX) + stageState.x;
401
+ } else if (diff.type === 'rightX') {
402
+ newPosX = this.render.toBoardValue(logicClosestRightX) + stageState.x - width;
403
+ }
404
+ isAttract = true;
405
+ break;
406
+ }
407
+ }
408
+ }
409
+ // 没有 y 对齐节点
410
+ if (pairY === null) {
411
+ const logicTopY = this.render.toStageValue(newPosY - stageState.y); // y坐标
412
+ const logicNumTopY = Math.round(logicTopY / this.render.bgSize); // y单元格个数
413
+ const logicClosestTopY = logicNumTopY * this.render.bgSize; // y磁贴目标坐标
414
+ const logicDiffTopY = Math.abs(logicTopY - logicClosestTopY); // y磁贴偏移量
415
+ const logicBottomY = this.render.toStageValue(newPosY + height - stageState.y); // y坐标
416
+ const logicNumBottomY = Math.round(logicBottomY / this.render.bgSize); // y单元格个数
417
+ const logicClosestBottomY = logicNumBottomY * this.render.bgSize; // y磁贴目标坐标
418
+ const logicDiffBottomY = Math.abs(logicBottomY - logicClosestBottomY); // y磁贴偏移量
419
+ // stage 逻辑边界磁贴
420
+ const logicStageBottomY = stageState.height;
421
+ const logicDiffStageBottomY = Math.abs(logicBottomY - logicStageBottomY);
422
+ // 距离近优先
423
+ for (const diff of [{ type: 'topY', value: logicDiffTopY }, { type: 'bottomY', value: logicDiffBottomY }, { type: 'stageBottomY', value: logicDiffStageBottomY }].sort((a, b) => a.value - b.value)) {
424
+ if (diff.value < 5) {
425
+ if (diff.type === 'stageBottomY') {
426
+ newPosY = this.render.toBoardValue(logicStageBottomY) + stageState.y - height;
427
+ } else if (diff.type === 'topY') {
428
+ newPosY = this.render.toBoardValue(logicClosestTopY) + stageState.y;
429
+ } else if (diff.type === 'bottomY') {
430
+ newPosY = this.render.toBoardValue(logicClosestBottomY) + stageState.y - height;
431
+ }
432
+ isAttract = true;
433
+ break;
434
+ }
435
+ }
436
+ }
437
+ }
438
+ return { pos: { x: newPosX, y: newPosY }, isAttract };
439
+ }
440
+ }