@mx-sose-front/mx-sose-graph 1.1.8 → 1.2.1

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 (180) hide show
  1. package/dist/assets/edgeWorker-b57ca007.js +2 -0
  2. package/dist/assets/edgeWorker-b57ca007.js.map +1 -0
  3. package/dist/index.d.ts +994 -31
  4. package/dist/index.esm.js +9541 -5145
  5. package/dist/index.esm.js.map +1 -1
  6. package/dist/index.umd.js +1 -1
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/style.css +1 -1
  9. package/package.json +1 -1
  10. package/src/components/Common/Tree.vue +451 -0
  11. package/src/components/Common/index.ts +2 -0
  12. package/src/components/DiagramListTooltip/DiagramListTooltip.vue +1 -2
  13. package/src/components/Edge/Edge.vue +172 -169
  14. package/src/components/Gantt/Gantt.vue +1544 -0
  15. package/src/components/GanttContextMenu/GanttContextMenu.vue +304 -0
  16. package/src/components/InteractionLayer.vue +343 -147
  17. package/src/components/Matrix/Matrix.vue +808 -0
  18. package/src/components/Matrix/index.ts +168 -0
  19. package/src/components/Shape/ConceptualRole.vue +2 -34
  20. package/src/components/Table/Table.vue +1193 -0
  21. package/src/constants/edgeShapeKeys.ts +8 -5
  22. package/src/constants/index.ts +279 -51
  23. package/src/hooks/index.ts +2 -0
  24. package/src/hooks/useChartRowSelection.ts +456 -0
  25. package/src/hooks/useResize.ts +2 -2
  26. package/src/hooks/useVirtualScroll.ts +258 -0
  27. package/src/index.ts +1 -1
  28. package/src/render/shape-renderer.ts +62 -2
  29. package/src/statics/icons/childIcons/AV-1/346/246/202/350/277/260/344/270/216/346/221/230/350/246/201/344/277/241/346/201/257/345/214/205@3x.png +0 -0
  30. package/src/statics/icons/childIcons/AV-1/346/246/202/350/277/260/346/221/230/350/246/201/345/233/276@3x.png +0 -0
  31. package/src/statics/icons/childIcons/AV-2/351/233/206/346/210/220/345/255/227/345/205/270/345/214/205@3x.png +0 -0
  32. package/src/statics/icons/childIcons/AV-2/351/233/206/346/210/220/345/255/227/345/205/270/350/241/250@3x.png +0 -0
  33. package/src/statics/icons/childIcons/CV-1/346/204/277/346/231/257/345/214/205@3x.png +0 -0
  34. package/src/statics/icons/childIcons/CV-1/346/204/277/346/231/257/345/233/276@3x.png +0 -0
  35. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/214/205@3x.png +0 -0
  36. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/233/276@3x-2.png +0 -0
  37. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/233/276@3x-3.png +0 -0
  38. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/233/276@3x.png +0 -0
  39. package/src/statics/icons/childIcons/CV-3/350/203/275/345/212/233/345/210/206/346/256/265/345/214/205@3x.png +0 -0
  40. package/src/statics/icons/childIcons/CV-3/350/203/275/345/212/233/351/230/266/346/256/265/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  41. package/src/statics/icons/childIcons/CV-4/350/203/275/345/212/233/344/276/235/350/265/226/345/214/205@3x.png +0 -0
  42. package/src/statics/icons/childIcons/CV-4/350/203/275/345/212/233/344/276/235/350/265/226/345/233/276@3x.png +0 -0
  43. package/src/statics/icons/childIcons/CV-5/350/203/275/345/212/233/345/210/260/347/273/204/347/273/207/347/232/204/345/274/200/345/217/221/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  44. package/src/statics/icons/childIcons/CV-5/350/203/275/345/212/233/345/210/260/347/273/204/347/273/207/347/232/204/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  45. package/src/statics/icons/childIcons/CV-6/350/203/275/345/212/233/345/210/260/344/270/232/345/212/241/346/264/273/345/212/250/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  46. package/src/statics/icons/childIcons/CV-6/350/203/275/345/212/233/345/210/260/344/275/234/346/210/230/346/264/273/345/212/250/347/232/204/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  47. package/src/statics/icons/childIcons/CV-7/350/203/275/345/212/233/345/210/260/346/234/215/345/212/241/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  48. package/src/statics/icons/childIcons/CV-7/350/203/275/345/212/233/345/210/260/346/234/215/345/212/241/347/232/204/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  49. package/src/statics/icons/childIcons/DIV-1/346/246/202/345/277/265/346/225/260/346/215/256/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  50. package/src/statics/icons/childIcons/DIV-1/346/246/202/345/277/265/346/225/260/346/215/256/346/250/241/345/236/213/345/233/276@3x.png +0 -0
  51. package/src/statics/icons/childIcons/DIV-2/351/200/273/350/276/221/346/225/260/346/215/256/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  52. package/src/statics/icons/childIcons/DIV-2/351/200/273/350/276/221/346/225/260/346/215/256/346/250/241/345/236/213/345/233/276@3x.png +0 -0
  53. package/src/statics/icons/childIcons/DIV-3/347/211/251/347/220/206/346/225/260/346/215/256/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  54. package/src/statics/icons/childIcons/OV-1/350/207/252/347/224/261/345/210/206/347/261/273/345/233/276@3x.png +0 -0
  55. package/src/statics/icons/childIcons/OV-1/351/253/230/347/272/247/344/275/234/346/210/230/346/246/202/345/277/265/345/233/276@3x.png +0 -0
  56. package/src/statics/icons/childIcons/OV-1/351/253/230/347/272/247/344/275/234/346/210/230/346/246/202/345/277/265/345/233/276/345/214/205@3x.png +0 -0
  57. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/345/206/205/351/203/250/346/217/217/350/277/260/345/233/276@3x-2.png +0 -0
  58. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/345/206/205/351/203/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  59. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  60. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  61. package/src/statics/icons/childIcons/OV-3/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265@3x.png +0 -0
  62. package/src/statics/icons/childIcons/OV-3/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  63. package/src/statics/icons/childIcons/OV-3/345/237/272/347/241/200/350/247/222/350/211/262/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265@3x.png +0 -0
  64. package/src/statics/icons/childIcons/OV-4/347/273/204/347/273/207/345/205/263/347/263/273/345/233/276@3x.png +0 -0
  65. package/src/statics/icons/childIcons/OV-4/347/273/204/347/273/207/345/205/263/347/263/273/345/233/276/345/214/205@3x.png +0 -0
  66. package/src/statics/icons/childIcons/OV-5a/344/275/234/346/210/230/346/264/273/345/212/250/345/210/206/350/247/243/346/240/221/345/214/205@3x.png +0 -0
  67. package/src/statics/icons/childIcons/OV-5a/344/275/234/346/210/230/346/264/273/345/212/250/345/210/206/350/247/243/346/240/221/345/233/276@3x.png +0 -0
  68. package/src/statics/icons/childIcons/OV-5b/344/275/234/346/210/230/346/264/273/345/212/250/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  69. package/src/statics/icons/childIcons/OV-5b/344/275/234/346/210/230/346/264/273/345/212/250/346/250/241/345/236/213/345/233/276@3x.png +0 -0
  70. package/src/statics/icons/childIcons/OV-6a/344/275/234/346/210/230/350/247/204/345/210/231/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  71. package/src/statics/icons/childIcons/OV-6a/344/275/234/346/210/230/350/265/204/346/272/220/345/217/202/346/225/260/345/233/276@3x.png +0 -0
  72. package/src/statics/icons/childIcons/OV-6b/347/212/266/346/200/201/350/275/254/346/215/242/345/233/276@3x.png +0 -0
  73. package/src/statics/icons/childIcons/OV-6b/347/212/266/346/200/201/350/275/254/346/215/242/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  74. package/src/statics/icons/childIcons/OV-6c/344/272/213/344/273/266/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  75. package/src/statics/icons/childIcons/OV-6c/344/275/234/346/210/230/344/272/213/344/273/266/350/267/237/350/270/252/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  76. package/src/statics/icons/childIcons/PV-1/351/241/271/347/233/256/347/273/204/345/220/210/345/205/263/347/263/273/345/214/205@3x.png +0 -0
  77. package/src/statics/icons/childIcons/PV-1/351/241/271/347/233/256/347/273/204/345/220/210/345/205/263/347/263/273/345/233/276@3x.png +0 -0
  78. package/src/statics/icons/childIcons/PV-2/351/241/271/347/233/256/346/227/266/351/227/264/350/277/233/345/272/246/345/214/205@3x.png +0 -0
  79. package/src/statics/icons/childIcons/PV-2/351/241/271/347/233/256/346/227/266/351/227/264/350/277/233/345/272/246/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  80. package/src/statics/icons/childIcons/PV-3/351/241/271/347/233/256/344/270/216/350/203/275/345/212/233/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  81. package/src/statics/icons/childIcons/PV-3/351/241/271/347/233/256/344/270/216/350/203/275/345/212/233/347/232/204/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  82. package/src/statics/icons/childIcons/SV-1 /347/263/273/347/273/237/346/216/245/345/217/243/345/206/205/351/203/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  83. package/src/statics/icons/childIcons/SV-1 /347/263/273/347/273/237/346/216/245/345/217/243/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  84. package/src/statics/icons/childIcons/SV-10a /347/263/273/347/273/237/345/217/202/346/225/260/345/233/276@3x.png +0 -0
  85. package/src/statics/icons/childIcons/SV-10a /347/263/273/347/273/237/350/247/204/345/210/231/346/250/241/345/236/213/350/241/250@3x.png +0 -0
  86. package/src/statics/icons/childIcons/SV-10a/347/263/273/347/273/237/350/247/204/345/210/231/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  87. package/src/statics/icons/childIcons/SV-10b /347/263/273/347/273/237/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  88. package/src/statics/icons/childIcons/SV-10b/347/263/273/347/273/237/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  89. package/src/statics/icons/childIcons/SV-10c /347/263/273/347/273/237/344/272/213/344/273/266/350/267/237/350/270/252/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  90. package/src/statics/icons/childIcons/SV-10c/347/263/273/347/273/237/344/272/213/344/273/266-/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  91. package/src/statics/icons/childIcons/SV-1/347/263/273/347/273/237/346/216/245/345/217/243/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  92. package/src/statics/icons/childIcons/SV-2 /347/263/273/347/273/237/345/206/205/351/203/250/350/265/204/346/272/220/346/265/201/345/212/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  93. package/src/statics/icons/childIcons/SV-2 /347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/345/212/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  94. package/src/statics/icons/childIcons/SV-2/347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  95. package/src/statics/icons/childIcons/SV-3 /347/263/273/347/273/237 - /347/263/273/347/273/237/347/237/251/351/230/265@3x.png +0 -0
  96. package/src/statics/icons/childIcons/SV-3/347/263/273/347/273/237-/347/263/273/347/273/237/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  97. package/src/statics/icons/childIcons/SV-4 /347/263/273/347/273/237/345/212/237/350/203/275/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  98. package/src/statics/icons/childIcons/SV-4 /347/263/273/347/273/237/345/212/237/350/203/275/346/265/201/347/250/213/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  99. package/src/statics/icons/childIcons/SV-4/347/263/273/347/273/237/345/212/237/350/203/275/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  100. package/src/statics/icons/childIcons/SV-5a /344/270/232/345/212/241/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/345/212/237/350/203/275/347/232/204/345/217/257/350/277/275/346/272/257/346/200/247/347/237/251/351/230/265@3x.png +0 -0
  101. package/src/statics/icons/childIcons/SV-5a/344/275/234/346/210/230/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/345/212/237/350/203/275/345/217/257/350/277/275/350/270/252/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  102. package/src/statics/icons/childIcons/SV-5b /344/270/232/345/212/241/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/347/232/204/345/217/257/350/277/275/346/272/257/346/200/247/347/237/251/351/230/265@3x.png +0 -0
  103. package/src/statics/icons/childIcons/SV-5b/344/275/234/346/210/230/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/345/217/257/350/277/275/350/270/252/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  104. package/src/statics/icons/childIcons/SV-6 /347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/345/212/250/347/237/251/351/230/265@3x.png +0 -0
  105. package/src/statics/icons/childIcons/SV-6/347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  106. package/src/statics/icons/childIcons/SV-7 /347/263/273/347/273/237/345/256/236/351/231/205/345/272/246/351/207/217/347/237/251/351/230/265@3x.png +0 -0
  107. package/src/statics/icons/childIcons/SV-7/347/263/273/347/273/237/345/272/246/351/207/217/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  108. package/src/statics/icons/childIcons/SV-8 /347/263/273/347/273/237/346/274/224/350/277/233/346/217/217/350/277/260/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  109. package/src/statics/icons/childIcons/SV-8/347/263/273/347/273/237/346/274/224/350/277/233/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  110. package/src/statics/icons/childIcons/SV-9 /347/263/273/347/273/237/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/350/241/250@3x.png +0 -0
  111. package/src/statics/icons/childIcons/SV-9/347/263/273/347/273/237/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/345/214/205@3x.png +0 -0
  112. package/src/statics/icons/childIcons/StdV-1 /346/240/207/345/207/206/351/205/215/347/275/256/350/241/250@3x.png +0 -0
  113. package/src/statics/icons/childIcons/StdV-1/346/240/207/345/207/206/351/205/215/347/275/256/346/226/207/344/273/266/345/214/205@3x.png +0 -0
  114. package/src/statics/icons/childIcons/StdV-2 /346/240/207/345/207/206/351/242/204/346/265/213/350/241/250@3x.png +0 -0
  115. package/src/statics/icons/childIcons/StdV-2/346/240/207/345/207/206/351/242/204/346/265/213/345/214/205@3x.png +0 -0
  116. package/src/statics/icons/childIcons/SvcV-10a /346/234/215/345/212/241/345/217/202/346/225/260/345/233/276@3x.png +0 -0
  117. package/src/statics/icons/childIcons/SvcV-10a/346/234/215/345/212/241/350/247/204/345/210/231/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  118. package/src/statics/icons/childIcons/SvcV-10b /346/234/215/345/212/241/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  119. package/src/statics/icons/childIcons/SvcV-10b/346/234/215/345/212/241/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  120. package/src/statics/icons/childIcons/SvcV-10c /346/234/215/345/212/241/344/272/213/344/273/266/350/267/237/350/270/252/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  121. package/src/statics/icons/childIcons/SvcV-10c/346/234/215/345/212/241/344/272/213/344/273/266-/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  122. package/src/statics/icons/childIcons/SvcV-1/346/234/215/345/212/241/344/270/212/344/270/213/346/226/207/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  123. package/src/statics/icons/childIcons/SvcV-1/346/234/215/345/212/241/350/203/214/346/231/257/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  124. package/src/statics/icons/childIcons/SvcV-2 /346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  125. package/src/statics/icons/childIcons/SvcV-2/346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  126. package/src/statics/icons/childIcons/SvcV-3a /347/263/273/347/273/237 -/346/234/215/345/212/241/347/237/251/351/230/265@3x-2.png +0 -0
  127. package/src/statics/icons/childIcons/SvcV-3a /347/263/273/347/273/237 -/346/234/215/345/212/241/347/237/251/351/230/265@3x.png +0 -0
  128. package/src/statics/icons/childIcons/SvcV-3a/347/263/273/347/273/237-/346/234/215/345/212/241/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  129. package/src/statics/icons/childIcons/SvcV-3b/346/234/215/345/212/241-/346/234/215/345/212/241/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  130. package/src/statics/icons/childIcons/SvcV-4 /346/234/215/345/212/241/345/212/237/350/203/275/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  131. package/src/statics/icons/childIcons/SvcV-4 /346/234/215/345/212/241/345/212/237/350/203/275/346/265/201/345/233/276@3x.png +0 -0
  132. package/src/statics/icons/childIcons/SvcV-4/346/234/215/345/212/241/345/212/237/350/203/275/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  133. package/src/statics/icons/childIcons/SvcV-5/344/275/234/346/210/230/346/264/273/345/212/250/345/210/260/346/234/215/345/212/241/345/217/257/350/277/275/350/270/252/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  134. package/src/statics/icons/childIcons/SvcV-6 /346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265@3x.png +0 -0
  135. package/src/statics/icons/childIcons/SvcV-6/346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  136. package/src/statics/icons/childIcons/SvcV-7 /346/234/215/345/212/241/345/205/270/345/236/213/345/272/246/351/207/217/347/237/251/351/230/265@3x.png +0 -0
  137. package/src/statics/icons/childIcons/SvcV-7/346/234/215/345/212/241/345/272/246/351/207/217/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  138. package/src/statics/icons/childIcons/SvcV-8 /346/234/215/345/212/241/346/274/224/350/277/233/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  139. package/src/statics/icons/childIcons/SvcV-8/346/234/215/345/212/241/346/274/224/350/277/233/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  140. package/src/statics/icons/childIcons/SvcV-9 /346/234/215/345/212/241/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/350/241/250@3x.png +0 -0
  141. package/src/statics/icons/childIcons/SvcV-9/346/234/215/345/212/241/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/345/214/205@3x.png +0 -0
  142. package/src/statics/icons/childIcons//344/275/223/347/263/273/346/236/266/346/236/204@3x.png +0 -0
  143. package/src/statics/icons/childIcons//344/275/234/346/210/230/350/247/206/350/247/222@3x.png +0 -0
  144. package/src/statics/icons/childIcons//345/205/250/346/231/257/350/247/206/350/247/222@3x.png +0 -0
  145. package/src/statics/icons/childIcons//345/205/254/345/217/270@3x.png +0 -0
  146. package/src/statics/icons/childIcons//345/215/217/350/256/256@3x.png +0 -0
  147. package/src/statics/icons/childIcons//345/215/217/350/256/256/345/261/202@3x.png +0 -0
  148. package/src/statics/icons/childIcons//345/215/217/350/256/256/346/240/210@3x.png +0 -0
  149. package/src/statics/icons/childIcons//345/221/275/344/273/244@3x.png +0 -0
  150. package/src/statics/icons/childIcons//346/210/230/347/225/245/346/246/202/345/277/265/350/241/250@3x.png +0 -0
  151. package/src/statics/icons/childIcons//346/216/247/345/210/266@3x.png +0 -0
  152. package/src/statics/icons/childIcons//346/224/257/346/214/201@3x.png +0 -0
  153. package/src/statics/icons/childIcons//346/225/260/346/215/256/344/277/241/346/201/257/350/247/206/350/247/222@3x.png +0 -0
  154. package/src/statics/icons/childIcons//346/234/215/345/212/241/350/247/206/350/247/222@3x.png +0 -0
  155. package/src/statics/icons/childIcons//346/240/207/345/207/206@3x.png +0 -0
  156. package/src/statics/icons/childIcons//346/240/207/345/207/206/350/247/206/350/247/222@3x.png +0 -0
  157. package/src/statics/icons/childIcons//347/263/273/347/273/237/350/247/206/350/247/222@3x.png +0 -0
  158. package/src/statics/icons/childIcons//350/203/275/345/212/233/350/247/206/350/247/222@3x.png +0 -0
  159. package/src/statics/icons/childIcons//351/241/271/347/233/256/350/247/206/350/247/222@3x.png +0 -0
  160. package/src/statics/icons/createMenu/down.png +0 -0
  161. package/src/statics/icons/createMenu/remove.png +0 -0
  162. package/src/statics/icons/createMenu/up.png +0 -0
  163. package/src/store/graphStore.ts +238 -45
  164. package/src/types/index.ts +87 -4
  165. package/src/utils/batchAutoExpand.ts +9 -10
  166. package/src/utils/containers.ts +72 -17
  167. package/src/utils/contextMenuUtils.ts +7 -7
  168. package/src/utils/dateUtils.ts +160 -0
  169. package/src/utils/diagram.ts +10 -8
  170. package/src/utils/drag.ts +6 -5
  171. package/src/utils/edgeUtils.ts +344 -427
  172. package/src/utils/edgeWorker.ts +471 -0
  173. package/src/utils/hittest.ts +37 -38
  174. package/src/utils/index.ts +3 -0
  175. package/src/utils/keyboardUtils.ts +5 -5
  176. package/src/utils/packageOutline.ts +96 -0
  177. package/src/utils/rafThrottle.ts +162 -0
  178. package/src/utils/workerManager.ts +335 -0
  179. package/src/view/graph.vue +47 -33
  180. /package/src/statics/icons/childIcons//346/210/230/347/225/{245@3x.png" → 245/345/261/202@3x.png"} +0 -0
@@ -11,7 +11,21 @@
11
11
  @model-type-property-id-click="clickModelTypePropertyIdButton" />
12
12
  </template>
13
13
  <!-- 命中容器的高亮矩形(虚线框) -->
14
- <div v-if="hoverRect" :class="[
14
+ <svg
15
+ v-if="hoverRect && hoverOutlineIsPackage"
16
+ :class="[
17
+ 'hover-container-outline-svg',
18
+ {
19
+ 'is-invalid': graphStore.hoverNestable === false,
20
+ 'is-valid': graphStore.hoverNestable === true,
21
+ },
22
+ ]"
23
+ :style="hoverPackageOutline.style"
24
+ :viewBox="`0 0 ${hoverPackageOutline.width} ${hoverPackageOutline.height}`"
25
+ >
26
+ <path class="outline-path" :d="hoverPackageOutline.path" />
27
+ </svg>
28
+ <div v-else-if="hoverRect" :class="[
15
29
  'hover-container-outline',
16
30
  {
17
31
  'is-invalid': graphStore.hoverNestable === false,
@@ -51,7 +65,16 @@
51
65
  </div>
52
66
 
53
67
  <!-- 高亮覆盖层 - 独立于 connect-layer,支持连线模式和拖拽模式 -->
54
- <div v-if="highlightOverlayBounds" class="highlight-overlay" :class="highlightOverlayColor" :style="{
68
+ <svg
69
+ v-if="highlightOverlayBounds && highlightOverlayIsPackage"
70
+ class="highlight-overlay-svg"
71
+ :class="highlightOverlayColor"
72
+ :style="highlightPackageOutline.style"
73
+ :viewBox="`0 0 ${highlightPackageOutline.width} ${highlightPackageOutline.height}`"
74
+ >
75
+ <path class="outline-path" :d="highlightPackageOutline.path" />
76
+ </svg>
77
+ <div v-else-if="highlightOverlayBounds" class="highlight-overlay" :class="highlightOverlayColor" :style="{
55
78
  left: highlightOverlayBounds.x + 'px',
56
79
  top: highlightOverlayBounds.y + 'px',
57
80
  width: highlightOverlayBounds.width + 'px',
@@ -84,6 +107,7 @@ import NameEditor from "./NameEditor/NameEditor.vue";
84
107
  // 工具:几何/命中/样式/拖拽
85
108
  import {
86
109
  toLocalPoint,
110
+ inBounds,
87
111
  getBounds,
88
112
  getDiagramRect,
89
113
  rectFromPoints,
@@ -95,7 +119,6 @@ import {
95
119
  } from "../utils/geom";
96
120
  import { pickTarget } from "../utils/hittest";
97
121
  import {
98
- adjustCanvasToFitAllShapes,
99
122
  actionButtonsStyle,
100
123
  getMarqueeStyle,
101
124
  getLayerStyle,
@@ -120,6 +143,11 @@ import { useNameEdit } from "../hooks/useNameEdit";
120
143
  import { guardOperate } from "../utils/license-guard";
121
144
  import { useResize } from "../hooks/useResize";
122
145
  import { useHighlight, type IHighlightUtils } from "../hooks/useHighlight";
146
+ import { createRAFThrottle, createRAFDebounce } from "../utils/rafThrottle";
147
+ import {
148
+ buildPackageOutlineOverlay,
149
+ PACKAGE_OUTLINE_PADDING,
150
+ } from "../utils/packageOutline";
123
151
 
124
152
  const props = defineProps<InteractionLayerProps>();
125
153
 
@@ -138,7 +166,7 @@ const cursorStyle = ref<"default" | "pointer">("default");
138
166
  const resizeGhostShadow = computed<Shape[]>(() => {
139
167
  const out: Shape[] = [];
140
168
  for (const id in groupGhost.value) {
141
- const s = graphStore.shapes.find((x) => x.id === id);
169
+ const s = graphStore.shapeMap.get(id);
142
170
  if (!s) continue;
143
171
  out.push({
144
172
  ...s,
@@ -152,11 +180,18 @@ const resizeGhostShadow = computed<Shape[]>(() => {
152
180
  const hoverRect = computed(() => {
153
181
  const id = graphStore.hoverContainerId;
154
182
  if (!id) return null;
155
- const s = graphStore.shapes.find((x) => x.id === id);
183
+ const s = graphStore.shapeMap.get(id);
156
184
  if (!s) return null;
157
185
  const b = getBounds(s);
158
186
  return { x: b.x, y: b.y, width: b.width, height: b.height };
159
187
  });
188
+
189
+ // 当前 hover 到的原始容器图元,用来判断是否需要切换成包轮廓覆盖层。
190
+ const hoverOutlineShape = computed(() => {
191
+ const id = graphStore.hoverContainerId;
192
+ if (!id) return null;
193
+ return graphStore.shapeMap.get(id) ?? null;
194
+ });
160
195
  // 把拖动缩放预览框合并,
161
196
  const allGhosts = computed<Shape[]>(() => {
162
197
  const byId = new Map<string, Shape>();
@@ -222,9 +257,10 @@ const { isResizing, groupGhost, startResize } = useResize(
222
257
 
223
258
  // 是否在画布内
224
259
  const isMouseInside = ref(false);
225
- // 记录最近一次 mousemove(用于 rAF 合并)
226
- let rafId: number | null = null;
227
- let latestEvt: MouseEvent | null = null;
260
+
261
+ // 创建 RAF 节流实例用于鼠标移动事件
262
+ const mouseMoveThrottle = createRAFThrottle();
263
+
228
264
  // 拖拽清理函数
229
265
  let offDrag: (() => void) | null = null;
230
266
 
@@ -244,33 +280,30 @@ const emitMouse = (evt: MouseEvent, inside: boolean) => {
244
280
  // 对外抛出
245
281
  eventBus.emit("canvas-mouse-move", payload);
246
282
  };
283
+
247
284
  // 鼠标进入画布
248
285
  const onMouseEnter = () => {
249
286
  isMouseInside.value = true;
250
287
  eventBus.emit("canvas-mouse-enter", { inside: true });
251
288
  };
289
+
252
290
  // 鼠标离开画布区域
253
291
  const onMouseLeave = () => {
254
292
  isMouseInside.value = false;
255
- // 停止 rAF
256
- if (rafId) cancelAnimationFrame(rafId);
257
- rafId = null;
258
- latestEvt = null;
293
+ // 取消待执行的 RAF
294
+ mouseMoveThrottle.cancel();
259
295
  // 通知外部隐藏坐标
260
296
  eventBus.emit("canvas-mouse-leave", { inside: false });
261
297
  };
262
- // 鼠标移动过程中
298
+
299
+ // 鼠标移动过程中 - 使用 RAF 节流优化
263
300
  const onMouseMove = (evt: MouseEvent) => {
264
301
  if (!isMouseInside.value) return;
265
- latestEvt = evt;
266
- // rAF 合并高频 mousemove
267
- if (rafId) return;
268
- rafId = requestAnimationFrame(() => {
269
- rafId = null;
302
+ // 使用 RAF 节流,同一帧内多次调用会合并为最后一次
303
+ mouseMoveThrottle.throttle((latestEvt: MouseEvent) => {
270
304
  if (!latestEvt) return;
271
305
  emitMouse(latestEvt, true);
272
- latestEvt = null;
273
- });
306
+ })(evt);
274
307
  };
275
308
 
276
309
  // 框选状态
@@ -306,10 +339,95 @@ const highlightUtils: IHighlightUtils = {
306
339
  // 保持兼容性:highlightedShape 计算属性
307
340
  const highlightedShape = computed(() => {
308
341
  if (!highlightedShapeId.value) return null;
309
- return graphStore.shapes.find(s => s.id === highlightedShapeId.value) || null;
342
+ return graphStore.shapeMap.get(highlightedShapeId.value) ?? null;
310
343
  });
344
+
345
+ // 包图元使用“文件夹轮廓”高亮,其他图元继续沿用默认矩形覆盖层。
346
+ const isPackageShape = (shape: Shape | null | undefined) => {
347
+ return !!shape?.shapeKey && !!props.packages?.includes(shape.shapeKey);
348
+ };
349
+
350
+ // 拖拽嵌套时,只有命中的容器是包图元才切换到 SVG 轮廓。
351
+ const hoverOutlineIsPackage = computed(() =>
352
+ isPackageShape(hoverOutlineShape.value),
353
+ );
354
+
355
+ // hover 覆盖层会额外向外扩一点,尽量保持和原矩形框接近的视觉反馈。
356
+ const hoverPackageOutline = computed(() =>
357
+ buildPackageOutlineOverlay({
358
+ bounds: hoverRect.value,
359
+ strokeWidth: 2,
360
+ padding: PACKAGE_OUTLINE_PADDING,
361
+ zIndex: 999,
362
+ }),
363
+ );
364
+
365
+ const highlightOverlayIsPackage = computed(() =>
366
+ isPackageShape(highlightedShape.value),
367
+ );
368
+
369
+ // 连线目标高亮复用同一套几何工具,只是描边更粗,且不额外外扩。
370
+ const highlightPackageOutline = computed(() =>
371
+ buildPackageOutlineOverlay({
372
+ bounds: highlightOverlayBounds.value,
373
+ strokeWidth: 3,
374
+ zIndex: 1001,
375
+ }),
376
+ );
377
+
378
+ const getCurrentTargetModels = () => {
379
+ if (connectMode.value === "action") {
380
+ return (
381
+ props.connectShapeData?.scenarioMenus?.find(
382
+ (menu) => menu.code === props.connectShapeData?.shapeKey
383
+ )?.targetModels ?? props.connectShapeData?.targetModels
384
+ );
385
+ }
386
+
387
+ return props.connectShapeData?.targetModels;
388
+ };
389
+
390
+ const resolveConnectTargetAtPoint = (pt: { x: number; y: number }) => {
391
+ const hit = pickTarget(graphStore.shapes, pt);
392
+
393
+ if (
394
+ ["shape", "pin"].includes(hit.kind) &&
395
+ hit.shape?.id &&
396
+ hit.shape.id !== props.connectShapeData?.sourceId
397
+ ) {
398
+ return hit.shape;
399
+ }
400
+
401
+ const hoveredShape = highlightedShape.value;
402
+ if (
403
+ !hoveredShape?.id ||
404
+ hoveredShape.id === props.connectShapeData?.sourceId
405
+ ) {
406
+ return null;
407
+ }
408
+
409
+ const bounds = getBounds(hoveredShape);
410
+ const minSide = Math.min(bounds.width, bounds.height);
411
+ const padding = minSide <= 30 ? 8 : minSide <= 40 ? 6 : 0;
412
+
413
+ if (
414
+ inBounds(pt, {
415
+ x: bounds.x - padding,
416
+ y: bounds.y - padding,
417
+ width: bounds.width + padding * 2,
418
+ height: bounds.height + padding * 2,
419
+ })
420
+ ) {
421
+ return hoveredShape;
422
+ }
423
+
424
+ return null;
425
+ };
426
+
311
427
  const sourceShape = ref<Shape | null>(null);
312
428
  const recordClickPoint = ref({ x: 0, y: 0 });
429
+ // 等待后端创建图元中,冻结连线预览
430
+ const pendingActionButton = ref(false);
313
431
 
314
432
  // 正在交互:缩放中 或 元素拖动中
315
433
  const isBusy = computed(
@@ -388,9 +506,9 @@ const onLayerClick = (evt: MouseEvent) => {
388
506
  }
389
507
  recordClickPoint.value = toLocalPoint(evt, layerRef.value);
390
508
  // 获取 sourceShape(先获取,确保存在)
391
- const foundSourceShape = graphStore.shapes.find(
392
- (shape) => shape.id === props.connectShapeData?.sourceId
393
- );
509
+ const foundSourceShape = props.connectShapeData?.sourceId
510
+ ? graphStore.shapeMap.get(props.connectShapeData.sourceId)
511
+ : undefined;
394
512
  if (!foundSourceShape) {
395
513
  // 如果找不到 sourceShape,不处理
396
514
  handleConnectLayerClick(evt);
@@ -404,11 +522,8 @@ const onLayerClick = (evt: MouseEvent) => {
404
522
  const clickX = localPoint.x;
405
523
  const clickY = localPoint.y;
406
524
 
407
- // 判断点击位置是否有图形
408
- const hasShapeAtPoint = EdgeUtils.isEndPointInShape(graphStore.shapes, {
409
- x: clickX,
410
- y: clickY,
411
- });
525
+ const clickedTargetShape = resolveConnectTargetAtPoint(localPoint);
526
+ const hasShapeAtPoint = !!clickedTargetShape;
412
527
 
413
528
  // 修改:无论是否在action模式下,只要在连接状态且点击空白处,都创建新图元
414
529
  if (!hasShapeAtPoint) {
@@ -465,9 +580,12 @@ const onLayerClick = (evt: MouseEvent) => {
465
580
  y: newShapeY,
466
581
  diagramId: diagramId,
467
582
  });
583
+ // 冻结连线预览,避免等待后端返回期间预览线跟着鼠标走
584
+ pendingActionButton.value = true;
585
+ showLine.value = false;
468
586
  return;
469
587
  } else {
470
- handleConnectLayerClick(evt);
588
+ handleConnectLayerClick(evt, clickedTargetShape, localPoint);
471
589
  return;
472
590
  }
473
591
  }
@@ -611,16 +729,14 @@ const onLayerMouseDown = (evt: MouseEvent) => {
611
729
  // 如果是 pin 类型,需要在移动过程中将“指针位置”校正为吸附后的指针坐标
612
730
  let targetPt = curr;
613
731
  if (ids.length === 1) {
614
- const draggedShape = graphStore.shapes.find(
615
- (x) => x.id === ids[0]
616
- );
732
+ const draggedShape = graphStore.shapeMap.get(ids[0]);
617
733
  if (
618
734
  draggedShape &&
619
735
  draggedShape.shapeType === "pin" &&
620
736
  draggedShape.parenShapeId
621
737
  ) {
622
- const parentShape = graphStore.shapes.find(
623
- (x) => x.id === draggedShape.parenShapeId
738
+ const parentShape = graphStore.shapeMap.get(
739
+ draggedShape.parenShapeId
624
740
  );
625
741
  if (parentShape) {
626
742
  // 使用移动专用的吸附方法:根据 dragOffset 计算应传入 moveDraggedShape 的指针坐标
@@ -683,14 +799,9 @@ const startMarquee = (anchor: { x: number; y: number }) => {
683
799
  //缓存 bounds,避免 move 中每次 getBounds(s)
684
800
  b: getBounds(s),
685
801
  }));
686
- // rAF 合并高频 move(只更新 marqueeRect,避免过多响应式刷新)
687
- let raf = 0;
802
+ // 创建 RAF 节流实例用于框选
803
+ const marqueeThrottle = createRAFThrottle();
688
804
  let latestPoint = anchorClamped;
689
- const updateRect = () => {
690
- raf = 0;
691
- // 根据“锚点 & 当前点”得到框选矩形
692
- marqueeRect.value = rectFromPoints(marqueeAnchor.value!, latestPoint);
693
- };
694
805
  // 拖拽生命周期
695
806
  offDrag?.();
696
807
  offDrag = null;
@@ -707,16 +818,16 @@ const startMarquee = (anchor: { x: number; y: number }) => {
707
818
  edges
708
819
  );
709
820
 
710
- // 根据“锚点 & 当前点”得到框选矩形(会自动处理反向拖拽)
711
- // rAF 合并更新,避免 mousemove 触发过多响应式刷新
712
- if (raf) return;
713
- raf = requestAnimationFrame(updateRect);
821
+ // 根据"锚点 & 当前点"得到框选矩形(会自动处理反向拖拽)
822
+ // 使用 RAF 节流更新,避免 mousemove 触发过多响应式刷新
823
+ marqueeThrottle.throttle(() => {
824
+ marqueeRect.value = rectFromPoints(marqueeAnchor.value!, latestPoint);
825
+ })();
714
826
  },
715
827
  // 结束框选,清理预览
716
828
  () => {
717
- // 结束时确保最后一次 rect 已更新
718
- if (raf) cancelAnimationFrame(raf);
719
- updateRect();
829
+ // 刷新最后一次更新
830
+ marqueeThrottle.flush();
720
831
 
721
832
  const rect = marqueeRect.value!;
722
833
  const right = rect.x + rect.width;
@@ -763,6 +874,10 @@ const isConnectAllowed = ref(false);
763
874
  // 处理右键点击事件
764
875
  const handleContextMenu = (event: MouseEvent) => {
765
876
  return guardOperate(async () => {
877
+ // 连线状态下不允许出现右键菜单
878
+ if (isConnecting.value) {
879
+ return;
880
+ }
766
881
  // 如果图元正在移动或缩放,则不显示菜单
767
882
  if (graphStore.isDragging || isResizing.value) {
768
883
  return;
@@ -795,14 +910,6 @@ const closeMenu = () => {
795
910
  contextMenuTarget.value = null;
796
911
  };
797
912
 
798
- watch(
799
- () => graphStore.shapes,
800
- () => {
801
- nextTick(adjustCanvasToFitAllShapes);
802
- },
803
- { deep: true, immediate: true }
804
- );
805
-
806
913
  // 监听图元状态
807
914
  watch(shouldCloseMenu, (shouldClose) => {
808
915
  if (shouldClose && showContextMenu.value) {
@@ -811,13 +918,13 @@ watch(shouldCloseMenu, (shouldClose) => {
811
918
  });
812
919
  watch(
813
920
  () => props.actionButtonShapeDataId,
814
- (newVal) => {
921
+ async (newVal) => {
815
922
  if (newVal) {
816
- const foundShape = graphStore.shapes.find((x) => x.id === newVal);
923
+ const foundShape = graphStore.shapeMap.get(newVal);
817
924
  if (foundShape) {
818
925
  // 连接 sourceShape 和新 shape
819
926
  if (sourceShape.value) {
820
- const connectionData = EdgeUtils.completeConnection(
927
+ const connectionData = await EdgeUtils.completeConnectionAsync(
821
928
  sourceShape.value,
822
929
  foundShape,
823
930
  { x: recordClickPoint.value.x, y: recordClickPoint.value.y },
@@ -851,40 +958,54 @@ watch(
851
958
  }
852
959
  graphStore.setConnectMode("connect");
853
960
  isConnecting.value = false;
961
+ pendingActionButton.value = false;
854
962
  clearHighlightTimeout();
963
+ } else {
964
+ // connectionData 为 null(如源和目标相同),也需要重置
965
+ pendingActionButton.value = false;
855
966
  }
967
+ } else {
968
+ pendingActionButton.value = false;
856
969
  }
970
+ } else {
971
+ pendingActionButton.value = false;
857
972
  }
858
973
  // 处理 actionButtonShapeData 的逻辑
859
974
  }
860
975
  }
861
976
  );
862
977
 
863
- // 鼠标移动事件处理
978
+ // 鼠标移动事件处理 - 使用 RAF 节流优化
864
979
  const handleMouseMove = (event: MouseEvent) => {
865
- const { clientX, clientY } = event;
866
- const localPoint = toLocalPoint(event, layerRef.value);
867
- // 使用工具类检查是否在画布内
868
- if (EdgeUtils.isWithinCanvas(clientX, clientY)) {
869
- mousePosition.value = { x: localPoint.x, y: localPoint.y };
980
+ // 使用 RAF 节流,同一帧内多次调用会合并为最后一次
981
+ connectMouseMoveThrottle.throttle((evt: MouseEvent) => {
982
+ const { clientX, clientY } = evt;
983
+ const localPoint = toLocalPoint(evt, layerRef.value);
984
+ // 使用工具类检查是否在画布内
985
+ if (EdgeUtils.isWithinCanvas(clientX, clientY)) {
986
+ mousePosition.value = { x: localPoint.x, y: localPoint.y };
870
987
 
871
- // 只有在连接状态下才显示线条
872
- if (isConnecting.value) {
873
- showLine.value = true;
874
- updateConnectPointToNearest(localPoint.x, localPoint.y);
875
- checkHoverTarget(localPoint.x, localPoint.y);
876
- }
877
- } else {
878
- if (isConnecting.value) {
879
- showLine.value = false;
988
+ // 只有在连接状态下才显示线条
989
+ if (isConnecting.value && !pendingActionButton.value) {
990
+ showLine.value = true;
991
+ updateConnectPointToNearest(localPoint.x, localPoint.y);
992
+ checkHoverTarget(localPoint.x, localPoint.y);
993
+ }
994
+ } else {
995
+ if (isConnecting.value) {
996
+ showLine.value = false;
997
+ }
998
+ highlightShape(null, false); // 使用highlightShape函数取消高亮,恢复原始样式
880
999
  }
881
- highlightShape(null, false); // 使用highlightShape函数取消高亮,恢复原始样式
882
- }
1000
+ })(event);
883
1001
  };
884
1002
 
885
1003
  // 用于跟踪上一次的hoverShape,避免重复发射事件
886
1004
  let lastHoverShapeId: string | null = null;
887
1005
 
1006
+ // 创建 RAF 节流实例用于连线时的鼠标移动
1007
+ const connectMouseMoveThrottle = createRAFThrottle();
1008
+
888
1009
  // 用于防抖 edge-check 事件和高亮,只有鼠标停留一段时间后才触发
889
1010
  let edgeCheckDebounceTimer: ReturnType<typeof setTimeout> | null = null;
890
1011
  const EDGE_CHECK_DEBOUNCE_DELAY = 150; // 150ms 防抖延迟
@@ -904,12 +1025,7 @@ const checkHoverTarget = (x: number, y: number) => {
904
1025
 
905
1026
  if (hoverShape) {
906
1027
  // 检查连接有效性
907
- let targetModels = props.connectShapeData?.targetModels;
908
- if (connectMode.value === "action") {
909
- targetModels = props.connectShapeData?.scenarioMenus?.find(
910
- (menu) => menu.code === props.connectShapeData?.shapeKey
911
- )?.targetModels;
912
- }
1028
+ const targetModels = getCurrentTargetModels();
913
1029
  let isAllowed = true;
914
1030
  if (
915
1031
  targetModels &&
@@ -921,8 +1037,8 @@ const checkHoverTarget = (x: number, y: number) => {
921
1037
  }
922
1038
  // 检查parenShapeId是否匹配(无论hoverShape是否改变都要检查)
923
1039
  if (props.connectShapeData?.sourceId) {
924
- const sourceShape = graphStore.shapes.find(
925
- (it) => it.id === props.connectShapeData?.sourceId
1040
+ const sourceShape = graphStore.shapeMap.get(
1041
+ props.connectShapeData.sourceId
926
1042
  );
927
1043
  if (
928
1044
  sourceShape &&
@@ -1003,15 +1119,14 @@ const checkHoverTarget = (x: number, y: number) => {
1003
1119
  const updateConnectPointToNearest = (mouseX: number, mouseY: number) => {
1004
1120
  if (!props.connectShapeData?.sourceId || !props.diagramBounds) return;
1005
1121
 
1006
- const sourceShape = graphStore.shapes.find(
1007
- (shape) => shape.id === props.connectShapeData?.sourceId
1008
- );
1122
+ const sourceShape = props.connectShapeData?.sourceId
1123
+ ? graphStore.shapeMap.get(props.connectShapeData.sourceId)
1124
+ : undefined;
1009
1125
 
1010
- // 使用工具类找到最近连接点
1126
+ // 使用同步版本,避免 Worker 异步延迟导致连线跟不上鼠标
1011
1127
  const nearestPoint = EdgeUtils.findNearestConnectPoint(
1012
1128
  { x: mouseX, y: mouseY },
1013
- sourceShape,
1014
- props.diagramBounds
1129
+ sourceShape
1015
1130
  );
1016
1131
 
1017
1132
  if (
@@ -1061,30 +1176,47 @@ watch(
1061
1176
  );
1062
1177
 
1063
1178
  // 处理连接层点击事件
1064
- const handleConnectLayerClick = (event: MouseEvent) => {
1065
- const localPoint = toLocalPoint(event, layerRef.value);
1066
-
1067
- const hit = pickTarget(graphStore.shapes, localPoint);
1179
+ const handleConnectLayerClick = (
1180
+ event: MouseEvent,
1181
+ resolvedShape?: Shape | null,
1182
+ localPointArg?: { x: number; y: number }
1183
+ ) => {
1184
+ const localPoint = localPointArg ?? toLocalPoint(event, layerRef.value);
1185
+ const clickedShape = resolvedShape ?? resolveConnectTargetAtPoint(localPoint);
1068
1186
 
1069
- if (
1070
- ["shape", "pin"].includes(hit.kind) &&
1071
- hit.shape?.id &&
1072
- props.connectShapeData?.sourceId &&
1073
- hit.shape?.id !== props.connectShapeData.sourceId
1074
- ) {
1187
+ if (clickedShape?.id && props.connectShapeData?.sourceId) {
1075
1188
  event.stopPropagation();
1076
- completeConnection(hit.shape, localPoint);
1189
+ completeConnection(clickedShape, localPoint);
1190
+ }
1191
+ };
1192
+
1193
+ const tryCompleteConnectionFromShapeClick = (shape: Shape) => {
1194
+ if (!isConnecting.value || !props.connectShapeData?.sourceId) {
1195
+ return false;
1196
+ }
1197
+
1198
+ if (!shape?.id || shape.id === props.connectShapeData.sourceId) {
1199
+ return false;
1077
1200
  }
1201
+
1202
+ const bounds = getBounds(shape);
1203
+ const clickPoint = {
1204
+ x: bounds.x + bounds.width / 2,
1205
+ y: bounds.y + bounds.height / 2,
1206
+ };
1207
+
1208
+ completeConnection(shape, clickPoint);
1209
+ return true;
1078
1210
  };
1079
1211
 
1080
1212
  // 完成连接
1081
- const completeConnection = (
1213
+ const completeConnection = async (
1082
1214
  clickedShape: Shape,
1083
1215
  clickPoint: { x: number; y: number }
1084
1216
  ) => {
1085
- const sourceShape = graphStore.shapes.find(
1086
- (shape: { id: string }) => shape.id === props.connectShapeData?.sourceId
1087
- );
1217
+ const sourceShape = props.connectShapeData?.sourceId
1218
+ ? graphStore.shapeMap.get(props.connectShapeData.sourceId)
1219
+ : undefined;
1088
1220
 
1089
1221
  // 如果高亮是红色的情况直接返回
1090
1222
  if (!isConnectAllowed.value) {
@@ -1110,7 +1242,7 @@ const completeConnection = (
1110
1242
  return;
1111
1243
  }
1112
1244
  // 检查目标图元类型是否符合targetModels要求
1113
- const targetModels = props.connectShapeData?.targetModels;
1245
+ const targetModels = getCurrentTargetModels();
1114
1246
  if (targetModels && Array.isArray(targetModels) && targetModels.length > 0) {
1115
1247
  const clickedShapeType = clickedShape.shapeKey || "";
1116
1248
  if (!targetModels.includes(clickedShapeType)) {
@@ -1123,13 +1255,15 @@ const completeConnection = (
1123
1255
  }
1124
1256
  }
1125
1257
 
1126
- // 检查是否已存在相同类型的边
1127
- const existingEdge = graphStore.shapes.find(
1128
- (shape: Shape) =>
1129
- shape.shapeType === "edge" &&
1130
- shape.sourceId === props.connectShapeData?.sourceId &&
1131
- shape.targetId === clickedShape.id &&
1132
- shape.shapeKey === props.connectShapeData?.shapeKey
1258
+ // 检查是否已存在相同类型的边(通过 edgesByNodeId 索引快速查找)
1259
+ const candidateEdges = props.connectShapeData?.sourceId
1260
+ ? (graphStore.edgesByNodeId.get(props.connectShapeData.sourceId) ?? [])
1261
+ : [];
1262
+ const existingEdge = candidateEdges.find(
1263
+ (edge) =>
1264
+ edge.sourceId === props.connectShapeData?.sourceId &&
1265
+ edge.targetId === clickedShape.id &&
1266
+ edge.shapeKey === props.connectShapeData?.shapeKey
1133
1267
  );
1134
1268
 
1135
1269
  // 如果边已存在,错误提示并返回
@@ -1143,7 +1277,7 @@ const completeConnection = (
1143
1277
  return;
1144
1278
  }
1145
1279
  // 使用工具类完成连接,传递当前的shapes列表以支持差异化路由
1146
- const connectionData = EdgeUtils.completeConnection(
1280
+ const connectionData = await EdgeUtils.completeConnectionAsync(
1147
1281
  sourceShape,
1148
1282
  clickedShape,
1149
1283
  clickPoint,
@@ -1190,9 +1324,9 @@ const handleMouseLeave = () => {
1190
1324
  // 初始化连接点位置
1191
1325
  const initializeConnectPoint = () => {
1192
1326
  if (props.connectShapeData?.sourceId && props.diagramBounds) {
1193
- const sourceShape = graphStore.shapes.find(
1194
- (shape) => shape.id === props.connectShapeData?.sourceId
1195
- );
1327
+ const sourceShape = props.connectShapeData?.sourceId
1328
+ ? graphStore.shapeMap.get(props.connectShapeData.sourceId)
1329
+ : undefined;
1196
1330
 
1197
1331
  // 使用工具类初始化连接点,传递当前鼠标位置和diagramBounds
1198
1332
  // 这样可以确保即使是第一次连线,也能计算出图元边界上的合适连接点,而不是使用中心点
@@ -1400,13 +1534,13 @@ const continueExternalCreateDrag = async (payload: {
1400
1534
  if (!externalCreateDragState.creatingId) return;
1401
1535
 
1402
1536
  let targetPt = pt;
1403
- const s = graphStore.shapes.find(
1404
- (x) => x.id === externalCreateDragState.creatingId
1537
+ const s = graphStore.shapeMap.get(
1538
+ externalCreateDragState.creatingId!
1405
1539
  );
1406
1540
  if (s && s.shapeType === "pin") {
1407
1541
  if (graphStore.hoverContainerId && graphStore.hoverNestable !== false) {
1408
- const parent = graphStore.shapes.find(
1409
- (x) => x.id === graphStore.hoverContainerId
1542
+ const parent = graphStore.shapeMap.get(
1543
+ graphStore.hoverContainerId
1410
1544
  );
1411
1545
  if (parent) {
1412
1546
  const { x: adjustedX, y: adjustedY } = snapPinToParentEdge(
@@ -1439,16 +1573,13 @@ const finishExternalCreateDrag = async (payload: {
1439
1573
  isInsideCanvasClient(payload.clientX, payload.clientY, layerRef.value)
1440
1574
  ) {
1441
1575
  let targetPt = pt;
1442
- const s0 = (graphStore.shapes || []).find(
1443
- (x: any) => x.id == externalCreateDragState.creatingId
1444
- ) as any;
1576
+ const s0: any = externalCreateDragState.creatingId
1577
+ ? graphStore.shapeMap.get(externalCreateDragState.creatingId)
1578
+ : undefined;
1445
1579
  // 推断这次 drop 的“候选父节点”
1446
1580
  let parent: Shape | null = null;
1447
1581
  if (graphStore.hoverContainerId && graphStore.hoverNestable !== false) {
1448
- parent =
1449
- (graphStore.shapes as any[]).find(
1450
- (x: any) => x.id === graphStore.hoverContainerId
1451
- ) || null;
1582
+ parent = graphStore.shapeMap.get(graphStore.hoverContainerId) ?? null;
1452
1583
  }
1453
1584
  // pin:松手瞬间就先算好最终吸附坐标
1454
1585
  if (s0 && s0.shapeType === "pin" && parent) {
@@ -1462,9 +1593,9 @@ const finishExternalCreateDrag = async (payload: {
1462
1593
 
1463
1594
  graphStore.moveDraggedShape(targetPt, { hitPointer: pt });
1464
1595
  await nextTick();
1465
- const s: any = (graphStore.shapes || []).find(
1466
- (x: any) => x.id == externalCreateDragState.creatingId
1467
- );
1596
+ const s: any = externalCreateDragState.creatingId
1597
+ ? graphStore.shapeMap.get(externalCreateDragState.creatingId)
1598
+ : undefined;
1468
1599
  if ((s && s.shapeType == "shape") || s.shapeType == "pin") {
1469
1600
  const pure = _.omit(s, ["inert"]);
1470
1601
  pure.bounds = {
@@ -1580,7 +1711,7 @@ const keyboardHandler = createKeyboardHandler({
1580
1711
  onCopy: () => {
1581
1712
  // 获取当前选中的图元
1582
1713
  const selectedShapes = graphStore.selectedIds
1583
- .map((id) => graphStore.shapes.find((s) => s.id === id))
1714
+ .map((id) => graphStore.shapeMap.get(id))
1584
1715
  .filter(Boolean) as Shape[];
1585
1716
 
1586
1717
  if (selectedShapes.length === 0) {
@@ -1593,7 +1724,7 @@ const keyboardHandler = createKeyboardHandler({
1593
1724
  onCut: () => {
1594
1725
  // 获取当前选中的图元
1595
1726
  const selectedShapes = graphStore.selectedIds
1596
- .map((id) => graphStore.shapes.find((s) => s.id === id))
1727
+ .map((id) => graphStore.shapeMap.get(id))
1597
1728
  .filter(Boolean) as Shape[];
1598
1729
 
1599
1730
  if (selectedShapes.length === 0) {
@@ -1643,32 +1774,57 @@ const flushMoveDraggedShape = () => {
1643
1774
  }
1644
1775
  };
1645
1776
 
1777
+ type InteractionCleanup = () => void;
1778
+
1779
+ const interactionCleanups: InteractionCleanup[] = [];
1780
+
1781
+ const registerWindowListener = <K extends keyof WindowEventMap>(
1782
+ event: K,
1783
+ handler: (event: WindowEventMap[K]) => void,
1784
+ ) => {
1785
+ window.addEventListener(event, handler as EventListener);
1786
+ interactionCleanups.push(() => window.removeEventListener(event, handler as EventListener));
1787
+ };
1788
+
1789
+ const registerDocumentListener = <K extends keyof DocumentEventMap>(
1790
+ event: K,
1791
+ handler: (event: DocumentEventMap[K]) => void,
1792
+ ) => {
1793
+ document.addEventListener(event, handler as EventListener);
1794
+ interactionCleanups.push(() => document.removeEventListener(event, handler as EventListener));
1795
+ };
1796
+
1797
+ const registerEventBusListener = (event: string, handler: (...args: any[]) => void) => {
1798
+ eventBus.on(event, handler);
1799
+ interactionCleanups.push(() => eventBus.off(event, handler));
1800
+ };
1801
+
1802
+ const handleSelectShapes = (ids: string[]) => {
1803
+ graphStore.clearSelection();
1804
+ graphStore.selectMany(ids);
1805
+ };
1806
+
1646
1807
  onMounted(() => {
1647
- window.addEventListener("keydown", keyboardHandler);
1808
+ registerWindowListener("keydown", keyboardHandler);
1648
1809
  // 添加连接层相关的事件监听
1649
1810
  if (props.connectShapeData) {
1650
- document.addEventListener("mousemove", handleMouseMove);
1651
- document.addEventListener("mouseleave", handleMouseLeave);
1811
+ registerDocumentListener("mousemove", handleMouseMove);
1812
+ registerDocumentListener("mouseleave", handleMouseLeave);
1652
1813
  initializeConnectPoint();
1653
1814
  }
1654
1815
 
1655
1816
  //拖动结束后更新情景菜单
1656
- eventBus.on("shape-drag-end-updateScenarioMenu", actionButtonsStyle);
1817
+ registerEventBusListener("shape-drag-end-updateScenarioMenu", actionButtonsStyle);
1657
1818
 
1658
1819
  // 监听选择图元事件
1659
- eventBus.on("select-shapes", (ids: string[]) => {
1660
- graphStore.clearSelection();
1661
- graphStore.selectMany(ids);
1662
- });
1820
+ registerEventBusListener("select-shapes", handleSelectShapes);
1663
1821
  });
1664
1822
  onUnmounted(() => {
1665
1823
  offDrag?.();
1824
+ while (interactionCleanups.length > 0) {
1825
+ interactionCleanups.pop()?.();
1826
+ }
1666
1827
  // 清理连接层相关的事件监听
1667
- document.removeEventListener("mousemove", handleMouseMove);
1668
- document.removeEventListener("mouseleave", handleMouseLeave);
1669
- window.removeEventListener("keydown", keyboardHandler);
1670
- eventBus.off("shape-drag-end-updateScenarioMenu", actionButtonsStyle);
1671
- if (rafId) cancelAnimationFrame(rafId);
1672
1828
  if (dragMoveRafId) cancelAnimationFrame(dragMoveRafId);
1673
1829
  dragMoveRafId = null;
1674
1830
  latestDragMove = null;
@@ -1677,6 +1833,7 @@ defineExpose({
1677
1833
  continueExternalCreateDrag,
1678
1834
  finishExternalCreateDrag,
1679
1835
  handleEdgeClick,
1836
+ tryCompleteConnectionFromShapeClick,
1680
1837
  getBoundingClientRect: () => layerRef.value?.getBoundingClientRect(),
1681
1838
  });
1682
1839
  </script>
@@ -1702,17 +1859,37 @@ defineExpose({
1702
1859
  top: 6px;
1703
1860
  }
1704
1861
 
1862
+ .hover-container-outline-svg {
1863
+ position: absolute;
1864
+ pointer-events: none;
1865
+ }
1866
+
1867
+ .hover-container-outline-svg .outline-path {
1868
+ fill: transparent;
1869
+ stroke-width: 2px;
1870
+ stroke-linejoin: round;
1871
+ }
1872
+
1705
1873
  /* 允许嵌套(后端 ok) */
1706
1874
  .hover-container-outline.is-valid {
1707
1875
  border: 2px solid #0000ff;
1708
1876
  }
1709
1877
 
1878
+ .hover-container-outline-svg.is-valid .outline-path {
1879
+ stroke: #0000ff;
1880
+ }
1881
+
1710
1882
  /* 不允许嵌套(后端 false) */
1711
1883
  .hover-container-outline.is-invalid {
1712
1884
  border: 2px solid #f1eded;
1713
1885
  background: rgba(240, 237, 237, 0.842);
1714
1886
  }
1715
1887
 
1888
+ .hover-container-outline-svg.is-invalid .outline-path {
1889
+ stroke: #f1eded;
1890
+ fill: rgba(240, 237, 237, 0.35);
1891
+ }
1892
+
1716
1893
  /* 删除了选择框、调整大小手柄和操作按钮相关的样式,这些样式已经移到了 SelectionBox 组件中 */
1717
1894
 
1718
1895
  .resize-ghost {
@@ -1768,11 +1945,30 @@ defineExpose({
1768
1945
  border-radius: 2px;
1769
1946
  }
1770
1947
 
1948
+ .highlight-overlay-svg {
1949
+ position: absolute;
1950
+ pointer-events: none;
1951
+ }
1952
+
1953
+ .highlight-overlay-svg .outline-path {
1954
+ fill: transparent;
1955
+ stroke-width: 3px;
1956
+ stroke-linejoin: round;
1957
+ }
1958
+
1771
1959
  .highlight-overlay.blue {
1772
1960
  border: 3px solid #1890ff;
1773
1961
  }
1774
1962
 
1963
+ .highlight-overlay-svg.blue .outline-path {
1964
+ stroke: #1890ff;
1965
+ }
1966
+
1775
1967
  .highlight-overlay.red {
1776
1968
  border: 3px solid #f56c6c;
1777
1969
  }
1970
+
1971
+ .highlight-overlay-svg.red .outline-path {
1972
+ stroke: #f56c6c;
1973
+ }
1778
1974
  </style>