renderer.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. import { RelationLineType, RelationType } from "@/enum";
  2. import { ColumnRelation, ProjectInfo, RemarkInfo, TableItemType, TopicAreaInfo } from "@/type";
  3. import { Graph } from "@antv/x6";
  4. const dasharrayMap = {
  5. // [RelationLineType.Dashdot]: "5 5,1 5",
  6. [RelationLineType.Dash]: "5,5",
  7. [RelationLineType.Solid]: "0",
  8. [RelationLineType.Dotted]: "1,5",
  9. }
  10. export const render = (graph: Graph, project: ProjectInfo) => {
  11. const { tables, relations, topicAreas, remarkInfos } = project;
  12. // 渲染表格
  13. const renderTable = (tableItem: TableItemType) => {
  14. graph.addNode({
  15. shape: "table-node",
  16. x: tableItem.table.style?.x || 100,
  17. y: tableItem.table.style?.y || 100,
  18. width: project.setting.tableWidth,
  19. height: 69,
  20. id: tableItem.table.id,
  21. data: tableItem,
  22. zIndex: 3,
  23. ports: {
  24. groups: {
  25. // 字段名前连接桩
  26. columnPort: {
  27. markup: [
  28. {
  29. tagName: "rect",
  30. selector: "rect",
  31. },
  32. {
  33. tagName: "circle",
  34. selector: "circle",
  35. },
  36. ],
  37. position: {
  38. name: "absolute",
  39. args: {
  40. x: 12,
  41. y: 42,
  42. },
  43. },
  44. },
  45. },
  46. },
  47. });
  48. };
  49. // 渲染主题区域
  50. const renderTopicArea = (topicArea: TopicAreaInfo) => {
  51. graph.addNode({
  52. shape: "topic-node",
  53. x: topicArea.style?.x || 100,
  54. y: topicArea.style?.y || 100,
  55. width: 200,
  56. height: 200,
  57. id: topicArea.id,
  58. data: topicArea,
  59. zIndex: 0,
  60. });
  61. };
  62. // 渲染备注
  63. const renderRemark = (remark: RemarkInfo) => {
  64. graph?.addNode({
  65. shape: "notice-node",
  66. x: remark.style?.x || 100,
  67. y: remark.style?.y || 100,
  68. width: 200,
  69. height: 200,
  70. id: remark.id,
  71. data: remark,
  72. zIndex: 1,
  73. });
  74. };
  75. // 渲染关系
  76. const renderRelationEdge = (relation: ColumnRelation) => {
  77. // 添加关系连线
  78. const relationEdge = graph?.addEdge({
  79. id: relation.id,
  80. router: {
  81. name: "er",
  82. args: {
  83. offset: "center",
  84. direction: "H",
  85. },
  86. },
  87. connector: { name: "rounded" },
  88. attrs: {
  89. line: {
  90. stroke: relation.style?.color || "#333",
  91. strokeWidth: relation.style?.width || 1,
  92. targetMarker: null,
  93. strokeDasharray: dasharrayMap[relation.style?.lineType as RelationLineType || RelationLineType.Solid]
  94. },
  95. },
  96. source: {
  97. cell: relation.primaryTable,
  98. port: relation.primaryKey + "_port2",
  99. anchor: "left",
  100. },
  101. target: {
  102. cell: relation.foreignTable,
  103. port: relation.foreignKey + "_port2",
  104. anchor: "left",
  105. },
  106. data: {
  107. type: "relation",
  108. },
  109. defaultLabel: {
  110. markup: [
  111. {
  112. tagName: "circle",
  113. selector: "bg",
  114. },
  115. {
  116. tagName: "text",
  117. selector: "txt",
  118. },
  119. ],
  120. attrs: {
  121. txt: {
  122. fill: "#fff",
  123. textAnchor: "middle",
  124. textVerticalAnchor: "middle",
  125. },
  126. bg: {
  127. ref: "txt",
  128. fill: "#333",
  129. r: 10,
  130. strokeWidth: 0,
  131. },
  132. },
  133. },
  134. });
  135. if (project.setting.showRelation) {
  136. relationEdge?.appendLabel({
  137. attrs: {
  138. txt: {
  139. text: relation.relationType === RelationType.OneToOne ||
  140. relation.relationType === RelationType.OneToMany
  141. ? "1"
  142. : "n",
  143. },
  144. bg: {
  145. fill: relation.style?.color || "#333",
  146. }
  147. },
  148. position: {
  149. distance: 25,
  150. },
  151. });
  152. relationEdge?.appendLabel({
  153. attrs: {
  154. txt: {
  155. text: relation.relationType === RelationType.OneToMany
  156. ? "n"
  157. : "1",
  158. },
  159. bg: {
  160. fill: relation.style?.color || "#333",
  161. }
  162. },
  163. position: {
  164. distance: -25,
  165. },
  166. });
  167. }
  168. };
  169. const cells = graph.getCells();
  170. const allIds = [
  171. ...tables.map((table) => table.table.id),
  172. ...topicAreas.map((topicArea) => topicArea.id),
  173. ...remarkInfos.map((remark) => remark.id),
  174. ...relations.map((relation) => relation.id),
  175. ];
  176. // 移除空数据节点
  177. cells.forEach((cell) => {
  178. if (!allIds.includes(cell.id)) {
  179. cell.remove();
  180. }
  181. });
  182. tables.forEach((tableItem) => {
  183. if (!graph.getCellById(tableItem.table.id)) {
  184. renderTable(tableItem);
  185. } else {
  186. const cell = graph.getCellById(tableItem.table.id);
  187. if (cell?.isNode()) {
  188. cell.setSize(project.setting.tableWidth, cell.size().height);
  189. cell.setPosition(tableItem.table.style?.x, tableItem.table.style?.y);
  190. cell.setData(tableItem);
  191. }
  192. }
  193. });
  194. topicAreas.forEach((topicArea) => {
  195. if (!graph.getCellById(topicArea.id)) {
  196. renderTopicArea(topicArea);
  197. } else {
  198. const cell = graph.getCellById(topicArea.id);
  199. if (cell?.isNode()) {
  200. cell.setData(topicArea);
  201. cell.setPosition(topicArea.style?.x, topicArea.style?.y);
  202. }
  203. }
  204. });
  205. remarkInfos.forEach((remark) => {
  206. if (!graph.getCellById(remark.id)) {
  207. renderRemark(remark);
  208. } else {
  209. const cell = graph.getCellById(remark.id);
  210. if (cell?.isNode()) {
  211. cell.setData(remark);
  212. cell.setPosition(remark.style?.x, remark.style?.y);
  213. }
  214. }
  215. });
  216. relations.forEach((relation) => {
  217. if (!graph.getCellById(relation.id)) {
  218. renderRelationEdge(relation);
  219. } else {
  220. const relationEdge = graph.getCellById(relation.id);
  221. if (relationEdge.isEdge()) {
  222. if (project.setting.showRelation) {
  223. // 更新标签
  224. relationEdge.setLabelAt(0, {
  225. attrs: {
  226. txt: {
  227. text:
  228. relation.relationType === RelationType.OneToOne ||
  229. relation.relationType === RelationType.OneToMany
  230. ? "1"
  231. : "n",
  232. },
  233. bg: {
  234. fill: relation.style?.color || "#333",
  235. }
  236. },
  237. position: {
  238. distance: 25,
  239. },
  240. });
  241. relationEdge.setLabelAt(1, {
  242. attrs: {
  243. txt: {
  244. text:
  245. relation.relationType === RelationType.OneToMany
  246. ? "n"
  247. : "1",
  248. },
  249. bg: {
  250. fill: relation.style?.color || "#333",
  251. }
  252. },
  253. position: {
  254. distance: -25,
  255. },
  256. });
  257. } else {
  258. relationEdge.setLabels([]);
  259. }
  260. relationEdge.setAttrs({
  261. line: {
  262. stroke: relation.style?.color || "#333",
  263. strokeWidth: relation.style?.width || 1,
  264. strokeDasharray: dasharrayMap[relation.style?.lineType as RelationLineType || RelationLineType.Solid]
  265. },
  266. });
  267. }
  268. }
  269. });
  270. };